diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000000..61534bd0f6 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,7 @@ +[target.riscv64gc-unknown-linux-gnu] +linker = "riscv64-linux-gnu-gcc" +runner = "qemu-riscv64 -L /usr/riscv64-linux-gnu/" + +[target.aarch64-unknown-linux-gnu] +linker = "aarch64-linux-gnu-gcc" +runner = "qemu-aarch64 -L /usr/aarch64-linux-gnu/" diff --git a/.github/cross-linux-riscv64/Dockerfile b/.github/cross-linux-riscv64/Dockerfile index 94d091f3a6..887dcc6997 100644 --- a/.github/cross-linux-riscv64/Dockerfile +++ b/.github/cross-linux-riscv64/Dockerfile @@ -28,7 +28,7 @@ RUN apt-get update && \ # install rust tools RUN curl --proto "=https" --tlsv1.2 --retry 3 -sSfL https://sh.rustup.rs | sh -s -- -y ENV PATH="/root/.cargo/bin:${PATH}" -RUN rustup -v toolchain install 1.84 +RUN rustup -v toolchain install 1.90 # add docker the manual way COPY install_docker.sh / RUN /install_docker.sh @@ -61,7 +61,10 @@ ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER="$CROSS_TOOLCHAIN_PREFIX"gcc RUST_TEST_THREADS=1 \ PKG_CONFIG_PATH="/usr/lib/riscv64-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}" -RUN rustup target add riscv64gc-unknown-linux-gnu --toolchain 1.84-x86_64-unknown-linux-gnu +RUN rustup target add riscv64gc-unknown-linux-gnu --toolchain 1.90-x86_64-unknown-linux-gnu + +# quickly install cargo nextest by using pre-built binary +RUN curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin #compile libssl-dev for riscv64! COPY build_openssl.sh / diff --git a/.github/workflows/benchmark.yaml b/.github/workflows/benchmark.yaml index d1843c3204..d483b2365d 100644 --- a/.github/workflows/benchmark.yaml +++ b/.github/workflows/benchmark.yaml @@ -7,7 +7,7 @@ on: env: CARGO_REGISTRIES_CRATES_IO_PROTOCOL: git - MSRV: "1.84" + MSRV: "1.90" jobs: run_benchmark: @@ -24,7 +24,7 @@ jobs: SCCACHE_AZURE_BLOB_CONTAINER: wasmerstoragesccacheblob SCCACHE_AZURE_CONNECTION_STRING: ${{ secrets.SCCACHE_AZURE_CONNECTION_STRING }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ab546fa51e..911fc2587c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,7 @@ name: Builds env: RUST_BACKTRACE: 1 CARGO_REGISTRIES_CRATES_IO_PROTOCOL: git - MSRV: "1.84" + MSRV: "1.90" on: push: @@ -51,10 +51,8 @@ jobs: - build: linux-arm64 os: ubuntu-22.04-arm artifact_name: "wasmer-linux-aarch64" - #llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-linux-aarch64.tar.xz" + #llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-linux-aarch64.tar.xz" cross_compilation_artifact_name: "cross_compiled_from_linux" - use_sccache: false - use_rustcache: false build_wasm: true enable_llvm: false enable_v8: false @@ -63,32 +61,29 @@ jobs: - build: linux-x64 os: ubuntu-22.04 artifact_name: "wasmer-linux-amd64" - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-linux-amd64.tar.xz" + llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-linux-amd64.tar.xz" cross_compilation_artifact_name: "cross_compiled_from_linux" - use_sccache: false build_wasm: true enable_llvm: true enable_v8: true enable_wasmi: true enable_wamr: true - build: macos-x64 - os: macos-13 - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-amd64.tar.xz" + os: macos-15-intel + llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-darwin-amd64.tar.xz" artifact_name: "wasmer-darwin-amd64" cross_compilation_artifact_name: "cross_compiled_from_mac" - use_sccache: false build_wasm: false enable_llvm: true enable_v8: true enable_wasmi: true enable_wamr: true - build: macos-arm64 - os: macos-14 + os: depot-macos-14 target: aarch64-apple-darwin artifact_name: "wasmer-darwin-arm64" - use_sccache: false build_wasm: false - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-aarch64.tar.xz" + llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-darwin-aarch64.tar.xz" enable_llvm: true enable_v8: true enable_wasmi: true @@ -96,10 +91,9 @@ jobs: - build: windows-x64 os: windows-2022 artifact_name: "wasmer-windows-amd64" - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-windows-amd64.tar.xz" + llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-windows-amd64.tar.xz" cross_compilation_artifact_name: "cross_compiled_from_win" build_wasm: false - use_sccache: false enable_llvm: true enable_v8: false enable_wasmi: true @@ -115,18 +109,17 @@ jobs: # enable_wasmi: true # enable_wamr: false - container: ${{ matrix.container }} env: SCCACHE_AZURE_BLOB_CONTAINER: wasmerstoragesccacheblob SCCACHE_AZURE_CONNECTION_STRING: ${{ secrets.SCCACHE_AZURE_CONNECTION_STRING }} TARGET: ${{ matrix.target }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Set up base deps on musl if: startsWith(matrix.build, 'linux-musl-x64') run: | - apk add bash mold make curl cmake ninja clang18 zstd-static llvm18-dev clang18-static llvm18-static ncurses-static zlib-static libxml2-dev libxml2-static xz-dev xz-static xz-libs libc++-dev libc++-static - ln -s /usr/bin/clang-18 /usr/bin/clang + apk add bash mold make curl cmake ninja clang21 zstd-static llvm21-dev clang21-static llvm21-static ncurses-static zlib-static libxml2-dev libxml2-static xz-dev xz-static xz-libs libc++-dev libc++-static + ln -s /usr/bin/clang-21 /usr/bin/clang - name: Install Linux tools if: startsWith(matrix.build, 'linux-x64') run: | @@ -162,11 +155,9 @@ jobs: uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ env.MSRV }} - target: ${{ matrix.target }} - - uses: Swatinem/rust-cache@v2 - if: ${{ matrix.use_sccache != true && matrix.use_rustcache != false }} - - name: Install LLVM (macOS Apple Silicon) - if: matrix.os == 'macos-13' && !matrix.llvm_url + target: ${{ matrix.target }} + - name: Install LLVM (macOS Intel) + if: matrix.os == 'macos-15-intel' && !matrix.llvm_url run: | brew install llvm - name: Install LLVM @@ -185,14 +176,14 @@ jobs: shell: bash run: | LLVM_DIR=$(pwd)/${{ env.LLVM_DIR }} - echo LLVM_SYS_180_PREFIX="${LLVM_DIR}" >> $GITHUB_ENV + echo LLVM_SYS_211_PREFIX="${LLVM_DIR}" >> $GITHUB_ENV echo LLVM_ENABLE=1 >> $GITHUB_ENV env: LLVM_DIR: .llvm - name: Add `brew` libraries (Apple Silicon) run: | echo "RUSTFLAGS=-L/opt/homebrew/lib" >> $GITHUB_ENV - if: matrix.os == 'macos-14' + if: matrix.os == 'macos-14' || matrix.os == 'depot-macos-14' - name: Set up dependencies for Mac OS run: | brew install automake @@ -206,18 +197,6 @@ jobs: ~/.cargo/registry ~/.cargo/git key: ${{ matrix.build }}-${{ matrix.target }}-cargo-${{ hashFiles('Cargo.lock') }}-v1 - - uses: actions/cache@v4 - if: matrix.use_sccache - with: - path: ${{ runner.tool_cache }}/cargo-sccache - key: ${{ matrix.build }}-${{ matrix.target }}-sccache-bin-${{ env.CARGO_SCCACHE_VERSION }}-v1 - - name: Install sccache - if: matrix.use_sccache - run: | - if [ ! -f '${{ runner.tool_cache }}/cargo-sccache/bin/sccache' ]; then - cargo install sccache --no-default-features --features=dist-client,azure --root '${{ runner.tool_cache }}/cargo-sccache' - fi - shell: bash - name: Setup Rust target run: | mkdir -p .cargo @@ -226,42 +205,14 @@ jobs: target = "${{ matrix.target }}" EOF if: matrix.target - - name: Set sccache port - if: matrix.use_sccache && matrix.random_sccache_port - run: | - netstat -aln | awk ' - $6 == "LISTEN" { - if ($4 ~ "[.:][0-9]+$") { - n = split($4, a, /[:.]/); - port = a[n]; - p[port] = 1 - } - } - END { - for (i = 3000; i < 65000 && p[i]; i++){}; - if (i == 65000) {exit 1}; - print "SCCACHE_SERVER_PORT=" i - } - ' >> $GITHUB_ENV - # echo "SCCACHE_SERVER_PORT=9000" - echo "Setting random sccache port to: $SCCACHE_SERVER_PORT" - shell: bash - - name: Start sccache - if: matrix.use_sccache - run: | - chmod +x '${{ runner.tool_cache }}/cargo-sccache/bin/sccache' - '${{ runner.tool_cache }}/cargo-sccache/bin/sccache' --start-server - '${{ runner.tool_cache }}/cargo-sccache/bin/sccache' -s - echo 'RUSTC_WRAPPER=${{ runner.tool_cache }}/cargo-sccache/bin/sccache' >> $GITHUB_ENV - shell: bash - name: Build C API headless shell: bash run: | - LLVM_CONFIG_PATH=/usr/bin/llvm-config-18 make package-capi-headless + LLVM_CONFIG_PATH=/usr/bin/llvm-config-21 make package-capi-headless - name: Build C API shell: bash run: | - LLVM_CONFIG_PATH=/usr/bin/llvm-config-18 make build-capi + LLVM_CONFIG_PATH=/usr/bin/llvm-config-21 make build-capi - name: Build Wasmer binary if: ${{ !startsWith(matrix.build, 'linux-x64') && !startsWith(matrix.build, 'linux-musl') }} shell: bash @@ -286,9 +237,9 @@ jobs: run: | echo "#!/bin/bash" >> /usr/bin/llvm-config echo 'if [ "$1" = "--libs" ]; then' >> /usr/bin/llvm-config - echo 'llvm-config-18 "$@" "--link-static"' >> /usr/bin/llvm-config + echo 'llvm-config-21 "$@" "--link-static"' >> /usr/bin/llvm-config echo "else" >> /usr/bin/llvm-config - echo 'llvm-config-18 "$@"' >> /usr/bin/llvm-config + echo 'llvm-config-21 "$@"' >> /usr/bin/llvm-config echo 'fi' >> /usr/bin/llvm-config cat /usr/bin/llvm-config chmod +x /usr/bin/llvm-config @@ -341,7 +292,7 @@ jobs: if: github.event_name != 'pull_request' || startsWith(github.head_ref, 'release-') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install Windows-GNU linker shell: bash run: | @@ -408,9 +359,9 @@ jobs: darwin_aarch64_jsc: name: macOS aarch64 (JSC) if: github.event_name != 'pull_request' || startsWith(github.head_ref, 'release-') - runs-on: macos-13 + runs-on: depot-macos-14 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable with: target: aarch64-apple-darwin @@ -442,9 +393,9 @@ jobs: darwin_x86_64_jsc: name: macOS x86_64 (JSC) if: github.event_name != 'pull_request' || startsWith(github.head_ref, 'release-') - runs-on: macos-13 + runs-on: macos-15-intel steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable with: target: x86_64-apple-darwin @@ -474,7 +425,7 @@ jobs: if: github.event_name != 'pull_request' || startsWith(github.head_ref, 'release-') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable with: target: riscv64gc-unknown-linux-gnu @@ -483,6 +434,15 @@ jobs: docker build -t wasmer/riscv64 ${GITHUB_WORKSPACE}/.github/cross-linux-riscv64/ env: CROSS_DOCKER_IN_DOCKER: true + - name: "Run wast test suite for all compilers" + run: test-stage-0-wast + env: + CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/riscv64:latest cargo + CROSS_DOCKER_IN_DOCKER: true + CARGO_TARGET: riscv64gc-unknown-linux-gnu + PKG_CONFIG_PATH: /usr/lib/riscv64-linux-gnu/pkgconfig + PKG_CONFIG_ALLOW_CROSS: true + ENABLE_LLVM: 0 - name: Build Wasmer binary run: | make build-wasmer diff --git a/.github/workflows/cache-bucket-cleanup.yaml b/.github/workflows/cache-bucket-cleanup.yaml index 224a2a94b4..d2baaf2a41 100644 --- a/.github/workflows/cache-bucket-cleanup.yaml +++ b/.github/workflows/cache-bucket-cleanup.yaml @@ -18,7 +18,7 @@ jobs: - name: Install boto3 library run: pip install boto3 - name: Clone repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Run cleanup env: AWS_ENDPOINT: https://1541b1e8a3fc6ad155ce67ef38899700.r2.cloudflarestorage.com diff --git a/.github/workflows/check-public-api.yaml b/.github/workflows/check-public-api.yaml index 06d421295c..b8119003be 100644 --- a/.github/workflows/check-public-api.yaml +++ b/.github/workflows/check-public-api.yaml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 diff --git a/.github/workflows/cifuzz.yaml b/.github/workflows/cifuzz.yaml deleted file mode 100644 index ef1b9dfc38..0000000000 --- a/.github/workflows/cifuzz.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# -# [todo] xdoardo (2024/10/17): -# -# We updated our MSRV and llvm, so we need to open a pr here -# https://github.com/google/oss-fuzz/blob/fb88de8bd2d220662271aabbe19427dc24134bf6/projects/wasmer/build.sh -# before re-enabling this. -# -# -# name: CIFuzz -# on: [pull_request] -# jobs: -# Fuzzing: -# runs-on: ubuntu-latest -# steps: -# - name: Build Fuzzers -# id: build -# uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master -# with: -# oss-fuzz-project-name: 'wasmer' -# language: rust -# - name: Run Fuzzers -# uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master -# with: -# oss-fuzz-project-name: 'wasmer' -# language: rust -# fuzz-seconds: 300 -# - name: Upload Crash -# uses: actions/upload-artifact@v4 -# if: failure() && steps.build.outcome == 'success' -# with: -# name: artifacts -# path: ./out/artifacts diff --git a/.github/workflows/cloudcompiler.yaml b/.github/workflows/cloudcompiler.yaml index 3ab284dd67..535efd1dd8 100644 --- a/.github/workflows/cloudcompiler.yaml +++ b/.github/workflows/cloudcompiler.yaml @@ -2,7 +2,7 @@ name: Release cloudcompiler.wasm env: RUST_BACKTRACE: 1 - MSRV: "1.84" + MSRV: "1.90" on: push: @@ -16,14 +16,13 @@ jobs: name: Set up runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 0 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ env.MSRV }} - target: ${{ matrix.target }} - name: Install wasm32-wasip1 target shell: bash run: | diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 6dc04948f3..33a9b2d361 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -8,14 +8,14 @@ on: - "lib/**" env: - MSRV: "1.84" + MSRV: "1.90" jobs: documentation: name: Documentation runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: @@ -27,10 +27,10 @@ jobs: mkdir ${{ env.LLVM_DIR }} tar xf llvm.tar.xz --strip-components=1 -C ${{ env.LLVM_DIR }} echo "${{ env.LLVM_DIR }}/bin" >> $GITHUB_PATH - echo "LLVM_SYS_180_PREFIX=${{ env.LLVM_DIR }}" >> $GITHUB_ENV + echo "LLVM_SYS_211_PREFIX=${{ env.LLVM_DIR }}" >> $GITHUB_ENV env: - LLVM_DIR: ${{ github.workspace }}/llvm-18 - LLVM_URL: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-linux-amd64.tar.xz" + LLVM_DIR: ${{ github.workspace }}/llvm-21 + LLVM_URL: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-linux-amd64.tar.xz" - name: Build & package documentation run: make package-docs - name: Publish documentation diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c75a37cce8..e6d1922ff2 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -24,10 +24,11 @@ env: # Rust, but it's not stable on 1.69 yet. By explicitly setting the protocol we # can override that behaviour CARGO_REGISTRIES_CRATES_IO_PROTOCOL: git - MSRV: "1.84" + MSRV: "1.90" NEXTEST_PROFILE: "ci" RUSTUP_WINDOWS_PATH_ADD_BIN: 1 WASI_SDK_VERSION: "22" + S3_CACHE_VERSION: "3" jobs: setup: @@ -52,30 +53,32 @@ jobs: name: Code lint runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ env.MSRV }} components: rustfmt, clippy + targets: wasm32-unknown-unknown - name: Install libtinfo shell: bash run: | sudo apt install -y libtinfo5 - name: Install LLVM (Linux) run: | - curl --proto '=https' --tlsv1.2 -sSf https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-linux-amd64.tar.xz -L -o /opt/llvm.tar.xz - mkdir -p /opt/llvm-18 - tar xf /opt/llvm.tar.xz --strip-components=1 -C /opt/llvm-18 - echo '/opt/llvm-18/bin' >> $GITHUB_PATH - echo 'LLVM_SYS_180_PREFIX=/opt/llvm-18' >> $GITHUB_ENV + curl --proto '=https' --tlsv1.2 -sSf https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-linux-amd64.tar.xz -L -o /opt/llvm.tar.xz + mkdir -p /opt/llvm-21 + tar xf /opt/llvm.tar.xz --strip-components=1 -C /opt/llvm-21 + echo '/opt/llvm-21/bin' >> $GITHUB_PATH + echo 'LLVM_SYS_211_PREFIX=/opt/llvm-21' >> $GITHUB_ENV - name: Cache + # TODO: v3 is unable to Restore the cache for some reason uses: whywaita/actions-cache-s3@v2 with: path: | ~/.cargo/* ./target/* - key: r22-${{ github.repository }}-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}-wasmer-make-lint-linux-x64 + key: cache-v${{ env.S3_CACHE_VERSION }}-${{ github.repository }}-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}-wasmer-make-lint-linux-x64 aws-s3-bucket: wasmer-rust-artifacts-cache aws-access-key-id: ${{ secrets.CLOUDFLARE_ARTIFACTS_CACHE_ACCESS_TOKEN }} aws-secret-access-key: ${{ secrets.CLOUDFLARE_ARTIFACTS_CACHE_ACCESS_KEY }} @@ -88,6 +91,7 @@ jobs: ENABLE_CRANELIFT: "1" ENABLE_LLVM: "1" ENABLE_SINGLEPASS: "1" + - run: make lint-js - name: Assert no files have changed run: | git status @@ -97,16 +101,16 @@ jobs: name: cargo-deny runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: EmbarkStudios/cargo-deny-action@v2 with: log-level: error test_nodejs: - name: Test on NodeJS + name: NodeJS runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: @@ -123,10 +127,10 @@ jobs: make test-js test_wasi_fyi: - name: Test wasi-fyi + name: Wasi-fyi runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: @@ -135,16 +139,16 @@ jobs: - name: Install wasm-pack run: | curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - - name: Install LLVM 18 + - name: Install LLVM 21 run: | - curl --proto '=https' --tlsv1.2 -sSf https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-linux-amd64.tar.xz -L -o llvm.tar.xz + curl --proto '=https' --tlsv1.2 -sSf https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-linux-amd64.tar.xz -L -o llvm.tar.xz LLVM_DIR=$(pwd)/${{ env.LLVM_DIR }} mkdir ${LLVM_DIR} tar xf llvm.tar.xz --strip-components=1 -C ${LLVM_DIR} echo "ENABLE_LLVM=1" >> $GITHUB_ENV echo "${LLVM_DIR}/bin" >> $GITHUB_PATH echo "${LLVM_DIR}/usr/bin" >> $GITHUB_PATH - echo "LLVM_SYS_180_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV + echo "LLVM_SYS_211_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV env: LLVM_DIR: .llvm - name: make test-wasi-fyi @@ -157,16 +161,15 @@ jobs: # make test-js-core test_wasix: - name: Test WASIX + name: WASIX runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ env.MSRV }} - name: Install Tools - # note: llvm-19 for building wasix-libc, llvm-18 later for building wasmer run: | sudo apt-get update sudo apt-get install -y git make lld curl @@ -190,14 +193,15 @@ jobs: run: | export RUST_LOG=wasixcc=trace export GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} - rustup toolchain install 1.89 --profile minimal --no-self-update - cargo +1.89 install wasixcc -F bin + rustup toolchain install 1.90 --profile minimal --no-self-update + cargo +1.90 install wasixcc -F bin mkdir wasixcc-install wasixcc --install-executables ./wasixcc-install echo "$(pwd)/wasixcc-install" >> $GITHUB_PATH mkdir -p ~/.wasixcc/llvm mkdir -p ~/.wasixcc/sysroot - wasixcc --download-all + wasixcc --download-sysroot v2025-11-06.1 + wasixcc --download-llvm - name: Tool versions run: | @@ -205,16 +209,16 @@ jobs: echo "llvm version: $(wasixcc -- --version)" echo "wasm-opt version: $(wasm-opt --version)" - - name: Install LLVM 18 (for building Wasmer) + - name: Install LLVM 21 (for building Wasmer) run: | - curl --proto '=https' --tlsv1.2 -sSf https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-linux-amd64.tar.xz -L -o llvm.tar.xz + curl --proto '=https' --tlsv1.2 -sSf https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-linux-amd64.tar.xz -L -o llvm.tar.xz LLVM_DIR=$(pwd)/${{ env.LLVM_DIR }} mkdir ${LLVM_DIR} tar xf llvm.tar.xz --strip-components=1 -C ${LLVM_DIR} echo "ENABLE_LLVM=1" >> $GITHUB_ENV echo "${LLVM_DIR}/bin" >> $GITHUB_PATH echo "${LLVM_DIR}/usr/bin" >> $GITHUB_PATH - echo "LLVM_SYS_180_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV + echo "LLVM_SYS_211_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV env: LLVM_DIR: .llvm @@ -222,36 +226,31 @@ jobs: run: | WASI_SDK=~/wasi-sdk WASIX_SYSROOT=$(pwd)/sysroot/wasix-sysroot/sysroot make test-wasix - test_wasm_build: - name: Test wasm build - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v5 - - name: rustup target add wasm32-wasip1 - run: rustup target add wasm32-wasip1 - - name: make build-wasmer-wasm - run: make build-wasmer-wasm - test_build_jsc: - name: Test JSC build + name: JSC runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ env.MSRV }} target: x86_64-unknown-linux-gnu + components: clippy - name: Install NodeJS uses: actions/setup-node@v4 with: node-version: 16 - name: Install libjavascriptcoregtk-4.0-dev run: sudo apt update && sudo apt install -y libjavascriptcoregtk-4.0-dev + + - name: lint jsc + run: make lint-jsc + - name: make build-wasmer-jsc run: make build-wasmer-jsc test_interpreter_api: - name: ${{ matrix.build-what.name }} on ${{ matrix.metadata.build }} + name: ${{ matrix.build-what.name }} - ${{ matrix.metadata.build }} runs-on: ${{ matrix.metadata.os }} strategy: fail-fast: false @@ -260,23 +259,26 @@ jobs: [ { key: wamr, + lint-cmd: "make lint-wamr", build-cmd: "make test-wamr-api", - name: "Test API for wamr feature", + name: "API (wamr)", }, { key: wasmi, + lint-cmd: "make lint-wasmi", build-cmd: "make test-wasmi-api", - name: "Test API for wasmi feature", + name: "API (wasmi)", }, { key: v8, + lint-cmd: "make lint-v8", build-cmd: "make test-v8-api", - name: "Test API for v8 feature", + name: "API (v8)", }, ] metadata: [ { build: linux-x64, os: ubuntu-22.04 }, - { build: macos-arm, os: macos-14 }, + { build: macos-arm, os: depot-macos-14 }, #{ # build: windows-x64, # os: windows-2022, @@ -284,7 +286,7 @@ jobs: ] container: ${{ matrix.metadata.container }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Setup MSVC (Windows) uses: ilammy/msvc-dev-cmd@v1 @@ -293,6 +295,7 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ env.MSRV }} + components: clippy - name: Install Nextest uses: taiki-e/install-action@nextest @@ -307,9 +310,9 @@ jobs: if: startsWith(matrix.metadata.build, 'macos-') shell: bash run: | - brew install ninja llvm@18 - echo "/opt/homebrew/opt/llvm@18/bin" >> $GITHUB_PATH - ls -laR /opt/homebrew/opt/llvm@18/bin/ + brew install ninja llvm@21 + echo "/opt/homebrew/opt/llvm@21/bin" >> $GITHUB_PATH + ls -laR /opt/homebrew/opt/llvm@21/bin/ - name: Install `ninja` on Windows if: startsWith(matrix.metadata.build, 'windows-') @@ -322,6 +325,9 @@ jobs: run: rm /usr/bin/link.exe if: startsWith(matrix.metadata.build, 'windows-') + - name: Lint ${{ matrix.build-what.key }} + run: ${{ matrix.build-what.lint-cmd }} + - name: Test WAMR API if: ${{ matrix.build-what.key == 'wamr' }} run: echo $GITHUB_PATH && ${{ matrix.build-what.build-cmd }} @@ -339,13 +345,13 @@ jobs: run: ${{ matrix.build-what.build-cmd }} test_build_docs_rs: - name: Test build docs rs + name: Build docs.rs runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@master with: - toolchain: "nightly-2025-02-09" + toolchain: "nightly-2025-09-27" target: x86_64-unknown-linux-gnu - run: cargo install toml-cli --locked # toml-cli is required to run `make test-build-docs-rs` @@ -354,23 +360,23 @@ jobs: run: | sudo apt-get install ninja-build -y - - name: Install LLVM 18 + - name: Install LLVM 21 run: | - curl --proto '=https' --tlsv1.2 -sSf https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-linux-amd64.tar.xz -L -o llvm.tar.xz + curl --proto '=https' --tlsv1.2 -sSf https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-linux-amd64.tar.xz -L -o llvm.tar.xz LLVM_DIR=$(pwd)/${{ env.LLVM_DIR }} mkdir ${LLVM_DIR} tar xf llvm.tar.xz --strip-components=1 -C ${LLVM_DIR} echo "ENABLE_LLVM=1" >> $GITHUB_ENV echo "${LLVM_DIR}/bin" >> $GITHUB_PATH echo "${LLVM_DIR}/usr/bin" >> $GITHUB_PATH - echo "LLVM_SYS_180_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV + echo "LLVM_SYS_211_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV env: LLVM_DIR: .llvm - name: make test-build-docs-rs-ci run: make test-build-docs-rs-ci build_linux_aarch64: - name: ${{ matrix.build-what.name }} on linux-aarch64 + name: ${{ matrix.build-what.name }} - linux-aarch64 runs-on: ubuntu-22.04-arm strategy: fail-fast: false @@ -380,16 +386,16 @@ jobs: { key: capi, build-cmd: "make build-capi && make package-capi", - name: "Build C-API", + name: "C-API", }, { key: wasmer, build-cmd: "make build-wasmer && make package-wasmer && make tar-wasmer", - name: "Build wasmer-cli", + name: "Wasmer-cli", }, ] steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ env.MSRV }} @@ -399,7 +405,7 @@ jobs: docker build -t wasmer/aarch64 ${GITHUB_WORKSPACE}/.github/cross-linux-aarch64/ env: CROSS_DOCKER_IN_DOCKER: true - - name: Build ${{ matrix.build-what.key }} + - name: ${{ matrix.build-what.key }} run: | ${{ matrix.build-what.build-cmd }} env: @@ -431,26 +437,31 @@ jobs: retention-days: 2 build_linux_riscv64: - name: ${{ matrix.build-what.name }} on linux-riscv64 + name: ${{ matrix.build-what.name }} - linux-riscv64 runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: build-what: [ + { + key: wast-tests, + build-cmd: "make test-stage-0-wast", + name: "Run WAST tests", + }, { key: capi, build-cmd: "make build-capi && make package-capi", - name: "Build C-API", + name: "C-API", }, { key: wasmer, build-cmd: "make build-wasmer && make package-wasmer && make tar-wasmer", - name: "Build wasmer-cli", + name: "Wasmer-cli", }, ] steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 #- uses: dtolnay/rust-toolchain@stable # with: # toolchain: ${{ env.MSRV }} @@ -490,7 +501,7 @@ jobs: retention-days: 2 build: - name: ${{ matrix.build-what.name }} on ${{ matrix.metadata.build }} + name: ${{ matrix.build-what.name }} - ${{ matrix.metadata.build }} runs-on: ${{ matrix.metadata.os }} needs: setup strategy: @@ -501,22 +512,27 @@ jobs: { key: capi, build-cmd: "make build-capi && make build-capi-headless && make package-capi && make tar-capi", - name: "Build and test C-API", + name: "C-API", }, { key: capi-v8, build-cmd: "make test-capi-v8", - name: "Build and test C-API with v8", + name: "C-API with v8", }, { key: wasmer, build-cmd: "make build-wasmer && make package-wasmer && make tar-wasmer", - name: "Build wasmer-cli", + name: "Wasmer-cli", + }, + { + key: "check", + build-cmd: "make check", + name: "Wasmer API (sys)", }, { key: "api-feats", build-cmd: "make check-api-features", - name: "Check wasmer API with all sys features enabled", + name: "API (sys)", }, ] metadata: [ @@ -525,7 +541,7 @@ jobs: os: ubuntu-22.04, target: x86_64-unknown-linux-gnu, exe: "", - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-linux-amd64.tar.xz", + llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-linux-amd64.tar.xz", # Unfortunately, building a shared lib of the c_api with the v8 # backend does not work, due to unsupported relocations to hidden # symbols in wee8. @@ -533,18 +549,18 @@ jobs: }, { build: macos-x64, - os: macos-13, + os: macos-15-intel, target: x86_64-apple-darwin, exe: "", - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-amd64.tar.xz", + llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-darwin-amd64.tar.xz", supports_v8: true, }, { build: macos-arm, - os: macos-14, + os: depot-macos-14, target: aarch64-apple-darwin, exe: "", - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-aarch64.tar.xz", + llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-darwin-aarch64.tar.xz", supports_v8: true, }, { @@ -552,8 +568,7 @@ jobs: os: windows-2022, target: x86_64-pc-windows-msvc, exe: ".exe", - # For now, disable LLVM in `windows-x64.` - # llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-windows-amd64.tar.xz' + llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-windows-amd64.tar.xz", supports_v8: false, }, { @@ -567,7 +582,7 @@ jobs: target: x86_64-unknown-linux-musl, os: ubuntu-22.04, exe: "", - container: "alpine:latest", + container: "alpine:edge", supports_v8: false, }, ] @@ -576,7 +591,9 @@ jobs: SCCACHE_AZURE_BLOB_CONTAINER: wasmerstoragesccacheblob SCCACHE_AZURE_CONNECTION_STRING: ${{ secrets.SCCACHE_AZURE_CONNECTION_STRING }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 + - name: Set up Depot CLI + uses: depot/setup-action@v1 - name: Set up libstdc++ on Linux if: matrix.metadata.build == 'linux-x64' run: | @@ -586,22 +603,20 @@ jobs: - name: Set up base deps on musl if: matrix.metadata.build == 'linux-musl' run: | - ./scripts/alpine-linux-install-deps.sh - echo "ENABLE_LLVM=0" >> $GITHUB_ENV - echo "LLVM_CONFIG_PATH=/usr/bin/llvm-config-18" >> $GITHUB_ENV - # echo "RUSTFLAGS=-L/usr/lib64 -L/usr/lib" >> $GITHUB_ENV + ./scripts/alpine-linux-install-deps.sh - name: Set up dependencies for Mac OS run: | brew install automake # using gnu-tar is a workaround for https://github.com/actions/cache/issues/403 brew install gnu-tar echo PATH="/usr/local/opt/gnu-tar/libexec/gnubin:$PATH" >> $GITHUB_ENV - if: matrix.metadata.os == 'macos-13' + if: matrix.metadata.os == 'macos-15-intel' - name: Install Rust uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ env.MSRV }} target: ${{ matrix.metadata.target }} + components: rustfmt,clippy - name: Install Nextest uses: taiki-e/install-action@nextest - name: Install MSVC dev-cmd (Windows) @@ -644,8 +659,8 @@ jobs: mkdir -p package mkdir -p package/winsdk cp -r /tmp/winsdk/* package/winsdk - - name: Install LLVM (macOS Apple Silicon) - if: matrix.metadata.os == 'macos-13' && !matrix.metadata.llvm_url + - name: Install LLVM (macOS Intel) + if: matrix.metadata.os == 'macos-15-intel' && !matrix.metadata.llvm_url run: | brew install llvm - name: Install LLVM @@ -659,7 +674,7 @@ jobs: echo "ENABLE_LLVM=1" >> $GITHUB_ENV echo "${LLVM_DIR}/bin" >> $GITHUB_PATH echo "${LLVM_DIR}/usr/bin" >> $GITHUB_PATH - echo "LLVM_SYS_180_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV + echo "LLVM_SYS_211_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV env: LLVM_DIR: .llvm - name: Add `brew` libs to `RUSTFLAGS` @@ -687,13 +702,14 @@ jobs: if: ${{ matrix.build-what.key == 'capi' && matrix.metadata.build == 'windows-x64' }} run: ls -R $CARGO_ROOT_DIR - name: Cache + # TODO: v3 is unable to Restore the cache for some reason uses: whywaita/actions-cache-s3@v2 with: path: | ~/.cargo/* ./target/* $CARGO_ROOT_DIR/* - key: r22-${{ github.repository }}-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}-wasmer-make-build-wasmer-${{ matrix.build-what.key }}-${{ matrix.metadata.build }} + key: cache-v${{ env.S3_CACHE_VERSION }}-${{ github.repository }}-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}-wasmer-make-build-wasmer-${{ matrix.build-what.key }}-${{ matrix.metadata.build }} aws-s3-bucket: wasmer-rust-artifacts-cache aws-access-key-id: ${{ secrets.CLOUDFLARE_ARTIFACTS_CACHE_ACCESS_TOKEN }} aws-secret-access-key: ${{ secrets.CLOUDFLARE_ARTIFACTS_CACHE_ACCESS_KEY }} @@ -704,18 +720,18 @@ jobs: - name: Build C-API shell: bash run: ${{ matrix.build-what.build-cmd }} - if: ${{ matrix.build-what.key == 'capi' }} + if: ${{ matrix.build-what.key == 'capi' && matrix.metadata.build != 'macos-x64' }} env: TARGET: ${{ matrix.metadata.target }} TARGET_DIR: target/${{ matrix.metadata.target }}/release CARGO_TARGET: ${{ matrix.metadata.target }} - - name: Test C-API (v8) + - name: C-API (v8) shell: bash run: ${{ matrix.build-what.build-cmd }} if: ${{ matrix.build-what.key == 'capi-v8' && matrix.metadata.supports_v8 == true }} - name: Build Wasmer shell: bash - if: ${{ matrix.build-what.key == 'wasmer' && matrix.metadata.build != 'windows-gnu' }} + if: ${{ matrix.build-what.key == 'wasmer' && matrix.metadata.build != 'windows-gnu' && matrix.metadata.build != 'macos-x64' }} run: ${{ matrix.build-what.build-cmd }} env: TARGET: ${{ matrix.metadata.target }} @@ -723,20 +739,31 @@ jobs: CARGO_TARGET: ${{ matrix.metadata.target }} - name: Check `wasmer` crate with all the `sys` features enabled shell: bash - if: ${{ matrix.build-what.key == 'api-feats' && matrix.metadata.build != 'windows-gnu' }} + if: ${{ matrix.build-what.key == 'api-feats' && matrix.metadata.build != 'windows-gnu' && matrix.metadata.build != 'macos-x64' }} run: ${{ matrix.build-what.build-cmd }} + + - name: Lint C-API + shell: bash + if: ${{ matrix.build-what.key == 'capi' && !(matrix.metadata.build == 'linux-musl' || matrix.metadata.build == 'windows-gnu' || matrix.metadata.build == 'macos-x64') }} + run: make lint-capi-ci + env: + TARGET: ${{ matrix.metadata.target }} + TARGET_DIR: target/${{ matrix.metadata.target }}/release + CARGO_TARGET: ${{ matrix.metadata.target }} + - name: Test C-API shell: bash - if: ${{ matrix.build-what.key == 'capi' && !(matrix.metadata.build == 'linux-musl' || matrix.metadata.build == 'windows-gnu') }} + if: ${{ matrix.build-what.key == 'capi' && !(matrix.metadata.build == 'linux-musl' || matrix.metadata.build == 'windows-gnu' || matrix.metadata.build == 'macos-x64') }} run: make test-capi-ci env: TARGET: ${{ matrix.metadata.target }} TARGET_DIR: target/${{ matrix.metadata.target }}/release CARGO_TARGET: ${{ matrix.metadata.target }} + # C-API tests were disabled for linux-musl and macos-arm (we can't run them) - name: Test C-API integration shell: bash - if: ${{ matrix.build-what.key == 'capi' && !(matrix.metadata.build == 'linux-musl' || matrix.metadata.build == 'windows-gnu') }} + if: ${{ matrix.build-what.key == 'capi' && !(matrix.metadata.build == 'linux-musl' || matrix.metadata.build == 'windows-gnu' || matrix.metadata.build == 'macos-x64') }} run: export WASMER_DIR=`pwd`/package && make test-stage-7-capi-integration-tests env: TARGET: ${{ matrix.metadata.target }} @@ -758,7 +785,7 @@ jobs: retention-days: 2 test: - name: ${{ matrix.stage.description }} on ${{ matrix.metadata.build }} + name: ${{ matrix.stage.description }} - ${{ matrix.metadata.build }} runs-on: ${{ matrix.metadata.os }} needs: setup strategy: @@ -767,27 +794,27 @@ jobs: stage: [ { - description: "Run wast test suite for all compilers", + description: "WAST (all comp.)", make: "test-stage-0-wast", }, { - description: "Unit-test packages on std", + description: "Packages - std", make: "test-stage-1-test-all", }, { - description: "Unit-test cranelift on no-std", + description: "Cranelift - no-std", make: "test-stage-2-test-compiler-cranelift-nostd", }, { - description: "Unit-test singlepass on no-std", + description: "Singlepass - no-std", make: "test-stage-3-test-compiler-singlepass-nostd", }, { - description: "Unit-test wasmer-cli", + description: "Wasmer-cli", make: "test-stage-4-wasmer-cli", }, { - description: "Unit-test examples", + description: "Examples", make: "test-stage-5-test-examples", }, ] @@ -797,36 +824,35 @@ jobs: os: ubuntu-22.04, target: x86_64-unknown-linux-gnu, exe: "", - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-linux-amd64.tar.xz", + llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-linux-amd64.tar.xz", }, { build: macos-x64, - os: macos-13, + os: macos-15-intel, target: x86_64-apple-darwin, exe: "", - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-amd64.tar.xz", + llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-darwin-amd64.tar.xz", }, { build: macos-arm, - os: macos-14, + os: depot-macos-14, target: aarch64-apple-darwin, exe: "", - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-aarch64.tar.xz", + llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-darwin-aarch64.tar.xz", }, { build: windows-x64, os: windows-2022, target: x86_64-pc-windows-msvc, exe: ".exe", - # For now, disable LLVM in `windows-x64.` - # llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-windows-amd64.tar.xz' + llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-windows-amd64.tar.xz" }, { build: linux-musl, target: x86_64-unknown-linux-musl, os: ubuntu-22.04, exe: "", - container: "alpine:latest", + container: "alpine:edge", }, ] container: ${{ matrix.metadata.container }} @@ -834,7 +860,10 @@ jobs: SCCACHE_AZURE_BLOB_CONTAINER: wasmerstoragesccacheblob SCCACHE_AZURE_CONNECTION_STRING: ${{ secrets.SCCACHE_AZURE_CONNECTION_STRING }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 + - name: Show disk capacity + if: startsWith(matrix.metadata.build, 'linux') + run: df -h - name: Set up libstdc++ on Linux if: matrix.metadata.build == 'linux-x64' run: | @@ -845,9 +874,6 @@ jobs: if: matrix.metadata.build == 'linux-musl' run: | ./scripts/alpine-linux-install-deps.sh - echo "ENABLE_LLVM=0" >> $GITHUB_ENV - echo "LLVM_CONFIG_PATH=/usr/bin/llvm-config-18" >> $GITHUB_ENV - # echo "RUSTFLAGS=-L/usr/lib64 -L/usr/lib" >> $GITHUB_ENV - name: Install MSVC dev-cmd (Windows) uses: ilammy/msvc-dev-cmd@v1 if: ${{ matrix.metadata.build == 'windows-x64' }} @@ -862,7 +888,7 @@ jobs: # using gnu-tar is a workaround for https://github.com/actions/cache/issues/403 brew install gnu-tar zstd echo PATH="/usr/local/opt/gnu-tar/libexec/gnubin:$PATH" >> $GITHUB_ENV - if: matrix.metadata.os == 'macos-13' + if: matrix.metadata.os == 'macos-15-intel' - name: Install Rust uses: dtolnay/rust-toolchain@stable with: @@ -870,8 +896,8 @@ jobs: target: ${{ matrix.metadata.target }} - name: Install Nextest uses: taiki-e/install-action@nextest - - name: Install LLVM (macOS Apple Silicon) - if: matrix.metadata.os == 'macos-13' && !matrix.metadata.llvm_url + - name: Install LLVM (macOS Intel) + if: matrix.metadata.os == 'macos-15-intel' && !matrix.metadata.llvm_url run: | brew install llvm echo "/opt/homebrew/opt/llvm/bin" >> GITHUB_PATH @@ -885,12 +911,12 @@ jobs: tar xf llvm.tar.xz --strip-components=1 -C ${LLVM_DIR} echo "${LLVM_DIR}/bin" >> $GITHUB_PATH echo "${LLVM_DIR}/usr/bin" >> $GITHUB_PATH - echo "LLVM_SYS_180_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV + echo "LLVM_SYS_211_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV echo "ENABLE_LLVM=1" >> $GITHUB_ENV env: LLVM_DIR: .llvm - name: Add `brew` libs to `RUSTFLAGS` - if: matrix.metadata.os == 'macos-14' + if: matrix.metadata.os == 'macos-14' || matrix.metadata.os == 'depot-macos-14' shell: bash run: | echo "RUSTFLAGS=-L/opt/homebrew/lib" >> $GITHUB_ENV @@ -905,12 +931,15 @@ jobs: EOF if: matrix.metadata.target - name: Cache + # TODO: fix disk space issue for a couple of Linux runners + if: ${{ !(matrix.stage.make == 'test-stage-5-test-examples' && (matrix.metadata.build == 'linux-musl' || matrix.metadata.build == 'linux-x64')) }} + # TODO: v3 is unable to Restore the cache for some reason uses: whywaita/actions-cache-s3@v2 with: path: | ~/.cargo/* ./target/* - key: r22-${{ github.repository }}-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}-wasmer-make-test-stage-${{ matrix.stage.make }}-${{ matrix.metadata.build }} + key: cache-v${{ env.S3_CACHE_VERSION }}-${{ github.repository }}-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}-wasmer-make-test-stage-${{ matrix.stage.make }}-${{ matrix.metadata.build }} aws-s3-bucket: wasmer-rust-artifacts-cache aws-access-key-id: ${{ secrets.CLOUDFLARE_ARTIFACTS_CACHE_ACCESS_TOKEN }} aws-secret-access-key: ${{ secrets.CLOUDFLARE_ARTIFACTS_CACHE_ACCESS_KEY }} @@ -921,13 +950,15 @@ jobs: - name: ${{ matrix.stage.description }} shell: bash run: make ${{ matrix.stage.make }} + # For MacOS x64 - run tests only on main or release branches + if: github.event_name != 'pull_request' || startsWith(github.head_ref, 'release-') || matrix.metadata.os != 'macos-15-intel' env: TARGET: ${{ matrix.metadata.target }} TARGET_DIR: target/${{ matrix.metadata.target }}/release CARGO_TARGET: ${{ matrix.metadata.target }} test_integration_cli: - name: CLI integration tests on ${{ matrix.build }} + name: CLI tests - ${{ matrix.build }} runs-on: ${{ matrix.os }} needs: [build, build_linux_aarch64, build_linux_riscv64] strategy: @@ -937,30 +968,30 @@ jobs: - build: linux-x64 os: ubuntu-22.04 target: x86_64-unknown-linux-gnu - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-linux-amd64.tar.xz" - - build: macos-x64 - os: macos-13 - target: x86_64-apple-darwin + llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-linux-amd64.tar.xz" + exe: "" # we only build the integration-test CLI, we don't run tests - build: macos-arm - os: macos-14 + os: depot-macos-14 target: aarch64-apple-darwin, + exe: "" - build: linux-musl target: x86_64-unknown-linux-musl os: ubuntu-22.04 - container: alpine:latest + container: alpine:edge + exe: "" - build: windows-x64 os: windows-latest target: x86_64-pc-windows-msvc - # For now, disable LLVM in `windows-x64.` - # llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-windows-amd64.tar.xz' + llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/21.x/llvm-windows-amd64.tar.xz" + exe: ".exe" container: ${{ matrix.container }} env: SCCACHE_AZURE_BLOB_CONTAINER: wasmerstoragesccacheblob SCCACHE_AZURE_CONNECTION_STRING: ${{ secrets.SCCACHE_AZURE_CONNECTION_STRING }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: goto-bus-stop/setup-zig@v2 with: version: 0.10.0 @@ -968,9 +999,6 @@ jobs: if: matrix.build == 'linux-musl' run: | ./scripts/alpine-linux-install-deps.sh - echo "ENABLE_LLVM=0" >> $GITHUB_ENV - echo "LLVM_CONFIG_PATH=/usr/bin/llvm-config-18" >> $GITHUB_ENV - # echo "RUSTFLAGS=-L/usr/lib64 -L/usr/lib" >> $GITHUB_ENV - uses: actions/download-artifact@v4 id: download with: @@ -984,16 +1012,17 @@ jobs: uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ env.MSRV }} - target: ${{ matrix.metadata.target }} + target: ${{ matrix.target }} - name: Install Nextest uses: taiki-e/install-action@nextest - name: Cache + # TODO: v3 is unable to Restore the cache for some reason uses: whywaita/actions-cache-s3@v2 with: path: | ~/.cargo/* ./target/* - key: r22-${{ github.repository }}-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}-wasmer-make-test-integration-cli-${{ matrix.build }} + key: cache-v${{ env.S3_CACHE_VERSION }}-${{ github.repository }}-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}-wasmer-make-test-integration-cli-${{ matrix.build }} aws-s3-bucket: wasmer-rust-artifacts-cache aws-access-key-id: ${{ secrets.CLOUDFLARE_ARTIFACTS_CACHE_ACCESS_TOKEN }} aws-secret-access-key: ${{ secrets.CLOUDFLARE_ARTIFACTS_CACHE_ACCESS_KEY }} @@ -1018,18 +1047,14 @@ jobs: with: name: capi-macos-arm path: package/cache/wasmercache3 - - uses: actions/download-artifact@v4 - with: - name: capi-macos-x64 - path: package/cache/wasmercache4 - uses: actions/download-artifact@v4 with: name: capi-linux-x64 - path: package/cache/wasmercache5 + path: package/cache/wasmercache4 - uses: actions/download-artifact@v4 with: name: capi-linux-riscv64 - path: package/cache/wasmercache6 + path: package/cache/wasmercache5 - name: Copy .tar.gz files to proper location shell: bash run: | @@ -1042,8 +1067,7 @@ jobs: cp package/cache/wasmercache2/build-capi.tar.gz package/cache/wasmer-windows-gnu64.tar.gz cp package/cache/wasmercache3/build-capi.tar.gz package/cache/wasmer-darwin-arm64.tar.gz cp package/cache/wasmercache4/build-capi.tar.gz package/cache/wasmer-darwin-amd64.tar.gz - cp package/cache/wasmercache5/build-capi.tar.gz package/cache/wasmer-linux-amd64.tar.gz - cp package/cache/wasmercache6/wasmer.tar.gz package/cache/wasmer-linux-riscv64.tar.gz + cp package/cache/wasmercache5/wasmer.tar.gz package/cache/wasmer-linux-riscv64.tar.gz - uses: actions/download-artifact@v4 if: ${{ matrix.build == 'windows-x64' }} with: @@ -1059,11 +1083,6 @@ jobs: with: name: capi-macos-arm path: download_link - - uses: actions/download-artifact@v4 - if: ${{ matrix.build == 'macos-x64' }} - with: - name: capi-macos-x64 - path: download_link - uses: actions/download-artifact@v4 if: ${{ matrix.build == 'linux-x64' }} with: @@ -1130,9 +1149,11 @@ jobs: # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} test-wasmer-integration-tests: + name: "Remote integ. tests" needs: [build] uses: wasmerio/wasmer-integration-tests/.github/workflows/integration-test-workflow.yaml@main with: fetch_artifact: "wasmer-cli-linux-x64" + registry: wasmer.io secrets: - token: ${{ secrets.WAPM_DEV_TOKEN }} + token: ${{ secrets.PROD_BACKEND_CIUSER_TOKEN }} diff --git a/.github/workflows/wasmer-config.yaml b/.github/workflows/wasmer-config.yaml index 6ace3c11a8..5e4856d2b9 100644 --- a/.github/workflows/wasmer-config.yaml +++ b/.github/workflows/wasmer-config.yaml @@ -20,7 +20,7 @@ jobs: name: Compile and Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Rust Cache uses: Swatinem/rust-cache@v2 - name: Setup Rust @@ -41,7 +41,7 @@ jobs: name: Linting and Formatting runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Rust Cache uses: Swatinem/rust-cache@v2 - name: Setup Rust diff --git a/.gitignore b/.gitignore index f6deb5be7f..0d9278440f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ .DS_Store .idea .gdb_history -/.cargo/ **/.vscode/* !/.vscode/settings.json api-docs-repo/ diff --git a/Cargo.lock b/Cargo.lock index 4aa3620eb4..895acadf9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ - "gimli 0.32.3", + "gimli", ] [[package]] @@ -28,29 +28,6 @@ dependencies = [ "cpufeatures", ] -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom 0.2.16", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy 0.8.27", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -66,6 +43,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -172,43 +155,44 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "askama" -version = "0.12.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7" dependencies = [ "askama_derive", - "askama_escape", + "itoa", + "percent-encoding", + "serde", + "serde_json", ] [[package]] name = "askama_derive" -version = "0.12.5" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac" dependencies = [ "askama_parser", "basic-toml", - "mime", - "mime_guess", + "memchr", "proc-macro2", "quote", + "rustc-hash", "serde", - "syn 2.0.106", + "serde_derive", + "syn 2.0.111", ] -[[package]] -name = "askama_escape" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" - [[package]] name = "askama_parser" -version = "0.2.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f" dependencies = [ - "nom 7.1.3", + "memchr", + "serde", + "serde_derive", + "winnow", ] [[package]] @@ -233,13 +217,12 @@ dependencies = [ [[package]] name = "assert_cmd" -version = "2.0.17" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd389a4b2970a01282ee455294913c0a43724daedcd1a24c3eb0ec1c1320b66" +checksum = "bcbb6924530aa9e0432442af08bbcafdad182db80d2e560da42a6d442535bf85" dependencies = [ "anstyle", - "bstr 1.12.0", - "doc-comment", + "bstr 1.12.1", "libc", "predicates 3.1.3", "predicates-core", @@ -280,7 +263,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -315,6 +298,49 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "axum" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425" +dependencies = [ + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.76" @@ -330,6 +356,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -362,11 +394,11 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.70.1" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cexpr", "clang-sys", "itertools 0.13.0", @@ -375,9 +407,9 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash 1.1.0", + "rustc-hash", "shlex", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -388,9 +420,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "blake3" @@ -427,12 +459,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", - "regex-automata 0.4.11", + "regex-automata 0.4.13", "serde", ] @@ -450,6 +482,9 @@ name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +dependencies = [ + "allocator-api2", +] [[package]] name = "bus" @@ -462,40 +497,18 @@ dependencies = [ "parking_lot_core", ] -[[package]] -name = "bytecheck" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" -dependencies = [ - "bytecheck_derive 0.6.12", - "ptr_meta 0.1.4", - "simdutf8", -] - [[package]] name = "bytecheck" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b" dependencies = [ - "bytecheck_derive 0.8.2", - "ptr_meta 0.3.1", + "bytecheck_derive", + "ptr_meta", "rancor", "simdutf8", ] -[[package]] -name = "bytecheck_derive" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "bytecheck_derive" version = "0.8.2" @@ -504,7 +517,7 @@ checksum = "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -515,39 +528,29 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" dependencies = [ "serde", ] [[package]] name = "bytesize" -version = "1.3.3" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e93abca9e28e0a1b9877922aacb20576e05d4679ffa78c3d6dc22a26a216659" +checksum = "6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3" dependencies = [ - "serde", + "serde_core", ] [[package]] name = "bzip2" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47" -dependencies = [ - "bzip2-sys", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.13+1.0.8" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +checksum = "f3a53fac24f34a81bc9954b5d6cfce0c21e18ec6959f44f56e8e90e4bb7c346c" dependencies = [ - "cc", - "pkg-config", + "libbz2-rs-sys", ] [[package]] @@ -568,18 +571,41 @@ dependencies = [ "serde", ] +[[package]] +name = "cargo-platform" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122ec45a44b270afd1402f351b782c676b173e3c3fb28d86ff7ebfb4d86a4ee4" +dependencies = [ + "serde", +] + [[package]] name = "cargo_metadata" -version = "0.15.4" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" dependencies = [ "camino", - "cargo-platform", + "cargo-platform 0.1.9", "semver 1.0.27", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.17", +] + +[[package]] +name = "cargo_metadata" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef987d17b0a113becdd19d3d0022d04d7ef41f9efe4f3fb63ac44ba61df3ade9" +dependencies = [ + "camino", + "cargo-platform 0.3.1", + "semver 1.0.27", + "serde", + "serde_json", + "thiserror 2.0.17", ] [[package]] @@ -590,27 +616,27 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cbindgen" -version = "0.27.0" +version = "0.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb" +checksum = "befbfd072a8e81c02f8c507aefce431fe5e7d051f83d48a23ffc9b9fe5a11799" dependencies = [ - "heck 0.4.1", - "indexmap 2.11.4", + "heck 0.5.0", + "indexmap 2.12.1", "log", "proc-macro2", "quote", "serde", "serde_json", - "syn 2.0.106", + "syn 2.0.111", "tempfile", - "toml 0.8.23", + "toml", ] [[package]] name = "cc" -version = "1.2.40" +version = "1.2.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" +checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a" dependencies = [ "find-msvc-tools", "jobserver", @@ -629,9 +655,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -676,7 +702,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", - "half 2.6.0", + "half 2.7.1", ] [[package]] @@ -702,9 +728,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.11" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" dependencies = [ "clap_builder", "clap_derive", @@ -712,48 +738,48 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.11" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.10.0", + "strsim 0.11.1", ] [[package]] name = "clap_complete" -version = "4.5.3" +version = "4.5.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a2d6eec27fce550d708b2be5d798797e5a55b246b323ef36924a0001996352" +checksum = "39615915e2ece2550c0149addac32fb5bd312c657f43845bb9088cb9c8a7c992" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "clap_mangen" -version = "0.2.29" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b4c3c54b30f0d9adcb47f25f61fcce35c4dd8916638c6b82fbd5f4fb4179e2" +checksum = "439ea63a92086df93893164221ad4f24142086d535b3a0957b9b9bea2dc86301" dependencies = [ "clap", "roff", @@ -776,34 +802,22 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "colored" -version = "1.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f741c91823341bebf717d4c71bda820630ce065443b58bd1b7451af008355" -dependencies = [ - "is-terminal", - "lazy_static", - "winapi", -] - -[[package]] -name = "colored" -version = "2.2.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" dependencies = [ - "lazy_static", "windows-sys 0.59.0", ] [[package]] name = "comfy-table" -version = "7.1.4" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a65ebfec4fb190b6f90e944a817d60499ee0744e582530e2c9900a22e591d9a" +checksum = "b03b7db8e0b4b2fdad6c551e634134e99ec000e5c8c3b6856c65e8bbaded7a3b" dependencies = [ "crossterm", "unicode-segmentation", - "unicode-width 0.2.2", + "unicode-width", ] [[package]] @@ -813,15 +827,15 @@ dependencies = [ "pretty_assertions", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.111", "trybuild", ] [[package]] name = "compiletest_rs" -version = "0.6.0" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0086d6ad78cf409c3061618cd98e2789d5c9ce598fc9651611cf62eae0a599cb" +checksum = "f150fe9105fcd2a57cad53f0c079a24de65195903ef670990f5909f695eac04c" dependencies = [ "diff", "filetime", @@ -836,7 +850,7 @@ dependencies = [ "serde_derive", "serde_json", "tester", - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -874,10 +888,62 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.2", "windows-sys 0.59.0", ] +[[package]] +name = "console" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b430743a6eb14e9764d4260d4c0d8123087d504eeb9c48f2b2a5e810dd369df4" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.61.2", +] + +[[package]] +name = "console-api" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8599749b6667e2f0c910c1d0dff6901163ff698a52d5a39720f61b5be4b20d3" +dependencies = [ + "futures-core", + "prost", + "prost-types", + "tonic", + "tonic-prost", + "tracing-core", +] + +[[package]] +name = "console-subscriber" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4915b7d8dd960457a1b6c380114c2944f728e7c65294ab247ae6b6f1f37592" +dependencies = [ + "console-api", + "crossbeam-channel", + "crossbeam-utils", + "futures-task", + "hdrhistogram", + "humantime", + "hyper-util", + "prost", + "prost-types", + "serde", + "serde_json", + "thread_local", + "tokio", + "tokio-stream", + "tonic", + "tracing", + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "constant_time_eq" version = "0.3.1" @@ -918,9 +984,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "corosensei" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "878ba85678ef5d34ffe1b5da981b0828232b4c7f2726b20984f59c7e79f6d514" +checksum = "1d46a43097861058cb45affe888e40ba19b57a8210650144cdc7b50c9d87840a" dependencies = [ "autocfg", "cfg-if", @@ -938,28 +1004,47 @@ dependencies = [ "libc", ] +[[package]] +name = "cranelift-assembler-x64" +version = "0.126.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30054f4aef4d614d37f27d5b77e36e165f0b27a71563be348e7c9fcfac41eed8" +dependencies = [ + "cranelift-assembler-x64-meta", +] + +[[package]] +name = "cranelift-assembler-x64-meta" +version = "0.126.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beab56413879d4f515e08bcf118b1cb85f294129bb117057f573d37bfbb925a" +dependencies = [ + "cranelift-srcgen", +] + [[package]] name = "cranelift-bforest" -version = "0.110.2" +version = "0.126.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305d51c180ebdc46ef61bc60c54ae6512db3bc9a05842a1f1e762e45977019ab" +checksum = "6d054747549a69b264d5299c8ca1b0dd45dc6bd0ee43f1edfcc42a8b12952c7a" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.110.3" +version = "0.126.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "690d8ae6c73748e5ce3d8fe59034dceadb8823e6c8994ba324141c5eae909b0e" +checksum = "98b92d481b77a7dc9d07c96e24a16f29e0c9c27d042828fdf7e49e54ee9819bf" [[package]] name = "cranelift-codegen" -version = "0.110.2" +version = "0.126.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7ca95e831c18d1356da783765c344207cbdffea91e13e47fa9327dbb2e0719" +checksum = "6eeccfc043d599b0ef1806942707fc51cdd1c3965c343956dc975a55d82a920f" dependencies = [ "bumpalo", + "cranelift-assembler-x64", "cranelift-bforest", "cranelift-bitset", "cranelift-codegen-meta", @@ -967,66 +1052,79 @@ dependencies = [ "cranelift-control", "cranelift-entity", "cranelift-isle", - "gimli 0.28.1", - "hashbrown 0.14.5", + "gimli", + "hashbrown 0.15.5", "log", + "pulley-interpreter", "regalloc2", - "rustc-hash 1.1.0", + "rustc-hash", + "serde", "smallvec", - "target-lexicon 0.12.16", + "target-lexicon 0.13.3", + "wasmtime-internal-math", ] [[package]] name = "cranelift-codegen-meta" -version = "0.110.3" +version = "0.126.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0a2d2ab65e6cbf91f81781d8da65ec2005510f18300eff21a99526ed6785863" +checksum = "1174cdb9d9d43b2bdaa612a07ed82af13db9b95526bc2c286c2aec4689bcc038" dependencies = [ + "cranelift-assembler-x64-meta", "cranelift-codegen-shared", + "cranelift-srcgen", + "heck 0.5.0", + "pulley-interpreter", ] [[package]] name = "cranelift-codegen-shared" -version = "0.110.3" +version = "0.126.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efcff860573cf3db9ae98fbd949240d78b319df686cc306872e7fab60e9c84d7" +checksum = "7d572be73fae802eb115f45e7e67a9ed16acb4ee683b67c4086768786545419a" [[package]] name = "cranelift-control" -version = "0.110.3" +version = "0.126.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d70e5b75c2d5541ef80a99966ccd97aaa54d2a6af19ea31759a28538e1685a" +checksum = "e1587465cc84c5cc793b44add928771945f3132bbf6b3621ee9473c631a87156" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.110.2" +version = "0.126.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a48cb0a194c9ba82fec35a1e492055388d89b2e3c03dee9dcf2488892be8004d" +checksum = "063b83448b1343e79282c3c7cbda7ed5f0816f0b763a4c15f7cecb0a17d87ea6" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.110.2" +version = "0.126.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8327afc6c1c05f4be62fefce5b439fa83521c65363a322e86ea32c85e7ceaf64" +checksum = "aa4461c2d2ca48bc72883f5f5c3129d9aefac832df1db824af9db8db3efee109" dependencies = [ "cranelift-codegen", - "hashbrown 0.14.5", + "hashbrown 0.15.5", "log", "smallvec", - "target-lexicon 0.12.16", + "target-lexicon 0.13.3", ] [[package]] name = "cranelift-isle" -version = "0.110.2" +version = "0.126.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56b08621c00321efcfa3eee6a3179adc009e21ea8d24ca7adc3c326184bc3f48" +checksum = "acd811b25e18f14810d09c504e06098acc1d9dbfa24879bf0d6b6fb44415fc66" + +[[package]] +name = "cranelift-srcgen" +version = "0.126.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d039de901c8d928222b8128e1b9a9ab27b82a7445cb749a871c75d9cb25c57d" [[package]] name = "crc" @@ -1054,9 +1152,9 @@ dependencies = [ [[package]] name = "criterion" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" dependencies = [ "anes", "cast", @@ -1064,16 +1162,11 @@ dependencies = [ "clap", "criterion-plot", "csv", - "is-terminal", - "itertools 0.10.5", + "itertools 0.13.0", "num-traits", - "once_cell", "oorandom", - "plotters", - "rayon", "regex", "serde", - "serde_derive", "serde_json", "tinytemplate", "walkdir", @@ -1081,12 +1174,12 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" dependencies = [ "cast", - "itertools 0.10.5", + "itertools 0.13.0", ] [[package]] @@ -1134,14 +1227,15 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossterm" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "crossterm_winapi", + "document-features", "parking_lot", - "rustix 0.38.44", + "rustix", "winapi", ] @@ -1172,35 +1266,25 @@ dependencies = [ [[package]] name = "csv" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" dependencies = [ "csv-core", "itoa", "ryu", - "serde", + "serde_core", ] [[package]] name = "csv-core" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" dependencies = [ "memchr", ] -[[package]] -name = "ctor" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" -dependencies = [ - "quote", - "syn 1.0.109", -] - [[package]] name = "cynic" version = "3.12.0" @@ -1229,7 +1313,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.106", + "syn 2.0.111", "thiserror 1.0.69", ] @@ -1239,7 +1323,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3136ed6464e975162667c08092fcb54947ce08785fca301162fd614c4dfd974f" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.1", "lalrpop-util", "logos", ] @@ -1253,17 +1337,7 @@ dependencies = [ "cynic-codegen", "darling 0.20.11", "quote", - "syn 2.0.106", -] - -[[package]] -name = "darling" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" -dependencies = [ - "darling_core 0.14.4", - "darling_macro 0.14.4", + "syn 2.0.111", ] [[package]] @@ -1286,20 +1360,6 @@ dependencies = [ "darling_macro 0.21.3", ] -[[package]] -name = "darling_core" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", - "syn 1.0.109", -] - [[package]] name = "darling_core" version = "0.20.11" @@ -1311,7 +1371,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -1324,18 +1384,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.106", -] - -[[package]] -name = "darling_macro" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" -dependencies = [ - "darling_core 0.14.4", - "quote", - "syn 1.0.109", + "syn 2.0.111", ] [[package]] @@ -1346,7 +1395,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -1357,20 +1406,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.106", -] - -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", + "syn 2.0.111", ] [[package]] @@ -1399,11 +1435,52 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26bf8fc351c5ed29b5c2f0cbbac1b209b74f60ecd62e675a998df72c49af5204" +[[package]] +name = "defmt" +version = "0.3.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad" +dependencies = [ + "defmt 1.0.1", +] + +[[package]] +name = "defmt" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.17", +] + [[package]] name = "deranged" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -1416,49 +1493,38 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "derive_builder" -version = "0.12.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" dependencies = [ "derive_builder_macro", ] [[package]] name = "derive_builder_core" -version = "0.12.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ - "darling 0.14.4", + "darling 0.20.11", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.111", ] [[package]] name = "derive_builder_macro" -version = "0.12.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 1.0.109", -] - -[[package]] -name = "derive_more" -version = "0.99.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -1478,20 +1544,19 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", "unicode-xid", ] [[package]] name = "dialoguer" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" +checksum = "25f104b501bf2364e78d0d3974cbc774f738f5865306ed128e1e0d7499c0ad96" dependencies = [ - "console", + "console 0.16.1", "shell-words", "tempfile", - "thiserror 1.0.69", "zeroize", ] @@ -1520,9 +1585,9 @@ dependencies = [ [[package]] name = "dirs" -version = "4.0.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ "dirs-sys", ] @@ -1539,13 +1604,14 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.7" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", - "redox_users", - "winapi", + "option-ext", + "redox_users 0.5.2", + "windows-sys 0.61.2", ] [[package]] @@ -1555,7 +1621,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users", + "redox_users 0.4.6", "winapi", ] @@ -1567,26 +1633,20 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] -[[package]] -name = "distance" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9d8664cf849d7d0f3114a3a387d2f5e4303176d746d5a951aaddc66dfe9240" - [[package]] name = "doc-comment" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" [[package]] name = "document-features" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" dependencies = [ "litrs", ] @@ -1621,13 +1681,13 @@ version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a31e49f416ec431ceef002ee220eee9da97687ec3ecea8040703edbaa75e157" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "byteorder", "lazy_static", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -1639,7 +1699,7 @@ dependencies = [ "byteorder", "dynasm", "fnv", - "memmap2 0.9.8", + "memmap2 0.9.9", ] [[package]] @@ -1651,7 +1711,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -1668,42 +1728,42 @@ checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "enum-iterator" -version = "0.7.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6" +checksum = "a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016" dependencies = [ "enum-iterator-derive", ] [[package]] name = "enum-iterator-derive" -version = "0.7.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" +checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.111", ] [[package]] name = "enum-ordinalize" -version = "4.3.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" dependencies = [ "enum-ordinalize-derive", ] [[package]] name = "enum-ordinalize-derive" -version = "4.3.1" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -1724,14 +1784,14 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "env_filter" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" dependencies = [ "log", ] @@ -1760,11 +1820,13 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.3.31" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" +checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" dependencies = [ "serde", + "serde_core", + "typeid", ] [[package]] @@ -1810,16 +1872,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" -[[package]] -name = "fern" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee" -dependencies = [ - "colored 1.9.4", - "log", -] - [[package]] name = "field-offset" version = "0.3.6" @@ -1844,9 +1896,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "fixedbitset" @@ -1856,11 +1908,12 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", + "libz-rs-sys", "miniz_oxide", ] @@ -1888,6 +1941,18 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.3.2" @@ -2011,7 +2076,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -2052,9 +2117,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -2066,7 +2131,7 @@ version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ - "unicode-width 0.2.2", + "unicode-width", ] [[package]] @@ -2084,45 +2149,48 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasip2", "wasm-bindgen", ] [[package]] -name = "ghost" -version = "0.1.20" +name = "gimli" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1323e4e10ffd5d48a21ea37f8d4e3b15dd841121d1301a86122fa0984bedf0a" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", + "fallible-iterator", + "indexmap 2.12.1", + "stable_deref_trait", ] [[package]] -name = "gimli" -version = "0.28.1" +name = "git-version" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "1ad568aa3db0fcbc81f2f116137f263d7304f512a1209b35b85150d3ef88ad19" dependencies = [ - "fallible-iterator", - "indexmap 2.11.4", - "stable_deref_trait", + "git-version-macro", ] -[[package]] -name = "gimli" -version = "0.32.3" +[[package]] +name = "git-version-macro" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] [[package]] name = "glob" @@ -2132,14 +2200,14 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "globset" -version = "0.4.16" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" dependencies = [ "aho-corasick", - "bstr 1.12.0", + "bstr 1.12.1", "log", - "regex-automata 0.4.11", + "regex-automata 0.4.13", "regex-syntax", ] @@ -2193,6 +2261,25 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "h2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap 2.12.1", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "1.8.3" @@ -2201,12 +2288,13 @@ checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "half" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "zerocopy 0.8.27", ] [[package]] @@ -2240,54 +2328,64 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash 0.7.8", -] +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "ahash 0.8.12", + "foldhash 0.1.5", ] [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ - "ahash 0.8.12", + "allocator-api2", + "equivalent", + "foldhash 0.2.0", ] [[package]] -name = "hashbrown" -version = "0.15.5" +name = "hdrhistogram" +version = "7.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" +dependencies = [ + "base64 0.21.7", + "byteorder", + "flate2", + "nom 7.1.3", + "num-traits", +] [[package]] -name = "hashbrown" -version = "0.16.0" +name = "heapless" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] [[package]] name = "heapless" -version = "0.8.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" dependencies = [ "hash32", "stable_deref_trait", @@ -2308,6 +2406,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.5.2" @@ -2340,12 +2444,11 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -2402,14 +2505,15 @@ checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hyper" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ "atomic-waker", "bytes", "futures-channel", "futures-core", + "h2", "http", "http-body", "httparse", @@ -2436,7 +2540,20 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.2", + "webpki-roots 1.0.3", +] + +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", ] [[package]] @@ -2472,11 +2589,11 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-core", @@ -2488,7 +2605,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.0", + "socket2", "tokio", "tower-service", "tracing", @@ -2520,9 +2637,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -2533,9 +2650,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -2546,11 +2663,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -2561,42 +2677,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -2639,15 +2751,15 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.23" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" +checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" dependencies = [ "crossbeam-deque", "globset", "log", "memchr", - "regex-automata 0.4.11", + "regex-automata 0.4.13", "same-file", "walkdir", "winapi-util", @@ -2665,52 +2777,49 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.4" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown 0.16.1", "serde", "serde_core", ] [[package]] name = "indicatif" -version = "0.17.11" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" +checksum = "9375e112e4b463ec1b1c6c011953545c65a30164fbab5b581df32b3abf0dcb88" dependencies = [ - "console", - "number_prefix", + "console 0.16.1", "portable-atomic", - "unicode-width 0.2.2", + "unicode-width", + "unit-prefix", "web-time", ] [[package]] name = "inkwell" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40fb405537710d51f6bdbc8471365ddd4cd6d3a3c3ad6e0c8291691031ba94b2" +version = "0.7.1" +source = "git+https://github.com/TheDan64/inkwell.git?rev=b9c53276e30935ccec841d12c9687a17e9199958#b9c53276e30935ccec841d12c9687a17e9199958" dependencies = [ - "either", "inkwell_internals", "libc", "llvm-sys", "once_cell", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] name = "inkwell_internals" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd28cfd4cfba665d47d31c08a6ba637eed16770abca2eccbbc3ca831fef1e44" +version = "0.12.0" +source = "git+https://github.com/TheDan64/inkwell.git?rev=b9c53276e30935ccec841d12c9687a17e9199958#b9c53276e30935ccec841d12c9687a17e9199958" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -2752,11 +2861,11 @@ dependencies = [ [[package]] name = "insta" -version = "1.43.2" +version = "1.44.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fdb647ebde000f43b5b53f773c30cf9b0cb4300453208713fa38b2c70935a0" +checksum = "b5c943d4415edd8153251b6f197de5eb1640e56d84e8d9159bea190421c73698" dependencies = [ - "console", + "console 0.15.11", "once_cell", "regex", "serde", @@ -2769,7 +2878,7 @@ version = "0.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb6250a98af259a26fd5a4a6081fccea9ac116e4c3178acf4aeb86d32d2b7715" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cc", "handlebars", "lazy_static", @@ -2781,23 +2890,11 @@ dependencies = [ [[package]] name = "inventory" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84344c6e0b90a9e2b6f3f9abe5cc74402684e348df7b32adca28747e0cef091a" -dependencies = [ - "ctor", - "ghost", -] - -[[package]] -name = "io-uring" -version = "0.7.10" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e" dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "libc", + "rustversion", ] [[package]] @@ -2825,22 +2922,11 @@ dependencies = [ "serde", ] -[[package]] -name = "is-terminal" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -2853,18 +2939,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itertools" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] @@ -2881,15 +2967,15 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -2931,11 +3017,17 @@ dependencies = [ "any_ascii", ] +[[package]] +name = "libbz2-rs-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4a545a15244c7d945065b5d392b2d2d7f21526fba56ce51467b06ed445e8f7" + [[package]] name = "libc" -version = "0.2.176" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libfuzzer-sys" @@ -2969,7 +3061,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "libc", "redox_syscall", ] @@ -2980,6 +3072,15 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac" +[[package]] +name = "libz-rs-sys" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "840db8cf39d9ec4dd794376f38acc40d0fc65eec2a8f484f7fd375b84602becd" +dependencies = [ + "zlib-rs", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -2988,19 +3089,13 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linked_hash_set" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae85b5be22d9843c80e5fc80e9b64c8a3b1f98f867c709956eca3efff4e92e2" +checksum = "984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8" dependencies = [ "linked-hash-map", ] -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -3009,21 +3104,21 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "litrs" -version = "0.4.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "llvm-sys" -version = "180.0.0" +version = "211.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778fa5fa02e32728e718f11eec147e6f134137399ab02fd2c13d32476337affa" +checksum = "108b3ad2b2eaf2a561fc74196273b20e3436e4a688b8b44e250d83974dc1b2e2" dependencies = [ "anyhow", "cc", @@ -3069,7 +3164,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -3087,7 +3182,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4de4e09ccbef442225e81339e930ed93dc339d4f1b2eaf479f89590ebeb9bf13" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.1", "loupe-derive", "rustversion", ] @@ -3110,11 +3205,11 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "lz4_flex" -version = "0.11.5" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a" +checksum = "ab6473172471198271ff72e9379150e9dfd70d8e533e0752a27e515b48dd375e" dependencies = [ - "twox-hash 2.1.2", + "twox-hash", ] [[package]] @@ -3127,6 +3222,16 @@ dependencies = [ "crc", ] +[[package]] +name = "lzma-rust2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c60a23ffb90d527e23192f1246b14746e2f7f071cb84476dd879071696c18a4a" +dependencies = [ + "crc", + "sha2", +] + [[package]] name = "lzma-sys" version = "0.1.20" @@ -3157,6 +3262,12 @@ dependencies = [ "libc", ] +[[package]] +name = "mach2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b" + [[package]] name = "macho-unwind-info" version = "0.5.0" @@ -3174,7 +3285,7 @@ version = "6.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -3189,14 +3300,20 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "regex-automata 0.4.11", + "regex-automata 0.4.13", ] +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + [[package]] name = "md5" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" +checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0" [[package]] name = "memchr" @@ -3215,9 +3332,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" dependencies = [ "libc", ] @@ -3294,30 +3411,30 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", "log", "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "miow" -version = "0.3.7" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +checksum = "536bfad37a309d62069485248eeaba1e8d9853aaf951caaeaed0585a95346f08" dependencies = [ - "winapi", + "windows-sys 0.61.2", ] [[package]] name = "more-asserts" -version = "0.2.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" +checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" [[package]] name = "multi-stash" @@ -3342,7 +3459,7 @@ checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -3381,7 +3498,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cfg-if", "cfg_aliases", "libc", @@ -3416,20 +3533,20 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "normpath" -version = "1.1.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec60c60a693226186f5d6edf073232bfb6464ed97eb22cf3b01c1e8198fd97f5" +checksum = "bf23ab2b905654b4cb177e30b629937b3868311d4e1cba859f899c041046e69b" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] name = "nu-ansi-term" -version = "0.50.1" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3459,9 +3576,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -3469,55 +3586,39 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] -[[package]] -name = "number_prefix" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" - [[package]] name = "object" -version = "0.30.4" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ - "flate2", "memchr", ] [[package]] name = "object" -version = "0.32.2" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "b8b28f24bd43920cd8e0bc4f9c6553e8b93221c512cb9a1014987fc89d36f830" dependencies = [ "crc32fast", "flate2", - "hashbrown 0.14.5", - "indexmap 2.11.4", + "hashbrown 0.16.1", + "indexmap 2.12.1", "memchr", "ruzstd", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -3526,9 +3627,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "oorandom" @@ -3538,22 +3639,22 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "opener" -version = "0.6.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c62dcb6174f9cb326eac248f07e955d5d559c272730b6c03e396b443b562788" +checksum = "cb9024962ab91e00c89d2a14352a8d0fc1a64346bf96f1839b45c09149564e47" dependencies = [ - "bstr 1.12.0", + "bstr 1.12.1", "normpath", - "winapi", + "windows-sys 0.60.2", ] [[package]] name = "openssl" -version = "0.10.73" +version = "0.10.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cfg-if", "foreign-types", "libc", @@ -3570,7 +3671,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -3581,9 +3682,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.109" +version = "0.9.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2" dependencies = [ "cc", "libc", @@ -3591,6 +3692,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "ouroboros" version = "0.18.5" @@ -3612,7 +3719,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -3718,7 +3825,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -3733,52 +3840,55 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.7.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ "fixedbitset", - "indexmap 2.11.4", + "hashbrown 0.15.5", + "indexmap 2.12.1", + "serde", ] [[package]] name = "phf" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ "phf_macros", "phf_shared", + "serde", ] [[package]] name = "phf_generator" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ + "fastrand", "phf_shared", - "rand 0.8.5", ] [[package]] name = "phf_macros" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ "phf_generator", "phf_shared", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "phf_shared" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ "siphasher 1.0.1", ] @@ -3800,7 +3910,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -3827,34 +3937,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -[[package]] -name = "plotters" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" - -[[package]] -name = "plotters-svg" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" -dependencies = [ - "plotters-backend", -] - [[package]] name = "portable-atomic" version = "1.11.1" @@ -3863,9 +3945,9 @@ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -3876,6 +3958,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppmd-rust" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d558c559f0450f16f2a27a1f017ef38468c1090c9ce63c8e51366232d53717b4" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -3946,7 +4034,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -3955,7 +4043,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit 0.23.6", + "toml_edit", ] [[package]] @@ -3977,14 +4065,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -3997,18 +4085,41 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", - "version_check", - "yansi", + "syn 2.0.111", + "version_check", + "yansi", +] + +[[package]] +name = "prost" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.111", ] [[package]] -name = "ptr_meta" -version = "0.1.4" +name = "prost-types" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" dependencies = [ - "ptr_meta_derive 0.1.4", + "prost", ] [[package]] @@ -4017,18 +4128,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79" dependencies = [ - "ptr_meta_derive 0.3.1", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "ptr_meta_derive", ] [[package]] @@ -4039,7 +4139,7 @@ checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -4053,6 +4153,28 @@ dependencies = [ "unicase", ] +[[package]] +name = "pulley-interpreter" +version = "39.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a09eb45f768f3a0396e85822790d867000c8b5f11551e7268c279e991457b16" +dependencies = [ + "cranelift-bitset", + "log", + "pulley-macros", +] + +[[package]] +name = "pulley-macros" +version = "39.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e29368432b8b7a8a343b75a6914621fad905c95d5c5297449a6546c127224f7a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "quick-error" version = "2.0.1" @@ -4070,9 +4192,9 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.1", + "rustc-hash", "rustls", - "socket2 0.6.0", + "socket2", "thiserror 2.0.17", "tokio", "tracing", @@ -4086,11 +4208,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", - "getrandom 0.3.3", + "getrandom 0.3.4", "lru-slab", "rand 0.9.2", "ring", - "rustc-hash 2.1.1", + "rustc-hash", "rustls", "rustls-pki-types", "slab", @@ -4109,16 +4231,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.0", + "socket2", "tracing", "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -4135,7 +4257,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee" dependencies = [ - "ptr_meta 0.3.1", + "ptr_meta", ] [[package]] @@ -4194,7 +4316,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] @@ -4223,7 +4345,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", ] [[package]] @@ -4237,6 +4359,17 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror 2.0.17", +] + [[package]] name = "ref-cast" version = "1.0.25" @@ -4254,31 +4387,32 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "regalloc2" -version = "0.9.3" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" +checksum = "efd8138ce7c3d7c13be4f61893154b5d711bd798d2d7be3ecb8dcc7e7a06ca98" dependencies = [ - "hashbrown 0.13.2", + "allocator-api2", + "bumpalo", + "hashbrown 0.15.5", "log", - "rustc-hash 1.1.0", - "slice-group-by", + "rustc-hash", "smallvec", ] [[package]] name = "regex" -version = "1.11.3" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.11", + "regex-automata 0.4.13", "regex-syntax", ] @@ -4290,9 +4424,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-automata" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -4301,15 +4435,15 @@ dependencies = [ [[package]] name = "regex-lite" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943f41321c63ef1c92fd763bfe054d2668f7f225a5c29f0105903dc2fc04ba30" +checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "region" @@ -4319,7 +4453,7 @@ checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7" dependencies = [ "bitflags 1.3.2", "libc", - "mach2", + "mach2 0.4.3", "windows-sys 0.52.0", ] @@ -4329,7 +4463,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6" dependencies = [ - "bytecheck 0.8.2", + "bytecheck", ] [[package]] @@ -4340,12 +4474,12 @@ checksum = "51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884" [[package]] name = "reqwest" -version = "0.12.23" +version = "0.12.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" dependencies = [ "async-compression", - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-core", @@ -4374,15 +4508,15 @@ dependencies = [ "tokio-native-tls", "tokio-rustls", "tokio-util", - "tower 0.5.2", - "tower-http 0.6.6", + "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 1.0.2", + "webpki-roots 1.0.3", ] [[package]] @@ -4405,12 +4539,12 @@ version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35a640b26f007713818e9a9b65d34da1cf58538207b052916a83d80e43f3ffa4" dependencies = [ - "bytecheck 0.8.2", + "bytecheck", "bytes", "hashbrown 0.15.5", - "indexmap 2.11.4", + "indexmap 2.12.1", "munge", - "ptr_meta 0.3.1", + "ptr_meta", "rancor", "rend", "rkyv_derive", @@ -4426,7 +4560,7 @@ checksum = "bd83f5f173ff41e00337d97f6572e416d022ef8a19f371817259ae960324c482" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -4463,12 +4597,6 @@ version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -4495,27 +4623,14 @@ dependencies = [ [[package]] name = "rustfix" -version = "0.5.1" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c50b74badcddeb8f7652fa8323ce440b95286f8e4b64ebfd871c609672704e" +checksum = "82fa69b198d894d84e23afde8e9ab2af4400b2cba20d6bf2b428a8b01c222c5a" dependencies = [ - "anyhow", - "log", "serde", "serde_json", -] - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags 2.9.4", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "thiserror 1.0.69", + "tracing", ] [[package]] @@ -4524,18 +4639,18 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", - "linux-raw-sys 0.11.0", + "linux-raw-sys", "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.32" +version = "0.23.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" +checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7" dependencies = [ "log", "once_cell", @@ -4548,9 +4663,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -4560,9 +4675,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ "web-time", "zeroize", @@ -4570,9 +4685,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.7" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "ring", "rustls-pki-types", @@ -4630,13 +4745,11 @@ dependencies = [ [[package]] name = "ruzstd" -version = "0.5.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" +checksum = "e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01" dependencies = [ - "byteorder", - "derive_more 0.99.20", - "twox-hash 1.6.3", + "twox-hash", ] [[package]] @@ -4664,6 +4777,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scc" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" +dependencies = [ + "sdd", +] + [[package]] name = "schannel" version = "0.1.28" @@ -4675,12 +4797,13 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.22" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" dependencies = [ "dyn-clone", - "indexmap 2.11.4", + "indexmap 2.12.1", + "ref-cast", "schemars_derive", "serde", "serde_json", @@ -4689,14 +4812,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.22" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +checksum = "301858a4023d78debd2353c7426dc486001bddc91ae31a76fb1f55132f7e2633" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -4722,16 +4845,22 @@ checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] +[[package]] +name = "sdd" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" + [[package]] name = "security-framework" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -4744,7 +4873,7 @@ version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -4763,9 +4892,9 @@ dependencies = [ [[package]] name = "self_cell" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" +checksum = "16c2f82143577edb4921b71ede051dac62ca3c16084e918bf7b40c96ae10eb33" [[package]] name = "semver" @@ -4853,7 +4982,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -4864,7 +4993,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -4893,18 +5022,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_spanned" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ "serde_core", ] @@ -4927,7 +5047,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.1", "itoa", "ryu", "serde", @@ -4936,27 +5056,25 @@ dependencies = [ [[package]] name = "serial_test" -version = "2.0.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" +checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" dependencies = [ - "dashmap 5.5.3", - "futures", - "lazy_static", - "log", + "once_cell", "parking_lot", + "scc", "serial_test_derive", ] [[package]] name = "serial_test_derive" -version = "2.0.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" +checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -5057,12 +5175,6 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" -[[package]] -name = "slice-group-by" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" - [[package]] name = "smallvec" version = "1.15.1" @@ -5077,33 +5189,26 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "smoltcp" -version = "0.8.2" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee34c1e1bfc7e9206cc0fb8030a90129b4e319ab53856249bb27642cab914fb3" +checksum = "dad095989c1533c1c266d9b1e8d70a1329dd3723c3edac6d03bbd67e7bf6f4bb" dependencies = [ "bitflags 1.3.2", "byteorder", + "cfg-if", + "defmt 0.3.100", + "heapless 0.8.0", "managed", ] [[package]] name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -5114,9 +5219,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -5155,9 +5260,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -5181,7 +5286,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -5203,15 +5308,15 @@ checksum = "422045212ea98508ae3d28025bc5aaa2bd4a9cdaecd442a08da2ee620ee9ea95" [[package]] name = "target-lexicon" -version = "0.12.16" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" [[package]] name = "target-triple" -version = "0.1.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac9aa371f599d22256307c24a9d748c041e548cbf599f35d890f9d365361790" +checksum = "591ef38edfb78ca4771ee32cf494cb8771944bee237a9b91fc9c1424ac4b777b" [[package]] name = "tempfile" @@ -5220,9 +5325,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", - "rustix 1.1.2", + "rustix", "windows-sys 0.61.2", ] @@ -5248,12 +5353,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.3.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" dependencies = [ - "rustix 0.38.44", - "windows-sys 0.48.0", + "rustix", + "windows-sys 0.60.2", ] [[package]] @@ -5276,14 +5381,14 @@ name = "test-generator" version = "0.1.0" dependencies = [ "anyhow", - "target-lexicon 0.12.16", + "target-lexicon 0.13.3", ] [[package]] name = "test-log" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e33b98a582ea0be1168eba097538ee8dd4bbe0f2b01b22ac92ea30054e5be7b" +checksum = "37d53ac171c92a39e4769491c4b4dde7022c60042254b5fc044ae409d34a24d4" dependencies = [ "test-log-macros", "tracing-subscriber", @@ -5291,13 +5396,13 @@ dependencies = [ [[package]] name = "test-log-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451b374529930d7601b1eef8d32bc79ae870b6079b069401709c2a8bf9e75f36" +checksum = "be35209fd0781c5401458ab66e4f98accf63553e8fae7425503e92fdd319783b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -5348,7 +5453,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -5359,7 +5464,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -5415,9 +5520,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -5450,32 +5555,31 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", + "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2 0.6.0", + "socket2", "tokio-macros", - "windows-sys 0.59.0", + "tracing", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -5559,9 +5663,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -5572,36 +5676,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "toml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "indexmap 2.11.4", - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.11", - "toml_edit 0.22.27", -] - -[[package]] -name = "toml" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.1", "serde_core", - "serde_spanned 1.0.2", - "toml_datetime 0.7.2", + "serde_spanned", + "toml_datetime", "toml_parser", "toml_writer", "winnow", @@ -5609,114 +5691,94 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.11" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_datetime" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap 2.11.4", - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.11", - "toml_write", - "winnow", -] - -[[package]] -name = "toml_edit" -version = "0.23.6" +version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" dependencies = [ - "indexmap 2.11.4", - "toml_datetime 0.7.2", + "indexmap 2.12.1", + "toml_datetime", "toml_parser", "winnow", ] [[package]] name = "toml_parser" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ "winnow", ] -[[package]] -name = "toml_write" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" - [[package]] name = "toml_writer" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d163a63c116ce562a22cda521fcc4d79152e7aba014456fb5eb442f6d6a10109" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" [[package]] -name = "tower" -version = "0.4.13" +name = "tonic" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" dependencies = [ - "futures-core", - "futures-util", + "async-trait", + "axum", + "base64 0.22.1", + "bytes", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", "pin-project", - "pin-project-lite", + "socket2", + "sync_wrapper", "tokio", + "tokio-stream", + "tower", "tower-layer", "tower-service", "tracing", ] [[package]] -name = "tower" -version = "0.5.2" +name = "tonic-prost" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", + "bytes", + "prost", + "tonic", ] [[package]] -name = "tower-http" +name = "tower" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ - "bitflags 2.9.4", - "bytes", + "futures-core", "futures-util", - "http", - "http-body", - "http-body-util", + "indexmap 2.12.1", "pin-project-lite", - "tower 0.4.13", + "slab", + "sync_wrapper", + "tokio", + "tokio-util", "tower-layer", "tower-service", "tracing", @@ -5724,20 +5786,22 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "bytes", "futures-util", "http", "http-body", + "http-body-util", "iri-string", "pin-project-lite", - "tower 0.5.2", + "tower", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -5772,7 +5836,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -5815,7 +5879,7 @@ dependencies = [ "matchers", "nu-ansi-term", "once_cell", - "regex-automata 0.4.11", + "regex-automata 0.4.13", "serde", "serde_json", "sharded-slab", @@ -5845,7 +5909,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -5867,9 +5931,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.111" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ded9fdb81f30a5708920310bfcd9ea7482ff9cba5f54601f7a19a877d5c2392" +checksum = "3e17e807bff86d2a06b52bca4276746584a78375055b6e45843925ce2802b335" dependencies = [ "glob", "serde", @@ -5877,7 +5941,7 @@ dependencies = [ "serde_json", "target-triple", "termcolor", - "toml 0.9.7", + "toml", ] [[package]] @@ -5921,19 +5985,15 @@ dependencies = [ [[package]] name = "twox-hash" -version = "1.6.3" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" -dependencies = [ - "cfg-if", - "static_assertions", -] +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" [[package]] -name = "twox-hash" -version = "2.1.2" +name = "typeid" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" @@ -5943,9 +6003,9 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "typetag" -version = "0.1.8" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4080564c5b2241b5bff53ab610082234e0c57b0417f4bd10596f183001505b8a" +checksum = "be2212c8a9b9bcfca32024de14998494cf9a5dfa59ea1b829de98bac374b86bf" dependencies = [ "erased-serde", "inventory", @@ -5956,13 +6016,13 @@ dependencies = [ [[package]] name = "typetag-impl" -version = "0.1.8" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e60147782cc30833c05fba3bab1d9b5771b2685a2557672ac96fa5d154099c0e" +checksum = "27a7a9b72ba121f6f1f6c3632b85604cac41aedb5ddc70accbebb6cac83de846" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.111", ] [[package]] @@ -5979,9 +6039,9 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "unicode-normalization" @@ -5998,12 +6058,6 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - [[package]] name = "unicode-width" version = "0.2.2" @@ -6018,132 +6072,141 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "uniffi" -version = "0.27.3" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3a4c447c50fcda7bc5604a8588b7e1f37ffbfd8838a1516a290398efa7c6f0" +checksum = "c866f627c3f04c3df068b68bb2d725492caaa539dd313e2a9d26bb85b1a32f4e" dependencies = [ "anyhow", + "cargo_metadata 0.19.2", + "uniffi_bindgen", "uniffi_build", "uniffi_core", "uniffi_macros", + "uniffi_pipeline", ] [[package]] name = "uniffi_bindgen" -version = "0.27.3" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0be2bc6bafd82c979b0faca77c7b26630d54017de9f5bd5a686ec6ef038ad5d9" +checksum = "7c8ca600167641ebe7c8ba9254af40492dda3397c528cc3b2f511bd23e8541a5" dependencies = [ "anyhow", "askama", "camino", - "cargo_metadata", + "cargo_metadata 0.19.2", "fs-err", "glob", "goblin", - "heck 0.4.1", + "heck 0.5.0", + "indexmap 2.12.1", "once_cell", - "paste", "serde", + "tempfile", "textwrap", - "toml 0.5.11", + "toml", + "uniffi_internal_macros", "uniffi_meta", - "uniffi_testing", + "uniffi_pipeline", "uniffi_udl", ] [[package]] name = "uniffi_build" -version = "0.27.3" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c59b65d59685ff3a10569287c6419f76487b4052ac52d5a0df38b2253d7f440" +checksum = "3e55c05228f4858bb258f651d21d743fcc1fe5a2ec20d3c0f9daefddb105ee4d" dependencies = [ "anyhow", - "camino", - "uniffi_bindgen", -] - -[[package]] -name = "uniffi_checksum_derive" -version = "0.27.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5c400339a9d1d17be34257d0b407e91d64af335e5b4fa49f4bf28467fc8d635" -dependencies = [ - "quote", - "syn 2.0.106", + "camino", + "uniffi_bindgen", ] [[package]] name = "uniffi_core" -version = "0.27.3" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a02e67ac9634b10da9e4aa63a29a7920b8f1395eafef1ea659b2dd76dda96906" +checksum = "7e7a5a038ebffe8f4cf91416b154ef3c2468b18e828b7009e01b1b99938089f9" dependencies = [ "anyhow", "bytes", - "camino", - "log", "once_cell", - "paste", "static_assertions", ] +[[package]] +name = "uniffi_internal_macros" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c2a6f93e7b73726e2015696ece25ca0ac5a5f1cf8d6a7ab5214dd0a01d2edf" +dependencies = [ + "anyhow", + "indexmap 2.12.1", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "uniffi_macros" -version = "0.27.3" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6f08d5592c669b80a8af5066027098bebec4b4af17a9b8b299bac5f518ab89e" +checksum = "64c6309fc36c7992afc03bc0c5b059c656bccbef3f2a4bc362980017f8936141" dependencies = [ - "bincode", "camino", "fs-err", "once_cell", "proc-macro2", "quote", "serde", - "syn 2.0.106", - "toml 0.5.11", + "syn 2.0.111", + "toml", "uniffi_meta", ] [[package]] name = "uniffi_meta" -version = "0.27.3" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583bab49f2bdf5681f9732f8b67a7e555ad920dbb5427be21450217bf1818189" +checksum = "0a138823392dba19b0aa494872689f97d0ee157de5852e2bec157ce6de9cdc22" dependencies = [ "anyhow", - "bytes", "siphasher 0.3.11", - "uniffi_checksum_derive", + "uniffi_internal_macros", + "uniffi_pipeline", ] [[package]] -name = "uniffi_testing" -version = "0.27.3" +name = "uniffi_pipeline" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13963044ca9bde9b709d2eee68bc11dafc7acea144ae0fdc0cf29ed4add44481" +checksum = "8c27c4b515d25f8e53cc918e238c39a79c3144a40eaf2e51c4a7958973422c29" dependencies = [ "anyhow", - "camino", - "cargo_metadata", - "fs-err", - "once_cell", + "heck 0.5.0", + "indexmap 2.12.1", + "tempfile", + "uniffi_internal_macros", ] [[package]] name = "uniffi_udl" -version = "0.27.3" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b92f984bb0d9a06778f256aec963e1e9a80714014f7a90fb0e01008821fe5a97" +checksum = "d0adacdd848aeed7af4f5af7d2f621d5e82531325d405e29463482becfdeafca" dependencies = [ "anyhow", "textwrap", "uniffi_meta", - "uniffi_testing", "weedle2", ] +[[package]] +name = "unit-prefix" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" + [[package]] name = "unix_mode" version = "0.1.4" @@ -6164,18 +6227,31 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.12.1" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +checksum = "d39cb1dbab692d82a977c0392ffac19e188bd9186a9f32806f0aaa859d75585a" dependencies = [ - "base64", + "base64 0.22.1", "flate2", "log", - "once_cell", + "percent-encoding", "rustls", "rustls-pki-types", - "url", - "webpki-roots 0.26.11", + "ureq-proto", + "utf-8", + "webpki-roots 1.0.3", +] + +[[package]] +name = "ureq-proto" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d81f9efa9df032be5934a46a068815a10a042b494b6a58cb0a1a97bb5467ed6f" +dependencies = [ + "base64 0.22.1", + "http", + "httparse", + "log", ] [[package]] @@ -6220,7 +6296,7 @@ version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "js-sys", "wasm-bindgen", ] @@ -6250,14 +6326,14 @@ dependencies = [ "anyhow", "async-trait", "bytes", - "dashmap 6.1.0", - "derive_more 2.0.1", + "dashmap", + "derive_more", "dunce", "filetime", "fs_extra", "futures", "getrandom 0.2.16", - "indexmap 2.11.4", + "indexmap 2.12.1", "libc", "pin-project-lite", "pretty_assertions", @@ -6266,7 +6342,7 @@ dependencies = [ "shared-buffer", "slab", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "tracing", "tracing-test", @@ -6285,9 +6361,10 @@ dependencies = [ "bytes", "futures", "mio", + "parking", "serde", - "socket2 0.5.10", - "thiserror 1.0.69", + "socket2", + "thiserror 2.0.17", "tracing", ] @@ -6297,11 +6374,11 @@ version = "0.601.0" dependencies = [ "anyhow", "async-trait", - "base64", + "base64 0.22.1", "bincode", - "bytecheck 0.6.12", + "bytecheck", "bytes", - "derive_more 2.0.1", + "derive_more", "futures-util", "hyper", "hyper-tungstenite", @@ -6315,8 +6392,8 @@ dependencies = [ "serde", "serial_test", "smoltcp", - "socket2 0.5.10", - "thiserror 1.0.69", + "socket2", + "thiserror 2.0.17", "tokio", "tokio-serde", "tokio-tungstenite 0.24.0", @@ -6396,9 +6473,9 @@ version = "0.601.0" dependencies = [ "anyhow", "async-trait", - "bitflags 1.3.2", + "bitflags 2.10.0", "once_cell", - "thiserror 1.0.69", + "thiserror 2.0.17", "tracing", "wai-bindgen-wasmer-impl", "wasmer", @@ -6475,15 +6552,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasi-test-generator" version = "6.1.0" @@ -6493,7 +6561,7 @@ dependencies = [ "serde", "serde_json", "tempfile", - "wast 216.0.1", + "wast", ] [[package]] @@ -6507,9 +6575,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -6518,25 +6586,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.54" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", @@ -6547,9 +6601,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6557,31 +6611,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.106", - "wasm-bindgen-backend", + "syn 2.0.111", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-bindgen-test" -version = "0.3.54" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e381134e148c1062f965a42ed1f5ee933eef2927c3f70d1812158f711d39865" +checksum = "bfc379bfb624eb59050b509c13e77b4eb53150c350db69628141abce842f2373" dependencies = [ "js-sys", "minicov", @@ -6592,13 +6646,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.54" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b673bca3298fe582aeef8352330ecbad91849f85090805582400850f8270a2e8" +checksum = "085b2df989e1e6f9620c1311df6c996e83fe16f57792b272ce1e024ac16a90f1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -6648,41 +6702,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.216.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1de2d0fd411c201b8d76c04213901f9bb221abf17dd59c2201542d0b118bb90" -dependencies = [ - "leb128", -] - -[[package]] -name = "wasm-encoder" -version = "0.221.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc8444fe4920de80a4fe5ab564fff2ae58b6b73166b89751f8c6c93509da32e5" -dependencies = [ - "leb128", - "wasmparser 0.221.3", -] - -[[package]] -name = "wasm-encoder" -version = "0.235.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3bc393c395cb621367ff02d854179882b9a351b4e0c93d1397e6090b53a5c2a" -dependencies = [ - "leb128fmt", - "wasmparser 0.235.0", -] - -[[package]] -name = "wasm-encoder" -version = "0.239.0" +version = "0.242.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be00faa2b4950c76fe618c409d2c3ea5a3c9422013e079482d78544bb2d184c" +checksum = "67f90e55bc9c6ee6954a757cc6eb3424d96b442e5252ed10fea627e518878d36" dependencies = [ "leb128fmt", - "wasmparser 0.239.0", + "wasmparser 0.242.0", ] [[package]] @@ -6719,9 +6744,11 @@ dependencies = [ "bytes", "cfg-if", "cmake", - "derive_more 2.0.1", - "hashbrown 0.11.2", - "indexmap 2.11.4", + "corosensei", + "derive_more", + "futures", + "hashbrown 0.16.1", + "indexmap 2.12.1", "js-sys", "loupe", "macro-wasmer-universal-test", @@ -6733,9 +6760,10 @@ dependencies = [ "serde-wasm-bindgen", "shared-buffer", "tar", - "target-lexicon 0.12.16", + "target-lexicon 0.13.3", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.17", + "tokio", "tracing", "ureq", "wasm-bindgen", @@ -6751,7 +6779,7 @@ dependencies = [ "wasmparser 0.224.1", "wat", "which", - "windows-sys 0.59.0", + "windows-sys 0.61.2", "xz", "zip", ] @@ -6764,7 +6792,7 @@ dependencies = [ "async-trait", "clap", "cynic", - "derive_more 2.0.1", + "derive_more", "futures", "indicatif", "log", @@ -6787,7 +6815,7 @@ version = "0.601.0" dependencies = [ "anyhow", "async-tungstenite", - "base64", + "base64 0.22.1", "cynic", "futures", "getrandom 0.2.16", @@ -6837,7 +6865,7 @@ dependencies = [ "inline-c", "libc", "paste", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "tracing", "tracing-subscriber", @@ -6861,7 +6889,7 @@ version = "6.1.0" dependencies = [ "cc", "regex", - "target-lexicon 0.11.2", + "target-lexicon 0.13.3", "walkdir", ] @@ -6876,9 +6904,9 @@ dependencies = [ "clap_lex", "criterion", "hex", - "rand 0.8.5", + "rand 0.9.2", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.17", "wasmer", "wasmer-compiler-singlepass", ] @@ -6889,7 +6917,7 @@ version = "6.1.0" dependencies = [ "cc", "regex", - "target-lexicon 0.11.2", + "target-lexicon 0.13.3", "walkdir", ] @@ -6898,20 +6926,21 @@ name = "wasmer-cli" version = "6.1.0" dependencies = [ "anyhow", - "assert_cmd 2.0.17", + "assert_cmd 2.1.1", "async-trait", - "base64", + "base64 0.22.1", "bytes", "bytesize", - "cargo_metadata", + "cargo_metadata 0.23.1", "cfg-if", "chrono", "clap", "clap_complete", "clap_mangen", - "colored 2.2.0", + "colored", "comfy-table", - "console", + "console 0.16.1", + "console-subscriber", "dialoguer", "dirs", "dotenvy", @@ -6919,26 +6948,27 @@ dependencies = [ "fuser", "futures", "futures-util", + "git-version", "hex", "http", "http-body-util", "humantime", "hyper", "hyper-util", - "indexmap 2.11.4", + "indexmap 2.12.1", "indicatif", "interfaces", - "is-terminal", "libc", "log", "lzma-rs", "mac_address", "mio", "normpath", - "object 0.32.2", + "object 0.38.0", "once_cell", "opener", "parking_lot", + "path-clean", "pathdiff", "predicates 3.1.3", "pretty_assertions", @@ -6952,14 +6982,14 @@ dependencies = [ "sha2", "shared-buffer", "tar", - "target-lexicon 0.12.16", + "target-lexicon 0.13.3", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.17", "time 0.1.45", "time 0.3.44", "tokio", "tokio-tungstenite 0.24.0", - "toml 0.8.23", + "toml", "tracing", "tracing-subscriber", "unix_mode", @@ -6996,14 +7026,15 @@ dependencies = [ "cfg-if", "enum-iterator", "enumset", - "hashbrown 0.11.2", + "hashbrown 0.16.1", + "itertools 0.14.0", "leb128", "libc", "loupe", "macho-unwind-info", - "memmap2 0.6.2", + "memmap2 0.9.9", "more-asserts", - "object 0.32.2", + "object 0.38.0", "region", "rkyv", "self_cell", @@ -7011,37 +7042,17 @@ dependencies = [ "serde_bytes", "shared-buffer", "smallvec", - "target-lexicon 0.12.16", - "thiserror 1.0.69", + "target-lexicon 0.13.3", + "tempfile", + "thiserror 2.0.17", "wasmer-types", "wasmer-vm", "wasmparser 0.224.1", - "windows-sys 0.59.0", + "which", + "windows-sys 0.61.2", "xxhash-rust", ] -[[package]] -name = "wasmer-compiler-cli" -version = "6.1.0" -dependencies = [ - "anyhow", - "bytesize", - "cfg-if", - "clap", - "colored 2.2.0", - "distance", - "fern", - "is-terminal", - "log", - "target-lexicon 0.12.16", - "unix_mode", - "wasmer-compiler", - "wasmer-compiler-cranelift", - "wasmer-compiler-llvm", - "wasmer-compiler-singlepass", - "wasmer-types", -] - [[package]] name = "wasmer-compiler-cranelift" version = "6.1.0" @@ -7049,13 +7060,13 @@ dependencies = [ "cranelift-codegen", "cranelift-entity", "cranelift-frontend", - "gimli 0.28.1", - "hashbrown 0.11.2", - "itertools 0.12.1", + "gimli", + "hashbrown 0.16.1", + "itertools 0.14.0", "more-asserts", "rayon", "smallvec", - "target-lexicon 0.12.16", + "target-lexicon 0.13.3", "tracing", "wasmer-compiler", "wasmer-types", @@ -7068,16 +7079,16 @@ dependencies = [ "byteorder", "cc", "inkwell", - "itertools 0.12.1", + "itertools 0.14.0", "libc", - "object 0.32.2", + "object 0.38.0", "phf", "rayon", "regex", "rustc_version 0.4.1", "semver 1.0.27", "smallvec", - "target-lexicon 0.12.16", + "target-lexicon 0.13.3", "tracing", "wasmer-compiler", "wasmer-types", @@ -7092,12 +7103,14 @@ dependencies = [ "dynasm", "dynasmrt", "enumset", - "gimli 0.28.1", - "hashbrown 0.11.2", + "gimli", + "hashbrown 0.16.1", + "itertools 0.14.0", "more-asserts", "rayon", "smallvec", - "target-lexicon 0.12.16", + "target-lexicon 0.13.3", + "tempfile", "wasmer-compiler", "wasmer-types", ] @@ -7111,7 +7124,7 @@ dependencies = [ "ciborium", "derive_builder", "hex", - "indexmap 2.11.4", + "indexmap 2.12.1", "pretty_assertions", "saffron", "schemars", @@ -7120,8 +7133,8 @@ dependencies = [ "serde_json", "serde_yaml", "tempfile", - "thiserror 1.0.69", - "toml 0.8.23", + "thiserror 2.0.17", + "toml", "url", ] @@ -7133,7 +7146,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.111", "wasmer-types", ] @@ -7170,7 +7183,7 @@ name = "wasmer-integration-tests-cli" version = "6.1.0" dependencies = [ "anyhow", - "assert_cmd 2.0.17", + "assert_cmd 2.1.1", "dirs", "flate2", "futures", @@ -7178,16 +7191,16 @@ dependencies = [ "insta", "libc", "md5", - "object 0.30.4", + "object 0.38.0", "once_cell", - "predicates 2.1.5", + "predicates 3.1.3", "pretty_assertions", - "rand 0.8.5", + "rand 0.9.2", "regex", "reqwest", "serde", "tar", - "target-lexicon 0.12.16", + "target-lexicon 0.13.3", "tempfile", "tokio", ] @@ -7202,11 +7215,11 @@ version = "0.601.0" dependencies = [ "anyhow", "async-trait", - "base64", + "base64 0.22.1", "bincode", - "bytecheck 0.6.12", + "bytecheck", "bytes", - "derive_more 2.0.1", + "derive_more", "lz4_flex", "num_enum", "rkyv", @@ -7214,7 +7227,7 @@ dependencies = [ "serde_json", "shared-buffer", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.17", "tracing", "tracing-test", "virtual-fs", @@ -7255,8 +7268,8 @@ dependencies = [ "shared-buffer", "tar", "tempfile", - "thiserror 1.0.69", - "toml 0.8.23", + "thiserror 2.0.17", + "toml", "ureq", "url", "wasmer-config", @@ -7280,9 +7293,9 @@ dependencies = [ "serde_yaml", "sha2", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", - "toml 0.8.23", + "toml", "tracing", "url", "walkdir", @@ -7296,7 +7309,7 @@ dependencies = [ name = "wasmer-swift" version = "0.601.0" dependencies = [ - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "uniffi", "virtual-fs", @@ -7324,12 +7337,12 @@ dependencies = [ name = "wasmer-types" version = "6.1.0" dependencies = [ - "bytecheck 0.6.12", + "bytecheck", "enum-iterator", "enumset", "getrandom 0.2.16", "hex", - "indexmap 2.11.4", + "indexmap 2.12.1", "loupe", "memoffset 0.9.1", "more-asserts", @@ -7337,8 +7350,8 @@ dependencies = [ "serde", "serde_bytes", "sha2", - "target-lexicon 0.12.16", - "thiserror 1.0.69", + "target-lexicon 0.13.3", + "thiserror 2.0.17", "wasmparser 0.224.1", "xxhash-rust", ] @@ -7352,24 +7365,25 @@ dependencies = [ "cfg-if", "corosensei", "crossbeam-queue", - "dashmap 6.1.0", + "dashmap", "enum-iterator", "fnv", - "indexmap 2.11.4", + "indexmap 2.12.1", "libc", "libunwind", "loupe", - "mach2", + "mach2 0.6.0", "memoffset 0.9.1", "more-asserts", + "parking_lot", "region", "rustversion", "scopeguard", "serde", - "thiserror 1.0.69", + "thiserror 2.0.17", "tracing", "wasmer-types", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -7379,22 +7393,22 @@ dependencies = [ "anyhow", "assert-panic", "async-trait", - "base64", + "base64 0.22.1", "bincode", "blake3", "bus", - "bytecheck 0.6.12", + "bytecheck", "bytes", "cfg-if", "chrono", "cooked-waker", "crossbeam-channel", - "dashmap 6.1.0", - "derive_more 2.0.1", + "dashmap", + "derive_more", "env_logger", "futures", "getrandom 0.2.16", - "heapless", + "heapless 0.9.2", "hex", "http", "http-body-util", @@ -7426,12 +7440,12 @@ dependencies = [ "tempfile", "terminal_size", "termios", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "tokio-stream", - "toml 0.8.23", - "tower 0.4.13", - "tower-http 0.5.2", + "toml", + "tower", + "tower-http", "tracing", "tracing-subscriber", "tracing-test", @@ -7446,7 +7460,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test", - "wasm-encoder 0.235.0", + "wasm-encoder 0.242.0", "wasmer", "wasmer-config", "wasmer-journal", @@ -7459,7 +7473,7 @@ dependencies = [ "web-sys", "webc", "weezl", - "windows-sys 0.59.0", + "windows-sys 0.61.2", "xxhash-rust", ] @@ -7468,7 +7482,7 @@ name = "wasmer-wasix-types" version = "0.601.0" dependencies = [ "anyhow", - "bitflags 1.3.2", + "bitflags 2.10.0", "byteorder", "cfg-if", "num_enum", @@ -7491,16 +7505,17 @@ name = "wasmer-wast" version = "6.1.0" dependencies = [ "anyhow", + "fs_extra", "futures", "serde", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "virtual-fs", "wasmer", "wasmer-types", "wasmer-wasix", - "wast 221.0.3", + "wast", ] [[package]] @@ -7518,6 +7533,7 @@ dependencies = [ "criterion", "crossbeam-queue", "glob", + "itertools 0.14.0", "reqwest", "rustc_version 0.4.1", "serial_test", @@ -7528,7 +7544,6 @@ dependencies = [ "tracing", "tracing-subscriber", "ureq", - "wasi-test-generator", "wasmer", "wasmer-cache", "wasmer-compiler", @@ -7602,26 +7617,13 @@ dependencies = [ "wasmi_core", ] -[[package]] -name = "wasmparser" -version = "0.121.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" -dependencies = [ - "bitflags 2.9.4", - "indexmap 2.11.4", - "semver 1.0.27", -] - [[package]] name = "wasmparser" version = "0.221.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d06bfa36ab3ac2be0dee563380147a5b81ba10dd8885d7fbbc9eb574be67d185" dependencies = [ - "bitflags 2.9.4", - "indexmap 2.11.4", - "semver 1.0.27", + "bitflags 2.10.0", ] [[package]] @@ -7630,86 +7632,60 @@ version = "0.224.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04f17a5917c2ddd3819e84c661fae0d6ba29d7b9c1f0e96c708c65a9c4188e11" dependencies = [ - "bitflags 2.9.4", -] - -[[package]] -name = "wasmparser" -version = "0.235.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917" -dependencies = [ - "bitflags 2.9.4", - "indexmap 2.11.4", + "bitflags 2.10.0", ] [[package]] name = "wasmparser" -version = "0.239.0" +version = "0.242.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" +checksum = "ed3c6e611f4cd748d85c767815823b777dc56afca793fcda27beae4e85028849" dependencies = [ - "bitflags 2.9.4", - "indexmap 2.11.4", + "bitflags 2.10.0", + "indexmap 2.12.1", "semver 1.0.27", ] [[package]] name = "wasmprinter" -version = "0.2.80" +version = "0.242.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60e73986a6b7fdfedb7c5bf9e7eb71135486507c8fbc4c0c42cffcb6532988b7" +checksum = "936a79bf33649f3aa0cd7cdf495e62ac0c718b3630ab53946df6dc2eff73a0d6" dependencies = [ "anyhow", - "wasmparser 0.121.2", -] - -[[package]] -name = "wast" -version = "216.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62cc4cc72b93d4a11c416ad1b4bb37888a9ea1dff575ee865f5bf26682ceba0e" -dependencies = [ - "bumpalo", - "leb128", - "memchr", - "unicode-width 0.1.14", - "wasm-encoder 0.216.1", + "termcolor", + "wasmparser 0.242.0", ] [[package]] -name = "wast" -version = "221.0.3" +name = "wasmtime-internal-math" +version = "39.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e0d10d282261b825ffb3d49f46e8309e60a8b608328b6a0b0578e80f3f98e57" +checksum = "cd1b856e1bbf0230ab560ba4204e944b141971adc4e6cdf3feb6979c1a7b7953" dependencies = [ - "bumpalo", - "leb128", - "memchr", - "unicode-width 0.2.2", - "wasm-encoder 0.221.3", + "libm", ] [[package]] name = "wast" -version = "239.0.0" +version = "242.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9139176fe8a2590e0fb174cdcaf373b224cb93c3dde08e4297c1361d2ba1ea5d" +checksum = "50a61ae2997784a4ae2a47b3a99f7cf0ad2a54db09624a28a0c2e9d7a24408ce" dependencies = [ "bumpalo", "leb128fmt", "memchr", - "unicode-width 0.2.2", - "wasm-encoder 0.239.0", + "unicode-width", + "wasm-encoder 0.242.0", ] [[package]] name = "wat" -version = "1.239.0" +version = "1.242.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e1c941927d34709f255558166f8901a2005f8ab4a9650432e9281b7cc6f3b75" +checksum = "5ae8cf6adfb79b5d89cb3fe68bd56aaab9409d9cf23b588097eae7d75585dae2" dependencies = [ - "wast 239.0.0", + "wast", ] [[package]] @@ -7739,9 +7715,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -7764,13 +7740,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "637506ca3c48eae3301e97f0167aa1b46cdfdd479d008b868a19715182e48ae3" dependencies = [ "anyhow", - "base64", + "base64 0.22.1", "bytes", "cfg-if", "ciborium", "document-features", "ignore", - "indexmap 2.11.4", + "indexmap 2.12.1", "leb128", "lexical-sort", "libc", @@ -7791,14 +7767,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.2", + "webpki-roots 1.0.3", ] [[package]] name = "webpki-roots" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" +checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" dependencies = [ "rustls-pki-types", ] @@ -7814,19 +7790,18 @@ dependencies = [ [[package]] name = "weezl" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "which" -version = "7.0.3" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" +checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d" dependencies = [ - "either", "env_home", - "rustix 1.1.2", + "rustix", "winsafe", ] @@ -7882,7 +7857,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -7893,7 +7868,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -7920,15 +7895,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -7965,21 +7931,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -8013,12 +7964,6 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -8031,12 +7976,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -8049,12 +7988,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -8079,12 +8012,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -8097,12 +8024,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -8115,12 +8036,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -8133,12 +8048,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -8174,9 +8083,9 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "xattr" @@ -8185,7 +8094,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ "libc", - "rustix 1.1.2", + "rustix", ] [[package]] @@ -8220,11 +8129,10 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -8232,13 +8140,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", "synstructure", ] @@ -8269,7 +8177,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -8280,7 +8188,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -8300,7 +8208,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", "synstructure", ] @@ -8321,14 +8229,14 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -8337,9 +8245,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -8348,45 +8256,48 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "zip" -version = "2.4.2" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" +checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b" dependencies = [ "aes", "arbitrary", "bzip2", "constant_time_eq", "crc32fast", - "crossbeam-utils", "deflate64", - "displaydoc", "flate2", - "getrandom 0.3.3", + "getrandom 0.3.4", "hmac", - "indexmap 2.11.4", - "lzma-rs", + "indexmap 2.12.1", + "lzma-rust2", "memchr", "pbkdf2", + "ppmd-rust", "sha1", - "thiserror 2.0.17", "time 0.3.44", - "xz2", "zeroize", "zopfli", "zstd", ] +[[package]] +name = "zlib-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2" + [[package]] name = "zopfli" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index 1a866eac9f..ed71d86dca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,29 +13,26 @@ version.workspace = true [dependencies] wasmer = { version = "=6.1.0", path = "lib/api", default-features = false } +wasmer-cache = { version = "=6.1.0", path = "lib/cache", optional = true } wasmer-compiler = { version = "=6.1.0", path = "lib/compiler", features = [ "compiler", ], optional = true } wasmer-compiler-cranelift = { version = "=6.1.0", path = "lib/compiler-cranelift", optional = true } -wasmer-compiler-singlepass = { version = "=6.1.0", path = "lib/compiler-singlepass", optional = true } wasmer-compiler-llvm = { version = "=6.1.0", path = "lib/compiler-llvm", optional = true } -wasmer-wasix = { path = "lib/wasix", optional = true } -wasmer-wast = { version = "=6.1.0", path = "tests/lib/wast", optional = true } -wasi-test-generator = { version = "=6.1.0", path = "tests/wasi-wast", optional = true } -wasmer-cache = { version = "=6.1.0", path = "lib/cache", optional = true } -wasmer-types = { version = "=6.1.0", path = "lib/types" } +wasmer-compiler-singlepass = { version = "=6.1.0", path = "lib/compiler-singlepass", optional = true } wasmer-middlewares = { version = "=6.1.0", path = "lib/middlewares", optional = true } - +wasmer-types = { version = "=6.1.0", path = "lib/types" } +wasmer-wast = { version = "=6.1.0", path = "tests/lib/wast", optional = true } +wasmer-wasix = { path = "lib/wasix", optional = true } # Third party dependencies - -cfg-if = "1.0" -tokio = { version = "1.39", features = [ +cfg-if.workspace = true +crossbeam-queue.workspace = true +tokio = { workspace = true, features = [ "rt", "rt-multi-thread", "macros", ], optional = true } -crossbeam-queue = "0.3.8" [workspace] members = [ @@ -47,7 +44,6 @@ members = [ "lib/c-api/examples/wasmer-capi-examples-runner", "lib/c-api/tests/wasmer-c-api-test-runner", "lib/cache", - "lib/cli-compiler", "lib/cli", "lib/compiler-cranelift", "lib/compiler-llvm", @@ -74,18 +70,17 @@ members = [ "tests/lib/wast", "tests/wasi-wast", "tests/wasmer-argus", - "lib/sdk", ] exclude = ["./lib/cli/tests/packages/axum"] resolver = "2" [workspace.package] authors = ["Wasmer Engineering Team "] -edition = "2021" +edition = "2024" homepage = "https://wasmer.io/" license = "MIT" repository = "https://github.com/wasmerio/wasmer" -rust-version = "1.84" +rust-version = "1.90" version = "6.1.0" [workspace.dependencies] @@ -101,84 +96,239 @@ shared-buffer = "0.1.4" loupe = "0.2.0" # Third-party crates -bytes = "1" -serde_bytes = { version = "0.11" } -hex = "0.4" anyhow = "1.0" -sha2 = "0.10" +assert-panic = "1.0.1" +assert_cmd = "2.1.1" async-trait = "0.1.68" -getrandom = "0.2" -ciborium = "0.2.2" -bytesize = "1.3.0" -semver = "1.0" -tempfile = "3.6.0" +async-tungstenite = "0.28.0" +axum = { version = "=0.6.9", default-features = false } +backtrace = "0.3" +base64 = "0.22.1" +bincode = "1.3" +bindgen = { version = "0.72.1", default-features = false } +bitflags = "2.10.0" +blake3 = "1.0" +build-deps = "0.1.4" +bus = "2.4.1" +bytecheck = { version = "0.8.2" } +byteorder = "1.3" +bytes = "1" +bytesize = "2.3.1" +cargo_metadata = "0.23.1" +cbindgen = { version = "0.29", default-features = false } +cc = "1.2.47" cfg-if = "1.0" -tar = "0.4.40" +chrono = { version = "^0.4.38", default-features = false } +ciborium = "0.2.2" +clap = { version = "4.5.53", default-features = false } +clap_builder = { version = "4.5.53" } +clap_complete = "4.5.61" +clap_derive = { version = "4.5.49" } +clap_lex = { version = "0.7.6" } +clap_mangen = "0.2.31" +cmake = "0.1.50" +colored = "3.0.0" +comfy-table = "7.2.1" +compiletest_rs = "0.11.2" +console = "0.16.1" +console-subscriber = "0.5.0" +cooked-waker = "^5" +corosensei = "0.3.0" +cranelift-codegen = { version = "=0.126.1", default-features = false } +cranelift-entity = { version = "=0.126.1", default-features = false } +cranelift-frontend = { version = "=0.126.1", default-features = false } +criterion = { version = "0.7", default-features = false } +crossbeam-channel = "0.5.15" +crossbeam-queue = "0.3.8" +cynic = { version = "3.7.2", default-features = false } +dashmap = "6.1.0" +derive_builder = "0.20.2" +derive_more = { version = "2.0.1", features = ["debug", "display"] } +dialoguer = "0.12.0" +dirs = "6.0.0" +dotenvy = "0.15.7" +dunce = "1.0.4" +dynasm = "4.0.0" +dynasmrt = "4.0.0" +enum-iterator = "2.3.0" +enumset = "1.1.0" +env_logger = { version = "0.11.5", default-features = false } +field-offset = "0.3.3" +filetime = "0.2.18" flate2 = "1.0.34" +fnv = "1.0.3" +fs_extra = { version = "1.3.0" } +futures = "0.3.30" +futures-util = { version = "0.3.31" } +getrandom = "0.2" +gimli = { version = "0.32.3" } +git-version = "0.3.9" +glob = "0.3" +graphql-ws-client = "0.11.0" +gumdrop = "0.8" +harsh = "0.2.2" +hashbrown = "0.16.1" +heapless = "0.9.2" +hex = "0.4" +hexdump = "0.1.2" +http = "1.4.0" +http-body-util = "0.1.1" +humantime = "2.1.0" +hyper = "1.8.1" +hyper-tungstenite = "0.13" +hyper-util = "0.1.5" +ignore = "0.4" +indicatif = "0.18.3" +indexmap = "2" +inline-c = "0.1.7" +# TODO: use a proper release +inkwell = { git = "https://github.com/TheDan64/inkwell.git", rev = "b9c53276e30935ccec841d12c9687a17e9199958", default-features = false } +insta = "1.44.2" +interfaces = "0.0.9" +ipnet = "2.10.1" +iprange = "0.6.7" +itertools = "0.14" +js-sys = "0.3.77" +leb128 = "0.2" +libc = { version = "0.2.178", default-features = false } +libfuzzer-sys = "0.4.0" +libunwind = "1.3.3" +linked_hash_set = "0.1.6" log = "0.4.22" -blake3 = "1.0" +lz4_flex = "0.12.0" +lzma-rs = "0.3.0" +mac_address = "1.1.5" +mach2 = "0.6.0" +macho-unwind-info = "0.5.0" +md5 = "0.8.0" +memmap2 = { version = "0.9.9" } +memoffset = "0.9.1" +merge-streams = "0.1.2" +mio = "1" +more-asserts = "0.3.1" +normpath = "1.5.0" +num_enum = "0.7.3" +object = "0.38.0" +once_cell = "1.17.1" +opener = "0.8.3" +parking = "2.2" +parking_lot = "0.12.1" +paste = "1.0.15" +path-clean = "1.0.1" +pathdiff = "0.2.1" +petgraph = "0.8.3" +phf = "0.13.1" +pin-project = "1.0.12" +pin-project-lite = "0.2.10" +pin-utils = "0.1.0" +predicates = "3.1.3" +pretty_assertions = "1.4.0" +proc-macro-error2 = "2.0.1" +proc-macro2 = "1" +quote = "1.0.20" +rand = "0.9.2" rayon = "1.7.0" -itertools = "0.12" -byteorder = "1.3" -more-asserts = "0.2" -enum-iterator = "0.7.0" -backtrace = "0.3" -hashbrown = "0.11" -smallvec = "1.6" +regex = "1.11" region = "3.0" -once_cell = "1.17.1" -num_enum = "0.7.3" -dashmap = "6.0.1" -http = "1.0.0" -hyper = "1" -hyper-util = "0.1.5" -http-body-util = "0.1.1" +replace_with = "0.1.7" reqwest = { version = "0.12.0", default-features = false } -enumset = "1.1.0" -memoffset = "0.9.0" -wasmparser = { version = "0.224.0", default-features = false, features = [ - "validate", - "features", - "simd", -] } rkyv = { version = "0.8.8", features = ["indexmap-2", "bytes-1"] } -memmap2 = { version = "0.6.2" } -toml = { version = "0.8", features = ["preserve_order"] } -indexmap = "2" +rustc-demangle = "0.1" +rustc_version = "0.4" +rusty_jsc = "0.1.0" +rusty_pool = "0.7.0" +rustversion = "1.0" +saffron = "0.1.0" +schemars = "1.1.0" +scopeguard = "1.1.0" +self_cell = "1.0" +semver = "1.0" serde = { version = "1", default-features = false } -serde_yaml = { version = "0.9.34" } +serde-wasm-bindgen = "0.6.5" +serde_bytes = { version = "0.11" } +serde_derive = "^1" serde_json = { version = "1" } -bytecheck = { version = "0.6.8" } -libc = { version = "^0.2", default-features = false } -gimli = { version = "0.28.1" } -futures-util = { version = "0.3.31" } -mio = "1" +serde_path_to_error = "0.1.14" +serde_yaml = { version = "0.9.34" } +serial_test = { version = "3.2.0", default-features = false } +sha2 = "0.10" +slab = "0.4" +smallvec = "1.6" +smoltcp = { version = "0.12.0", default-features = false } +socket2 = { version = "0.6.1", features = ["all"] } +syn = { version = "2", default-features = false } +tar = "0.4.40" +target-lexicon = { version = "0.13.3", default-features = false } +tempfile = "3.6.0" +terminal_size = "0.4.3" +termios = "0.3" +test-log = { version = "0.2", default-features = false } +thiserror = "2.0.17" +time = { version = "0.3.44", default-features = false } # MIO 1.0 starts at tokio version 1.39, hence the minimum requirement. tokio = { version = "1.39.0", default-features = false } +tokio-serde = "0.9" +tokio-stream = "0.1" tokio-tungstenite = { version = "0.24.0" } -tracing = { version = "0.1" } -tracing-subscriber = { version = "0.3" } +tokio-util = "0.7.8" +toml = { version = "0.9.8", features = ["preserve_order"] } +tower = "0.5.2" +tower-http = "0.6.7" +tracing = { version = "0.1", default-features = false } +tracing-subscriber = { version = "0.3", default-features = false } tracing-test = { version = "0.2" } -socket2 = { version = "0.5.7", features = ["all"] } -pretty_assertions = "1.4.0" -base64 = "0.22.0" -time = "0.3.36" +tracing-wasm = "0.2" +trybuild = "1.0.11" +typetag = "0.2.21" +uniffi = "0.30.0" +unix_mode = "0.1.3" +ureq = "3.1.4" url = "2.5" -thiserror = "1" -target-lexicon = { version = "0.12.2", default-features = false } -object = { version = "0.32.0", default-features = true } -derive_more = { version = "2.0.1", features = ["debug", "display"] } -wasm-encoder = { version = "0.235.0", default-features = false, features = [ +urlencoding = "^2" +uuid = { version = "1", default-features = false } +wai-bindgen-gen-core = { version = "0.2.1", default-features = false } +wai-bindgen-gen-rust = { version = "0.2.1", default-features = false } +wai-bindgen-gen-rust-wasm = { version = "0.2.1", default-features = false } +wai-bindgen-rust = { version = "0.2.1", default-features = false } +wai-bindgen-wasmer-impl = "0.2.2" +wai-parser = "0.2.1" +waker-fn = "1.1" +walkdir = "2.3.2" +wasm-bindgen = "0.2.100" +wasm-bindgen-futures = "0.4.37" +wasm-bindgen-test = "0.3.0" +wasm-coredump-builder = "0.1.11" +wasm-encoder = { version = "0.242.0", default-features = false, features = [ "std", ] } -ignore = "0.4" +wasm-smith = "0.4.4" +wasmi_c_api_impl = "0.40.0" +wasmparser = { version = "0.224.0", default-features = false, features = [ + "validate", + "features", + "simd", +] } +wasmprinter = "0.242.0" +wasmer-inline-c = "0.1.1" +wast = "242.0.0" +wat = "1.242.0" +wcgi = "0.3.0" +wcgi-host = "0.3.0" +web-sys = "0.3.64" +web-time = "1.1" +weezl = "^0.1" +which = "8.0.0" +windows-sys = { version = "0.61.2", default-features = false } +xxhash-rust = { version = "0.8.10", default-features = false } +xz = "0.1.0" +zip = { version = "6.0.0", default-features = false } [build-dependencies] test-generator = { path = "tests/lib/test-generator" } -build-deps = "0.1.4" -anyhow = "1.0" -glob = "0.3" -rustc_version = "0.4" +build-deps.workspace = true +anyhow.workspace = true +glob.workspace = true +rustc_version.workspace = true [dev-dependencies] wasmer = { version = "=6.1.0", path = "lib/api", features = [ @@ -186,24 +336,25 @@ wasmer = { version = "=6.1.0", path = "lib/api", features = [ "singlepass", "sys", ] } -anyhow = "1.0" -criterion = { version = "0.5", features = ["csv_output"] } -clap = { version = "=4.4.11" } -clap_builder = { version = "=4.4.11" } -clap_derive = { version = "=4.4.7" } -clap_lex = { version = "=0.6.0" } -serial_test = { version = "2.0", default-features = false } +anyhow.workspace = true +clap.workspace = true +clap_builder.workspace = true +clap_derive.workspace = true +clap_lex.workspace = true +criterion = { workspace = true, features = ["csv_output"] } +serial_test = { workspace = true, default-features = false } compiler-test-derive = { path = "tests/lib/compiler-test-derive" } -tempfile = "3.6.0" -ureq = "2.6" +tempfile.workspace = true +ureq.workspace = true # For logging tests using the `RUST_LOG=debug` when testing -test-log = { version = "0.2", default-features = false, features = ["trace"] } -tracing = { version = "0.1", default-features = false, features = ["log"] } -tracing-subscriber = { version = "0.3", default-features = false, features = [ +test-log = { workspace = true, default-features = false, features = ["trace"] } +tracing = { workspace = true, default-features = false, features = ["log"] } +tracing-subscriber = { workspace = true, default-features = false, features = [ "env-filter", "fmt", ] } reqwest = { workspace = true, features = ["blocking", "rustls-tls"] } +itertools.workspace = true [features] # Don't add the compiler features in default, please add them on the Makefile @@ -238,6 +389,7 @@ wasmer-artifact-load = ["wasmer-compiler/wasmer-artifact-load"] wasmer-artifact-create = ["wasmer-compiler/wasmer-artifact-create"] static-artifact-load = ["wasmer-compiler/static-artifact-load"] static-artifact-create = ["wasmer-compiler/static-artifact-create"] +experimental-async = ["wasmer/experimental-async"] # Testing features test-singlepass = ["singlepass"] @@ -444,3 +596,8 @@ required-features = ["cranelift"] name = "http-dynamic-size" path = "examples/http_dynamic_size.rs" required-features = ["cranelift"] + +[[example]] +name = "throw-exception" +path = "examples/throw_exception.rs" +required-features = ["llvm"] diff --git a/Makefile b/Makefile index d2a25bf881..1f06fd9aff 100644 --- a/Makefile +++ b/Makefile @@ -155,25 +155,25 @@ else ifneq ($(filter 1 true,$(ENABLE_LLVM)),) LLVM_VERSION := $(shell llvm-config --version) compilers += llvm # … or try to autodetect LLVM from `llvm-config-`. -else ifneq (, $(shell which llvm-config-18 2>/dev/null)) - LLVM_VERSION := $(shell llvm-config-18 --version) +else ifneq (, $(shell which llvm-config-21 2>/dev/null)) + LLVM_VERSION := $(shell llvm-config-21 --version) compilers += llvm - # need force LLVM_SYS_180_PREFIX, or llvm_sys will not build in the case - export LLVM_SYS_180_PREFIX = $(shell llvm-config-18 --prefix) + # need force LLVM_SYS_211_PREFIX, or llvm_sys will not build in the case + export LLVM_SYS_211_PREFIX = $(shell llvm-config-21 --prefix) else ifneq (, $(shell which llvm-config 2>/dev/null)) LLVM_VERSION := $(shell llvm-config --version) - ifneq (, $(findstring 18,$(LLVM_VERSION))) + ifneq (, $(findstring 21,$(LLVM_VERSION))) compilers += llvm - export LLVM_SYS_180_PREFIX = $(shell llvm-config --prefix) - else ifneq (, $(findstring 18,$(LLVM_VERSION))) + export LLVM_SYS_211_PREFIX = $(shell llvm-config --prefix) + else ifneq (, $(findstring 21,$(LLVM_VERSION))) compilers += llvm - export LLVM_SYS_180_PREFIX = $(shell llvm-config --prefix) + export LLVM_SYS_211_PREFIX = $(shell llvm-config --prefix) endif endif # If findstring is not empty, then it have found the value -exclude_tests := --exclude wasmer-c-api --exclude wasmer-cli --exclude wasmer-compiler-cli +exclude_tests := --exclude wasmer-c-api --exclude wasmer-cli # We run integration tests separately (it requires building the c-api) exclude_tests += --exclude wasmer-integration-tests-cli exclude_tests += --exclude wasmer-integration-tests-ios @@ -371,8 +371,8 @@ HOST_TARGET=$(shell rustc -Vv | grep 'host: ' | cut -d':' -f2 | tr -d ' ') TARGET_DIR ?= target/release -ifneq (, $(TARGET)) - TARGET_DIR ?= target/$(TARGET)/release +ifneq (, $(CARGO_TARGET)) + TARGET_DIR = target/$(CARGO_TARGET)/release endif $(info -----------) @@ -380,17 +380,17 @@ $(info $(bold)$(green)INFORMATION$(reset)) $(info -----------) $(info ) $(info Host Target: `$(bold)$(green)$(HOST_TARGET)$(reset)`.) -ifneq (, $(TARGET)) +ifneq (, $(CARGO_TARGET)) # We use spaces instead of tabs to indent `$(info)` # otherwise it's considered as a command outside a # target and it will fail. - $(info Build Target: $(bold)$(green)$(TARGET)$(reset) $(yellow)($(TARGET_DIR))$(reset)) + $(info Build Target: $(bold)$(green)$(CARGO_TARGET)$(reset) $(yellow)($(TARGET_DIR))$(reset)) endif ifneq (, $(LIBC)) # We use spaces instead of tabs to indent `$(info)` # otherwise it's considered as a command outside a # target and it will fail. - $(info C standard library: $(bold)$(green)$(LIBC)$(reset)) + $(info C standard library: $(bold)$(green)$(LIBC)$(reset)) endif $(info Enabled Compilers: $(bold)$(green)$(subst $(space),$(reset)$(comma)$(space)$(bold)$(green),$(compilers))$(reset).) $(info Testing the following compilers & engines:) @@ -401,7 +401,7 @@ $(info   * Compilers: `$(bold)$(green)${compiler_features}$(reset)`.) $(info Rust version: $(bold)$(green)$(shell rustc --version)$(reset).) $(info NodeJS version: $(bold)$(green)$(shell node --version)$(reset).) ifeq ($(ENABLE_LLVM), 1) - $(info LLVM version: $(bold)$(green)${LLVM_VERSION}$(reset).) + $(info LLVM version: $(bold)$(green)${LLVM_VERSION}$(reset).) endif $(info ) $(info ) @@ -437,13 +437,13 @@ endif # install will go through. all: build-wasmer build-capi build-capi-headless -check: check-wasmer check-wasmer-wasm check-capi +check: check-wasmer check-api-no-async check-capi check-wasmer: $(CARGO_BINARY) check $(CARGO_TARGET_FLAG) --manifest-path lib/cli/Cargo.toml $(compiler_features) --bin wasmer --locked -check-wasmer-wasm: - $(CARGO_BINARY) check --manifest-path lib/cli-compiler/Cargo.toml --target wasm32-wasip1 --features singlepass,cranelift --bin wasmer-compiler --locked +check-api-no-async: + $(CARGO_BINARY) check $(CARGO_TARGET_FLAG) --manifest-path lib/api/Cargo.toml $(compiler_features) --locked check-capi: RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) check $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml \ @@ -468,14 +468,12 @@ build-wasmer-api-js: $(CARGO_BINARY) rustc --target wasm32-unknown-unknown --release --manifest-path lib/api/Cargo.toml --no-default-features --features "js, js-default, wasm-types-polyfill, enable-serde" --crate-type=cdylib --locked build-wasmer-debug: - $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/cli/Cargo.toml $(compiler_features) --bin wasmer --locked + RUSTFLAGS="--cfg tokio_unstable" \ + $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --features tokio-subscriber --manifest-path lib/cli/Cargo.toml $(compiler_features) --bin wasmer --locked bench: $(CARGO_BINARY) bench $(CARGO_TARGET_FLAG) $(compiler_features) -build-wasmer-wasm: - $(CARGO_BINARY) build --release --manifest-path lib/cli-compiler/Cargo.toml --target wasm32-wasip1 --features singlepass,cranelift --bin wasmer-compiler --locked - # For best results ensure the release profile looks like the following # in Cargo.toml: # [profile.release] @@ -500,7 +498,7 @@ else endif build-docs: - $(CARGO_BINARY) doc $(CARGO_TARGET_FLAG) --release $(compiler_features) --document-private-items --no-deps --workspace --exclude wasmer-c-api --exclude wasmer-swift --locked + $(CARGO_BINARY) doc $(CARGO_TARGET_FLAG) --release $(compiler_features) --features wasmer/experimental-async --document-private-items --no-deps --workspace --exclude wasmer-c-api --exclude wasmer-swift --locked # The tokio crate was excluded from the docs build because the code (which is not under our control) # does not currently compile its docs successfully @@ -547,10 +545,10 @@ test-build-docs-rs-ci: fi; \ printf "*** Building doc for package with manifest $$manifest_path and features $$features ***\n\n"; \ if [ -z "$$features" ]; then \ - RUSTDOCFLAGS="--cfg=docsrs" $(CARGO_BINARY) +nightly-2025-02-09 doc $(CARGO_TARGET_FLAG) --manifest-path "$$manifest_path" --no-deps --locked || exit 1; \ + RUSTDOCFLAGS="--cfg=docsrs" $(CARGO_BINARY) +nightly doc $(CARGO_TARGET_FLAG) --manifest-path "$$manifest_path" --no-deps --locked || exit 1; \ else \ printf "Following features are inferred from Cargo.toml: $$features\n\n\n"; \ - RUSTDOCFLAGS="--cfg=docsrs" $(CARGO_BINARY) +nightly-2025-02-09 doc $(CARGO_TARGET_FLAG) --manifest-path "$$manifest_path" --no-deps --features "$$features" --locked || exit 1; \ + RUSTDOCFLAGS="--cfg=docsrs" $(CARGO_BINARY) +nightly doc $(CARGO_TARGET_FLAG) --manifest-path "$$manifest_path" --no-deps --features "$$features" --locked || exit 1; \ fi; \ done @@ -629,19 +627,19 @@ build-capi-headless-ios: # test compilers test-stage-0-wast: - $(CARGO_BINARY) nextest run $(CARGO_TARGET_FLAG) --release $(compiler_features) --locked --jobs=1 + $(CARGO_BINARY) nextest run $(CARGO_TARGET_FLAG) --release $(compiler_features) --locked # test packages test-stage-1-test-all: - $(CARGO_BINARY) nextest run $(CARGO_TARGET_FLAG) --workspace --release $(exclude_tests) --exclude wasmer-c-api-test-runner --exclude wasmer-capi-examples-runner $(compiler_features) --locked --jobs=1 - $(CARGO_BINARY) test --doc $(CARGO_TARGET_FLAG) --workspace --release $(exclude_tests) --exclude wasmer-c-api-test-runner --exclude wasmer-capi-examples-runner $(compiler_features) --locked --jobs=1 + $(CARGO_BINARY) nextest run $(CARGO_TARGET_FLAG) --workspace --release $(exclude_tests) --exclude wasmer-c-api-test-runner --exclude wasmer-capi-examples-runner $(compiler_features) --features experimental-async --locked && \ + $(CARGO_BINARY) test --doc $(CARGO_TARGET_FLAG) --workspace --release $(exclude_tests) --exclude wasmer-c-api-test-runner --exclude wasmer-capi-examples-runner $(compiler_features) --features experimental-async --locked test-stage-2-test-compiler-cranelift-nostd: $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --manifest-path lib/compiler-cranelift/Cargo.toml --release --no-default-features --features=std --locked test-stage-3-test-compiler-singlepass-nostd: $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --manifest-path lib/compiler-singlepass/Cargo.toml --release --no-default-features --features=std --locked test-stage-4-wasmer-cli: - $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --manifest-path lib/virtual-fs/Cargo.toml --release --locked - $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --manifest-path lib/cli/Cargo.toml $(compiler_features) --release --locked + $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --manifest-path lib/virtual-fs/Cargo.toml --release --locked && \ +$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --manifest-path lib/cli/Cargo.toml $(compiler_features) --release --locked # test examples test-stage-5-test-examples: @@ -650,8 +648,8 @@ test-stage-6-test-examples-release: $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --release $(compiler_features) --features wasi --examples --locked test-stage-7-capi-integration-tests: - $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --release --package wasmer-c-api-test-runner --locked - $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --release --package wasmer-capi-examples-runner --locked + $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --release --package wasmer-c-api-test-runner --locked && \ +$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --release --package wasmer-capi-examples-runner --locked test: test-compilers test-packages test-examples @@ -687,6 +685,9 @@ test-js: test-js-api test-js-wasi test-js-api: cd lib/api && wasm-pack test --node -- --no-default-features --features js-default,wat +lint-js: + cargo clippy --target wasm32-unknown-unknown --manifest-path lib/api/Cargo.toml --no-default-features --features "js-default" --locked -- -D clippy::all + test-js-wasi: cd lib/wasix && wasm-pack test --node -- --no-default-features --features test-js,wasmer/js,wasmer/std @@ -716,6 +717,9 @@ test-llvm: $(foreach llvm_engine,$(filter llvm-%,$(compilers_engines)),test-$(ll # same as test-capi, but without the build-capi step first test-capi-ci: $(foreach compiler_engine,$(capi_compilers_engines),test-capi-crate-$(compiler_engine) test-capi-integration-$(compiler_engine)) +# Run clippy for the C API crate across the CI matrix. +lint-capi-ci: $(foreach compiler_engine,$(capi_compilers_engines),lint-capi-crate-$(compiler_engine)) + # This test requires building the capi with all the available # compilers first test-capi: build-capi package-capi test-capi-ci @@ -730,6 +734,10 @@ test-capi-crate-%: WASMER_CAPI_CONFIG=$(shell echo $@ | sed -e s/test-capi-crate-//) $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \ --no-default-features --features wat,compiler,wasi,middlewares,webc_runner $(capi_compiler_features) --locked -- --nocapture +lint-capi-crate-%: + WASMER_CAPI_CONFIG=$(shell echo $@ | sed -e s/lint-capi-crate-//) RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) clippy $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \ + --no-default-features --features wat,compiler,wasi,middlewares,webc_runner $(capi_compiler_features) --locked -- -D clippy::all + test-capi-integration-%: # note: you need to do make build-capi and make package-capi first! # Test the Wasmer C API tests for C @@ -765,7 +773,7 @@ test-integration-cli-wamr-ci: require-nextest build-wasmer-wamr rustup target add wasm32-wasip1 $(CARGO_BINARY) nextest run $(CARGO_TARGET_FLAG) --features webc_runner,wamr -p wasmer-integration-tests-cli --locked --no-fail-fast -E "not (test(deploy) | test(snapshot) | test(login) | test(init) | test(gen_c_header) | test(up_to_date) | test(publish) | test(create) | test(whoami) | test(config) | test(c_flags))" -test-integration-cli-wasmi-ci: require-nextest build-wasmer-wasmi +test-integration-cli-wasmi-ci: require-nextest rustup target add wasm32-wasip1 $(CARGO_BINARY) nextest run $(CARGO_TARGET_FLAG) --features webc_runner,wamr -p wasmer-integration-tests-cli --locked --no-fail-fast -E "not (test(deploy) | test(snapshot) | test(login) | test(init) | test(gen_c_header) | test(up_to_date) | test(publish) | test(create) | test(whoami) | test(config) | test(c_flags))" @@ -1050,16 +1058,33 @@ update-testsuite: lint-packages: RUSTFLAGS += -D dead-code -D nonstandard-style -D unused-imports -D unused-mut -D unused-variables -D unused-unsafe -D unreachable-patterns -D bad-style -D improper-ctypes -D unused-allocation -D unused-comparisons -D while-true -D unconditional-recursion -D bare-trait-objects -D function_item_references -D clippy::uninlined_format_args # TODO: add `-D missing-docs` lint-packages: - RUSTFLAGS="${RUSTFLAGS}" cargo clippy --all --exclude wasmer-cli --exclude wasmer-swift --locked -- -D clippy::all + RUSTFLAGS="${RUSTFLAGS}" cargo clippy --all --examples --exclude wasmer-cli --exclude wasmer-swift --locked -- -D clippy::all RUSTFLAGS="${RUSTFLAGS}" cargo clippy --manifest-path lib/cli/Cargo.toml --locked $(compiler_features) -- -D clippy::all RUSTFLAGS="${RUSTFLAGS}" cargo clippy --manifest-path fuzz/Cargo.toml --locked $(compiler_features) -- -D clippy::all +lint-wasmi: + RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) clippy $(CARGO_TARGET_FLAG) --package=wasmer --no-default-features --features="wasmi-default" --locked -- -D clippy::all + +lint-wamr: + RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) clippy $(CARGO_TARGET_FLAG) --package=wasmer --no-default-features --features="wamr-default" --locked -- -D clippy::all + +lint-v8: + RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) clippy $(CARGO_TARGET_FLAG) --package=wasmer --no-default-features --features="v8-default" --locked -- -D clippy::all + +lint-jsc: + RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) clippy $(CARGO_TARGET_FLAG) --package=wasmer --no-default-features --features="jsc-default,wat" --locked -- -D clippy::all + +lint-package-crate: + RUSTFLAGS="${RUSTFLAGS}" cargo clippy --manifest-path lib/package/Cargo.toml --locked -- -D clippy::all + lint-formatting: cargo fmt --all -- --check cargo fmt --manifest-path fuzz/Cargo.toml -- --check lint: lint-formatting lint-packages +lint-all: lint-formatting lint-packages lint-wasmi lint-wamr lint-v8 lint-jsc lint-capi-ci lint-package-crate + install-local: package tar -C ~/.wasmer -zxvf wasmer.tar.gz diff --git a/README.md b/README.md index fef44a0f19..e917572ebc 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,7 @@ languages** with the Wasmer SDK: | ![Ruby logo] | [**Ruby**][Ruby integration] | [`wasmer` Ruby Gem] | [Learn][ruby docs] | | ![Java logo] | [**Java**][Java integration] | [`wasmer/wasmer-jni` Bintray package] | [Learn][java docs] | | ![R logo] | [**R**][R integration] | _no published package_ | [Learn][r docs] | +| ![R logo] | [**R**][R integration_1] | _no published package_ | [Learn][r docs_1] | | ![Postgres logo] | [**Postgres**][Postgres integration] | _no published package_ | [Learn][postgres docs] | | ![Swift logo] | [**Swift**][Swift integration] | _no published package_ | | | ![Dart logo] | [**Dart**][Dart integration] | [`wasm` pub package] | | @@ -202,6 +203,8 @@ languages** with the Wasmer SDK: [r logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/r.svg [r integration]: https://github.com/dirkschumacher/wasmr [r docs]: https://github.com/dirkschumacher/wasmr#example +[r integration_1]: https://sounkou-bioinfo.r-universe.dev/wasmer +[r docs_1]: https://sounkou-bioinfo.r-universe.dev/wasmer/doc/manual.html [postgres logo]: https://raw.githubusercontent.com/wasmerio/wasmer/master/assets/languages/postgres.svg [postgres integration]: https://github.com/wasmerio/wasmer-postgres [postgres docs]: https://github.com/wasmerio/wasmer-postgres#usage--documentation @@ -263,6 +266,7 @@ Wasmer has an amazing community of developers and contributors. Welcome, please - [Wasmer Community Discord](https://discord.gg/rWkMNStrEW) - [Wasmer on Twitter](https://twitter.com/wasmerio) +- [Wasmer on LinkedIn](https://www.linkedin.com/company/wasmerio) -------- diff --git a/benches/compile.rs b/benches/compile.rs index 6ce896a57a..f1642691d4 100644 --- a/benches/compile.rs +++ b/benches/compile.rs @@ -1,5 +1,5 @@ use criterion::{ - criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, + BenchmarkGroup, Criterion, criterion_group, criterion_main, measurement::WallTime, }; use wasmer::*; diff --git a/benches/deserialize_modules.rs b/benches/deserialize_modules.rs index 10207a7723..789a2fe8ad 100644 --- a/benches/deserialize_modules.rs +++ b/benches/deserialize_modules.rs @@ -1,4 +1,4 @@ -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{Criterion, criterion_group, criterion_main}; use wasmer::*; diff --git a/benches/import_functions.rs b/benches/import_functions.rs index 23fafc44c1..b32fea30ba 100644 --- a/benches/import_functions.rs +++ b/benches/import_functions.rs @@ -1,4 +1,6 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use std::hint::black_box; + +use criterion::{Criterion, criterion_group, criterion_main}; use wasmer::*; diff --git a/benches/run.rs b/benches/run.rs index d83eeff64c..a4ff0a3462 100644 --- a/benches/run.rs +++ b/benches/run.rs @@ -1,18 +1,18 @@ -use criterion::{criterion_group, criterion_main, Criterion}; -use wasmer::{sys::*, *}; +use criterion::{Criterion, criterion_group, criterion_main}; +use wasmer::*; static BENCHMARKS_ARTIFACTS_BASE_URL: &str = "https://pub-083d1a0568d446d1aa5b2e07bd16983b.r2.dev"; #[allow(unreachable_code)] fn get_engine() -> Engine { #[cfg(feature = "llvm")] - return LLVM::new().into(); + return wasmer_compiler_llvm::LLVM::new().into(); #[cfg(feature = "singlepass")] - return Singlepass::new().into(); + return wasmer_compiler_singlepass::Singlepass::new().into(); #[cfg(feature = "cranelift")] - return Cranelift::new().into(); + return wasmer_compiler_cranelift::Cranelift::new().into(); #[cfg(not(any(feature = "cranelift", feature = "llvm", feature = "singlepass")))] return Default::default(); diff --git a/benches/static_and_dynamic_functions.rs b/benches/static_and_dynamic_functions.rs index ab2d17b171..082c130f60 100644 --- a/benches/static_and_dynamic_functions.rs +++ b/benches/static_and_dynamic_functions.rs @@ -1,4 +1,6 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use std::hint::black_box; + +use criterion::{Criterion, criterion_group, criterion_main}; use wasmer::*; @@ -50,31 +52,29 @@ pub fn run_basic_static_function(store: &mut Store, compiler_name: &str, c: &mut }); let dyn_f_many: &Function = instance.exports.get("add20").unwrap(); - let f_many: TypedFunction< - ( - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - ), - i32, - > = dyn_f_many.typed(store).unwrap(); + type TupleWithMany = ( + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + ); + let f_many: TypedFunction = dyn_f_many.typed(store).unwrap(); c.bench_function( &format!("basic static func with many args {compiler_name}"), |b| { diff --git a/build.rs b/build.rs index 5028469735..07de79eaad 100644 --- a/build.rs +++ b/build.rs @@ -9,11 +9,27 @@ use std::fs; use std::path::PathBuf; use std::process::Command; use test_generator::{ - test_directory, test_directory_module, wasi_processor, wast_processor, with_test_module, - Testsuite, + Testsuite, test_directory, test_directory_module, wasi_processor, wast_processor, + with_test_module, }; fn main() -> anyhow::Result<()> { + println!( + "cargo:rustc-env=CFG_TARGET_OS={}", + std::env::var("CARGO_CFG_TARGET_OS") + .expect("CARGO_CFG_TARGET_OS must be provided by cargo") + ); + println!( + "cargo:rustc-env=CFG_TARGET_ARCH={}", + std::env::var("CARGO_CFG_TARGET_ARCH") + .expect("CARGO_CFG_TARGET_ARCH must be provided by cargo") + ); + println!( + "cargo:rustc-env=CFG_TARGET_ENV={}", + std::env::var("CARGO_CFG_TARGET_ENV") + .expect("CARGO_CFG_TARGET_ENV must be provided by cargo") + ); + // As rerun-if-changed doesn't support globs, we use another crate // to check changes in directories. build_deps::rerun_if_changed_paths("tests/wasi-wast/wasi/unstable/*") diff --git a/deny.toml b/deny.toml index 293f8df2aa..8769a1b707 100644 --- a/deny.toml +++ b/deny.toml @@ -101,15 +101,14 @@ allow = [ "MPL-2.0", "0BSD", "CC0-1.0", - "OpenSSL", "BSD-3-Clause", - "Unicode-DFS-2016", - "Unicode-3.0", # BOOST source license # NOTE: not to be confused with business source license! "BSL-1.0", "Unicode-3.0", "CDLA-Permissive-2.0", + "Zlib", + "bzip2-1.0.6" ] # The confidence threshold for detecting a license from license text. # The higher the value, the more closely the license text must be to the @@ -130,7 +129,20 @@ exceptions = [ # Some crates don't have (easily) machine readable licensing information, # adding a clarification entry for it allows you to manually specify the # licensing information -#[[licenses.clarify]] +[[licenses.clarify]] +crate = "wasmer-compiler-singlepass" +expression = "BUSL-1.1" +license-files = [ + { path = "LICENSE", hash = 0x11303e40 }, +] + +[[licenses.clarify]] +crate = "wasmer-compiler-llvm" +expression = "BUSL-1.1" +license-files = [ + { path = "LICENSE", hash = 0x79b6d01b }, +] + # The package spec the clarification applies to #crate = "ring" # The SPDX expression for the license requirements of the crate diff --git a/docs/ATTRIBUTIONS.md b/docs/ATTRIBUTIONS.md index c322f14091..0bae77e815 100644 --- a/docs/ATTRIBUTIONS.md +++ b/docs/ATTRIBUTIONS.md @@ -603,3 +603,72 @@ used by default, but certain options use it (e.g., the optional closure compiler flag will run closure compiler from third_party/). ``` + +### Zlib + +```text +version 1.3.1, January 22nd, 2024 + + Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu +``` + +### bzip2-1.0.6 + +```text +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2010 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@bzip.org +bzip2/libbzip2 version 1.0.6 of 6 September 2010 +``` diff --git a/docs/BUILD.md b/docs/BUILD.md index ada65e811a..e6694eaae3 100644 --- a/docs/BUILD.md +++ b/docs/BUILD.md @@ -2,9 +2,8 @@ ## Installing Rustup -Building Wasmer from source requires [Rust](https://rustup.rs/) **1.84+**. - -The easiest way to install Rust on your system is via Rustup. To get Rustup on Linux and macOS, you can run the following: +Wasmer supports building with the latest **3** stable releases of Rust. +The easiest way to install Rust on your system is via [Rustup](https://rustup.rs/). To get Rustup on Linux and macOS, you can run the following: ```bash curl https://sh.rustup.rs -sSf | sh @@ -19,17 +18,17 @@ curl https://sh.rustup.rs -sSf | sh Linux is fully supported by Wasmer. WASI(x) is also fully supported. Users building from source can enable the LLVM backend following the instruction in -the dedicated section below and installing LLVM version 18. To install it, +the dedicated section below and installing LLVM version 21. To install it, refer to [LLVM's download -page](https://github.com/llvm/llvm-project/releases/tag/llvmorg-18.1.7) or +page](https://github.com/llvm/llvm-project/releases/tag/llvmorg-21.1.6) or check your distro's package manager. ### macOS macOS is fully supported by Wasmer. WASI(x) is also fully supported. Users building from source can enable the LLVM backend following the instruction in -the dedicated section below and installing LLVM version 18. To install it on -macOS, you can use [homebrew](https://brew.sh/): `brew install llvm@18`. +the dedicated section below and installing LLVM version 21. To install it on +macOS, you can use [homebrew](https://brew.sh/): `brew install llvm@21`. ### Windows @@ -38,7 +37,7 @@ Windows is fully supported by Wasmer. WASI(x) is also fully supported. 1. Install [Visual Studio](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community&rel=15) 2. Install [Rust for Windows](https://win.rustup.rs/) 3. Install [Git for Windows](https://git-scm.com/download/win). Allow it to add `git.exe` to your PATH (default settings for the installer are fine). -4. \(optional\) Install [LLVM 18.0](https://github.com/llvm/llvm-project/releases/download/llvmorg-18.1.7/LLVM-18.1.7-win64.exe) +4. \(optional\) Install [LLVM 21.0](https://github.com/llvm/llvm-project/releases/download/llvmorg-21.1.6/LLVM-21.1.6-win64.exe) ## Building the Wasmer Runtime @@ -92,12 +91,12 @@ variable, and force its enabling with `ENABLE_SINGLEPASS=1`. If you want support for the Wasmer LLVM compiler, then you will also need to: -- Ensure that LLVM >=18.0.x is installed on your system +- Ensure that LLVM >=21.1.x is installed on your system - You can refer to [LLVM install instructions](https://github.com/wasmerio/wasmer/tree/master/lib/compiler-llvm#requirements) - You can also [download and use a prebuilt LLVM binary](https://releases.llvm.org/download.html) - In case `llvm-config` is not accessible, set the correct environment variable - for LLVM to access: For example, the environment variable for LLVM 18.0.x - would be: `LLVM_SYS_180_PREFIX=/path/to/unpacked/llvm-18.0` + for LLVM to access: For example, the environment variable for LLVM 21.1.x + would be: `LLVM_SYS_211_PREFIX=/path/to/unpacked/llvm-21.1` And create a Wasmer release diff --git a/docs/schema/generated/jsonschema/types/AppConfigV1.schema.json b/docs/schema/generated/jsonschema/types/AppConfigV1.schema.json index 6c9fe72498..22c62d3346 100644 --- a/docs/schema/generated/jsonschema/types/AppConfigV1.schema.json +++ b/docs/schema/generated/jsonschema/types/AppConfigV1.schema.json @@ -1,11 +1,8 @@ { "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "AppConfigV1", - "description": "User-facing app.yaml config file for apps.\n\nNOTE: only used by the backend, Edge itself does not use this format, and uses [`super::AppVersionV1Spec`] instead.", + "description": "User-facing app.yaml config file for apps.\n\nNOTE: only used by the backend; Edge itself does not use this format and\nrelies on the internal `AppVersionV1Spec` representation instead.", "type": "object", - "required": [ - "package" - ], "properties": { "app_id": { "description": "App id assigned by the backend.\n\nThis will get populated once the app has been deployed.\n\nThis id is also used to map to the existing app during deployments.", @@ -17,7 +14,7 @@ "capabilities": { "anyOf": [ { - "$ref": "#/definitions/AppConfigCapabilityMapV1" + "$ref": "#/$defs/AppConfigCapabilityMapV1" }, { "type": "null" @@ -42,7 +39,7 @@ ] }, "domains": { - "description": "Domains for the app.\n\nThis can include both provider-supplied alias domains and custom domains.", + "description": "Domains for the app.\n\nThis can include both provider-supplied\nalias domains and custom domains.", "type": [ "array", "null" @@ -64,7 +61,7 @@ "null" ], "items": { - "$ref": "#/definitions/HealthCheckV1" + "$ref": "#/$defs/HealthCheckV1" } }, "jobs": { @@ -73,14 +70,14 @@ "null" ], "items": { - "$ref": "#/definitions/Job" + "$ref": "#/$defs/Job" } }, "locality": { "description": "Location-related configuration for the app.", "anyOf": [ { - "$ref": "#/definitions/Locality" + "$ref": "#/$defs/Locality" }, { "type": "null" @@ -103,12 +100,12 @@ }, "package": { "description": "The package to execute.", - "$ref": "#/definitions/PackageSource" + "$ref": "#/$defs/PackageSource" }, "redirect": { "anyOf": [ { - "$ref": "#/definitions/Redirect" + "$ref": "#/$defs/Redirect" }, { "type": "null" @@ -118,7 +115,7 @@ "scaling": { "anyOf": [ { - "$ref": "#/definitions/AppScalingConfigV1" + "$ref": "#/$defs/AppScalingConfigV1" }, { "type": "null" @@ -131,7 +128,7 @@ "null" ], "items": { - "$ref": "#/definitions/AppScheduledTask" + "$ref": "#/$defs/AppScheduledTask" } }, "volumes": { @@ -140,21 +137,24 @@ "null" ], "items": { - "$ref": "#/definitions/AppVolume" + "$ref": "#/$defs/AppVolume" } } }, "additionalProperties": true, - "definitions": { + "required": [ + "package" + ], + "$defs": { "AppConfigCapabilityInstaBootV1": { - "description": "Enables accelerated instance boot times with startup snapshots.\n\nHow it works: The Edge runtime will create a pre-initialized snapshot of apps that is ready to serve requests Your app will then restore from the generated snapshot, which has the potential to significantly speed up cold starts.\n\nTo drive the initialization, multiple http requests can be specified. All the specified requests will be sent to the app before the snapshot is created, allowing the app to pre-load files, pre initialize caches, ...", + "description": "Enables accelerated instance boot times with startup snapshots.\n\nHow it works:\nThe Edge runtime will create a pre-initialized snapshot of apps that is\nready to serve requests\nYour app will then restore from the generated snapshot, which has the\npotential to significantly speed up cold starts.\n\nTo drive the initialization, multiple http requests can be specified.\nAll the specified requests will be sent to the app before the snapshot is\ncreated, allowing the app to pre-load files, pre initialize caches, ...", "type": "object", "properties": { "max_age": { - "description": "Maximum age of snapshots.\n\nFormat: 5m, 1h, 2d, ...\n\nAfter the specified time new snapshots will be created, and the old ones discarded.", + "description": "Maximum age of snapshots.\n\nFormat: 5m, 1h, 2d, ...\n\nAfter the specified time new snapshots will be created, and the old\nones discarded.", "anyOf": [ { - "$ref": "#/definitions/PrettyDuration" + "$ref": "#/$defs/PrettyDuration" }, { "type": "null" @@ -163,34 +163,34 @@ }, "mode": { "description": "The method to use to generate the instaboot snapshot for the instance.", - "default": null, "anyOf": [ { - "$ref": "#/definitions/InstabootSnapshotModeV1" + "$ref": "#/$defs/InstabootSnapshotModeV1" }, { "type": "null" } - ] + ], + "default": null }, "requests": { - "description": "HTTP requests to perform during startup snapshot creation. Apps can perform all the appropriate warmup logic in these requests.\n\nNOTE: if no requests are configured, then a single HTTP request to '/' will be performed instead.", + "description": "HTTP requests to perform during startup snapshot creation.\nApps can perform all the appropriate warmup logic in these requests.\n\nNOTE: if no requests are configured, then a single HTTP\nrequest to '/' will be performed instead.", "type": "array", "items": { - "$ref": "#/definitions/HttpRequest" + "$ref": "#/$defs/HttpRequest" } } } }, "AppConfigCapabilityMapV1": { - "description": "Restricted version of [`super::CapabilityMapV1`], with only a select subset of settings.", + "description": "Restricted version of the internal `CapabilityMapV1`, with only a select\nsubset of settings.", "type": "object", "properties": { "instaboot": { "description": "Enables app bootstrapping with startup snapshots.", "anyOf": [ { - "$ref": "#/definitions/AppConfigCapabilityInstaBootV1" + "$ref": "#/$defs/AppConfigCapabilityInstaBootV1" }, { "type": "null" @@ -201,7 +201,7 @@ "description": "Instance memory settings.", "anyOf": [ { - "$ref": "#/definitions/AppConfigCapabilityMemoryV1" + "$ref": "#/$defs/AppConfigCapabilityMemoryV1" }, { "type": "null" @@ -212,7 +212,7 @@ "description": "Runtime settings.", "anyOf": [ { - "$ref": "#/definitions/AppConfigCapabilityRuntimeV1" + "$ref": "#/$defs/AppConfigCapabilityRuntimeV1" }, { "type": "null" @@ -222,7 +222,7 @@ "ssh": { "anyOf": [ { - "$ref": "#/definitions/CapabilitySshServerV1" + "$ref": "#/$defs/CapabilitySshServerV1" }, { "type": "null" @@ -233,7 +233,7 @@ "additionalProperties": true }, "AppConfigCapabilityMemoryV1": { - "description": "Memory capability settings.\n\nNOTE: this is kept separate from the [`super::CapabilityMemoryV1`] struct to have separation between the high-level app.yaml and the more internal App entity.", + "description": "Memory capability settings.\n\nNOTE: this is kept separate from the internal `CapabilityMemoryV1` struct\nto keep the high-level app.yaml distinct from the internal App entity.", "type": "object", "properties": { "limit": { @@ -271,7 +271,7 @@ "mode": { "anyOf": [ { - "$ref": "#/definitions/AppScalingModeV1" + "$ref": "#/$defs/AppScalingModeV1" }, { "type": "null" @@ -288,21 +288,17 @@ }, "AppScheduledTask": { "type": "object", - "required": [ - "name" - ], "properties": { "name": { "type": "string" } - } + }, + "required": [ + "name" + ] }, "AppVolume": { "type": "object", - "required": [ - "mount", - "name" - ], "properties": { "mount": { "type": "string" @@ -310,7 +306,11 @@ "name": { "type": "string" } - } + }, + "required": [ + "name", + "mount" + ] }, "CapabilitySshServerV1": { "description": "Configure SSH server credentials and settings.", @@ -329,7 +329,7 @@ "null" ], "items": { - "$ref": "#/definitions/SshUserV1" + "$ref": "#/$defs/SshUserV1" } } }, @@ -341,7 +341,7 @@ "capabilities": { "anyOf": [ { - "$ref": "#/definitions/ExecutableJobCompatibilityMapV1" + "$ref": "#/$defs/ExecutableJobCompatibilityMapV1" }, { "type": "null" @@ -349,7 +349,7 @@ ] }, "cli_args": { - "description": "CLI arguments passed to the runner. Only applicable for runners that accept CLI arguments.", + "description": "CLI arguments passed to the runner.\nOnly applicable for runners that accept CLI arguments.", "type": [ "array", "null" @@ -379,7 +379,7 @@ "description": "The package that contains the command to run. Defaults to the app config's package.", "anyOf": [ { - "$ref": "#/definitions/PackageSource" + "$ref": "#/$defs/PackageSource" }, { "type": "null" @@ -392,7 +392,7 @@ "null" ], "items": { - "$ref": "#/definitions/AppVolume" + "$ref": "#/$defs/AppVolume" } } } @@ -404,7 +404,7 @@ "description": "Instance memory settings.", "anyOf": [ { - "$ref": "#/definitions/AppConfigCapabilityMemoryV1" + "$ref": "#/$defs/AppConfigCapabilityMemoryV1" }, { "type": "null" @@ -417,9 +417,6 @@ "HealthCheckHttpV1": { "description": "Health check configuration for http endpoints.", "type": "object", - "required": [ - "path" - ], "properties": { "body": { "description": "Request body as a string.", @@ -431,7 +428,7 @@ "expect": { "anyOf": [ { - "$ref": "#/definitions/HttpRequestExpect" + "$ref": "#/$defs/HttpRequestExpect" }, { "type": "null" @@ -445,7 +442,7 @@ "null" ], "items": { - "$ref": "#/definitions/HttpHeader" + "$ref": "#/$defs/HttpHeader" } }, "healthy_threshold": { @@ -455,7 +452,7 @@ "null" ], "format": "uint32", - "minimum": 0.0 + "minimum": 0 }, "interval": { "description": "Interval for the health check.\n\nFormat: 1s, 5m, 11h, ...\n\nDefaults to 60s.", @@ -479,7 +476,7 @@ "description": "Request timeout.\n\nFormat: 1s, 5m, 11h, ...", "anyOf": [ { - "$ref": "#/definitions/PrettyDuration" + "$ref": "#/$defs/PrettyDuration" }, { "type": "null" @@ -493,33 +490,32 @@ "null" ], "format": "uint32", - "minimum": 0.0 + "minimum": 0 } - } + }, + "required": [ + "path" + ] }, "HealthCheckV1": { "oneOf": [ { "type": "object", - "required": [ - "http" - ], "properties": { "http": { - "$ref": "#/definitions/HealthCheckHttpV1" + "$ref": "#/$defs/HealthCheckHttpV1" } }, - "additionalProperties": false + "additionalProperties": false, + "required": [ + "http" + ] } ] }, "HttpHeader": { "description": "Definition for an HTTP header.", "type": "object", - "required": [ - "name", - "value" - ], "properties": { "name": { "type": "string" @@ -527,14 +523,15 @@ "value": { "type": "string" } - } + }, + "required": [ + "name", + "value" + ] }, "HttpRequest": { "description": "Defines an HTTP request.", "type": "object", - "required": [ - "path" - ], "properties": { "body": { "description": "Request body as a string.", @@ -546,7 +543,7 @@ "expect": { "anyOf": [ { - "$ref": "#/definitions/HttpRequestExpect" + "$ref": "#/$defs/HttpRequestExpect" }, { "type": "null" @@ -560,7 +557,7 @@ "null" ], "items": { - "$ref": "#/definitions/HttpHeader" + "$ref": "#/$defs/HttpHeader" } }, "method": { @@ -578,14 +575,17 @@ "description": "Request timeout.\n\nFormat: 1s, 5m, 11h, ...", "anyOf": [ { - "$ref": "#/definitions/PrettyDuration" + "$ref": "#/$defs/PrettyDuration" }, { "type": "null" } ] } - } + }, + "required": [ + "path" + ] }, "HttpRequestExpect": { "description": "Validation checks for an [`HttpRequest`].", @@ -614,7 +614,8 @@ "items": { "type": "integer", "format": "uint16", - "minimum": 0.0 + "maximum": 65535, + "minimum": 0 } } } @@ -623,65 +624,60 @@ "description": "How will an instance be bootstrapped?", "oneOf": [ { - "description": "Start the instance without any snapshot triggers. Once the requests are done, use [`snapshot_and_stop`](wasmer_wasix::WasiProcess::snapshot_and_stop) to capture a snapshot and shut the instance down.", + "description": "Start the instance without any snapshot triggers. Once the requests are done,\nuse `wasmer_wasix::WasiProcess::snapshot_and_stop` to capture a snapshot\nand shut the instance down.", "type": "string", - "enum": [ - "bootstrap" - ] + "const": "bootstrap" }, { - "description": "Explicitly enable the given snapshot triggers before starting the instance. The instance's process will have its stop_running_after_checkpoint flag set, so the first snapshot will cause the instance to shut down.", + "description": "Explicitly enable the given snapshot triggers before starting the instance.\nThe instance's process will have its stop_running_after_checkpoint flag set,\nso the first snapshot will cause the instance to shut down.", "type": "object", - "required": [ - "triggers" - ], "properties": { "triggers": { "type": "array", "items": { - "$ref": "#/definitions/SnapshotTrigger" + "$ref": "#/$defs/SnapshotTrigger" } } }, - "additionalProperties": false + "additionalProperties": false, + "required": [ + "triggers" + ] } ] }, "Job": { "description": "Job configuration.", "type": "object", - "required": [ - "action", - "name", - "trigger" - ], "properties": { "action": { - "$ref": "#/definitions/JobAction" + "$ref": "#/$defs/JobAction" }, "jitter_percent_max": { - "description": "Maximum percent of \"jitter\" to introduce between invocations.\n\nValue range: 0-100\n\nJitter is used to spread out jobs over time. The calculation works by multiplying the time between invocations by a random amount, and taking the percentage of that random amount.\n\nSee also [`Self::jitter_percent_min`] to set a minimum jitter.", + "description": "Maximum percent of \"jitter\" to introduce between invocations.\n\nValue range: 0-100\n\nJitter is used to spread out jobs over time.\nThe calculation works by multiplying the time between invocations\nby a random amount, and taking the percentage of that random amount.\n\nSee also [`Self::jitter_percent_min`] to set a minimum jitter.", "type": [ "integer", "null" ], "format": "uint8", - "minimum": 0.0 + "maximum": 255, + "minimum": 0 }, "jitter_percent_min": { - "description": "Minimum \"jitter\" to introduce between invocations.\n\nValue range: 0-100\n\nJitter is used to spread out jobs over time. The calculation works by multiplying the time between invocations by a random amount, and taking the percentage of that random amount.\n\nIf not specified while `jitter_percent_max` is, it will default to 10%.\n\nSee also [`Self::jitter_percent_max`] to set a maximum jitter.", + "description": "Minimum \"jitter\" to introduce between invocations.\n\nValue range: 0-100\n\nJitter is used to spread out jobs over time.\nThe calculation works by multiplying the time between invocations\nby a random amount, and taking the percentage of that random amount.\n\nIf not specified while `jitter_percent_max` is, it will default to 10%.\n\nSee also [`Self::jitter_percent_max`] to set a maximum jitter.", "type": [ "integer", "null" ], "format": "uint8", - "minimum": 0.0 + "maximum": 255, + "minimum": 0 }, "max_schedule_drift": { - "description": "Don't start job if past the due time by this amount, instead opting to wait for the next instance of it to be triggered.", + "description": "Don't start job if past the due time by this amount,\ninstead opting to wait for the next instance of it\nto be triggered.", "anyOf": [ { - "$ref": "#/definitions/PrettyDuration" + "$ref": "#/$defs/PrettyDuration" }, { "type": "null" @@ -697,12 +693,12 @@ "null" ], "format": "uint32", - "minimum": 0.0 + "minimum": 0 }, "timeout": { "anyOf": [ { - "$ref": "#/definitions/PrettyDuration" + "$ref": "#/$defs/PrettyDuration" }, { "type": "null" @@ -710,37 +706,40 @@ ] }, "trigger": { - "$ref": "#/definitions/JobTrigger" + "$ref": "#/$defs/JobTrigger" } }, - "additionalProperties": true + "additionalProperties": true, + "required": [ + "name", + "trigger", + "action" + ] }, "JobAction": { "type": "object", "oneOf": [ { "type": "object", - "required": [ - "fetch" - ], "properties": { "fetch": { - "$ref": "#/definitions/HttpRequest" + "$ref": "#/$defs/HttpRequest" } }, - "additionalProperties": false + "required": [ + "fetch" + ] }, { "type": "object", - "required": [ - "execute" - ], "properties": { "execute": { - "$ref": "#/definitions/ExecutableJob" + "$ref": "#/$defs/ExecutableJob" } }, - "additionalProperties": false + "required": [ + "execute" + ] } ] }, @@ -749,9 +748,6 @@ }, "Locality": { "type": "object", - "required": [ - "regions" - ], "properties": { "regions": { "type": "array", @@ -759,7 +755,10 @@ "type": "string" } } - } + }, + "required": [ + "regions" + ] }, "PackageSource": { "type": "string" @@ -769,40 +768,36 @@ { "description": "Plain text password.", "type": "object", - "required": [ - "password", - "type" - ], "properties": { "password": { "type": "string" }, "type": { "type": "string", - "enum": [ - "plain" - ] + "const": "plain" } - } + }, + "required": [ + "type", + "password" + ] }, { "description": "Bcrypt password hash.", "type": "object", - "required": [ - "hash", - "type" - ], "properties": { "hash": { "type": "string" }, "type": { "type": "string", - "enum": [ - "bcrypt" - ] + "const": "bcrypt" } - } + }, + "required": [ + "type", + "hash" + ] } ] }, @@ -827,9 +822,6 @@ }, "SshUserV1": { "type": "object", - "required": [ - "username" - ], "properties": { "authorized_keys": { "description": "SSH public keys for this user.", @@ -848,7 +840,7 @@ "null" ], "items": { - "$ref": "#/definitions/PasswordV1" + "$ref": "#/$defs/PasswordV1" } }, "username": { @@ -856,7 +848,10 @@ "type": "string" } }, - "additionalProperties": true + "additionalProperties": true, + "required": [ + "username" + ] } } } \ No newline at end of file diff --git a/examples/compiler_cranelift.rs b/examples/compiler_cranelift.rs index cb8b8f9192..14493e84f5 100644 --- a/examples/compiler_cranelift.rs +++ b/examples/compiler_cranelift.rs @@ -10,7 +10,7 @@ //! //! Ready? -use wasmer::{imports, wat2wasm, Instance, Module, Store, Value}; +use wasmer::{Instance, Module, Store, Value, imports, wat2wasm}; use wasmer_compiler_cranelift::Cranelift; fn main() -> Result<(), Box> { @@ -52,7 +52,7 @@ fn main() -> Result<(), Box> { // slice of `Value`s. The results are a boxed slice of `Value`s. let results = sum.call(&mut store, &[Value::I32(1), Value::I32(2)])?; - println!("Results: {:?}", results); + println!("Results: {results:?}"); assert_eq!(results.to_vec(), vec![Value::I32(3)]); Ok(()) diff --git a/examples/compiler_llvm.rs b/examples/compiler_llvm.rs index 2622227259..4a7f60e2b4 100644 --- a/examples/compiler_llvm.rs +++ b/examples/compiler_llvm.rs @@ -10,7 +10,7 @@ //! //! Ready? -use wasmer::{imports, wat2wasm, Instance, Module, Store, Value}; +use wasmer::{Instance, Module, Store, Value, imports, wat2wasm}; use wasmer_compiler_llvm::LLVM; fn main() -> Result<(), Box> { @@ -52,7 +52,7 @@ fn main() -> Result<(), Box> { // slice of `Value`s. The results are a boxed slice of `Value`s. let results = sum.call(&mut store, &[Value::I32(1), Value::I32(2)])?; - println!("Results: {:?}", results); + println!("Results: {results:?}"); assert_eq!(results.to_vec(), vec![Value::I32(3)]); Ok(()) diff --git a/examples/compiler_singlepass.rs b/examples/compiler_singlepass.rs index 01fb181b12..931e33db34 100644 --- a/examples/compiler_singlepass.rs +++ b/examples/compiler_singlepass.rs @@ -10,7 +10,7 @@ //! //! Ready? -use wasmer::{imports, wat2wasm, Instance, Module, Store, Value}; +use wasmer::{Instance, Module, Store, Value, imports, wat2wasm}; use wasmer_compiler_singlepass::Singlepass; fn main() -> Result<(), Box> { @@ -52,7 +52,7 @@ fn main() -> Result<(), Box> { // slice of `Value`s. The results are a boxed slice of `Value`s. let results = sum.call(&mut store, &[Value::I32(1), Value::I32(2)])?; - println!("Results: {:?}", results); + println!("Results: {results:?}"); assert_eq!(results.to_vec(), vec![Value::I32(3)]); Ok(()) diff --git a/examples/early_exit.rs b/examples/early_exit.rs index 1d9e7bc594..154c06bf7f 100644 --- a/examples/early_exit.rs +++ b/examples/early_exit.rs @@ -16,7 +16,7 @@ use anyhow::bail; use std::fmt; -use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, TypedFunction}; +use wasmer::{Function, Instance, Module, Store, TypedFunction, imports, wat2wasm}; // First we need to create an error type that we'll use to signal the end of execution. #[derive(Debug, Clone, Copy)] @@ -78,27 +78,24 @@ fn main() -> anyhow::Result<()> { // Get the `run` function which we'll use as our entrypoint. println!("Calling `run` function..."); let run_func: TypedFunction<(i32, i32), i32> = - instance.exports.get_typed_function(&mut store, "run")?; + instance.exports.get_typed_function(&store, "run")?; // When we call a function it can either succeed or fail. We expect it to fail. match run_func.call(&mut store, 1, 7) { Ok(result) => { - bail!( - "Expected early termination with `ExitCode`, found: {}", - result - ); + bail!("Expected early termination with `ExitCode`, found: {result}"); } // In case of a failure, which we expect, we attempt to downcast the error into the error // type that we were expecting. Err(e) => match e.downcast::() { // We found the exit code used to terminate execution. Ok(exit_code) => { - println!("Exited early with exit code: {}", exit_code); + println!("Exited early with exit code: {exit_code}"); Ok(()) } Err(e) => { - bail!("Unknown error `{}` found. expected `ExitCode`", e); + bail!("Unknown error `{e}` found. expected `ExitCode`"); } }, } diff --git a/examples/engine.rs b/examples/engine.rs index d8836de7c0..0aae886761 100644 --- a/examples/engine.rs +++ b/examples/engine.rs @@ -18,7 +18,7 @@ //! //! Ready? -use wasmer::{imports, sys::EngineBuilder, wat2wasm, Instance, Module, Store, Value}; +use wasmer::{Instance, Module, Store, Value, imports, sys::EngineBuilder, wat2wasm}; use wasmer_compiler_cranelift::Cranelift; fn main() -> Result<(), Box> { @@ -78,7 +78,7 @@ fn main() -> Result<(), Box> { let sum = instance.exports.get_function("sum")?; let results = sum.call(&mut store, &[Value::I32(1), Value::I32(2)])?; - println!("Results: {:?}", results); + println!("Results: {results:?}"); assert_eq!(results.to_vec(), vec![Value::I32(3)]); Ok(()) diff --git a/examples/engine_cross_compilation.rs b/examples/engine_cross_compilation.rs index 9bc8ca7803..c4a2856d3b 100644 --- a/examples/engine_cross_compilation.rs +++ b/examples/engine_cross_compilation.rs @@ -20,8 +20,9 @@ use std::str::FromStr; use wasmer::{ + Module, RuntimeError, Store, sys::{CpuFeature, EngineBuilder}, - wat2wasm, Module, RuntimeError, Store, + wat2wasm, }; use wasmer_compiler_cranelift::Cranelift; use wasmer_types::target::{Target, Triple}; @@ -65,7 +66,7 @@ fn main() -> Result<(), Box> { // // Let's build the target. let target = Target::new(triple, cpu_feature); - println!("Chosen target: {:?}", target); + println!("Chosen target: {target:?}"); // Define the engine that will drive everything. // diff --git a/examples/engine_headless.rs b/examples/engine_headless.rs index 984bedecf9..ec75248c51 100644 --- a/examples/engine_headless.rs +++ b/examples/engine_headless.rs @@ -45,7 +45,7 @@ //! Ready? use tempfile::NamedTempFile; -use wasmer::{imports, sys::EngineBuilder, wat2wasm, Instance, Module, Store, Value}; +use wasmer::{Instance, Module, Store, Value, imports, sys::EngineBuilder, wat2wasm}; use wasmer_compiler_cranelift::Cranelift; fn main() -> Result<(), Box> { @@ -122,7 +122,7 @@ fn main() -> Result<(), Box> { let sum = instance.exports.get_function("sum")?; let results = sum.call(&mut store, &[Value::I32(1), Value::I32(2)])?; - println!("Results: {:?}", results); + println!("Results: {results:?}"); assert_eq!(results.to_vec(), vec![Value::I32(3)]); } diff --git a/examples/errors.rs b/examples/errors.rs index c034c409de..98de26f599 100644 --- a/examples/errors.rs +++ b/examples/errors.rs @@ -13,7 +13,7 @@ //! //! Ready? -use wasmer::{imports, wat2wasm, Instance, Module, Store, TypedFunction}; +use wasmer::{Instance, Module, Store, TypedFunction, imports, wat2wasm}; fn main() -> Result<(), Box> { // Let's declare the Wasm module with the text representation. @@ -60,7 +60,7 @@ fn main() -> Result<(), Box> { let div_by_zero: TypedFunction<(), i32> = instance .exports .get_function("div_by_zero")? - .typed(&mut store)?; + .typed(&store)?; println!("Calling `div_by_zero` function..."); // Let's call the `div_by_zero` exported function. @@ -81,12 +81,12 @@ fn main() -> Result<(), Box> { let frames = e.trace(); let frames_len = frames.len(); - for i in 0..frames_len { + for (i, frame) in frames.iter().enumerate() { println!( " Frame #{}: {:?}::{:?}", frames_len - i, - frames[i].module_name(), - frames[i].function_name().or(Some("")).unwrap() + frame.module_name(), + frame.function_name().unwrap_or("") ); } } diff --git a/examples/exports_function.rs b/examples/exports_function.rs index e984322cf2..2c420f31f8 100644 --- a/examples/exports_function.rs +++ b/examples/exports_function.rs @@ -17,7 +17,7 @@ //! //! Ready? -use wasmer::{imports, wat2wasm, Instance, Module, Store, TypedFunction, Value}; +use wasmer::{Instance, Module, Store, TypedFunction, Value, imports, wat2wasm}; fn main() -> Result<(), Box> { // Let's declare the Wasm module with the text representation. @@ -70,7 +70,7 @@ fn main() -> Result<(), Box> { let args = [Value::I32(1), Value::I32(2)]; let result = sum.call(&mut store, &args)?; - println!("Results: {:?}", result); + println!("Results: {result:?}"); assert_eq!(result.to_vec(), vec![Value::I32(3)]); // That was fun. But what if we can get rid of the `Value`s? Well, @@ -81,7 +81,7 @@ fn main() -> Result<(), Box> { // `Rets`, respectively for the parameters and the results. If // those values don't match the exported function signature, an // error will be raised. - let sum_typed: TypedFunction<(i32, i32), i32> = sum.typed(&mut store)?; + let sum_typed: TypedFunction<(i32, i32), i32> = sum.typed(&store)?; println!("Calling `sum` function (natively)..."); // Let's call the `sum` exported function. The parameters are @@ -89,7 +89,7 @@ fn main() -> Result<(), Box> { // result, in this case particular case, in a unit of type `i32`. let result = sum_typed.call(&mut store, 3, 4)?; - println!("Results: {:?}", result); + println!("Results: {result:?}"); assert_eq!(result, 7); // Much nicer, isn't it? diff --git a/examples/exports_global.rs b/examples/exports_global.rs index cdb8455acb..2f51af5f2a 100644 --- a/examples/exports_global.rs +++ b/examples/exports_global.rs @@ -15,7 +15,7 @@ //! //! Ready? -use wasmer::{imports, wat2wasm, Instance, Module, Mutability, Store, Type, TypedFunction, Value}; +use wasmer::{Instance, Module, Mutability, Store, Type, TypedFunction, Value, imports, wat2wasm}; fn main() -> Result<(), Box> { // Let's declare the Wasm module with the text representation. @@ -83,18 +83,16 @@ fn main() -> Result<(), Box> { // // We will use an exported function for the `one` global // and the Global API for `some`. - let get_one: TypedFunction<(), f32> = instance - .exports - .get_function("get_one")? - .typed(&mut store)?; + let get_one: TypedFunction<(), f32> = + instance.exports.get_function("get_one")?.typed(&store)?; let one_value = get_one.call(&mut store)?; let some_value = some.get(&mut store); - println!("`one` value: {:?}", one_value); + println!("`one` value: {one_value:?}"); assert_eq!(one_value, 1.0); - println!("`some` value: {:?}", some_value); + println!("`some` value: {some_value:?}"); assert_eq!(some_value, Value::F32(0.0)); println!("Setting global values..."); @@ -109,7 +107,7 @@ fn main() -> Result<(), Box> { // ); let one_result = one.get(&mut store); - println!("`one` value after `set`: {:?}", one_result); + println!("`one` value after `set`: {one_result:?}"); assert_eq!(one_result, Value::F32(1.0)); // Setting the values of globals can be done in two ways: @@ -117,18 +115,16 @@ fn main() -> Result<(), Box> { // 2. Using the Global API directly. // // We will use both for the `some` global. - let set_some: TypedFunction = instance - .exports - .get_function("set_some")? - .typed(&mut store)?; + let set_some: TypedFunction = + instance.exports.get_function("set_some")?.typed(&store)?; set_some.call(&mut store, 21.0)?; let some_result = some.get(&mut store); - println!("`some` value after `set_some`: {:?}", some_result); + println!("`some` value after `set_some`: {some_result:?}"); assert_eq!(some_result, Value::F32(21.0)); some.set(&mut store, Value::F32(42.0))?; let some_result = some.get(&mut store); - println!("`some` value after `set`: {:?}", some_result); + println!("`some` value after `set`: {some_result:?}"); assert_eq!(some_result, Value::F32(42.0)); Ok(()) diff --git a/examples/exports_memory.rs b/examples/exports_memory.rs index 3990efca3e..5b5b988b1e 100644 --- a/examples/exports_memory.rs +++ b/examples/exports_memory.rs @@ -11,7 +11,7 @@ //! //! Ready? -use wasmer::{imports, wat2wasm, Instance, Module, Store, TypedFunction, WasmPtr}; +use wasmer::{Instance, Module, Store, TypedFunction, WasmPtr, imports, wat2wasm}; fn main() -> Result<(), Box> { // Let's declare the Wasm module with the text representation. @@ -46,7 +46,7 @@ fn main() -> Result<(), Box> { let instance = Instance::new(&mut store, &module, &import_object)?; let load: TypedFunction<(), (WasmPtr, i32)> = - instance.exports.get_typed_function(&mut store, "load")?; + instance.exports.get_typed_function(&store, "load")?; // Here we go. // @@ -69,7 +69,7 @@ fn main() -> Result<(), Box> { // which will tell us the offset and length of the string. let (ptr, length) = load.call(&mut store)?; println!("String offset: {:?}", ptr.offset()); - println!("String length: {:?}", length); + println!("String length: {length:?}"); // We now know where to find our string, let's read it. // @@ -77,7 +77,7 @@ fn main() -> Result<(), Box> { // decode them into a string. let memory_view = memory.view(&store); let str = ptr.read_utf8_string(&memory_view, length as u32).unwrap(); - println!("Memory contents: {:?}", str); + println!("Memory contents: {str:?}"); // What about changing the contents of the memory with a more // appropriate string? @@ -86,8 +86,8 @@ fn main() -> Result<(), Box> { // of each element. let new_str = b"Hello, Wasmer!"; let values = ptr.slice(&memory_view, new_str.len() as u32).unwrap(); - for i in 0..new_str.len() { - values.index(i as u64).write(new_str[i]).unwrap(); + for (i, &str) in new_str.iter().enumerate() { + values.index(i as u64).write(str).unwrap(); } // And now, let's see the result. @@ -100,7 +100,7 @@ fn main() -> Result<(), Box> { let str = ptr .read_utf8_string(&memory_view, new_str.len() as u32) .unwrap(); - println!("New memory contents: {:?}", str); + println!("New memory contents: {str:?}"); // Much better, don't you think? diff --git a/examples/features.rs b/examples/features.rs index c732afbfb8..5b7fce12e9 100644 --- a/examples/features.rs +++ b/examples/features.rs @@ -11,9 +11,9 @@ //! Ready? use wasmer::{ - imports, + Instance, Module, Store, Value, imports, sys::{EngineBuilder, Features}, - wat2wasm, Instance, Module, Store, Value, + wat2wasm, }; use wasmer_compiler_cranelift::Cranelift; diff --git a/examples/funcref.rs b/examples/funcref.rs index 548a7fde59..b555ecad91 100644 --- a/examples/funcref.rs +++ b/examples/funcref.rs @@ -1,5 +1,5 @@ use std::error::Error; -use wasmer::{imports, Instance, Module, Store, Table, TableType, Type, Value}; +use wasmer::{Instance, Module, Store, Table, TableType, Type, Value, imports}; fn main() -> Result<(), Box> { // 1) Create a default Wasmer Store. diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 83d16ff6f7..60aeadf7e2 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -6,7 +6,7 @@ //! cargo run --example hello-world --release --features "cranelift" //! ``` -use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, TypedFunction}; +use wasmer::{Function, Instance, Module, Store, TypedFunction, imports, wat2wasm}; fn main() -> anyhow::Result<()> { // First we create a simple Wasm program to use with Wasmer. @@ -65,7 +65,7 @@ fn main() -> anyhow::Result<()> { // // Recall that the Wasm module exported a function named "run", this is getting // that exported function from the `Instance`. - let run_func: TypedFunction<(), ()> = instance.exports.get_typed_function(&mut store, "run")?; + let run_func: TypedFunction<(), ()> = instance.exports.get_typed_function(&store, "run")?; // Finally, we call our exported Wasm function which will call our "say_hello" // function and return. diff --git a/examples/http_dynamic_size.rs b/examples/http_dynamic_size.rs index 91317f989c..99b287dc7a 100644 --- a/examples/http_dynamic_size.rs +++ b/examples/http_dynamic_size.rs @@ -1,7 +1,7 @@ use anyhow::Result; use wasmer::{ - imports, wat2wasm, AsStoreRef, Function, FunctionEnv, FunctionEnvMut, Instance, Memory, - MemoryView, Module, Store, WasmPtr, + AsStoreRef, Function, FunctionEnv, FunctionEnvMut, Instance, Memory, MemoryView, Module, Store, + WasmPtr, imports, wat2wasm, }; // Utils @@ -38,16 +38,7 @@ fn http_get(mut ctx: FunctionEnvMut, url: u32, url_len: u32) -> u32 // Get request let response = ureq::get(&address).call().unwrap(); - let capacity = match response - .header("Content-Length") - .map(|it| it.parse::()) - { - Some(Ok(len)) => len, - _ => 1024, - }; - let mut buffer = Vec::with_capacity(capacity); - let mut reader = response.into_reader(); - reader.read_to_end(&mut buffer).unwrap(); + let buffer = response.into_body().read_to_vec().unwrap(); (buffer, memory_size) }; diff --git a/examples/imports_exports.rs b/examples/imports_exports.rs index bb430b15cf..ed833a3930 100644 --- a/examples/imports_exports.rs +++ b/examples/imports_exports.rs @@ -16,8 +16,8 @@ //! Ready? use wasmer::{ - imports, wat2wasm, Function, FunctionType, Global, Instance, Memory, Module, Store, Table, - Type, Value, + Function, FunctionType, Global, Instance, Memory, Module, Store, Table, Type, Value, imports, + wat2wasm, }; fn main() -> Result<(), Box> { diff --git a/examples/imports_function.rs b/examples/imports_function.rs index b8eff999a9..634f0ffa2a 100644 --- a/examples/imports_function.rs +++ b/examples/imports_function.rs @@ -18,8 +18,8 @@ //! Ready? use wasmer::{ - imports, wat2wasm, Function, FunctionEnv, FunctionEnvMut, FunctionType, Instance, Module, - Store, Type, TypedFunction, Value, + Function, FunctionEnv, FunctionEnvMut, FunctionType, Instance, Module, Store, Type, + TypedFunction, Value, imports, wat2wasm, }; fn main() -> Result<(), Box> { @@ -56,7 +56,7 @@ fn main() -> Result<(), Box> { let result = args[0].unwrap_i32() * 2; - println!("Result of `multiply_dynamic`: {:?}", result); + println!("Result of `multiply_dynamic`: {result:?}"); Ok(vec![Value::I32(result)]) }); @@ -65,7 +65,7 @@ fn main() -> Result<(), Box> { println!("Calling `multiply_typed`..."); let result = a * 3; - println!("Result of `multiply_typed`: {:?}", result); + println!("Result of `multiply_typed`: {result:?}"); result } @@ -87,14 +87,14 @@ fn main() -> Result<(), Box> { // // The Wasm module exports a function called `sum`. Let's get it. let sum: TypedFunction<(i32, i32), i32> = - instance.exports.get_function("sum")?.typed(&mut store)?; + instance.exports.get_function("sum")?.typed(&store)?; println!("Calling `sum` function..."); // Let's call the `sum` exported function. It will call each // of the imported functions. let result = sum.call(&mut store, 1, 2)?; - println!("Results of `sum`: {:?}", result); + println!("Results of `sum`: {result:?}"); assert_eq!(result, 8); Ok(()) diff --git a/examples/imports_function_env.rs b/examples/imports_function_env.rs index 6e38860033..d84400aeb8 100644 --- a/examples/imports_function_env.rs +++ b/examples/imports_function_env.rs @@ -21,8 +21,8 @@ use std::sync::{Arc, Mutex}; use wasmer::{ - imports, wat2wasm, Function, FunctionEnv, FunctionEnvMut, Instance, Module, Store, - TypedFunction, + Function, FunctionEnv, FunctionEnvMut, Instance, Module, Store, TypedFunction, imports, + wat2wasm, }; fn main() -> Result<(), Box> { @@ -108,10 +108,10 @@ fn main() -> Result<(), Box> { let increment_counter_loop: TypedFunction = instance .exports .get_function("increment_counter_loop")? - .typed(&mut store)?; + .typed(&store)?; let counter_value: i32 = *shared_counter.lock().unwrap(); - println!("Initial ounter value: {:?}", counter_value); + println!("Initial counter value: {counter_value:?}"); println!("Calling `increment_counter_loop` function..."); // Let's call the `increment_counter_loop` exported function. @@ -120,10 +120,10 @@ fn main() -> Result<(), Box> { let result = increment_counter_loop.call(&mut store, 5)?; let counter_value: i32 = *shared_counter.lock().unwrap(); - println!("New counter value (host): {:?}", counter_value); + println!("New counter value (host): {counter_value:?}"); assert_eq!(counter_value, 5); - println!("New counter value (guest): {:?}", result); + println!("New counter value (guest): {result:?}"); assert_eq!(result, 5); Ok(()) diff --git a/examples/imports_function_env_global.rs b/examples/imports_function_env_global.rs index 61ac3418b4..7a62d75414 100644 --- a/examples/imports_function_env_global.rs +++ b/examples/imports_function_env_global.rs @@ -22,8 +22,8 @@ use std::sync::{Arc, Mutex}; use wasmer::{ - imports, wat2wasm, Function, FunctionEnv, FunctionEnvMut, Global, Instance, Module, Store, - TypedFunction, Value, + Function, FunctionEnv, FunctionEnvMut, Global, Instance, Module, Store, TypedFunction, Value, + imports, wat2wasm, }; fn main() -> Result<(), Box> { @@ -122,10 +122,10 @@ fn main() -> Result<(), Box> { let increment_counter_loop: TypedFunction = instance .exports .get_function("increment_counter_loop")? - .typed(&mut store)?; + .typed(&store)?; let counter_value: i32 = *shared_counter.lock().unwrap(); - println!("Initial ounter value: {:?}", counter_value); + println!("Initial counter value: {counter_value:?}"); println!("Calling `increment_counter_loop` function..."); // Let's call the `increment_counter_loop` exported function. @@ -134,14 +134,14 @@ fn main() -> Result<(), Box> { let result = increment_counter_loop.call(&mut store, 5)?; let counter_value: i32 = *shared_counter.lock().unwrap(); - println!("New counter value (host): {:?}", counter_value); + println!("New counter value (host): {counter_value:?}"); assert_eq!(counter_value, 5); - println!("New counter value (guest): {:?}", result); + println!("New counter value (guest): {result:?}"); assert_eq!(result, 5); let global_counter = g_counter.get(&mut store); - println!("New global counter value: {:?}", global_counter); + println!("New global counter value: {global_counter:?}"); assert_eq!(global_counter.unwrap_i32(), 10); Ok(()) diff --git a/examples/imports_global.rs b/examples/imports_global.rs index 7080f6b229..5d03c8bf12 100644 --- a/examples/imports_global.rs +++ b/examples/imports_global.rs @@ -15,7 +15,7 @@ //! //! Ready? -use wasmer::{imports, wat2wasm, Global, Instance, Module, Store, TypedFunction, Value}; +use wasmer::{Global, Instance, Module, Store, TypedFunction, Value, imports, wat2wasm}; fn main() -> Result<(), Box> { // Let's declare the Wasm module with the text representation. @@ -60,21 +60,17 @@ fn main() -> Result<(), Box> { // // The Wasm module only imports some globals. We'll have to interact // with them either using the Global API or exported functions. - let get_some: TypedFunction<(), f32> = instance - .exports - .get_function("get_some")? - .typed(&mut store)?; - let get_other: TypedFunction<(), f32> = instance - .exports - .get_function("get_other")? - .typed(&mut store)?; + let get_some: TypedFunction<(), f32> = + instance.exports.get_function("get_some")?.typed(&store)?; + let get_other: TypedFunction<(), f32> = + instance.exports.get_function("get_other")?.typed(&store)?; let some_result = get_some.call(&mut store)?; let other_result = get_other.call(&mut store)?; - println!("some value (via `get_some`): {:?}", some_result); + println!("some value (via `get_some`): {some_result:?}"); println!("some value (via Global API): {:?}", some.get(&mut store)); - println!("other value (via `get_other`): {:?}", other_result); + println!("other value (via `get_other`): {other_result:?}"); println!("other value (via Global API): {:?}", other.get(&mut store)); assert_eq!(some_result, some.get(&mut store).f32().unwrap()); @@ -88,16 +84,14 @@ fn main() -> Result<(), Box> { other.set(&mut store, Value::F32(21.0))?; let other_result = other.get(&mut store); - println!("other value after `set`: {:?}", other_result); + println!("other value after `set`: {other_result:?}"); assert_eq!(other_result, Value::F32(21.0)); println!("Altering global values through exported functions..."); // Changes made to global through exported functions will // be reflected on the host side. - let set_other: TypedFunction = instance - .exports - .get_function("set_other")? - .typed(&mut store)?; + let set_other: TypedFunction = + instance.exports.get_function("set_other")?.typed(&store)?; set_other.call(&mut store, 42.0)?; println!("other value (via Global API): {:?}", other.get(&mut store)); diff --git a/examples/instance.rs b/examples/instance.rs index 35cc70748e..e6bba7f895 100644 --- a/examples/instance.rs +++ b/examples/instance.rs @@ -14,7 +14,7 @@ //! //! Ready? -use wasmer::{imports, wat2wasm, Instance, Module, Store, TypedFunction}; +use wasmer::{Instance, Module, Store, TypedFunction, imports, wat2wasm}; fn main() -> Result<(), Box> { // Let's declare the Wasm module. @@ -58,15 +58,13 @@ fn main() -> Result<(), Box> { // Here we are retrieving the exported function. We won't go into details here // as the main focus of this example is to show how to create an instance out // of a Wasm module and have basic interactions with it. - let add_one: TypedFunction = instance - .exports - .get_function("add_one")? - .typed(&mut store)?; + let add_one: TypedFunction = + instance.exports.get_function("add_one")?.typed(&store)?; println!("Calling `add_one` function..."); let result = add_one.call(&mut store, 1)?; - println!("Results of `add_one`: {:?}", result); + println!("Results of `add_one`: {result:?}"); assert_eq!(result, 2); Ok(()) diff --git a/examples/memory.rs b/examples/memory.rs index 2644638708..22fb6367b2 100644 --- a/examples/memory.rs +++ b/examples/memory.rs @@ -14,8 +14,9 @@ //! //! Ready? +#[cfg(not(feature = "wamr"))] use std::mem; -use wasmer::{imports, wat2wasm, Bytes, Instance, Module, Pages, Store, TypedFunction}; +use wasmer::{Bytes, Instance, Module, Pages, Store, TypedFunction, imports, wat2wasm}; // this example is a work in progress: // TODO: clean it up and comment it https://github.com/wasmerio/wasmer/issues/1749 @@ -68,13 +69,11 @@ fn main() -> anyhow::Result<()> { // The module exports some utility functions, let's get them. // // These function will be used later in this example. - let mem_size: TypedFunction<(), i32> = instance - .exports - .get_typed_function(&mut store, "mem_size")?; - let get_at: TypedFunction = - instance.exports.get_typed_function(&mut store, "get_at")?; + let mem_size: TypedFunction<(), i32> = + instance.exports.get_typed_function(&store, "mem_size")?; + let get_at: TypedFunction = instance.exports.get_typed_function(&store, "get_at")?; let set_at: TypedFunction<(i32, i32), ()> = - instance.exports.get_typed_function(&mut store, "set_at")?; + instance.exports.get_typed_function(&store, "set_at")?; let memory = instance.exports.get_memory("memory")?; // We now have an instance ready to be used. @@ -90,7 +89,7 @@ fn main() -> anyhow::Result<()> { println!("Querying memory size..."); let memory_view = memory.view(&store); assert_eq!(memory_view.size(), Pages::from(1)); - assert_eq!(memory_view.size().bytes(), Bytes::from(65536 as usize)); + assert_eq!(memory_view.size().bytes(), Bytes::from(65536_usize)); assert_eq!(memory_view.data_size(), 65536); // Sometimes, the guest module may also export a function to let you @@ -98,7 +97,7 @@ fn main() -> anyhow::Result<()> { let result = mem_size.call(&mut store)?; let memory_view = memory.view(&store); - println!("Memory size: {:?}", result); + println!("Memory size: {result:?}"); assert_eq!(Pages::from(result as u32), memory_view.size()); // Now that we know the size of our memory, it's time to see how wa diff --git a/examples/memory_grow.rs b/examples/memory_grow.rs index 11a587e660..1ea7992515 100644 --- a/examples/memory_grow.rs +++ b/examples/memory_grow.rs @@ -6,7 +6,7 @@ //! cargo run --example memory-grow --release --features "cranelift" //! ``` -use wasmer::{imports, wat2wasm, Instance, Module, Store}; +use wasmer::{Instance, Module, Store, imports, wat2wasm}; fn main() -> anyhow::Result<()> { let wasm_bytes = wat2wasm( @@ -40,7 +40,7 @@ fn main() -> anyhow::Result<()> { ); let result = memory.grow(&mut store, 1); - println!("Attempt to exceed max: {:?}", result); + println!("Attempt to exceed max: {result:?}"); Ok(()) } diff --git a/examples/metering.rs b/examples/metering.rs index a9551cb96f..8e7a513688 100644 --- a/examples/metering.rs +++ b/examples/metering.rs @@ -18,14 +18,14 @@ use anyhow::bail; use std::sync::Arc; use wasmer::wasmparser::Operator; use wasmer::{ - imports, + Instance, Module, Store, TypedFunction, imports, sys::{CompilerConfig, EngineBuilder}, - wat2wasm, Instance, Module, Store, TypedFunction, + wat2wasm, }; use wasmer_compiler_cranelift::Cranelift; use wasmer_middlewares::{ - metering::{get_remaining_points, set_remaining_points, MeteringPoints}, Metering, + metering::{MeteringPoints, get_remaining_points, set_remaining_points}, }; fn main() -> anyhow::Result<()> { @@ -89,10 +89,8 @@ fn main() -> anyhow::Result<()> { // // Our module exports a single `add_one` function. We want to // measure the cost of executing this function. - let add_one: TypedFunction = instance - .exports - .get_function("add_one")? - .typed(&mut store)?; + let add_one: TypedFunction = + instance.exports.get_function("add_one")?.typed(&store)?; println!("Calling `add_one` function once..."); add_one.call(&mut store, 1)?; @@ -109,10 +107,7 @@ fn main() -> anyhow::Result<()> { MeteringPoints::Remaining(6) ); - println!( - "Remaining points after the first call: {:?}", - remaining_points_after_first_call - ); + println!("Remaining points after the first call: {remaining_points_after_first_call:?}"); println!("Calling `add_one` function twice..."); add_one.call(&mut store, 1)?; @@ -125,10 +120,7 @@ fn main() -> anyhow::Result<()> { MeteringPoints::Remaining(2) ); - println!( - "Remaining points after the second call: {:?}", - remaining_points_after_second_call - ); + println!("Remaining points after the second call: {remaining_points_after_second_call:?}"); // Because calling our `add_one` function consumes 4 points, // calling it a third time will fail: we already consume 8 @@ -136,10 +128,7 @@ fn main() -> anyhow::Result<()> { println!("Calling `add_one` function a third time..."); match add_one.call(&mut store, 1) { Ok(result) => { - bail!( - "Expected failure while calling `add_one`, found: {}", - result - ); + bail!("Expected failure while calling `add_one`, found: {result}"); } Err(_) => { println!("Calling `add_one` failed."); @@ -164,7 +153,7 @@ fn main() -> anyhow::Result<()> { let remaining_points = get_remaining_points(&mut store, &instance); assert_eq!(remaining_points, MeteringPoints::Remaining(new_limit)); - println!("Remaining points: {:?}", remaining_points); + println!("Remaining points: {remaining_points:?}"); Ok(()) } diff --git a/examples/platform_ios_headless.rs b/examples/platform_ios_headless.rs index 585ccc5bf9..69c70ec050 100644 --- a/examples/platform_ios_headless.rs +++ b/examples/platform_ios_headless.rs @@ -14,7 +14,7 @@ #![allow(unused)] use std::path::Path; use std::str::FromStr; -use wasmer::{sys::CpuFeature, wat2wasm, Module, RuntimeError, Store}; +use wasmer::{Module, RuntimeError, Store, sys::CpuFeature, wat2wasm}; use wasmer_compiler_cranelift::Cranelift; use wasmer_types::target::{Target, Triple}; /* diff --git a/examples/table.rs b/examples/table.rs index 52e5b9f458..b3557acfa9 100644 --- a/examples/table.rs +++ b/examples/table.rs @@ -1,5 +1,5 @@ use wasmer::{ - imports, wat2wasm, Function, Instance, Module, Store, TableType, Type, TypedFunction, Value, + Function, Instance, Module, Store, TableType, Type, TypedFunction, Value, imports, wat2wasm, }; /// A function we'll call through a table. @@ -61,7 +61,7 @@ fn main() -> anyhow::Result<()> { // to be passed to the function found in the table. let call_via_table: TypedFunction<(i32, i32, i32), i32> = instance .exports - .get_typed_function(&mut store, "call_callback")?; + .get_typed_function(&store, "call_callback")?; // And then call it with table index 1 and arguments 2 and 7. let result = call_via_table.call(&mut store, 1, 2, 7)?; @@ -72,7 +72,7 @@ fn main() -> anyhow::Result<()> { // We then get the table from the instance. let guest_table = instance.exports.get_table("__indirect_function_table")?; // And demonstrate that it has the properties that we set in the Wasm. - assert_eq!(guest_table.size(&mut store), 3); + assert_eq!(guest_table.size(&store), 3); assert_eq!( guest_table.ty(&store), TableType { @@ -106,7 +106,7 @@ fn main() -> anyhow::Result<()> { let previous_size = guest_table.grow(&mut store, 3, func.into())?; assert_eq!(previous_size, 3); - assert_eq!(guest_table.size(&mut store), 6); + assert_eq!(guest_table.size(&store), 6); assert_eq!( guest_table.ty(&store), TableType { diff --git a/examples/throw_exception.rs b/examples/throw_exception.rs new file mode 100644 index 0000000000..df36c8a4e5 --- /dev/null +++ b/examples/throw_exception.rs @@ -0,0 +1,146 @@ +use std::sync::{Arc, atomic::AtomicUsize}; + +use wasmer::{ + Function, FunctionEnv, FunctionEnvMut, FunctionType, Instance, Module, RuntimeError, Store, + Type, TypedFunction, Value, imports, sys::Target, wat2wasm, +}; +use wasmer_types::Features; + +fn main() -> Result<(), Box> { + // Let's declare the Wasm module with the text representation. + let wasm_bytes = wat2wasm( + br#" +(module + (tag $exn (import "env" "tag") (param i32)) + (func $log (import "env" "log") (param i32)) + (func $throw1 (import "env" "throw1")) + (func $throw2 (import "env" "throw2")) + + (func $f (export "f") + (local $e exnref) + (block $outer (result i32 exnref) + (try_table (catch_ref $exn $outer) + call $throw2 + unreachable + ) + unreachable + ) + drop + call $log + (block $outer2 (result i32 exnref) + (try_table (catch_ref $exn $outer2) + call $throw1 + unreachable + ) + unreachable + ) + local.set $e + call $log + local.get $e + throw_ref + ) +) +"#, + )?; + + // We need an LLVM backend with the exception handling feature enabled. + let target = Target::default(); + let features = Features::detect_from_wasm(&wasm_bytes).unwrap(); + + let config = wasmer_compiler_llvm::LLVM::new(); + let engine = wasmer_compiler::EngineBuilder::new(config) + .set_features(Some(features)) + .set_target(Some(target)) + .engine(); + + // Create a Store. + let mut store = Store::new(engine); + + // Declare a tag. + let tag = wasmer::Tag::new(&mut store, vec![Type::I32]); + + // Store the tag in an environment so we can access it in the `throw` function. + struct MyEnv { + tag: wasmer::Tag, + } + let env = FunctionEnv::new(&mut store, MyEnv { tag: tag.clone() }); + + println!("Compiling module..."); + // Let's compile the Wasm module. + let module = Module::new(&store, wasm_bytes)?; + + let log_count = Arc::new(AtomicUsize::new(0)); + + // Create the functions + let log_wasm_value = { + let log_count = log_count.clone(); + move |param: i32| { + println!("Logging from wasm: {param}"); + log_count.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + } + }; + let log = Function::new_typed(&mut store, log_wasm_value); + + // Both Function::new_with_env and Function::new_typed_with_env can throw + // exceptions if they return a Result with a RuntimeError. + fn throw1( + mut env: FunctionEnvMut, + _params: &[Value], + ) -> Result, RuntimeError> { + println!("Throwing exception 1"); + + // To "throw" an exception from native code, we create a new one and + // return it wrapped in a `RuntimeError`. The Wasmer runtime will + // recognize it and will start the unwinding process. + let (env, mut ctx) = env.data_and_store_mut(); + let exn = wasmer::Exception::new(&mut ctx, &env.tag, &[Value::I32(69)]); + Err(RuntimeError::exception(&ctx, exn)) + } + let throw1 = + Function::new_with_env(&mut store, &env, FunctionType::new(vec![], vec![]), throw1); + + fn throw2(mut env: FunctionEnvMut) -> Result<(), RuntimeError> { + println!("Throwing exception 2"); + let (env, mut ctx) = env.data_and_store_mut(); + let exn = wasmer::Exception::new(&mut ctx, &env.tag, &[Value::I32(42)]); + Err(RuntimeError::exception(&ctx, exn)) + } + let throw2 = Function::new_typed_with_env(&mut store, &env, throw2); + + // Create an import object. + let import_object = imports! { + "env" => { + "tag" => tag, + "log" => log, + "throw1" => throw1, + "throw2" => throw2, + } + }; + + println!("Instantiating module..."); + // Let's instantiate the Wasm module. + let instance = Instance::new(&mut store, &module, &import_object)?; + + // Here we go. + let f: TypedFunction<(), ()> = instance.exports.get_function("f")?.typed(&store)?; + + println!("Calling `f` function..."); + let result = f.call(&mut store); + + // Now we can inspect the exception, since it was propagated back to us. + let err = result.unwrap_err(); + let exn = err.to_exception().expect("should be an exception"); + let values = exn.payload(&mut store); + println!("Caught exception with payload: {values:?}"); + + assert_eq!(values, vec![Value::I32(69)]); + assert_eq!(log_count.load(std::sync::atomic::Ordering::SeqCst), 2); + + Ok(()) +} + +#[test] +#[cfg(not(windows))] +fn test_throw_exception() -> Result<(), Box> { + main() +} diff --git a/examples/tunables_limit_memory.rs b/examples/tunables_limit_memory.rs index 33e3b69e35..d3265f2764 100644 --- a/examples/tunables_limit_memory.rs +++ b/examples/tunables_limit_memory.rs @@ -3,13 +3,13 @@ use wasmer_compiler_cranelift::Cranelift; // This is to be able to set the tunables use wasmer::{ - imports, + Engine, Instance, Memory, MemoryError, MemoryStyle, MemoryType, Module, Pages, Store, + TableStyle, TableType, imports, sys::{ - vm::{VMMemory, VMMemoryDefinition, VMTable, VMTableDefinition}, BaseTunables, NativeEngineExt, Target, Tunables, + vm::{VMMemory, VMMemoryDefinition, VMTable, VMTableDefinition}, }, - wat2wasm, Engine, Instance, Memory, MemoryError, MemoryStyle, MemoryType, Module, Pages, Store, - TableStyle, TableType, + wat2wasm, }; /// A custom tunables that allows you to set a memory limit. @@ -35,7 +35,7 @@ impl LimitingTunables { /// valid. However, this can produce invalid types, such that /// validate_memory must be called before creating the memory. fn adjust_memory(&self, requested: &MemoryType) -> MemoryType { - let mut adjusted = requested.clone(); + let mut adjusted = *requested; if requested.maximum.is_none() { adjusted.maximum = Some(self.limit); } @@ -105,8 +105,10 @@ impl Tunables for LimitingTunables { ) -> Result { let adjusted = self.adjust_memory(ty); self.validate_memory(&adjusted)?; - self.base - .create_vm_memory(&adjusted, style, vm_definition_location) + unsafe { + self.base + .create_vm_memory(&adjusted, style, vm_definition_location) + } } /// Create a table owned by the host given a [`TableType`] and a [`TableStyle`]. @@ -125,7 +127,7 @@ impl Tunables for LimitingTunables { style: &TableStyle, vm_definition_location: NonNull, ) -> Result { - self.base.create_vm_table(ty, style, vm_definition_location) + unsafe { self.base.create_vm_table(ty, style, vm_definition_location) } } } @@ -169,7 +171,7 @@ fn main() -> Result<(), Box> { assert_eq!(memories.len(), 1); let first_memory = memories.pop().unwrap(); - println!("Memory of this instance: {:?}", first_memory); + println!("Memory of this instance: {first_memory:?}"); assert_eq!(first_memory.ty(&store).maximum.unwrap(), Pages(24)); Ok(()) diff --git a/examples/wasi.rs b/examples/wasi.rs index e3bea0c5a0..1dc0fe457e 100644 --- a/examples/wasi.rs +++ b/examples/wasi.rs @@ -17,9 +17,9 @@ use std::{io::Read, sync::Arc}; use wasmer_wasix::{ + Pipe, PluggableRuntime, Runtime, runners::wasi::{RuntimeOrEngine, WasiRunner}, runtime::{module_cache::HashedModuleData, task_manager::tokio::TokioTaskManager}, - Pipe, PluggableRuntime, Runtime, }; fn main() -> Result<(), Box> { diff --git a/examples/wasi_pipes.rs b/examples/wasi_pipes.rs index 93392fa8e2..d60dcb00c3 100644 --- a/examples/wasi_pipes.rs +++ b/examples/wasi_pipes.rs @@ -15,8 +15,8 @@ use std::io::{Read, Write}; use wasmer::Module; use wasmer_wasix::{ - runners::wasi::{RuntimeOrEngine, WasiRunner}, Pipe, + runners::wasi::{RuntimeOrEngine, WasiRunner}, }; fn main() -> Result<(), Box> { @@ -35,12 +35,12 @@ fn main() -> Result<(), Box> { let module = Module::new(&engine, &wasm_bytes[..])?; let msg = "racecar go zoom"; - println!("Writing \"{}\" to the WASI stdin...", msg); + println!("Writing \"{msg}\" to the WASI stdin..."); let (mut stdin_sender, stdin_reader) = Pipe::channel(); let (stdout_sender, mut stdout_reader) = Pipe::channel(); // To write to the stdin - writeln!(stdin_sender, "{}", msg)?; + writeln!(stdin_sender, "{msg}")?; { // Create a WASI runner. We use a scope to make sure the runner is dropped diff --git a/flake.lock b/flake.lock index 8d268d8d52..a14e238db4 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1726560853, - "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -20,16 +20,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1730137625, - "narHash": "sha256-9z8oOgFZiaguj+bbi3k4QhAD6JabWrnv7fscC/mt0KE=", + "lastModified": 1759735786, + "narHash": "sha256-a0+h02lyP2KwSNrZz4wLJTu9ikujNsTWIC874Bv7IJ0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "64b80bfb316b57cdb8919a9110ef63393d74382a", + "rev": "20c4598c84a671783f741e02bf05cbfaf4907cff", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-24.05", + "ref": "nixos-25.05", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index 9e761650fb..b4cb649589 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,7 @@ description = "Wasmer Webassembly runtime"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; flakeutils.url = "github:numtide/flake-utils"; }; @@ -35,10 +35,15 @@ openssl # LLVM and related dependencies - llvmPackages_18.libllvm - llvmPackages_18.llvm + llvmPackages_21.libllvm + llvmPackages_21.llvm + llvmPackages_21.llvm.dev + llvmPackages_21.libclang.dev libxml2 libffi + cmake + ninja + webkitgtk_4_0 # Rust tooling @@ -67,12 +72,24 @@ wasm-tools ]; - env.LLVM_SYS_180_PREFIX = pkgs.llvmPackages_18.llvm.dev; - - # shellHook = '' - # LD_LIBRARY_PATH = "${ env.LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [ pkgs.stdenv.cc.cc pkgs.openssl.out ] }:$LD_LIBRARY_PATH" - # ''; - + shellHook = '' + export LLVM_SYS_211_PREFIX="${pkgs.llvmPackages_21.llvm.dev}" + export LIBCLANG_PATH="${pkgs.llvmPackages_21.libclang.lib}/lib" + export PKG_CONFIG_PATH="${pkgs.webkitgtk_4_0.dev}/lib/pkgconfig:$PKG_CONFIG_PATH" + export LIBRARY_PATH="${pkgs.llvmPackages_21.compiler-rt-libc}/lib/linux:$LIBRARY_PATH" + export LD_LIBRARY_PATH="${pkgs.llvmPackages_21.compiler-rt-libc}/lib/linux:$LD_LIBRARY_PATH" + export BINDGEN_EXTRA_CLANG_ARGS="$( + < ${pkgs.llvmPackages_21.stdenv.cc}/nix-support/libc-crt1-cflags + ) $( + < ${pkgs.llvmPackages_21.stdenv.cc}/nix-support/libc-cflags + ) $( + < ${pkgs.llvmPackages_21.stdenv.cc}/nix-support/cc-cflags + ) $( + < ${pkgs.llvmPackages_21.stdenv.cc}/nix-support/libcxx-cxxflags + ) \ + -isystem ${pkgs.glibc.dev}/include \ + -idirafter ${pkgs.llvmPackages_21.clang}/lib/clang/${pkgs.lib.getVersion pkgs.llvmPackages_21.clang}/include" + ''; }; } ); diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index d4a2e6a4a3..059ea44157 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -3,22 +3,22 @@ name = "wasmer-bin-fuzz" version = "0.0.0" authors = ["Automatically generated"] publish = false -edition = "2018" +edition.workspace = true [package.metadata] cargo-fuzz = true [dependencies] -anyhow = "1" -wasm-smith = "0.4.4" -libfuzzer-sys = "0.4.0" +anyhow.workspace = true +wasm-smith.workspace = true +libfuzzer-sys.workspace = true wasmer = { path = "../lib/api" } wasmer-compiler-cranelift = { path = "../lib/compiler-cranelift", optional = true } wasmer-compiler-llvm = { path = "../lib/compiler-llvm", optional = true } wasmer-compiler-singlepass = { path = "../lib/compiler-singlepass", optional = true } wasmer-compiler = { path = "../lib/compiler", optional = true } wasmer-middlewares = { path = "../lib/middlewares" } -wasmprinter = "0.2" +wasmprinter.workspace = true [features] cranelift = [ "wasmer-compiler-cranelift" ] diff --git a/fuzz/fuzz_targets/equivalence_universal.rs b/fuzz/fuzz_targets/equivalence_universal.rs index 4db992f314..0c1cba8469 100644 --- a/fuzz/fuzz_targets/equivalence_universal.rs +++ b/fuzz/fuzz_targets/equivalence_universal.rs @@ -4,7 +4,7 @@ use anyhow::Result; use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target}; use wasm_smith::{Config, ConfiguredModule}; -use wasmer::{imports, CompilerConfig, EngineBuilder, Instance, Module, Store, Val}; +use wasmer::{CompilerConfig, EngineBuilder, Instance, Module, Store, Val, imports}; #[cfg(feature = "cranelift")] use wasmer_compiler_cranelift::Cranelift; #[cfg(feature = "llvm")] diff --git a/fuzz/fuzz_targets/metering.rs b/fuzz/fuzz_targets/metering.rs index 6c4f7f89f0..ac23d04932 100644 --- a/fuzz/fuzz_targets/metering.rs +++ b/fuzz/fuzz_targets/metering.rs @@ -4,7 +4,7 @@ use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target}; use std::sync::Arc; use wasm_smith::{Config, ConfiguredModule}; use wasmer::wasmparser::Operator; -use wasmer::{imports, CompilerConfig, Instance, Module, Store}; +use wasmer::{CompilerConfig, Instance, Module, Store, imports}; use wasmer_compiler_cranelift::Cranelift; use wasmer_middlewares::Metering; diff --git a/fuzz/fuzz_targets/universal_cranelift.rs b/fuzz/fuzz_targets/universal_cranelift.rs index 764947f66a..ea42d7eba9 100644 --- a/fuzz/fuzz_targets/universal_cranelift.rs +++ b/fuzz/fuzz_targets/universal_cranelift.rs @@ -2,7 +2,7 @@ use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target}; use wasm_smith::{Config, ConfiguredModule}; -use wasmer::{imports, CompilerConfig, Instance, Module, Store}; +use wasmer::{CompilerConfig, Instance, Module, Store, imports}; use wasmer_compiler_cranelift::Cranelift; #[derive(Arbitrary, Debug, Default, Copy, Clone)] diff --git a/fuzz/fuzz_targets/universal_llvm.rs b/fuzz/fuzz_targets/universal_llvm.rs index 1f051f8976..2f3fc9cc27 100644 --- a/fuzz/fuzz_targets/universal_llvm.rs +++ b/fuzz/fuzz_targets/universal_llvm.rs @@ -2,7 +2,7 @@ use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target}; use wasm_smith::{Config, ConfiguredModule}; -use wasmer::{imports, CompilerConfig, Instance, Module, Store}; +use wasmer::{CompilerConfig, Instance, Module, Store, imports}; use wasmer_compiler_llvm::LLVM; #[derive(Arbitrary, Debug, Default, Copy, Clone)] diff --git a/fuzz/fuzz_targets/universal_singlepass.rs b/fuzz/fuzz_targets/universal_singlepass.rs index 762f6ece7f..2d35056383 100644 --- a/fuzz/fuzz_targets/universal_singlepass.rs +++ b/fuzz/fuzz_targets/universal_singlepass.rs @@ -2,7 +2,7 @@ use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target}; use wasm_smith::{Config, ConfiguredModule}; -use wasmer::{imports, Instance, Module, Store}; +use wasmer::{Instance, Module, Store, imports}; use wasmer_compiler_singlepass::Singlepass; #[derive(Arbitrary, Debug, Default, Copy, Clone)] diff --git a/lib/api/Cargo.toml b/lib/api/Cargo.toml index 37f91a092f..a5c0ed4b56 100644 --- a/lib/api/Cargo.toml +++ b/lib/api/Cargo.toml @@ -35,13 +35,13 @@ cfg-if.workspace = true thiserror.workspace = true more-asserts.workspace = true bytes.workspace = true -tracing.workspace = true +tracing = { workspace = true, default-features = true } # - Optional shared dependencies. -wat = { version = "1.216.0", optional = true } -rustc-demangle = "0.1" +wat = { workspace = true, optional = true } +rustc-demangle.workspace = true shared-buffer.workspace = true -wasmi_c_api = { version = "0.40.0", package = "wasmi_c_api_impl", optional = true, features = [ +wasmi_c_api_impl = { workspace = true, optional = true, features = [ "prefix-symbols", ] } @@ -49,7 +49,7 @@ loupe = { workspace = true, optional = true, features = [ "indexmap", "enable-indexmap", ] } -paste = "1.0.15" +paste.workspace = true derive_more = { workspace = true, features = ["from", "debug"] } # Dependencies and Development Dependencies for `sys`. @@ -64,21 +64,25 @@ target-lexicon = { workspace = true, default-features = false } wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "=6.1.0", optional = true } wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "=6.1.0", optional = true } wasmer-compiler-llvm = { path = "../compiler-llvm", version = "=6.1.0", optional = true } +corosensei = { workspace = true, optional = true } +futures = { workspace = true, optional = true } -wasm-bindgen = { version = "0.2.74", optional = true } -js-sys = { version = "0.3.51", optional = true } -rusty_jsc = { version = "0.1.0", optional = true } +wasm-bindgen = { workspace = true, optional = true } +js-sys = { workspace = true, optional = true } +rusty_jsc = { workspace = true, optional = true } wasmparser = { workspace = true, default-features = false, optional = true } # - Mandatory dependencies for `sys` on Windows. [target.'cfg(all(not(target_arch = "wasm32"), target_os = "windows"))'.dependencies] -windows-sys = "0.59" +windows-sys.workspace = true # - Development Dependencies for `sys`. [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] -wat = "1.0" +wat.workspace = true tempfile.workspace = true anyhow.workspace = true macro-wasmer-universal-test = { version = "6.1.0", path = "./macro-wasmer-universal-test" } +futures = "0.3" +tokio = { workspace = true, features = ["full"] } # Dependencies and Develoment Dependencies for `js`. [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -86,22 +90,22 @@ macro-wasmer-universal-test = { version = "6.1.0", path = "./macro-wasmer-univer wasmer-types = { path = "../types", version = "=6.1.0", default-features = false, features = [ "std", ] } -wasm-bindgen = "0.2.100" -js-sys = "0.3.77" +wasm-bindgen.workspace = true +js-sys.workspace = true wasmer-derive = { path = "../derive", version = "=6.1.0" } wasmer-compiler = { path = "../compiler", version = "=6.1.0" } # - Optional dependencies for `js`. wasmparser = { workspace = true, default-features = false, optional = true } hashbrown = { workspace = true, optional = true } -serde-wasm-bindgen = { version = "0.6.5" } +serde-wasm-bindgen.workspace = true serde.workspace = true target-lexicon.workspace = true # - Development Dependencies for `js`. [target.'cfg(target_arch = "wasm32")'.dev-dependencies] -wat = "1.0" +wat.workspace = true anyhow.workspace = true -wasm-bindgen-test = "0.3.0" +wasm-bindgen-test.workspace = true macro-wasmer-universal-test = { version = "6.1.0", path = "./macro-wasmer-universal-test" } # Specific to `js`. @@ -128,6 +132,9 @@ artifact-size = [ sys = ["std", "dep:wasmer-vm", "dep:wasmer-compiler"] sys-default = ["sys", "wat", "cranelift"] +# Experimental concurrent execution support +experimental-async = ["sys", "dep:futures", "dep:corosensei"] + # - Compilers. compiler = [ "sys", @@ -145,7 +152,7 @@ wamr-default = ["wamr", "wat"] wamr = ["wasm-c-api", "std", "dep:which", "dep:zip", "dep:ureq"] # --- Enable the wasmi backend and use it as default backend. -wasmi = ["wasm-c-api", "std", "dep:wasmi_c_api"] +wasmi = ["wasm-c-api", "std", "dep:wasmi_c_api_impl"] # --- Enable the wasmi backend and use it as defaul backend only if it is the only one enabled. wasmi-default = ["wasmi", "wat"] @@ -183,22 +190,22 @@ static-artifact-load = ["wasmer-compiler/static-artifact-load"] static-artifact-create = ["wasmer-compiler/static-artifact-create"] [build-dependencies] -cmake = "0.1.50" +cmake.workspace = true tar.workspace = true -ureq = { version = "2.10.1", optional = true } -which = { version = "7.0.0", optional = true } -xz = { version = "0.1.0", optional = true } -zip = { version = "2.2.0", optional = true } +ureq = { workspace = true, optional = true } +which = { workspace = true, optional = true } +xz = { workspace = true, optional = true } +zip = { workspace = true, optional = true, default-features = true } [target.'cfg(target_env = "musl")'.build-dependencies] -bindgen = { version = "0.70.1", default-features = false, features = [ +bindgen = { workspace = true, default-features = false, features = [ "static", "logging", "prettyplease", ] } [target.'cfg(not(target_env = "musl"))'.build-dependencies] -bindgen = { version = "0.70.1" } +bindgen = { workspace = true, default-features = true } [package.metadata.docs.rs] features = [ diff --git a/lib/api/build.rs b/lib/api/build.rs index 0a440fbe27..d4968044d4 100644 --- a/lib/api/build.rs +++ b/lib/api/build.rs @@ -19,7 +19,7 @@ fn build_wamr() { "freebsd" => "freebsd", "android" => "android", "ios" => "ios", - other => panic!("Unsupported CARGO_CFG_TARGET_OS: {}", other), + other => panic!("Unsupported CARGO_CFG_TARGET_OS: {other}"), }; // Read target arch from cargo env @@ -32,7 +32,7 @@ fn build_wamr() { "mips" => "MIPS", "powerpc" => "POWERPC", "powerpc64" => "POWERPC64", - other => panic!("Unsupported CARGO_CFG_TARGET_ARCH: {}", other), + other => panic!("Unsupported CARGO_CFG_TARGET_ARCH: {other}"), }; // Cleanup tmp data from prior builds @@ -43,10 +43,13 @@ fn build_wamr() { let _ = std::fs::remove_dir_all(&zip_dir); // Fetch & extract wasm-micro-runtime source - let zip = ureq::get(WAMR_ZIP).call().expect("failed to download wamr"); - let mut zip_data = Vec::new(); - zip.into_reader() - .read_to_end(&mut zip_data) + let zip_data = ureq::get(WAMR_ZIP) + .call() + .expect("failed to download wamr") + .body_mut() + .with_config() + .limit(50 * 1024 * 1024) // 50MB + .read_to_vec() .expect("failed to download wamr"); std::fs::create_dir_all(&zip_dir) .expect("Failed to create temporary zip extraction directory"); @@ -143,6 +146,11 @@ fn build_wamr() { ) -> Option { if item_info.name.starts_with("wasm") { let new_name = format!("wamr_{}", item_info.name); + // TODO: refactor to not use static mut + #[allow( + static_mut_refs, + reason = "existing behaviour that was disallowed by edition 2024" + )] unsafe { WAMR_RENAMED.push((item_info.name.to_string(), new_name.clone())); } @@ -166,8 +174,9 @@ fn build_wamr() { .generate() .expect("Unable to generate bindings"); let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let bindings_path = out_path.join("wamr_bindings.rs"); bindings - .write_to_file(out_path.join("wamr_bindings.rs")) + .write_to_file(&bindings_path) .expect("Couldn't write bindings"); let objcopy_names = ["llvm-objcopy", "objcopy", "gobjcopy"]; @@ -190,6 +199,11 @@ fn build_wamr() { let objcopy = objcopy.unwrap(); unsafe { + // TODO: refactor to not use static mut + #[allow( + static_mut_refs, + reason = "existing behaviour that was disallowed by edition 2024" + )] let syms: Vec = WAMR_RENAMED .iter() .map(|(old, new)| @@ -232,29 +246,43 @@ fn build_v8() { use std::{env, path::PathBuf}; let url = match ( - env::var("CARGO_CFG_TARGET_OS").unwrap().as_str(), - env::var("CARGO_CFG_TARGET_ARCH").unwrap().as_str(), - env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default().as_str(), - ) { - ("macos", "aarch64", _) => "https://github.com/wasmerio/wee8-custom-builds/releases/download/11.8/wee8-darwin-aarch64.tar.xz", - ("macos", "x86_64", _) => "https://github.com/wasmerio/wee8-custom-builds/releases/download/11.8/wee8-darwin-amd64.tar.xz", - ("linux", "x86_64", "gnu") => "https://github.com/wasmerio/wee8-custom-builds/releases/download/11.8/wee8-linux-amd64.tar.xz", - ("linux", "x86_64", "musl") => "https://github.com/wasmerio/wee8-custom-builds/releases/download/11.8/wee8-linux-musl-amd64.tar.xz", - ("android", "aarch64", _) => "https://github.com/wasmerio/wee8-custom-builds/releases/download/11.8/wee8-android-arm64.tar.xz", - // Not supported in 6.0.0-alpha1 - //("windows", "x86_64", _) => "https://github.com/wasmerio/wee8-custom-builds/releases/download/11.7-custom1/wee8-windows-amd64.tar.xz", - (os, arch, _) => panic!("target os + arch combination not supported: {os}, {arch}"), - }; + env::var("CARGO_CFG_TARGET_OS").unwrap().as_str(), + env::var("CARGO_CFG_TARGET_ARCH").unwrap().as_str(), + env::var("CARGO_CFG_TARGET_ENV") + .unwrap_or_default() + .as_str(), + ) { + ("macos", "aarch64", _) => { + "https://github.com/wasmerio/wee8-custom-builds/releases/download/11.8/wee8-darwin-aarch64.tar.xz" + } + ("macos", "x86_64", _) => { + "https://github.com/wasmerio/wee8-custom-builds/releases/download/11.8/wee8-darwin-amd64.tar.xz" + } + ("linux", "x86_64", "gnu") => { + "https://github.com/wasmerio/wee8-custom-builds/releases/download/11.8/wee8-linux-amd64.tar.xz" + } + ("linux", "x86_64", "musl") => { + "https://github.com/wasmerio/wee8-custom-builds/releases/download/11.8/wee8-linux-musl-amd64.tar.xz" + } + ("android", "aarch64", _) => { + "https://github.com/wasmerio/wee8-custom-builds/releases/download/11.8/wee8-android-arm64.tar.xz" + } + // Not supported in 6.0.0-alpha1 + //("windows", "x86_64", _) => "https://github.com/wasmerio/wee8-custom-builds/releases/download/11.7-custom1/wee8-windows-amd64.tar.xz", + (os, arch, _) => panic!("target os + arch combination not supported: {os}, {arch}"), + }; let out_dir = env::var("OUT_DIR").unwrap(); let crate_root = env::var("CARGO_MANIFEST_DIR").unwrap(); let v8_header_path = PathBuf::from(&crate_root).join("third-party").join("wee8"); - let tar = ureq::get(url).call().expect("failed to download v8"); - - let mut tar_data = Vec::new(); - tar.into_reader() - .read_to_end(&mut tar_data) + let tar_data = ureq::get(url) + .call() + .expect("failed to download v8") + .body_mut() + .with_config() + .limit(50 * 1024 * 1024) // 50MB + .read_to_vec() .expect("failed to download v8 lib"); let tar = xz::read::XzDecoder::new(tar_data.as_slice()); @@ -268,7 +296,7 @@ fn build_v8() { let mut archive = tar::Archive::new(tar); archive.unpack(out_dir.clone()).unwrap(); - println!("cargo:rustc-link-search=native={}", out_dir); + println!("cargo:rustc-link-search=native={out_dir}"); if cfg!(any(target_os = "linux",)) { println!("cargo:rustc-link-lib=stdc++"); @@ -294,6 +322,11 @@ fn build_v8() { ) -> Option { if item_info.name.starts_with("wasm") { let new_name = format!("wee8_{}", item_info.name); + // TODO: refactor to not use static mut + #[allow( + static_mut_refs, + reason = "existing behaviour that was disallowed by edition 2024" + )] unsafe { WEE8_RENAMED.push((item_info.name.to_string(), new_name.clone())); } @@ -347,6 +380,11 @@ fn build_v8() { let objcopy = objcopy.unwrap(); + // TODO: refactor to not use static mut + #[allow( + static_mut_refs, + reason = "existing behaviour that was disallowed by edition 2024" + )] unsafe { let syms: Vec = WEE8_RENAMED .iter() @@ -361,10 +399,12 @@ fn build_v8() { } }) .collect(); - let output = dbg!(std::process::Command::new(objcopy) - .args(syms) - .arg(out_path.join("obj").join("libwee8.a").display().to_string()) - .arg(out_path.join("libwee8prefixed.a").display().to_string())) + let output = dbg!( + std::process::Command::new(objcopy) + .args(syms) + .arg(out_path.join("obj").join("libwee8.a").display().to_string()) + .arg(out_path.join("libwee8prefixed.a").display().to_string()) + ) .output() .unwrap(); @@ -421,9 +461,32 @@ fn build_wasmi() { .generate() .expect("Unable to generate bindings for `wasmi`!"); let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let bindings_path = out_path.join("wasmi_bindings.rs"); bindings - .write_to_file(out_path.join("wasmi_bindings.rs")) + .write_to_file(&bindings_path) .expect("Couldn't write bindings"); + + let original = + std::fs::read_to_string(&bindings_path).expect("Failed to read generated wasmi bindings"); + let mut patched = String::with_capacity(original.len()); + for line in original.lines() { + let trimmed = line.trim_start(); + let indent_len = line.len() - trimmed.len(); + let indent = &line[..indent_len]; + if trimmed.starts_with("extern \"") + && trimmed.ends_with('{') + && !trimmed.starts_with("unsafe ") + { + patched.push_str(indent); + patched.push_str("unsafe "); + patched.push_str(trimmed); + } else { + patched.push_str(line); + } + patched.push('\n'); + } + std::fs::write(&bindings_path, patched) + .expect("Failed to post-process wasmi bindings for Rust 2024"); } #[allow(unused)] fn main() { diff --git a/lib/api/macro-wasmer-universal-test/Cargo.toml b/lib/api/macro-wasmer-universal-test/Cargo.toml index 11d9f9acbd..5a43e597dc 100644 --- a/lib/api/macro-wasmer-universal-test/Cargo.toml +++ b/lib/api/macro-wasmer-universal-test/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "macro-wasmer-universal-test" -version = "6.1.0" -edition = "2021" -license = "MIT" description = "Universal test macro for wasmer-test" +version.workspace = true +edition.workspace = true +license.workspace = true [lib] proc-macro = true [dependencies] -proc-macro2 = "1.0.60" -syn = { version = "2.0", default-features = false, features = [ +proc-macro2.workspace = true +syn = { workspace = true, default-features = false, features = [ "full", "parsing", "printing", @@ -19,4 +19,4 @@ syn = { version = "2.0", default-features = false, features = [ "extra-traits", "proc-macro", ] } -quote = "1.0.20" +quote.workspace = true diff --git a/lib/api/macro-wasmer-universal-test/src/lib.rs b/lib/api/macro-wasmer-universal-test/src/lib.rs index 2e7abc3bae..5b9274a502 100644 --- a/lib/api/macro-wasmer-universal-test/src/lib.rs +++ b/lib/api/macro-wasmer-universal-test/src/lib.rs @@ -1,7 +1,7 @@ use proc_macro2::{Ident, Span, TokenStream}; use syn::{ - parse::{Parse, ParseStream}, Attribute, Signature, Visibility, + parse::{Parse, ParseStream}, }; #[proc_macro_attribute] diff --git a/lib/api/src/backend/js/entities/engine.rs b/lib/api/src/backend/js/entities/engine.rs index cdb2316c30..2be7a65522 100644 --- a/lib/api/src/backend/js/entities/engine.rs +++ b/lib/api/src/backend/js/entities/engine.rs @@ -1,4 +1,4 @@ -use wasmer_types::{target::Target, Features}; +use wasmer_types::{Features, target::Target}; /// The engine for the JavaScript runtime. #[derive(Clone, Debug)] @@ -31,13 +31,13 @@ impl Engine { impl Default for Engine { fn default() -> Self { - Engine + Self } } /// Returns the default engine for the JS engine pub(crate) fn default_engine() -> Engine { - Engine::default() + Engine } impl crate::Engine { @@ -71,11 +71,11 @@ impl crate::Engine { } } -impl Into for Engine { - fn into(self) -> crate::Engine { - crate::Engine { - be: crate::BackendEngine::Js(self), - id: crate::Engine::atomic_next_engine_id(), +impl From for crate::Engine { + fn from(val: Engine) -> Self { + Self { + be: crate::BackendEngine::Js(val), + id: Self::atomic_next_engine_id(), } } } diff --git a/lib/api/src/backend/js/entities/exception.rs b/lib/api/src/backend/js/entities/exception.rs index be352635d4..f7b8ca40c1 100644 --- a/lib/api/src/backend/js/entities/exception.rs +++ b/lib/api/src/backend/js/entities/exception.rs @@ -2,8 +2,8 @@ use super::store::StoreHandle; use crate::{ - js::vm::{VMException, VMExceptionRef}, AsStoreMut, AsStoreRef, Tag, Value, + js::vm::{VMException, VMExceptionRef}, }; use std::any::Any; use wasmer_types::{TagType, Type}; @@ -20,42 +20,6 @@ unsafe impl Sync for Exception {} impl Exception { /// Create a new [`Exception`]. pub fn new(store: &mut impl AsStoreMut, tag: Tag, payload: &[Value]) -> Self { - todo!() - } -} - -#[derive(Debug, Clone)] -#[repr(transparent)] -/// A WebAssembly `exnref` in `js`. -pub(crate) struct ExceptionRef; - -impl ExceptionRef { - pub fn new(_store: &mut impl AsStoreMut, _value: T) -> Self - where - T: Any + Send + Sync + 'static + Sized, - { - unimplemented!("ExceptionRef is not yet supported in js"); - } - - pub fn downcast<'a, T>(&self, _store: &'a impl AsStoreRef) -> Option<&'a T> - where - T: Any + Send + Sync + 'static + Sized, - { - unimplemented!("ExceptionRef is not yet supported in js"); - } - - pub(crate) fn vm_exceptionref(&self) -> VMExceptionRef { - unimplemented!("ExceptionRef is not yet supported in js"); - } - - pub(crate) unsafe fn from_vm_exceptionref( - _store: &mut impl AsStoreMut, - _vm_exceptionref: VMExceptionRef, - ) -> Self { - unimplemented!("ExceptionRef is not yet supported in js"); - } - - pub fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { - true + unimplemented!("Exception handling is not yet supported in js"); } } diff --git a/lib/api/src/backend/js/entities/function/env.rs b/lib/api/src/backend/js/entities/function/env.rs index b05024cd78..5b377a326c 100644 --- a/lib/api/src/backend/js/entities/function/env.rs +++ b/lib/api/src/backend/js/entities/function/env.rs @@ -1,9 +1,9 @@ use std::{any::Any, fmt::Debug, marker::PhantomData}; use crate::{ + StoreMut, js::{store::StoreHandle, vm::VMFunctionEnvironment}, store::{AsStoreMut, AsStoreRef, StoreRef}, - StoreMut, }; #[derive(Debug)] @@ -62,7 +62,7 @@ impl FunctionEnv { } /// Convert it into a `FunctionEnvMut` - pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut + pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut<'_, T> where T: Any + Send + 'static + Sized, { @@ -103,7 +103,7 @@ pub struct FunctionEnvMut<'a, T: 'a> { pub(crate) func_env: FunctionEnv, } -impl<'a, T> Debug for FunctionEnvMut<'a, T> +impl Debug for FunctionEnvMut<'_, T> where T: Send + Debug + 'static, { @@ -137,7 +137,7 @@ impl FunctionEnvMut<'_, T> { } /// Borrows a new mutable reference of both the attached Store and host state - pub fn data_and_store_mut(&mut self) -> (&mut T, StoreMut) { + pub fn data_and_store_mut(&mut self) -> (&mut T, StoreMut<'_>) { let data = self.func_env.as_mut(&mut self.store_mut) as *mut T; // telling the borrow check to close his eyes here // this is still relatively safe to do as func_env are @@ -202,6 +202,6 @@ impl<'a, T> From> for crate::FunctionEnvMut<'a, T> { impl From> for crate::FunctionEnv { fn from(value: FunctionEnv) -> Self { - crate::FunctionEnv(crate::BackendFunctionEnv::Js(value)) + Self(crate::BackendFunctionEnv::Js(value)) } } diff --git a/lib/api/src/backend/js/entities/function/mod.rs b/lib/api/src/backend/js/entities/function/mod.rs index 667fa091ec..d69b21d424 100644 --- a/lib/api/src/backend/js/entities/function/mod.rs +++ b/lib/api/src/backend/js/entities/function/mod.rs @@ -5,19 +5,19 @@ use std::marker::PhantomData; pub(crate) use typed::*; use js_sys::{Array, Function as JsFunction}; -use wasm_bindgen::{prelude::*, JsCast}; +use wasm_bindgen::{JsCast, prelude::*}; use wasmer_types::{FunctionType, RawValue}; use crate::{ - js::{ - utils::convert::{js_value_to_wasmer, wasmer_value_to_js, AsJs as _}, - vm::{function::VMFunction, VMFuncRef, VMFunctionCallback}, - }, - vm::{VMExtern, VMExternFunction}, AsStoreMut, AsStoreRef, BackendFunction, BackendFunctionEnv, BackendFunctionEnvMut, FromToNativeWasmType, FunctionEnv, FunctionEnvMut, HostFunction, HostFunctionKind, IntoResult, NativeWasmType, NativeWasmTypeInto, RuntimeError, StoreMut, Value, WasmTypeList, WithEnv, WithoutEnv, + js::{ + utils::convert::{AsJs as _, js_value_to_wasmer, wasmer_value_to_js}, + vm::{VMFuncRef, VMFunctionCallback, function::VMFunction}, + }, + vm::{VMExtern, VMExternFunction}, }; use std::panic::{self, AssertUnwindSafe}; @@ -94,7 +94,7 @@ impl Function { .map(|(i, param)| js_value_to_wasmer(param, &args.get(i as u32))) .collect::>(); let results = func(env, &wasm_arguments)?; - return Ok(wasmer_value_to_js(&results[0])); + Ok(wasmer_value_to_js(&results[0])) }) as Box Result>) .into_js_value(), @@ -108,7 +108,7 @@ impl Function { .map(|(i, param)| js_value_to_wasmer(param, &args.get(i as u32))) .collect::>(); let results = func(env, &wasm_arguments)?; - return Ok(wasmer_array_to_js_array(&results)); + Ok(wasmer_array_to_js_array(&results)) }) as Box Result>) .into_js_value(), @@ -233,7 +233,7 @@ impl Function { break; } Ok(wasmer_types::OnCalledAction::Trap(trap)) => { - return Err(RuntimeError::user(trap)) + return Err(RuntimeError::user(trap)); } Err(trap) => return Err(RuntimeError::user(trap)), } @@ -281,7 +281,9 @@ impl Function { #[track_caller] fn closures_unsupported_panic() -> ! { - unimplemented!("Closures (functions with captured environments) are currently unsupported with native functions. See: https://github.com/wasmerio/wasmer/issues/1840") + unimplemented!( + "Closures (functions with captured environments) are currently unsupported with native functions. See: https://github.com/wasmerio/wasmer/issues/1840" + ) } /// Checks whether this `Function` can be used with the given context. @@ -383,15 +385,23 @@ macro_rules! impl_host_function { Func: Fn($( $x , )*) -> RetsAsResult + 'static, { // let env: &Env = unsafe { &*(ptr as *const u8 as *const Env) }; - let func: &Func = &*(&() as *const () as *const Func); - let mut store = StoreMut::from_raw(store_ptr as *mut _); + let func: &Func = unsafe { &*(&() as *const () as *const Func) }; + let mut store = unsafe { StoreMut::from_raw(store_ptr as *mut _) }; let result = panic::catch_unwind(AssertUnwindSafe(|| { - func($( FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x)) ),* ).into_result() + func($( + { + let native = unsafe { NativeWasmTypeInto::from_abi(&mut store, $x) }; + FromToNativeWasmType::from_native(native) + } + ),* ).into_result() })); match result { - Ok(Ok(result)) => return result.into_c_struct(&mut store), + Ok(Ok(result)) => { + let c_struct = unsafe { result.into_c_struct(&mut store) }; + return c_struct; + }, #[cfg(feature = "std")] #[allow(deprecated)] Ok(Err(trap)) => crate::backend::js::error::raise(Box::new(trap)), @@ -423,22 +433,35 @@ macro_rules! impl_host_function { T: Send + 'static, Func: Fn(FunctionEnvMut<'_, T>, $( $x , )*) -> RetsAsResult + 'static, { - let mut store = StoreMut::from_raw(store_ptr as *mut _); - let mut store2 = StoreMut::from_raw(store_ptr as *mut _); + let mut store = unsafe { StoreMut::from_raw(store_ptr as *mut _) }; + let mut store2 = unsafe { StoreMut::from_raw(store_ptr as *mut _) }; let result = { // let env: &Env = unsafe { &*(ptr as *const u8 as *const Env) }; - let func: &Func = &*(&() as *const () as *const Func); + let func: &Func = unsafe { &*(&() as *const () as *const Func) }; panic::catch_unwind(AssertUnwindSafe(|| { let handle: crate::backend::js::store::StoreHandle = - crate::backend::js::store::StoreHandle::from_internal(store2.objects_mut().id(), crate::backend::js::store::InternalStoreHandle::from_index(handle_index).unwrap()); + unsafe { + crate::backend::js::store::StoreHandle::from_internal( + store2.objects_mut().id(), + crate::backend::js::store::InternalStoreHandle::from_index(handle_index).unwrap(), + ) + }; let env: crate::backend::js::function::env::FunctionEnvMut = crate::backend::js::function::env::FunctionEnv::from_handle(handle).into_mut(&mut store2); - func(BackendFunctionEnvMut::Js(env).into(), $( FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x)) ),* ).into_result() + func(BackendFunctionEnvMut::Js(env).into(), $( + { + let native = unsafe { NativeWasmTypeInto::from_abi(&mut store, $x) }; + FromToNativeWasmType::from_native(native) + } + ),* ).into_result() })) }; match result { - Ok(Ok(result)) => return result.into_c_struct(&mut store), + Ok(Ok(result)) => { + let c_struct = unsafe { result.into_c_struct(&mut store) }; + return c_struct; + }, #[allow(deprecated)] #[cfg(feature = "std")] Ok(Err(trap)) => crate::js::error::raise(Box::new(trap)), diff --git a/lib/api/src/backend/js/entities/function/typed.rs b/lib/api/src/backend/js/entities/function/typed.rs index 029dd229c1..229fab787d 100644 --- a/lib/api/src/backend/js/entities/function/typed.rs +++ b/lib/api/src/backend/js/entities/function/typed.rs @@ -8,9 +8,9 @@ //! let add_one_native: TypedFunction = add_one.typed().unwrap(); //! ``` use crate::{ - js::utils::convert::{js_value_to_wasmer, AsJs}, AsStoreMut, FromToNativeWasmType, NativeWasmType, NativeWasmTypeInto, RuntimeError, TypedFunction, Value, WasmTypeList, + js::utils::convert::{AsJs, js_value_to_wasmer}, }; use js_sys::Array; use std::iter::FromIterator; @@ -38,14 +38,20 @@ macro_rules! impl_native_traits { let mut r; // TODO: This loop is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451 loop { - r = self.func.as_js().handle.function.apply( - &JsValue::UNDEFINED, - unsafe { - &Array::from_iter(params_list.clone() - .into_iter() - .map(|(b, a)| Value::from_raw(store, b, a).as_jsvalue(store))) - } - ); + let args_array = unsafe { + Array::from_iter( + params_list + .clone() + .into_iter() + .map(|(b, a)| Value::from_raw(store, b, a).as_jsvalue(store)), + ) + }; + r = self + .func + .as_js() + .handle + .function + .apply(&JsValue::UNDEFINED, &args_array); let store_mut = store.as_store_mut(); if let Some(callback) = store_mut.inner.on_called.take() { match callback(store_mut) { @@ -109,9 +115,15 @@ impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15 +); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16 +); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17 +); impl_native_traits!( A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18 ); diff --git a/lib/api/src/backend/js/entities/global.rs b/lib/api/src/backend/js/entities/global.rs index 9b5ca611e4..277e92db02 100644 --- a/lib/api/src/backend/js/entities/global.rs +++ b/lib/api/src/backend/js/entities/global.rs @@ -1,10 +1,10 @@ -use wasm_bindgen::{prelude::*, JsValue}; +use wasm_bindgen::{JsValue, prelude::*}; use wasmer_types::{GlobalType, Mutability, RawValue, Type}; use crate::{ + AsStoreMut, AsStoreRef, BackendGlobal, RuntimeError, Value, js::vm::VMGlobal, vm::{VMExtern, VMExternGlobal}, - AsStoreMut, AsStoreRef, BackendGlobal, RuntimeError, Value, }; use js_sys::WebAssembly; @@ -127,7 +127,7 @@ impl Global { _ => { return Err(RuntimeError::new( "The type is not yet supported in the JS Global API".to_owned(), - )) + )); } }; self.handle.global.set_value(&new_value); diff --git a/lib/api/src/backend/js/entities/instance.rs b/lib/api/src/backend/js/entities/instance.rs index bae0211142..7b3e2217b4 100644 --- a/lib/api/src/backend/js/entities/instance.rs +++ b/lib/api/src/backend/js/entities/instance.rs @@ -1,11 +1,11 @@ use js_sys::WebAssembly; use crate::{ + AsStoreMut, BackendInstance, Exports, Extern, Imports, InstantiationError, Module, js::{ utils::{convert::AsJs, js_handle::JsHandle}, vm::VMInstance, }, - AsStoreMut, BackendInstance, Exports, Extern, Imports, InstantiationError, Module, }; #[derive(Clone, PartialEq, Eq)] @@ -27,9 +27,9 @@ impl Instance { let instance = module .as_js() .instantiate(&mut store, imports) - .map_err(|e| InstantiationError::Start(e))?; + .map_err(InstantiationError::Start)?; - Self::from_module_and_instance(store, &module, instance) + Self::from_module_and_instance(store, module, instance) } pub(crate) fn new_by_index( @@ -62,13 +62,13 @@ impl Instance { let js_export = unsafe { js_sys::Reflect::get(&instance_exports, &name.into()).unwrap() }; let extern_ = Extern::from_jsvalue(&mut store, extern_type, &js_export) - .map_err(|e| wasm_bindgen::JsValue::from(e)) + .map_err(wasm_bindgen::JsValue::from) .unwrap(); Ok((name.to_string(), extern_)) }) .collect::>()?; - let instance = Instance { + let instance = Self { _handle: JsHandle::new(instance), }; diff --git a/lib/api/src/backend/js/entities/memory/buffer.rs b/lib/api/src/backend/js/entities/memory/buffer.rs index c93da285fb..a582580eeb 100644 --- a/lib/api/src/backend/js/entities/memory/buffer.rs +++ b/lib/api/src/backend/js/entities/memory/buffer.rs @@ -1,5 +1,5 @@ use super::Memory; -use crate::{js::store::StoreObjects, MemoryAccessError}; +use crate::{MemoryAccessError, js::store::StoreObjects}; use std::{marker::PhantomData, mem::MaybeUninit, slice}; use tracing::warn; @@ -10,7 +10,7 @@ pub(crate) struct MemoryBuffer<'a> { pub(crate) marker: PhantomData<(&'a Memory, &'a StoreObjects)>, } -impl<'a> MemoryBuffer<'a> { +impl MemoryBuffer<'_> { pub(crate) fn read(&self, offset: u64, buf: &mut [u8]) -> Result<(), MemoryAccessError> { let end = offset .checked_add(buf.len() as u64) @@ -26,7 +26,7 @@ impl<'a> MemoryBuffer<'a> { return Err(MemoryAccessError::HeapOutOfBounds); } view.subarray(offset as _, end as _) - .copy_to(unsafe { &mut slice::from_raw_parts_mut(buf.as_mut_ptr(), buf.len()) }); + .copy_to(unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr(), buf.len()) }); Ok(()) } @@ -55,10 +55,10 @@ impl<'a> MemoryBuffer<'a> { return Err(MemoryAccessError::HeapOutOfBounds); } let buf_ptr = buf.as_mut_ptr() as *mut u8; - view.subarray(offset as _, end as _) - .copy_to(unsafe { &mut slice::from_raw_parts_mut(buf_ptr, buf.len()) }); + let mut slice = unsafe { slice::from_raw_parts_mut(buf_ptr, buf.len()) }; + view.subarray(offset as _, end as _).copy_to(slice); - Ok(unsafe { slice::from_raw_parts_mut(buf_ptr, buf.len()) }) + Ok(slice) } pub(crate) fn write(&self, offset: u64, data: &[u8]) -> Result<(), MemoryAccessError> { diff --git a/lib/api/src/backend/js/entities/memory/mod.rs b/lib/api/src/backend/js/entities/memory/mod.rs index 76ff50e5d8..750bb23f72 100644 --- a/lib/api/src/backend/js/entities/memory/mod.rs +++ b/lib/api/src/backend/js/entities/memory/mod.rs @@ -11,9 +11,9 @@ use wasm_bindgen::JsCast; use wasmer_types::{MemoryError, MemoryType, Pages, WASM_PAGE_SIZE}; use crate::{ + AsStoreMut, AsStoreRef, BackendMemory, js::vm::memory::VMMemory, vm::{VMExtern, VMExternMemory}, - AsStoreMut, AsStoreRef, BackendMemory, }; #[derive(Debug, Clone, Eq)] @@ -186,7 +186,7 @@ impl std::cmp::PartialEq for Memory { impl From for crate::Memory { fn from(value: Memory) -> Self { - crate::Memory(crate::BackendMemory::Js(value)) + Self(crate::BackendMemory::Js(value)) } } diff --git a/lib/api/src/backend/js/entities/memory/view.rs b/lib/api/src/backend/js/entities/memory/view.rs index e4c451624d..628af3958e 100644 --- a/lib/api/src/backend/js/entities/memory/view.rs +++ b/lib/api/src/backend/js/entities/memory/view.rs @@ -91,9 +91,9 @@ impl<'a> MemoryView<'a> { /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value}; /// # let mut store = Store::default(); /// # - /// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap(); + /// let m = Memory::new(& mut store, MemoryType::new(1, None, false)).unwrap(); /// - /// assert_eq!(m.size(), Pages(1)); + /// assert_eq!(m.size(&store), Pages(1)); /// ``` pub fn size(&self) -> Pages { Bytes(self.size as usize).try_into().unwrap() diff --git a/lib/api/src/backend/js/entities/module.rs b/lib/api/src/backend/js/entities/module.rs index b734661f96..38d83bce46 100644 --- a/lib/api/src/backend/js/entities/module.rs +++ b/lib/api/src/backend/js/entities/module.rs @@ -3,7 +3,7 @@ use std::path::Path; use bytes::Bytes; use js_sys::{Reflect, Uint8Array, WebAssembly}; use tracing::{debug, warn}; -use wasm_bindgen::{prelude::*, JsValue}; +use wasm_bindgen::{JsValue, prelude::*}; use wasmer_types::{ CompileError, DeserializeError, ExportType, ExportsIterator, ExternType, FunctionType, GlobalType, ImportType, ImportsIterator, MemoryType, ModuleInfo, Mutability, Pages, @@ -11,12 +11,12 @@ use wasmer_types::{ }; use crate::{ + AsEngineRef, AsStoreMut, BackendModule, Extern, Imports, InstantiationError, IntoBytes, + RuntimeError, js::{ utils::{convert::AsJs as _, js_handle::JsHandle}, vm::VMInstance, }, - AsEngineRef, AsStoreMut, BackendModule, Extern, Imports, InstantiationError, IntoBytes, - RuntimeError, }; /// WebAssembly in the browser doesn't yet output the descriptor/types @@ -71,15 +71,15 @@ impl Module { _engine: &impl AsEngineRef, binary: &[u8], ) -> Result { - let js_bytes = Uint8Array::view(binary); + let js_bytes = unsafe { Uint8Array::view(binary) }; let module = WebAssembly::Module::new(&js_bytes.into()).map_err(|e| { - CompileError::Validate(format!( - "{}", + CompileError::Validate( e.as_string() .unwrap_or("Unknown validation error".to_string()) - )) + .to_string(), + ) })?; - Ok(Self::from_js_module(module, binary)) + Ok(unsafe { Self::from_js_module(module, binary) }) } /// Creates a new WebAssembly module skipping any kind of validation from a javascript module @@ -205,8 +205,8 @@ impl Module { // in case the import is not found, the JS Wasm VM will handle // the error for us, so we don't need to handle it } - Ok(WebAssembly::Instance::new(&self.module, &imports_object) - .map_err(|e: JsValue| -> RuntimeError { e.into() })?) + WebAssembly::Instance::new(&self.module, &imports_object) + .map_err(|e: JsValue| -> RuntimeError { e.into() }) } pub fn name(&self) -> Option<&str> { @@ -257,7 +257,7 @@ impl Module { path: impl AsRef, ) -> Result { let bytes = std::fs::read(path.as_ref())?; - Self::deserialize(engine, bytes) + unsafe { Self::deserialize(engine, bytes) } } pub unsafe fn deserialize_from_file( @@ -265,7 +265,7 @@ impl Module { path: impl AsRef, ) -> Result { let bytes = std::fs::read(path.as_ref())?; - Self::deserialize(engine, bytes) + unsafe { Self::deserialize(engine, bytes) } } pub fn set_name(&mut self, name: &str) -> bool { @@ -372,7 +372,12 @@ impl Module { ExternType::Tag(_) => "tag", }; if expected_kind != kind.as_str() { - return Err(format!("The provided type hint for the export {} is {} which doesn't match the expected kind: {}", i, kind.as_str(), expected_kind)); + return Err(format!( + "The provided type hint for the export {} is {} which doesn't match the expected kind: {}", + i, + kind.as_str(), + expected_kind + )); } } self.type_hints = Some(type_hints); @@ -459,8 +464,8 @@ impl Module { impl From for Module { #[track_caller] - fn from(module: WebAssembly::Module) -> Module { - Module { + fn from(module: WebAssembly::Module) -> Self { + Self { module: JsHandle::new(module), name: None, type_hints: None, @@ -471,9 +476,9 @@ impl From for Module { } impl From<(WebAssembly::Module, T)> for crate::module::Module { - fn from((module, binary): (WebAssembly::Module, T)) -> crate::module::Module { + fn from((module, binary): (WebAssembly::Module, T)) -> Self { unsafe { - crate::module::Module(BackendModule::Js(Module::from_js_module( + Self(BackendModule::Js(Module::from_js_module( module, binary.into_bytes(), ))) @@ -482,8 +487,8 @@ impl From<(WebAssembly::Module, T)> for crate::module::Module { } impl From for crate::module::Module { - fn from(module: WebAssembly::Module) -> crate::module::Module { - crate::module::Module(BackendModule::Js(module.into())) + fn from(module: WebAssembly::Module) -> Self { + Self(BackendModule::Js(module.into())) } } impl From for WebAssembly::Module { @@ -503,16 +508,16 @@ impl crate::Module { /// Convert a reference to [`self`] into a reference [`crate::backend::js::module::Module`]. pub fn as_js(&self) -> &crate::backend::js::module::Module { - match self.0 { - BackendModule::Js(ref s) => s, + match &self.0 { + BackendModule::Js(s) => s, _ => panic!("Not a `js` module!"), } } /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::js::module::Module`]. pub fn as_js_mut(&mut self) -> &mut crate::backend::js::module::Module { - match self.0 { - BackendModule::Js(ref mut s) => s, + match &mut self.0 { + BackendModule::Js(s) => s, _ => panic!("Not a `js` module!"), } } diff --git a/lib/api/src/backend/js/entities/store/handle.rs b/lib/api/src/backend/js/entities/store/handle.rs index 686da2ce41..187deda4e5 100644 --- a/lib/api/src/backend/js/entities/store/handle.rs +++ b/lib/api/src/backend/js/entities/store/handle.rs @@ -2,7 +2,7 @@ use std::{marker::PhantomData, num::NonZeroUsize}; use wasmer_types::StoreId; -use super::{obj::StoreObject, StoreObjects}; +use super::{StoreObjects, obj::StoreObject}; /// Handle to an object managed by a context. /// diff --git a/lib/api/src/backend/js/entities/store/obj.rs b/lib/api/src/backend/js/entities/store/obj.rs index 4f4a75f5d0..ff840f187b 100644 --- a/lib/api/src/backend/js/entities/store/obj.rs +++ b/lib/api/src/backend/js/entities/store/obj.rs @@ -81,7 +81,7 @@ impl StoreObjects { } /// Return an immutable iterator over all globals - pub fn iter_globals(&self) -> core::slice::Iter { + pub fn iter_globals(&self) -> core::slice::Iter<'_, VMGlobal> { self.globals.iter() } diff --git a/lib/api/src/backend/js/entities/table.rs b/lib/api/src/backend/js/entities/table.rs index 436f407991..e376facc89 100644 --- a/lib/api/src/backend/js/entities/table.rs +++ b/lib/api/src/backend/js/entities/table.rs @@ -1,7 +1,7 @@ use crate::{ + AsStoreMut, AsStoreRef, BackendTable, RuntimeError, Value, js::vm::{VMFunction, VMTable}, vm::{VMExtern, VMExternTable}, - AsStoreMut, AsStoreRef, BackendTable, RuntimeError, Value, }; use js_sys::Function; use wasmer_types::{FunctionType, TableType}; @@ -71,7 +71,7 @@ impl Table { } pub fn get(&self, store: &mut impl AsStoreMut, index: u32) -> Option { - if let Some(func) = self.handle.table.get(index).ok() { + if let Ok(func) = self.handle.table.get(index) { let ty = FunctionType::new(vec![], vec![]); let vm_function = VMFunction::new(func, ty); let function = crate::Function::from_vm_extern( @@ -151,16 +151,16 @@ impl crate::Table { /// Convert a reference to [`self`] into a reference [`crate::backend::js::table::Table`]. pub fn as_js(&self) -> &crate::backend::js::table::Table { - match self.0 { - BackendTable::Js(ref s) => s, + match &self.0 { + BackendTable::Js(s) => s, _ => panic!("Not a `js` table!"), } } /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::js::table::Table`]. pub fn as_js_mut(&mut self) -> &mut crate::backend::js::table::Table { - match self.0 { - BackendTable::Js(ref mut s) => s, + match &mut self.0 { + BackendTable::Js(s) => s, _ => panic!("Not a `js` table!"), } } @@ -178,7 +178,7 @@ impl crate::BackendTable { /// Convert a reference to [`self`] into a reference [`crate::backend::js::table::Table`]. pub fn as_js(&self) -> &crate::backend::js::table::Table { match self { - Self::Js(ref s) => s, + Self::Js(s) => s, _ => panic!("Not a `js` table!"), } } @@ -186,7 +186,7 @@ impl crate::BackendTable { /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::js::table::Table`]. pub fn as_js_mut(&mut self) -> &mut crate::backend::js::table::Table { match self { - Self::Js(ref mut s) => s, + Self::Js(s) => s, _ => panic!("Not a `js` table!"), } } diff --git a/lib/api/src/backend/js/entities/tag.rs b/lib/api/src/backend/js/entities/tag.rs index b00c9c3b9f..7456d26ea0 100644 --- a/lib/api/src/backend/js/entities/tag.rs +++ b/lib/api/src/backend/js/entities/tag.rs @@ -1,9 +1,9 @@ use wasmer_types::{TagType, Type}; use crate::{ + AsStoreMut, AsStoreRef, BackendTag, TagKind, js::vm::VMTag, vm::{VMExtern, VMExternTag}, - AsStoreMut, AsStoreRef, BackendTag, TagKind, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -24,7 +24,7 @@ impl Tag { let descriptor = js_sys::Object::new(); let params: Box<[Type]> = params.into(); let parameters: Vec = params - .into_iter() + .iter() .map(|param| match param { Type::I32 => "i32".to_string(), Type::I64 => "i64".to_string(), @@ -62,7 +62,7 @@ impl Tag { impl crate::Tag { /// Consume [`self`] into [`crate::backend::js::tag::Tag`]. - pub fn into_js(self) -> crate::backend::js::tag::Tag { + pub(crate) fn into_js(self) -> crate::backend::js::tag::Tag { match self.0 { BackendTag::Js(s) => s, _ => panic!("Not a `js` tag!"), @@ -70,7 +70,7 @@ impl crate::Tag { } /// Convert a reference to [`self`] into a reference [`crate::backend::js::tag::Tag`]. - pub fn as_js(&self) -> &crate::backend::js::tag::Tag { + pub(crate) fn as_js(&self) -> &crate::backend::js::tag::Tag { match self.0 { BackendTag::Js(ref s) => s, _ => panic!("Not a `js` tag!"), @@ -78,7 +78,7 @@ impl crate::Tag { } /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::js::tag::Tag`]. - pub fn as_js_mut(&mut self) -> &mut crate::backend::js::tag::Tag { + pub(crate) fn as_js_mut(&mut self) -> &mut crate::backend::js::tag::Tag { match self.0 { BackendTag::Js(ref mut s) => s, _ => panic!("Not a `js` tag!"), diff --git a/lib/api/src/backend/js/error.rs b/lib/api/src/backend/js/error.rs index f52554a18b..7b5e28fb75 100644 --- a/lib/api/src/backend/js/error.rs +++ b/lib/api/src/backend/js/error.rs @@ -1,9 +1,12 @@ use std::error::Error; use js_sys::Reflect; -use wasm_bindgen::{prelude::*, JsValue}; +use wasm_bindgen::{JsValue, prelude::*}; -use crate::RuntimeError; +use crate::{ + RuntimeError, + js::{exception::Exception, vm::VMExceptionRef}, +}; #[derive(Debug)] enum InnerTrap { @@ -50,6 +53,16 @@ impl Trap { _ => false, } } + + /// Returns true if the `Trap` is an exception + pub fn is_exception(&self) -> bool { + false + } + + /// If the `Trap` is an uncaught exception, returns it. + pub fn to_exception_ref(&self) -> Option { + None + } } #[wasm_bindgen] @@ -81,13 +94,13 @@ impl From for RuntimeError { fn from(value: JsValue) -> Self { // We try to downcast the error and see if it's an instance of Trap // instead, so we don't need to re-wrap it. - if let Some(obj) = value.dyn_ref() { - if let Some(trap) = downcast_from_ptr(obj) { - return trap.into(); - } + if let Some(obj) = value.dyn_ref() + && let Some(trap) = downcast_from_ptr(obj) + { + return trap.into(); } - RuntimeError::from(Trap { + Self::from(Trap { inner: InnerTrap::Js(value.into()), }) } @@ -111,10 +124,7 @@ fn downcast_from_ptr(value: &JsValue) -> Option { .and_then(|v: JsValue| v.dyn_into()) .ok(); - if marker_func.is_none() { - // We couldn't find the marker, so it's something else. - return None; - } + marker_func.as_ref()?; // Safety: The marker function exists, therefore it's safe to convert back // to a Trap. @@ -150,27 +160,27 @@ impl From for JsTrap { fn from(value: JsValue) -> Self { // Let's try some easy special cases first if let Some(error) = value.dyn_ref::() { - return JsTrap::Message(error.message().into()); + return Self::Message(error.message().into()); } if let Some(s) = value.as_string() { - return JsTrap::Message(s); + return Self::Message(s); } // Otherwise, we'll try to stringify the error and hope for the best if let Some(obj) = value.dyn_ref::() { - return JsTrap::Message(obj.to_string().into()); + return Self::Message(obj.to_string().into()); } - JsTrap::Unknown + Self::Unknown } } impl std::fmt::Display for JsTrap { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - JsTrap::Message(m) => write!(f, "{m}"), - JsTrap::Unknown => write!(f, "unknown"), + Self::Message(m) => write!(f, "{m}"), + Self::Unknown => write!(f, "unknown"), } } } @@ -195,13 +205,13 @@ impl From for RuntimeError { return trap.downcast::().unwrap(); } - RuntimeError::new_from_source(crate::BackendTrap::Js(trap), vec![], None) + Self::new_from_source(crate::BackendTrap::Js(trap), vec![], None) } } impl From for wasm_bindgen::JsValue { fn from(value: RuntimeError) -> Self { - wasm_bindgen::JsValue::from(value.to_string()) + Self::from(value.to_string()) } } diff --git a/lib/api/src/backend/js/utils/convert.rs b/lib/api/src/backend/js/utils/convert.rs index c65008478f..a8c00724f7 100644 --- a/lib/api/src/backend/js/utils/convert.rs +++ b/lib/api/src/backend/js/utils/convert.rs @@ -8,6 +8,7 @@ use wasm_bindgen::{JsCast, JsError, JsValue}; use wasmer_types::ExternType; use crate::{ + Extern, Function, Global, Memory, Table, Tag, Type, imports::Imports, instance::Instance, js::{ @@ -16,7 +17,6 @@ use crate::{ }, store::{AsStoreMut, AsStoreRef}, value::Value, - Extern, Function, Global, Memory, Table, Tag, Type, }; /// Convert the given type to a [`JsValue`]. @@ -236,8 +236,8 @@ impl AsJs for Instance { ) -> Result { let js_instance: js_sys::WebAssembly::Instance = value.clone().into(); let (instance, exports) = JsInstance::from_module_and_instance(store, module, js_instance) - .map_err(|e| JsError::new(&format!("Can't get the instance: {:?}", e)))?; - Ok(Instance { + .map_err(|e| JsError::new(&format!("Can't get the instance: {e:?}")))?; + Ok(Self { _inner: crate::BackendInstance::Js(instance), module: module.clone(), exports, @@ -258,14 +258,13 @@ impl AsJs for Memory { value: &JsValue, ) -> Result { if let Some(memory) = value.dyn_ref::() { - Ok(Memory::from_vm_extern( + Ok(Self::from_vm_extern( store, - crate::vm::VMExternMemory::Js(VMMemory::new(memory.clone(), memory_type.clone())), + crate::vm::VMExternMemory::Js(VMMemory::new(memory.clone(), *memory_type)), )) } else { Err(JsError::new(&format!( - "Extern expect to be of type Memory, but received {:?}", - value + "Extern expect to be of type Memory, but received {value:?}", ))) } } @@ -284,7 +283,7 @@ impl AsJs for Function { value: &JsValue, ) -> Result { if value.is_instance_of::() { - Ok(Function::from_vm_extern( + Ok(Self::from_vm_extern( store, crate::vm::VMExternFunction::Js(VMFunction::new( value.clone().unchecked_into::(), @@ -293,8 +292,7 @@ impl AsJs for Function { )) } else { Err(JsError::new(&format!( - "Extern expect to be of type Function, but received {:?}", - value + "Extern expect to be of type Function, but received {value:?}", ))) } } @@ -312,7 +310,7 @@ impl AsJs for Tag { value: &JsValue, ) -> Result { if value.is_instance_of::() { - Ok(Tag::from_vm_extern( + Ok(Self::from_vm_extern( store, crate::vm::VMExternTag::Js(VMTag::new( value.clone().unchecked_into::(), @@ -321,8 +319,7 @@ impl AsJs for Tag { )) } else { Err(JsError::new(&format!( - "Extern expect to be of type Tag, but received {:?}", - value + "Extern expect to be of type Tag, but received {value:?}", ))) } } @@ -341,17 +338,16 @@ impl AsJs for Global { value: &JsValue, ) -> Result { if value.is_instance_of::() { - Ok(Global::from_vm_extern( + Ok(Self::from_vm_extern( store, crate::vm::VMExternGlobal::Js(VMGlobal::new( value.clone().unchecked_into::(), - global_type.clone(), + *global_type, )), )) } else { Err(JsError::new(&format!( - "Extern expect to be of type Global, but received {:?}", - value + "Extern expect to be of type Global, but received {value:?}", ))) } } @@ -370,17 +366,16 @@ impl AsJs for Table { value: &JsValue, ) -> Result { if value.is_instance_of::() { - Ok(Table::from_vm_extern( + Ok(Self::from_vm_extern( store, crate::vm::VMExternTable::Js(VMTable::new( value.clone().unchecked_into::(), - table_type.clone(), + *table_type, )), )) } else { Err(JsError::new(&format!( - "Extern expect to be of type Table, but received {:?}", - value + "Extern expect to be of type Table, but received {value:?}", ))) } } diff --git a/lib/api/src/backend/js/utils/js_handle.rs b/lib/api/src/backend/js/utils/js_handle.rs index 043cc1eb28..c9ff1be1c9 100644 --- a/lib/api/src/backend/js/utils/js_handle.rs +++ b/lib/api/src/backend/js/utils/js_handle.rs @@ -19,7 +19,7 @@ pub(crate) struct JsHandle { impl JsHandle { #[track_caller] pub fn new(value: T) -> Self { - JsHandle { + Self { value, integrity: IntegrityCheck::new(std::any::type_name::()), } @@ -34,7 +34,7 @@ impl JsHandle { impl PartialEq for JsHandle { fn eq(&self, other: &Self) -> bool { - let JsHandle { + let Self { value, integrity: _, } = self; @@ -48,11 +48,11 @@ impl Eq for JsHandle {} impl From for JsHandle { #[track_caller] fn from(value: T) -> Self { - JsHandle::new(value) + Self::new(value) } } -impl> From> for JsValue { +impl> From> for JsValue { fn from(value: JsHandle) -> Self { value.into_inner().into() } @@ -120,7 +120,7 @@ mod integrity_check { impl IntegrityCheck { #[track_caller] pub(crate) fn new(type_name: &'static str) -> Self { - IntegrityCheck { + Self { original_thread: super::current_thread_id(), created: Location::caller(), type_name, @@ -133,7 +133,7 @@ mod integrity_check { let current_thread = super::current_thread_id(); if current_thread != self.original_thread { - let IntegrityCheck { + let Self { original_thread, created, type_name, diff --git a/lib/api/src/backend/js/vm/memory.rs b/lib/api/src/backend/js/vm/memory.rs index 706694b746..4a15d8ea91 100644 --- a/lib/api/src/backend/js/vm/memory.rs +++ b/lib/api/src/backend/js/vm/memory.rs @@ -42,12 +42,12 @@ impl VMMemory { } /// Attempts to clone this memory (if its clonable) - pub(crate) fn try_clone(&self) -> Result { + pub(crate) fn try_clone(&self) -> Result { Ok(self.clone()) } /// Copies this memory to a new memory - pub fn copy(&mut self) -> Result { + pub fn copy(&mut self) -> Result { let new_memory = crate::js::memory::Memory::js_memory_from_type(&self.ty)?; let src = crate::js::memory::MemoryView::new_raw(&self.memory); @@ -80,21 +80,21 @@ impl VMMemory { } src.copy_to_memory(amount as u64, &dst).map_err(|err| { - wasmer_types::MemoryError::Generic(format!("failed to copy the memory - {}", err)) + wasmer_types::MemoryError::Generic(format!("failed to copy the memory - {err}")) })?; trace!("memory copy finished (size={})", dst.size().bytes().0); Ok(Self { memory: JsHandle::new(new_memory), - ty: self.ty.clone(), + ty: self.ty, }) } } impl From for JsValue { fn from(value: VMMemory) -> Self { - JsValue::from(value.memory) + Self::from(value.memory) } } diff --git a/lib/api/src/backend/jsc/entities/engine.rs b/lib/api/src/backend/jsc/entities/engine.rs index c026f4b18f..11e735f3a1 100644 --- a/lib/api/src/backend/jsc/entities/engine.rs +++ b/lib/api/src/backend/jsc/entities/engine.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use rusty_jsc::{JSContext, JSObject}; -use wasmer_types::{target::Target, Features}; +use wasmer_types::{Features, target::Target}; use crate::{AsEngineRef, AsStoreRef}; @@ -105,21 +105,21 @@ impl IntoJSC for crate::engine::EngineRef<'_> { impl IntoJSC for crate::store::StoreRef<'_> { #[inline] fn jsc(&self) -> &JSCEngine { - &self.engine().jsc() + self.engine().jsc() } } impl IntoJSC for crate::store::StoreMut<'_> { #[inline] fn jsc(&self) -> &JSCEngine { - &self.engine().jsc() + self.engine().jsc() } } impl IntoJSC for crate::Store { #[inline] fn jsc(&self) -> &JSCEngine { - &self.engine().jsc() + self.engine().jsc() } } @@ -266,11 +266,11 @@ impl crate::Engine { } } -impl Into for Engine { - fn into(self) -> crate::Engine { - crate::Engine { - be: crate::BackendEngine::Jsc(self), - id: crate::Engine::atomic_next_engine_id(), +impl From for crate::Engine { + fn from(engine: Engine) -> Self { + Self { + be: crate::BackendEngine::Jsc(engine), + id: Self::atomic_next_engine_id(), } } } diff --git a/lib/api/src/backend/jsc/entities/exception.rs b/lib/api/src/backend/jsc/entities/exception.rs index f7a2a63f99..beb8949c98 100644 --- a/lib/api/src/backend/jsc/entities/exception.rs +++ b/lib/api/src/backend/jsc/entities/exception.rs @@ -4,8 +4,8 @@ use std::any::Any; use wasmer_types::{TagType, Type}; use crate::{ - jsc::vm::{VMException, VMExceptionRef}, AsStoreMut, AsStoreRef, Tag, Value, + jsc::vm::{VMException, VMExceptionRef}, }; use super::store::StoreHandle; @@ -22,42 +22,6 @@ unsafe impl Sync for Exception {} impl Exception { /// Create a new [`Exception`]. pub fn new(store: &mut impl AsStoreMut, tag: Tag, payload: &[Value]) -> Self { - todo!() - } -} - -#[derive(Debug, Clone)] -#[repr(transparent)] -/// A WebAssembly `exnref` in `jsc`. -pub(crate) struct ExceptionRef; - -impl ExceptionRef { - pub fn new(_store: &mut impl AsStoreMut, _value: T) -> Self - where - T: Any + Send + Sync + 'static + Sized, - { - unimplemented!("ExceptionRef is not yet supported in jsc"); - } - - pub fn downcast<'a, T>(&self, _store: &'a impl AsStoreRef) -> Option<&'a T> - where - T: Any + Send + Sync + 'static + Sized, - { - unimplemented!("ExceptionRef is not yet supported in jsc"); - } - - pub(crate) fn vm_exceptionref(&self) -> VMExceptionRef { - unimplemented!("ExceptionRef is not yet supported in jsc"); - } - - pub(crate) unsafe fn from_vm_exceptionref( - _store: &mut impl AsStoreMut, - _vm_exceptionref: VMExceptionRef, - ) -> Self { - unimplemented!("ExceptionRef is not yet supported in jsc"); - } - - pub fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { - true + unimplemented!("Exception handling is not yet supported in jsc"); } } diff --git a/lib/api/src/backend/jsc/entities/function/env.rs b/lib/api/src/backend/jsc/entities/function/env.rs index 81f4aef391..88739f08a5 100644 --- a/lib/api/src/backend/jsc/entities/function/env.rs +++ b/lib/api/src/backend/jsc/entities/function/env.rs @@ -1,9 +1,9 @@ use std::{any::Any, fmt::Debug, marker::PhantomData}; use crate::{ + StoreMut, jsc::{store::StoreHandle, vm::VMFunctionEnvironment}, store::{AsStoreMut, AsStoreRef, StoreRef}, - StoreMut, }; #[derive(Debug)] @@ -62,7 +62,7 @@ impl FunctionEnv { } /// Convert it into a `FunctionEnvMut` - pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut + pub fn into_mut<'a>(self, store: &'a mut impl AsStoreMut) -> FunctionEnvMut<'a, T> where T: Any + Send + 'static + Sized, { @@ -137,7 +137,7 @@ impl FunctionEnvMut<'_, T> { } /// Borrows a new mutable reference of both the attached Store and host state - pub fn data_and_store_mut(&mut self) -> (&mut T, StoreMut) { + pub fn data_and_store_mut<'a>(&'a mut self) -> (&'a mut T, StoreMut<'a>) { let data = self.func_env.as_mut(&mut self.store_mut) as *mut T; // telling the borrow check to close his eyes here // this is still relatively safe to do as func_env are @@ -196,12 +196,12 @@ impl crate::FunctionEnv { impl<'a, T> From> for crate::FunctionEnvMut<'a, T> { fn from(value: FunctionEnvMut<'a, T>) -> Self { - crate::FunctionEnvMut(crate::BackendFunctionEnvMut::Jsc(value)) + Self(crate::BackendFunctionEnvMut::Jsc(value)) } } impl From> for crate::FunctionEnv { fn from(value: FunctionEnv) -> Self { - crate::FunctionEnv(crate::BackendFunctionEnv::Jsc(value)) + Self(crate::BackendFunctionEnv::Jsc(value)) } } diff --git a/lib/api/src/backend/jsc/entities/function/mod.rs b/lib/api/src/backend/jsc/entities/function/mod.rs index 6856dfeeb2..afe36b214a 100644 --- a/lib/api/src/backend/jsc/entities/function/mod.rs +++ b/lib/api/src/backend/jsc/entities/function/mod.rs @@ -2,22 +2,22 @@ pub(crate) mod env; pub(crate) mod typed; use rusty_jsc::{ - callback, callback_closure, JSContext, JSObject, JSObjectCallAsFunctionCallback, JSValue, + JSContext, JSObject, JSObjectCallAsFunctionCallback, JSValue, callback, callback_closure, }; use std::marker::PhantomData; use std::panic::{self, AssertUnwindSafe}; use wasmer_types::{FunctionType, RawValue}; use crate::{ + AsStoreMut, AsStoreRef, BackendFunction, BackendFunctionEnvMut, FromToNativeWasmType, + FunctionEnv, FunctionEnvMut, HostFunction, HostFunctionKind, IntoResult, NativeWasmType, + NativeWasmTypeInto, RuntimeError, StoreMut, Value, WasmTypeList, WithEnv, WithoutEnv, jsc::{ store::{InternalStoreHandle, StoreHandle}, - utils::convert::{jsc_value_to_wasmer, AsJsc}, + utils::convert::{AsJsc, jsc_value_to_wasmer}, vm::{VMFuncRef, VMFunction, VMFunctionEnvironment}, }, vm::VMExtern, - AsStoreMut, AsStoreRef, BackendFunction, BackendFunctionEnvMut, FromToNativeWasmType, - FunctionEnv, FunctionEnvMut, HostFunction, HostFunctionKind, IntoResult, NativeWasmType, - NativeWasmTypeInto, RuntimeError, StoreMut, Value, WasmTypeList, WithEnv, WithoutEnv, }; use super::engine::IntoJSC; @@ -91,17 +91,17 @@ impl Function { .map(|(i, param)| jsc_value_to_wasmer(&ctx, param, &args[i])) .collect::>(); let results = func(env, &wasm_arguments).map_err(|e| { - let value = format!("{}", e); + let value = format!("{e}"); JSValue::string(&ctx, value) })?; match new_function_type.results().len() { 0 => Ok(JSValue::undefined(&ctx)), - 1 => Ok(results[0].as_jsc_value(&mut store)), + 1 => Ok(results[0].as_jsc_value(&store)), _ => Ok(JSObject::new_array( &ctx, &results .into_iter() - .map(|result| result.as_jsc_value(&mut store)) + .map(|result| result.as_jsc_value(&store)) .collect::>(), )? .to_jsvalue()), @@ -148,23 +148,23 @@ impl Function { let callback = function.callback(store.jsc().context()); let bind = callback - .get_property(&context, "bind".to_string()) - .to_object(&context) + .get_property(context, "bind".to_string()) + .to_object(context) .unwrap(); let callback_with_env = bind .call( - &context, + context, Some(&callback), &[ - JSValue::undefined(&context), + JSValue::undefined(context), JSValue::number( - &context, + context, env.as_jsc().handle.internal_handle().index() as f64, ), ], ) .unwrap() - .to_object(&context) + .to_object(context) .unwrap(); let ty = function.ty(); @@ -201,9 +201,9 @@ impl Function { let mut global = context.get_global_object(); let store_ptr = store_mut.as_raw() as usize; global.set_property( - &context, + context, "__store_ptr".to_string(), - JSValue::number(&context, store_ptr as _), + JSValue::number(context, store_ptr as _), ); let params_list = params @@ -217,7 +217,7 @@ impl Function { let store_mut = store.as_store_mut(); let engine = store_mut.engine(); let context = engine.as_jsc().context(); - r = self.handle.function.call(&context, None, ¶ms_list); + r = self.handle.function.call(context, None, ¶ms_list); if let Some(callback) = store_mut.inner.on_called.take() { match callback(store_mut) { Ok(wasmer_types::OnCalledAction::InvokeAgain) => { @@ -227,7 +227,7 @@ impl Function { break; } Ok(wasmer_types::OnCalledAction::Trap(trap)) => { - return Err(RuntimeError::user(trap)) + return Err(RuntimeError::user(trap)); } Err(trap) => return Err(RuntimeError::user(trap)), } @@ -243,15 +243,15 @@ impl Function { match result_types.len() { 0 => Ok(Box::new([])), 1 => { - let value = jsc_value_to_wasmer(&context, &result_types[0], &result); + let value = jsc_value_to_wasmer(context, &result_types[0], &result); Ok(vec![value].into_boxed_slice()) } n => { - let result = result.to_object(&context).unwrap(); + let result = result.to_object(context).unwrap(); Ok((0..n) .map(|i| { - let js_val = result.get_property_at_index(&context, i as _).unwrap(); - jsc_value_to_wasmer(&context, &result_types[i], &js_val) + let js_val = result.get_property_at_index(context, i as _).unwrap(); + jsc_value_to_wasmer(context, &result_types[i], &js_val) }) .collect::>() .into_boxed_slice()) @@ -294,7 +294,7 @@ impl std::fmt::Debug for Function { /// Represents a low-level Wasm static host function. See /// `super::Function::new` and `super::Function::new_env` to learn /// more. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug, Hash)] pub struct WasmFunction { callback: JSObjectCallAsFunctionCallback, _phantom: PhantomData<(Args, Rets)>, @@ -397,28 +397,31 @@ macro_rules! impl_host_function { { use std::convert::TryInto; - let func: &Func = &*(&() as *const () as *const Func); + let func: &Func = unsafe { &*(&() as *const () as *const Func) }; let global = ctx.get_global_object(); let store_ptr = global.get_property(&ctx, "__store_ptr".to_string()).to_number(&ctx).unwrap(); if store_ptr.is_nan() { panic!("Store pointer is invalid. Received {}", store_ptr as usize) } - let mut store = StoreMut::from_raw(store_ptr as usize as *mut _); + let mut store = unsafe { StoreMut::from_raw(store_ptr as usize as *mut _) }; let result = panic::catch_unwind(AssertUnwindSafe(|| { type JSArray<'a> = &'a [JSValue; count_idents!( $( $x ),* )]; let args_without_store: JSArray = arguments.try_into().unwrap(); let [ $( $x ),* ] = args_without_store; - func($( FromToNativeWasmType::from_native( $x::Native::from_raw(&mut store, RawValue { u128: { - // TODO: This may not be the fastest way, but JSC doesn't expose a BigInt interface - // so the only thing we can do is parse from the string repr - if $x.is_number(&ctx) { - $x.to_number(&ctx).unwrap() as _ - } - else { - $x.to_string(&ctx).unwrap().to_string().parse::().unwrap() - } - } }) ) ),* ).into_result() + func($( FromToNativeWasmType::from_native( unsafe { + $x::Native::from_raw(&mut store, RawValue { + u128: { + // TODO: This may not be the fastest way, but JSC doesn't expose a BigInt interface + // so the only thing we can do is parse from the string repr + if $x.is_number(&ctx) { + $x.to_number(&ctx).unwrap() as _ + } else { + $x.to_string(&ctx).unwrap().to_string().parse::().unwrap() + } + } + }) + }) ),* ).into_result() })); match result { @@ -427,27 +430,22 @@ macro_rules! impl_host_function { 0 => {Ok(JSValue::undefined(&ctx))}, 1 => { let ty = Rets::wasm_types()[0]; - let mut arr = result.into_array(&mut store); - let val = Value::from_raw(&mut store, ty, arr.as_mut()[0]); + let mut arr = unsafe { result.into_array(&mut store) }; + let val = unsafe { Value::from_raw(&mut store, ty, arr.as_mut()[0]) }; let value: JSValue = val.as_jsc_value(&store); Ok(value) } _n => { - let mut arr = result.into_array(&mut store); + let mut arr = unsafe { result.into_array(&mut store) }; let result_values = Rets::wasm_types().iter().enumerate().map(|(i, ret_type)| { let raw = arr.as_mut()[i]; - Value::from_raw(&mut store, *ret_type, raw).as_jsc_value(&mut store) + let value = unsafe { Value::from_raw(&mut store, *ret_type, raw) }; + value.as_jsc_value(&mut store) }).collect::>(); Ok(JSObject::new_array(&ctx, &result_values).unwrap().to_jsvalue()) } } }, - #[cfg(feature = "std")] - Ok(Err(err)) => { - let trap = crate::backend::jsc::error::Trap::user(Box::new(err)); - Err(trap.into_jsc_value(&ctx)) - }, - #[cfg(feature = "core")] Ok(Err(err)) => { let trap = crate::backend::jsc::error::Trap::user(Box::new(err)); Err(trap.into_jsc_value(&ctx)) @@ -488,33 +486,44 @@ macro_rules! impl_host_function { { use std::convert::TryInto; - let func: &Func = &*(&() as *const () as *const Func); + let func: &Func = unsafe { &*(&() as *const () as *const Func) }; let global = ctx.get_global_object(); let store_ptr = global.get_property(&ctx, "__store_ptr".to_string()).to_number(&ctx).unwrap(); if store_ptr.is_nan() { panic!("Store pointer is invalid. Received {}", store_ptr as usize) } - let mut store = StoreMut::from_raw(store_ptr as usize as *mut _); + let mut store = unsafe { StoreMut::from_raw(store_ptr as usize as *mut _) }; let handle_index = arguments[0].to_number(&ctx).unwrap() as usize; - let handle: StoreHandle = StoreHandle::from_internal(store.objects_mut().id(), InternalStoreHandle::from_index(handle_index).unwrap()); + let handle: StoreHandle = unsafe { + StoreHandle::from_internal( + store.objects_mut().id(), + InternalStoreHandle::from_index(handle_index).unwrap(), + ) + }; let env = crate::backend::jsc::function::env::FunctionEnv::from_handle(handle).into_mut(&mut store); let result = panic::catch_unwind(AssertUnwindSafe(|| { type JSArray<'a> = &'a [JSValue; count_idents!( $( $x ),* )]; let args_without_store: JSArray = arguments[1..].try_into().unwrap(); let [ $( $x ),* ] = args_without_store; - let mut store = StoreMut::from_raw(store_ptr as usize as *mut _); - func(BackendFunctionEnvMut::Jsc(env).into(), $( FromToNativeWasmType::from_native( $x::Native::from_raw(&mut store, RawValue { u128: { - // TODO: This may not be the fastest way, but JSC doesn't expose a BigInt interface - // so the only thing we can do is parse from the string repr - if $x.is_number(&ctx) { - $x.to_number(&ctx).unwrap() as _ - } - else { - $x.to_string(&ctx).unwrap().to_string().parse::().unwrap() - } - } }) ) ),* ).into_result() + let mut store = unsafe { StoreMut::from_raw(store_ptr as usize as *mut _) }; + func( + BackendFunctionEnvMut::Jsc(env).into(), + $( FromToNativeWasmType::from_native( unsafe { + $x::Native::from_raw(&mut store, RawValue { + u128: { + // TODO: This may not be the fastest way, but JSC doesn't expose a BigInt interface + // so the only thing we can do is parse from the string repr + if $x.is_number(&ctx) { + $x.to_number(&ctx).unwrap() as _ + } else { + $x.to_string(&ctx).unwrap().to_string().parse::().unwrap() + } + } + }) + }) ),* + ).into_result() })); match result { @@ -525,9 +534,9 @@ macro_rules! impl_host_function { // unimplemented!(); let ty = Rets::wasm_types()[0]; - let mut arr = result.into_array(&mut store); + let mut arr = unsafe { result.into_array(&mut store) }; // Value::from_raw(&store, ty, arr[0]) - let val = Value::from_raw(&mut store, ty, arr.as_mut()[0]); + let val = unsafe { Value::from_raw(&mut store, ty, arr.as_mut()[0]) }; let value: JSValue = val.as_jsc_value(&store); Ok(value) // *mut_rets = val.as_raw(&mut store); @@ -536,23 +545,18 @@ macro_rules! impl_host_function { // if !results.is_array(&context) { // panic!("Expected results to be an array.") // } - let mut arr = result.into_array(&mut store); + let mut arr = unsafe { result.into_array(&mut store) }; let result_values = Rets::wasm_types().iter().enumerate().map(|(i, ret_type)| { let raw = arr.as_mut()[i]; - Value::from_raw(&mut store, *ret_type, raw).as_jsc_value(&mut store) + let value = unsafe { Value::from_raw(&mut store, *ret_type, raw) }; + value.as_jsc_value(&mut store) }).collect::>(); Ok(JSObject::new_array(&ctx, &result_values).unwrap().to_jsvalue()) } } }, - #[cfg(feature = "std")] Ok(Err(err)) => { - let trap = crate::jsc::vm::Trap::user(Box::new(err)); - Err(trap.into_jsc_value(&ctx)) - }, - #[cfg(feature = "core")] - Ok(Err(err)) => { - let trap = crate::jsc::vm::Trap::user(Box::new(err)); + let trap = crate::backend::jsc::error::Trap::user(Box::new(err)); Err(trap.into_jsc_value(&ctx)) }, Err(panic) => { diff --git a/lib/api/src/backend/jsc/entities/function/typed.rs b/lib/api/src/backend/jsc/entities/function/typed.rs index 846da4e462..b0d3c3026f 100644 --- a/lib/api/src/backend/jsc/entities/function/typed.rs +++ b/lib/api/src/backend/jsc/entities/function/typed.rs @@ -9,13 +9,13 @@ //! ``` // use std::panic::{catch_unwind, AssertUnwindSafe}; use crate::{ + AsStoreMut, FromToNativeWasmType, NativeWasmType, NativeWasmTypeInto, RuntimeError, + TypedFunction, Value, WasmTypeList, backend::jsc::{ engine::IntoJSC, error::Trap, - utils::convert::{jsc_value_to_wasmer, AsJsc}, + utils::convert::{AsJsc, jsc_value_to_wasmer}, }, - AsStoreMut, FromToNativeWasmType, NativeWasmType, NativeWasmTypeInto, RuntimeError, - TypedFunction, Value, WasmTypeList, }; use rusty_jsc::JSValue; @@ -49,7 +49,7 @@ macro_rules! impl_native_traits { let global = context.get_global_object(); let store_ptr = store_mut.as_raw() as usize; - global.set_property(&context, "__store_ptr".to_string(), JSValue::number(&context, store_ptr as _)).unwrap(); + global.set_property(context, "__store_ptr".to_string(), JSValue::number(context, store_ptr as _)).unwrap(); let results = { let mut r; @@ -60,7 +60,7 @@ macro_rules! impl_native_traits { let context = store_mut.jsc().context(); r = self.func.as_jsc().handle.function .call( - &context, + context, None, ¶ms_list, ); @@ -92,20 +92,20 @@ macro_rules! impl_native_traits { 0 => {}, 1 => unsafe { let ty = Rets::wasm_types()[0]; - let val = jsc_value_to_wasmer(&context, &ty, &results); + let val = jsc_value_to_wasmer(context, &ty, &results); *mut_rets = val.as_raw(&mut store); } _n => { - if !results.is_array(&context) { + if !results.is_array(context) { panic!("Expected results to be an array.") } - let results = results.to_object(&context).unwrap(); + let results = results.to_object(context).unwrap(); for (i, ret_type) in Rets::wasm_types().iter().enumerate() { let store_mut = store.as_store_mut(); let context = store_mut.jsc().context(); - let ret = results.get_property_at_index(&context, i as _).unwrap(); + let ret = results.get_property_at_index(context, i as _).unwrap(); unsafe { - let val = jsc_value_to_wasmer(&context, &ret_type, &ret); + let val = jsc_value_to_wasmer(context, &ret_type, &ret); let slot = mut_rets.add(i); *slot = val.as_raw(&mut store); } @@ -141,9 +141,15 @@ impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15 +); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16 +); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17 +); impl_native_traits!( A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18 ); diff --git a/lib/api/src/backend/jsc/entities/global.rs b/lib/api/src/backend/jsc/entities/global.rs index e0a35269bc..3b55df5694 100644 --- a/lib/api/src/backend/jsc/entities/global.rs +++ b/lib/api/src/backend/jsc/entities/global.rs @@ -2,12 +2,12 @@ use rusty_jsc::{JSObject, JSValue}; use wasmer_types::{GlobalType, Mutability, Type}; use crate::{ + AsStoreMut, AsStoreRef, BackendGlobal, RuntimeError, Value, jsc::{ - utils::convert::{jsc_value_to_wasmer, AsJsc}, + utils::convert::{AsJsc, jsc_value_to_wasmer}, vm::VMGlobal, }, vm::VMExtern, - AsStoreMut, AsStoreRef, BackendGlobal, RuntimeError, Value, }; use super::store::StoreObject; @@ -45,7 +45,7 @@ impl Global { let engine = store_mut.engine(); let context = engine.as_jsc().context(); - let mut descriptor = JSObject::new(&context); + let mut descriptor = JSObject::new(context); let type_str = match val.ty() { Type::I32 => "i32", Type::I64 => "i64", @@ -59,22 +59,22 @@ impl Global { // This is the value type as string, even though is incorrectly called "value" // in the JS API. descriptor.set_property( - &context, + context, "value".to_string(), - JSValue::string(&context, type_str.to_string()), + JSValue::string(context, type_str.to_string()), ); descriptor.set_property( - &context, + context, "mutable".to_string(), - JSValue::boolean(&context, mutability.is_mutable()), + JSValue::boolean(context, mutability.is_mutable()), ); let value: JSValue = val.as_jsc_value(&store_mut); let js_global = engine .as_jsc() .wasm_global_type() - .construct(&context, &[descriptor.to_jsvalue(), value]) - .map_err(|e| >::into(e))?; + .construct(context, &[descriptor.to_jsvalue(), value]) + .map_err(>::into)?; let vm_global = VMGlobal::new(js_global, global_ty); crate::backend::jsc::vm::VMGlobal::list_mut(store.objects_mut().as_jsc_mut()) .push(vm_global.clone()); @@ -92,8 +92,8 @@ impl Global { let value = self .handle .global - .get_property(&context, "value".to_string()); - jsc_value_to_wasmer(&context, &self.handle.ty.ty, &value) + .get_property(context, "value".to_string()); + jsc_value_to_wasmer(context, &self.handle.ty.ty, &value) } pub fn set(&self, store: &mut impl AsStoreMut, val: Value) -> Result<(), RuntimeError> { @@ -103,8 +103,8 @@ impl Global { let context = engine.as_jsc().context(); self.handle .global - .set_property(&context, "value".to_string(), new_value) - .map_err(|e| >::into(e)) + .set_property(context, "value".to_string(), new_value) + .map_err(>::into) } pub(crate) fn from_vm_extern( diff --git a/lib/api/src/backend/jsc/entities/instance.rs b/lib/api/src/backend/jsc/entities/instance.rs index f7074dcf74..7e46e9a798 100644 --- a/lib/api/src/backend/jsc/entities/instance.rs +++ b/lib/api/src/backend/jsc/entities/instance.rs @@ -1,6 +1,6 @@ use crate::{ - jsc::{utils::convert::AsJsc, vm::VMInstance}, AsStoreMut, BackendInstance, Exports, Extern, Imports, InstantiationError, Module, + jsc::{utils::convert::AsJsc, vm::VMInstance}, }; use super::engine::IntoJSC; @@ -15,6 +15,7 @@ pub struct Instance { // unsafe impl Send for Instance {} impl Instance { + #[allow(clippy::result_large_err)] pub(crate) fn new( mut store: &mut impl AsStoreMut, module: &Module, @@ -23,11 +24,12 @@ impl Instance { let instance = module .as_jsc() .instantiate(&mut store, imports) - .map_err(|e| InstantiationError::Start(e))?; + .map_err(InstantiationError::Start)?; - Self::from_module_and_instance(store, &module, instance) + Self::from_module_and_instance(store, module, instance) } + #[allow(clippy::result_large_err)] pub(crate) fn new_by_index( store: &mut impl AsStoreMut, module: &Module, @@ -40,6 +42,7 @@ impl Instance { Self::new(store, module, &imports) } + #[allow(clippy::result_large_err)] pub(crate) fn from_module_and_instance( mut store: &mut impl AsStoreMut, module: &Module, @@ -49,8 +52,8 @@ impl Instance { let context = engine.jsc().context(); let mut instance_exports = instance - .get_property(&context, "exports".to_string()) - .to_object(&context) + .get_property(context, "exports".to_string()) + .to_object(context) .unwrap(); let exports_ty = module.exports().collect::>(); @@ -63,7 +66,7 @@ impl Instance { let context = store.jsc().context(); let extern_type = export_type.ty(); // Annotation is here to prevent spurious IDE warnings. - let js_export = instance_exports.get_property(&context, name.to_string()); + let js_export = instance_exports.get_property(context, name.to_string()); let extern_ = Extern::from_jsc_value(&mut store, extern_type, &js_export).unwrap(); Ok((name.to_string(), extern_)) }) diff --git a/lib/api/src/backend/jsc/entities/memory/buffer.rs b/lib/api/src/backend/jsc/entities/memory/buffer.rs index ef0846974c..ef47d23ab6 100644 --- a/lib/api/src/backend/jsc/entities/memory/buffer.rs +++ b/lib/api/src/backend/jsc/entities/memory/buffer.rs @@ -89,51 +89,59 @@ impl<'a> MemoryBuffer<'a> { unsafe fn volatile_memcpy_read(mut src: *const u8, mut dst: *mut u8, mut len: usize) { #[inline] unsafe fn copy_one(src: &mut *const u8, dst: &mut *mut u8, len: &mut usize) { - #[repr(packed)] + #[repr(C, packed)] struct Unaligned(T); - let val = (*src as *const Unaligned).read_volatile(); - (*dst as *mut Unaligned).write(val); - *src = src.add(std::mem::size_of::()); - *dst = dst.add(std::mem::size_of::()); - *len -= std::mem::size_of::(); + unsafe { + let val = (*src as *const Unaligned).read_volatile(); + (*dst as *mut Unaligned).write(val); + *src = src.add(std::mem::size_of::()); + *dst = dst.add(std::mem::size_of::()); + *len -= std::mem::size_of::(); + } } - while len >= 8 { - copy_one::(&mut src, &mut dst, &mut len); - } - if len >= 4 { - copy_one::(&mut src, &mut dst, &mut len); - } - if len >= 2 { - copy_one::(&mut src, &mut dst, &mut len); - } - if len >= 1 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { + while len >= 8 { + copy_one::(&mut src, &mut dst, &mut len); + } + if len >= 4 { + copy_one::(&mut src, &mut dst, &mut len); + } + if len >= 2 { + copy_one::(&mut src, &mut dst, &mut len); + } + if len >= 1 { + copy_one::(&mut src, &mut dst, &mut len); + } } } #[inline] unsafe fn volatile_memcpy_write(mut src: *const u8, mut dst: *mut u8, mut len: usize) { #[inline] unsafe fn copy_one(src: &mut *const u8, dst: &mut *mut u8, len: &mut usize) { - #[repr(packed)] + #[repr(C, packed)] struct Unaligned(T); - let val = (*src as *const Unaligned).read(); - (*dst as *mut Unaligned).write_volatile(val); - *src = src.add(std::mem::size_of::()); - *dst = dst.add(std::mem::size_of::()); - *len -= std::mem::size_of::(); + unsafe { + let val = (*src as *const Unaligned).read(); + (*dst as *mut Unaligned).write_volatile(val); + *src = src.add(std::mem::size_of::()); + *dst = dst.add(std::mem::size_of::()); + *len -= std::mem::size_of::(); + } } - while len >= 8 { - copy_one::(&mut src, &mut dst, &mut len); - } - if len >= 4 { - copy_one::(&mut src, &mut dst, &mut len); - } - if len >= 2 { - copy_one::(&mut src, &mut dst, &mut len); - } - if len >= 1 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { + while len >= 8 { + copy_one::(&mut src, &mut dst, &mut len); + } + if len >= 4 { + copy_one::(&mut src, &mut dst, &mut len); + } + if len >= 2 { + copy_one::(&mut src, &mut dst, &mut len); + } + if len >= 1 { + copy_one::(&mut src, &mut dst, &mut len); + } } } diff --git a/lib/api/src/backend/jsc/entities/memory/mod.rs b/lib/api/src/backend/jsc/entities/memory/mod.rs index 1ef1b4249b..04b974b667 100644 --- a/lib/api/src/backend/jsc/entities/memory/mod.rs +++ b/lib/api/src/backend/jsc/entities/memory/mod.rs @@ -4,7 +4,7 @@ pub(crate) use view::*; pub(crate) mod buffer; pub(crate) use buffer::*; -use crate::{jsc::vm::VMMemory, vm::VMExtern, AsStoreMut, AsStoreRef, BackendMemory}; +use crate::{AsStoreMut, AsStoreRef, BackendMemory, jsc::vm::VMMemory, vm::VMExtern}; use rusty_jsc::{JSObject, JSValue}; use wasmer_types::{MemoryError, MemoryType, Pages}; @@ -42,30 +42,30 @@ impl Memory { let engine = store_ref.engine(); let context = engine.as_jsc().context(); - let mut descriptor = JSObject::new(&context); + let mut descriptor = JSObject::new(context); descriptor.set_property( - &context, + context, "initial".to_string(), - JSValue::number(&context, ty.minimum.0.into()), + JSValue::number(context, ty.minimum.0.into()), ); if let Some(max) = ty.maximum { descriptor.set_property( - &context, + context, "maximum".to_string(), - JSValue::number(&context, max.0.into()), + JSValue::number(context, max.0.into()), ); } descriptor.set_property( - &context, + context, "shared".to_string(), - JSValue::boolean(&context, ty.shared), + JSValue::boolean(context, ty.shared), ); engine .as_jsc() .wasm_memory_type() - .construct(&context, &[descriptor.to_jsvalue()]) - .map_err(|e| MemoryError::Generic(format!("{:?}", e))) + .construct(context, &[descriptor.to_jsvalue()]) + .map_err(|e| MemoryError::Generic(format!("{e:?}"))) } pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self { @@ -121,15 +121,15 @@ impl Memory { let func = self .handle .memory - .get_property(&context, "grow".to_string()) - .to_object(&context) + .get_property(context, "grow".to_string()) + .to_object(context) .unwrap(); match func.call( - &context, + context, Some(&self.handle.memory), - &[JSValue::number(&context, pages.0 as _)], + &[JSValue::number(context, pages.0 as _)], ) { - Ok(val) => Ok(Pages(val.to_number(&context).unwrap() as _)), + Ok(val) => Ok(Pages(val.to_number(context).unwrap() as _)), Err(e) => { let old_pages = pages; Err(MemoryError::CouldNotGrow { diff --git a/lib/api/src/backend/jsc/entities/memory/view.rs b/lib/api/src/backend/jsc/entities/memory/view.rs index cfdae79c29..686ebc7005 100644 --- a/lib/api/src/backend/jsc/entities/memory/view.rs +++ b/lib/api/src/backend/jsc/entities/memory/view.rs @@ -28,12 +28,12 @@ impl<'a> MemoryView<'a> { let context = engine.as_jsc().context(); let buffer = memory - .get_property(&context, "buffer".to_string()) - .to_object(&context) + .get_property(context, "buffer".to_string()) + .to_object(context) .unwrap(); - let typed_buffer = JSObject::create_typed_array_from_buffer(&context, buffer).unwrap(); + let typed_buffer = JSObject::create_typed_array_from_buffer(context, buffer).unwrap(); - let mut buffer_data = typed_buffer.get_typed_array_buffer(&context).unwrap(); + let mut buffer_data = typed_buffer.get_typed_array_buffer(context).unwrap(); // println!("BUFFER DATA {}", buffer_data.to_string(&context)); // let definition = memory.handle.get(store.as_store_ref().objects()).vmmemory(); @@ -71,7 +71,7 @@ impl<'a> MemoryView<'a> { /// function that writes to the memory or by resizing the memory. #[doc(hidden)] pub unsafe fn data_unchecked(&self) -> &[u8] { - self.data_unchecked_mut() + unsafe { std::slice::from_raw_parts(self.buffer.base, self.buffer.len) } } /// Retrieve a mutable slice of the memory contents. @@ -86,7 +86,7 @@ impl<'a> MemoryView<'a> { #[allow(clippy::mut_from_ref)] #[doc(hidden)] pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] { - std::slice::from_raw_parts_mut(self.buffer.base, self.buffer.len) + unsafe { std::slice::from_raw_parts_mut(self.buffer.base, self.buffer.len) } } /// Returns the size (in [`Pages`]) of the `Memory`. diff --git a/lib/api/src/backend/jsc/entities/module.rs b/lib/api/src/backend/jsc/entities/module.rs index 8cdc47be67..4d7e2f1136 100644 --- a/lib/api/src/backend/jsc/entities/module.rs +++ b/lib/api/src/backend/jsc/entities/module.rs @@ -9,9 +9,9 @@ use wasmer_types::{ }; use crate::{ - jsc::{utils::convert::AsJsc, vm::VMInstance}, AsEngineRef, AsStoreMut, AsStoreRef, BackendModule, Imports, InstantiationError, IntoBytes, RuntimeError, + jsc::{utils::convert::AsJsc, vm::VMInstance}, }; use super::engine::IntoJSC; @@ -51,14 +51,14 @@ impl Module { let engine = engine.as_engine_ref(); let jsc = engine.jsc(); let context = jsc.context(); - let bytes = JSObject::create_typed_array_with_bytes(&context, &mut binary).unwrap(); + let bytes = JSObject::create_typed_array_with_bytes(context, &mut binary).unwrap(); let module_type = jsc.wasm_module_type(); let global_wasm = jsc.global_wasm(); let module = module_type - .construct(&context, &[bytes.to_jsvalue()]) - .map_err(|e| CompileError::Validate(format!("{}", e.to_string(&context).unwrap())))?; + .construct(context, &[bytes.to_jsvalue()]) + .map_err(|e| CompileError::Validate(format!("{}", e.to_string(context).unwrap())))?; - Ok(Self::from_js_module(module, binary)) + Ok(unsafe { Self::from_js_module(module, binary) }) } /// Creates a new WebAssembly module skipping any kind of validation from a javascript module @@ -84,22 +84,24 @@ impl Module { let jsc = engine.jsc(); let context = jsc.context(); let mut binary = binary.to_vec(); - let bytes = JSObject::create_typed_array_with_bytes(&context, &mut binary).unwrap(); + let bytes = JSObject::create_typed_array_with_bytes(context, &mut binary).unwrap(); let global_wasm = jsc.global_wasm(); let validate_type = jsc.wasm_validate_type(); - match validate_type.call(&context, Some(&global_wasm), &[bytes.to_jsvalue()]) { + match validate_type.call(context, Some(global_wasm), &[bytes.to_jsvalue()]) { Ok(val) => { - if val.to_bool(&context) { + if val.to_bool(context) { Ok(()) } else { - Err(CompileError::Validate(format!("Not a valid wasm binary"))) + Err(CompileError::Validate( + "Not a valid wasm binary".to_string(), + )) } } Err(e) => Err(CompileError::Validate(format!( "Error while validating: {}", - e.to_string(&context).unwrap() + e.to_string(context).unwrap() ))), } } @@ -114,38 +116,47 @@ impl Module { .into_iter() .any(|(_, import)| !import.is_from_store(store)) { - return Err(RuntimeError::user(Box::new( - InstantiationError::DifferentStores, - ))); + #[cfg(feature = "std")] + { + return Err(RuntimeError::user(Box::new( + InstantiationError::DifferentStores, + ))); + } + #[cfg(not(feature = "std"))] + { + return Err(RuntimeError::new( + "cannot mix imports from different stores", + )); + } } let store = store.as_store_mut(); let context = store.jsc().context(); - let mut imports_object = JSObject::new(&context); + let mut imports_object = JSObject::new(context); for import_type in self.imports() { let resolved_import = imports.get_export(import_type.module(), import_type.name()); if let Some(import) = resolved_import { - let val = imports_object.get_property(&context, import_type.module().to_string()); - if !val.is_undefined(&context) { + let val = imports_object.get_property(context, import_type.module().to_string()); + if !val.is_undefined(context) { // If the namespace is already set - let mut obj_val = val.to_object(&context).unwrap(); + let mut obj_val = val.to_object(context).unwrap(); obj_val.set_property( - &context, + context, import_type.name().to_string(), import.as_jsc_value(&store.as_store_ref()), ); } else { // If the namespace doesn't exist - let mut import_namespace = JSObject::new(&context); + let mut import_namespace = JSObject::new(context); import_namespace.set_property( - &context, + context, import_type.name().to_string(), import.as_jsc_value(&store.as_store_ref()), ); imports_object .set_property( - &context, + context, import_type.module().to_string(), import_namespace.to_jsvalue(), ) @@ -163,11 +174,12 @@ impl Module { } let instance_type = store.jsc().wasm_instance_type(); - let instance = instance_type.construct( - &context, - &[self.module.to_jsvalue(), imports_object.to_jsvalue()], - ); - Ok(instance.map_err(|e: JSValue| -> RuntimeError { e.into() })?) + instance_type + .construct( + context, + &[self.module.to_jsvalue(), imports_object.to_jsvalue()], + ) + .map_err(|e: JSValue| -> RuntimeError { e.into() }) } pub fn name(&self) -> Option<&str> { @@ -175,24 +187,23 @@ impl Module { } pub fn serialize(&self) -> Result { - return self.raw_bytes.clone().ok_or(SerializeError::Generic( + self.raw_bytes.clone().ok_or(SerializeError::Generic( "Not able to serialize module".to_string(), - )); + )) } pub unsafe fn deserialize_unchecked( engine: &impl AsEngineRef, bytes: impl IntoBytes, ) -> Result { - Self::deserialize(engine, bytes) + unsafe { Self::deserialize(engine, bytes) } } pub unsafe fn deserialize( engine: &impl AsEngineRef, bytes: impl IntoBytes, ) -> Result { - return Self::from_binary(engine, &bytes.into_bytes()) - .map_err(|e| DeserializeError::Compiler(e)); + Self::from_binary(engine, &bytes.into_bytes()).map_err(DeserializeError::Compiler) } pub unsafe fn deserialize_from_file_unchecked( @@ -200,7 +211,7 @@ impl Module { path: impl AsRef, ) -> Result { let bytes = std::fs::read(path.as_ref())?; - Self::deserialize_unchecked(engine, bytes) + unsafe { Self::deserialize_unchecked(engine, bytes) } } pub unsafe fn deserialize_from_file( @@ -208,7 +219,7 @@ impl Module { path: impl AsRef, ) -> Result { let bytes = std::fs::read(path.as_ref())?; - Self::deserialize(engine, bytes) + unsafe { Self::deserialize(engine, bytes) } } pub fn set_name(&mut self, name: &str) -> bool { diff --git a/lib/api/src/backend/jsc/entities/store/obj.rs b/lib/api/src/backend/jsc/entities/store/obj.rs index e15b1cde40..e840a257a2 100644 --- a/lib/api/src/backend/jsc/entities/store/obj.rs +++ b/lib/api/src/backend/jsc/entities/store/obj.rs @@ -80,7 +80,7 @@ impl StoreObjects { } /// Return an immutable iterator over all globals - pub fn iter_globals(&self) -> core::slice::Iter { + pub fn iter_globals<'a>(&'a self) -> core::slice::Iter<'a, VMGlobal> { self.globals.iter() } diff --git a/lib/api/src/backend/jsc/entities/table.rs b/lib/api/src/backend/jsc/entities/table.rs index a5a2873e69..7f3d71f2bb 100644 --- a/lib/api/src/backend/jsc/entities/table.rs +++ b/lib/api/src/backend/jsc/entities/table.rs @@ -2,9 +2,9 @@ use rusty_jsc::{JSObject, JSValue}; use wasmer_types::TableType; use crate::{ + AsStoreMut, AsStoreRef, BackendTable, RuntimeError, Value, jsc::vm::{VMExternTable, VMTable}, vm::VMExtern, - AsStoreMut, AsStoreRef, BackendTable, RuntimeError, Value, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -35,30 +35,30 @@ impl Table { let engine = store_mut.engine(); let context = engine.as_jsc().context(); - let mut descriptor = JSObject::new(&context); + let mut descriptor = JSObject::new(context); descriptor.set_property( - &context, + context, "initial".to_string(), - JSValue::number(&context, ty.minimum.into()), + JSValue::number(context, ty.minimum.into()), ); if let Some(max) = ty.maximum { descriptor.set_property( - &context, + context, "maximum".to_string(), - JSValue::number(&context, max.into()), + JSValue::number(context, max.into()), ); } descriptor.set_property( - &context, + context, "element".to_string(), - JSValue::string(&context, "anyfunc".to_string()), + JSValue::string(context, "anyfunc".to_string()), ); let js_table = engine .as_jsc() .wasm_table_type() - .construct(&context, &[descriptor.to_jsvalue()]) - .map_err(|e| >::into(e))?; + .construct(context, &[descriptor.to_jsvalue()]) + .map_err(>::into)?; let vm_table = VMTable::new(js_table, ty); Ok(Self { handle: vm_table }) } @@ -94,8 +94,8 @@ impl Table { let context = engine.as_jsc().context(); self.handle .table - .get_property(&context, "length".to_string()) - .to_number(&context) + .get_property(context, "length".to_string()) + .to_number(context) .unwrap() as _ } @@ -111,15 +111,15 @@ impl Table { let func = self .handle .table - .get_property(&context, "grow".to_string()) - .to_object(&context) + .get_property(context, "grow".to_string()) + .to_object(context) .unwrap(); match func.call( - &context, + context, Some(&self.handle.table), - &[JSValue::number(&context, delta as _)], + &[JSValue::number(context, delta as _)], ) { - Ok(val) => Ok(val.to_number(&context).unwrap() as _), + Ok(val) => Ok(val.to_number(context).unwrap() as _), Err(e) => Err(>::into(e)), } } @@ -187,7 +187,7 @@ impl crate::BackendTable { /// Convert a reference to [`self`] into a reference [`crate::backend::jsc::table::Table`]. pub fn as_jsc(&self) -> &crate::backend::jsc::table::Table { match self { - Self::Jsc(ref s) => s, + Self::Jsc(s) => s, _ => panic!("Not a `jsc` table!"), } } @@ -195,7 +195,7 @@ impl crate::BackendTable { /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::jsc::table::Table`]. pub fn as_jsc_mut(&mut self) -> &mut crate::backend::jsc::table::Table { match self { - Self::Jsc(ref mut s) => s, + Self::Jsc(s) => s, _ => panic!("Not a `jsc` table!"), } } diff --git a/lib/api/src/backend/jsc/entities/tag.rs b/lib/api/src/backend/jsc/entities/tag.rs index c77261b6c3..55def4d396 100644 --- a/lib/api/src/backend/jsc/entities/tag.rs +++ b/lib/api/src/backend/jsc/entities/tag.rs @@ -1,9 +1,9 @@ use wasmer_types::{TagType, Type}; use crate::{ + AsStoreMut, AsStoreRef, jsc::vm::VMTag, vm::{VMExtern, VMExternTag}, - AsStoreMut, AsStoreRef, }; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/lib/api/src/backend/jsc/error.rs b/lib/api/src/backend/jsc/error.rs index 65b79012ab..02feb2cf89 100644 --- a/lib/api/src/backend/jsc/error.rs +++ b/lib/api/src/backend/jsc/error.rs @@ -1,13 +1,13 @@ use rusty_jsc::{JSContext, JSObject, JSValue}; -use crate::RuntimeError; +use crate::{RuntimeError, jsc::vm::VMExceptionRef}; use std::error::Error; use std::fmt; #[derive(Debug)] enum InnerTrap { User(Box), - JSC(JSValue), + Jsc(JSValue), } /// A struct representing a Trap @@ -52,23 +52,33 @@ impl Trap { } } + /// Returns true if the `Trap` is an exception + pub fn is_exception(&self) -> bool { + false + } + + /// If the `Trap` is an uncaught exception, returns it. + pub fn to_exception_ref(&self) -> Option { + None + } + pub(crate) fn into_jsc_value(self, ctx: &JSContext) -> JSValue { match self.inner { InnerTrap::User(err) => { let obj = JSObject::new(ctx); let err_ptr = Box::leak(Box::new(err)); - let wasmer_error_ptr = JSValue::number(&ctx, err_ptr as *mut _ as usize as _); - obj.set_property(&ctx, "wasmer_error_ptr".to_string(), wasmer_error_ptr) + let wasmer_error_ptr = JSValue::number(ctx, err_ptr as *mut _ as usize as _); + obj.set_property(ctx, "wasmer_error_ptr".to_string(), wasmer_error_ptr) .unwrap(); obj.to_jsvalue() } - InnerTrap::JSC(value) => value, + InnerTrap::Jsc(value) => value, } } pub(crate) fn from_jsc_value(ctx: &JSContext, val: JSValue) -> Self { let obj_val = val.to_object(ctx).unwrap(); - let wasmer_error_ptr = obj_val.get_property(&ctx, "wasmer_error_ptr".to_string()); + let wasmer_error_ptr = obj_val.get_property(ctx, "wasmer_error_ptr".to_string()); if wasmer_error_ptr.is_number(ctx) { let err_ptr = wasmer_error_ptr.to_number(ctx).unwrap() as usize as *mut Box; @@ -76,7 +86,7 @@ impl Trap { return Self::user(*err); } Self { - inner: InnerTrap::JSC(val), + inner: InnerTrap::Jsc(val), } } } @@ -93,8 +103,8 @@ impl std::error::Error for Trap { impl fmt::Display for Trap { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.inner { - InnerTrap::User(e) => write!(f, "user: {}", e), - InnerTrap::JSC(value) => write!(f, "jsc: obscure"), + InnerTrap::User(e) => write!(f, "user: {e}"), + InnerTrap::Jsc(_value) => write!(f, "jsc: obscure"), } } } @@ -102,7 +112,7 @@ impl fmt::Display for Trap { impl From for RuntimeError { fn from(original: JSValue) -> Self { let trap = Trap { - inner: InnerTrap::JSC(original), + inner: InnerTrap::Jsc(original), }; trap.into() // unimplemented!("TODO: implement Trap::from(JSValue) for RuntimeError"); @@ -122,6 +132,6 @@ impl From for RuntimeError { return trap.downcast::().unwrap(); } - RuntimeError::new_from_source(crate::BackendTrap::Jsc(trap), vec![], None) + Self::new_from_source(crate::BackendTrap::Jsc(trap), vec![], None) } } diff --git a/lib/api/src/backend/jsc/utils/convert.rs b/lib/api/src/backend/jsc/utils/convert.rs index 3128134eab..1b545b2f04 100644 --- a/lib/api/src/backend/jsc/utils/convert.rs +++ b/lib/api/src/backend/jsc/utils/convert.rs @@ -1,7 +1,7 @@ use rusty_jsc::{JSContext, JSValue}; use wasmer_types::{ExternType, Type}; -use crate::{jsc::engine::IntoJSC, AsStoreMut, AsStoreRef, Extern, Function, Value}; +use crate::{AsStoreMut, AsStoreRef, Extern, Function, Value, jsc::engine::IntoJSC}; /// Convert the given type to a [`JsValue`]. pub trait AsJsc: Sized { @@ -20,13 +20,13 @@ pub trait AsJsc: Sized { #[inline] pub fn jsc_value_to_wasmer(context: &JSContext, ty: &Type, js_val: &JSValue) -> Value { match ty { - Type::I32 => Value::I32(js_val.to_number(&context).unwrap() as _), + Type::I32 => Value::I32(js_val.to_number(context).unwrap() as _), Type::I64 => { - let number = if js_val.is_number(&context) { - js_val.to_number(&context).unwrap() as _ + let number = if js_val.is_number(context) { + js_val.to_number(context).unwrap() as _ } else { js_val - .to_string(&context) + .to_string(context) .unwrap() .to_string() .parse() @@ -34,14 +34,14 @@ pub fn jsc_value_to_wasmer(context: &JSContext, ty: &Type, js_val: &JSValue) -> }; Value::I64(number) } - Type::F32 => Value::F32(js_val.to_number(&context).unwrap() as _), - Type::F64 => Value::F64(js_val.to_number(&context).unwrap()), + Type::F32 => Value::F32(js_val.to_number(context).unwrap() as _), + Type::F64 => Value::F64(js_val.to_number(context).unwrap()), Type::V128 => { - let number = if js_val.is_number(&context) { - js_val.to_number(&context).unwrap() as _ + let number = if js_val.is_number(context) { + js_val.to_number(context).unwrap() as _ } else { js_val - .to_string(&context) + .to_string(context) .unwrap() .to_string() .parse() @@ -63,17 +63,17 @@ impl AsJsc for Value { let engine = store.as_store_ref(); let context = engine.jsc().context(); match self { - Self::I32(i) => JSValue::number(&context, *i as _), + Self::I32(i) => JSValue::number(context, *i as _), // JavascriptCore will fail with: // new WebAssembly.Global({value: "i64", mutable: false}, 3); // But will succeed with // new WebAssembly.Global({value: "i64", mutable: false}, "3"); - Self::I64(i) => JSValue::string(&context, (*i).to_string()), - Self::F32(f) => JSValue::number(&context, *f as _), - Self::F64(f) => JSValue::number(&context, *f), - Self::V128(v) => JSValue::number(&context, *v as _), + Self::I64(i) => JSValue::string(context, (*i).to_string()), + Self::F32(f) => JSValue::number(context, *f as _), + Self::F64(f) => JSValue::number(context, *f), + Self::V128(v) => JSValue::number(context, *v as _), Self::FuncRef(Some(func)) => func.as_jsc().handle.function.clone().to_jsvalue(), - Self::FuncRef(None) => JSValue::null(&context), + Self::FuncRef(None) => JSValue::null(context), Self::ExternRef(_) => { unimplemented!("ExternRefs are not yet supported in the JSC Function API",) } @@ -119,7 +119,7 @@ impl AsJsc for Extern { let context = engine.jsc().context(); match extern_type { ExternType::Function(function_type) => { - let obj_val = val.to_object(&context).unwrap(); + let obj_val = val.to_object(context).unwrap(); Ok(Self::Function(Function::from_vm_extern( store, crate::vm::VMExternFunction::Jsc( @@ -131,32 +131,32 @@ impl AsJsc for Extern { ))) } ExternType::Global(global_type) => { - let obj_val = val.to_object(&context).unwrap(); + let obj_val = val.to_object(context).unwrap(); Ok(Self::Global(crate::Global::from_vm_extern( store, crate::vm::VMExternGlobal::Jsc(crate::backend::jsc::vm::VMExternGlobal::new( obj_val, - global_type.clone(), + *global_type, )), ))) } ExternType::Memory(memory_type) => { - let obj_val = val.to_object(&context).unwrap(); + let obj_val = val.to_object(context).unwrap(); Ok(Self::Memory(crate::Memory::from_vm_extern( store, crate::vm::VMExternMemory::Jsc(crate::backend::jsc::vm::VMExternMemory::new( obj_val, - memory_type.clone(), + *memory_type, )), ))) } ExternType::Table(table_type) => { - let obj_val = val.to_object(&context).unwrap(); + let obj_val = val.to_object(context).unwrap(); Ok(Self::Table(crate::Table::from_vm_extern( store, crate::vm::VMExternTable::Jsc(crate::backend::jsc::vm::VMExternTable::new( obj_val, - table_type.clone(), + *table_type, )), ))) } diff --git a/lib/api/src/backend/jsc/vm/memory.rs b/lib/api/src/backend/jsc/vm/memory.rs index a75bfae4f2..60460a568a 100644 --- a/lib/api/src/backend/jsc/vm/memory.rs +++ b/lib/api/src/backend/jsc/vm/memory.rs @@ -34,12 +34,12 @@ impl VMMemory { } /// Attempts to clone this memory (if its clonable) - pub(crate) fn try_clone(&self) -> Result { + pub(crate) fn try_clone(&self) -> Result { Ok(self.clone()) } /// Copies this memory to a new memory - pub fn copy(&self, store: &impl AsStoreRef) -> Result { + pub fn copy(&self, store: &impl AsStoreRef) -> Result { let new_memory = crate::jsc::memory::Memory::js_memory_from_type(&store, &self.ty)?; trace!("memory copy started"); @@ -50,14 +50,14 @@ impl VMMemory { let dst_size = dst.data_size() as usize; src.copy_to_memory(amount as u64, &dst).map_err(|err| { - wasmer_types::MemoryError::Generic(format!("failed to copy the memory - {}", err)) + wasmer_types::MemoryError::Generic(format!("failed to copy the memory - {err}")) })?; trace!("memory copy finished (size={})", dst.size().bytes().0); Ok(Self { memory: new_memory, - ty: self.ty.clone(), + ty: self.ty, }) } } diff --git a/lib/api/src/backend/sys/async_runtime.rs b/lib/api/src/backend/sys/async_runtime.rs new file mode 100644 index 0000000000..0ebaf40684 --- /dev/null +++ b/lib/api/src/backend/sys/async_runtime.rs @@ -0,0 +1,326 @@ +use std::{ + cell::RefCell, + collections::HashMap, + future::Future, + marker::PhantomData, + pin::Pin, + ptr, + rc::Rc, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, +}; + +use corosensei::{Coroutine, CoroutineResult, Yielder}; + +use super::entities::function::Function as SysFunction; +use crate::{ + AsStoreMut, AsStoreRef, ForcedStoreInstallGuard, LocalRwLockWriteGuard, RuntimeError, Store, + StoreAsync, StoreContext, StoreInner, StoreMut, StoreRef, Value, +}; +use wasmer_types::StoreId; + +type HostFuture = Pin, RuntimeError>> + 'static>>; + +pub(crate) fn call_function_async( + function: SysFunction, + store: StoreAsync, + params: Vec, +) -> AsyncCallFuture { + AsyncCallFuture::new(function, store, params) +} + +struct AsyncYield(HostFuture); + +enum AsyncResume { + Start, + HostFutureReady(Result, RuntimeError>), +} + +#[allow(clippy::type_complexity)] +pub(crate) struct AsyncCallFuture { + coroutine: Option, RuntimeError>>>, + pending_store_install: Option>>>, + pending_future: Option, + next_resume: Option, + result: Option, RuntimeError>>, + + // Store handle we can use to lock the store down + store: StoreAsync, +} + +// We can't use any of the existing AsStoreMut types here, since we keep +// changing the store context underneath us while the coroutine yields. +// To work around it, we use this dummy struct, which just grabs the store +// from the store context. Since we always have a store context installed +// when resuming the coroutine, this is safe in that it can access the store +// through the store context. HOWEVER, references returned from this struct +// CAN NOT BE HELD ACROSS A YIELD POINT. We don't do this anywhere in the +// `Function::call code. +struct AsyncCallStoreMut { + store_id: StoreId, +} + +impl AsStoreRef for AsyncCallStoreMut { + fn as_store_ref(&self) -> StoreRef<'_> { + // Safety: This is only used with Function::call, which doesn't store + // the returned reference anywhere, including when calling into WASM + // code. + unsafe { + StoreRef { + inner: StoreContext::get_current_transient(self.store_id) + .as_ref() + .unwrap(), + } + } + } +} + +impl AsStoreMut for AsyncCallStoreMut { + fn as_store_mut(&mut self) -> StoreMut<'_> { + // Safety: This is only used with Function::call, which doesn't store + // the returned reference anywhere, including when calling into WASM + // code. + unsafe { + StoreMut { + inner: StoreContext::get_current_transient(self.store_id) + .as_mut() + .unwrap(), + } + } + } + + fn objects_mut(&mut self) -> &mut crate::StoreObjects { + // Safety: This is only used with Function::call, which doesn't store + // the returned reference anywhere, including when calling into WASM + // code. + unsafe { + &mut StoreContext::get_current_transient(self.store_id) + .as_mut() + .unwrap() + .objects + } + } +} + +impl AsyncCallFuture { + pub(crate) fn new(function: SysFunction, store: StoreAsync, params: Vec) -> Self { + let store_id = store.id; + let coroutine = + Coroutine::new(move |yielder: &Yielder, resume| { + assert!(matches!(resume, AsyncResume::Start)); + + let ctx_state = CoroutineContext::new(yielder); + ctx_state.enter(); + let result = { + let mut store_mut = AsyncCallStoreMut { store_id }; + function.call(&mut store_mut, ¶ms) + }; + ctx_state.leave(); + result + }); + + Self { + coroutine: Some(coroutine), + pending_store_install: None, + pending_future: None, + next_resume: Some(AsyncResume::Start), + result: None, + store, + } + } +} + +impl Future for AsyncCallFuture { + type Output = Result, RuntimeError>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + loop { + if let Some(future) = self.pending_future.as_mut() { + match future.as_mut().poll(cx) { + Poll::Ready(result) => { + self.pending_future = None; + self.next_resume = Some(AsyncResume::HostFutureReady(result)); + } + Poll::Pending => return Poll::Pending, + } + } + + // If we're ready, return early + if self.coroutine.is_none() { + return Poll::Ready(self.result.take().expect("polled after completion")); + } + + // Start a store installation if not in progress already + if self.pending_store_install.is_none() { + self.pending_store_install = Some(Box::pin(install_store_context(StoreAsync { + id: self.store.id, + inner: self.store.inner.clone(), + }))); + } + + // Acquiring a store lock should be the last step before resuming + // the coroutine, to minimize the time we hold the lock. + let store_context_guard = match self + .pending_store_install + .as_mut() + .unwrap() + .as_mut() + .poll(cx) + { + Poll::Ready(guard) => { + self.pending_store_install = None; + guard + } + Poll::Pending => return Poll::Pending, + }; + + let resume_arg = self.next_resume.take().expect("no resume arg available"); + let coroutine = self.coroutine.as_mut().unwrap(); + match coroutine.resume(resume_arg) { + CoroutineResult::Yield(AsyncYield(fut)) => { + self.pending_future = Some(fut); + } + CoroutineResult::Return(result) => { + self.coroutine = None; + self.result = Some(result); + } + } + + // Uninstall the store context to unlock the store after the coroutine + // yields or returns. + drop(store_context_guard); + } + } +} + +async fn install_store_context(store: StoreAsync) -> ForcedStoreInstallGuard { + match unsafe { crate::StoreContext::try_get_current_async(store.id) } { + crate::GetStoreAsyncGuardResult::NotInstalled => { + // We always need to acquire a new write lock on the store. + let store_guard = store.inner.write().await; + unsafe { crate::StoreContext::install_async(store_guard) } + } + _ => { + // If we're already in a store context, it is unsafe to reuse + // the existing store ref since it'll also be accessible from + // the imported function that tried to poll us, which is a + // double mutable borrow. + // Note to people who discover this code: this *would* be safe + // if we had a separate variation of call_async that just + // used the existing coroutine context instead of spawning a + // new coroutine. However, the current call_async always spawns + // a new coroutine, so we can't allow this; every coroutine + // needs to own its write lock on the store to make sure there + // are no overlapping mutable borrows. If this is something + // you're interested in, feel free to open a GitHub issue outlining + // your use-case. + panic!( + "Function::call_async futures cannot be polled recursively \ + from within another imported function. If you need to await \ + a recursive call_async, consider spawning the future into \ + your async runtime and awaiting the resulting task; \ + e.g. tokio::task::spawn(func.call_async(...)).await" + ); + } + } +} + +pub enum AsyncRuntimeError { + YieldOutsideAsyncContext, + RuntimeError(RuntimeError), +} + +pub(crate) fn block_on_host_future(future: Fut) -> Result, AsyncRuntimeError> +where + Fut: Future, RuntimeError>> + 'static, +{ + CURRENT_CONTEXT.with(|cell| { + match CoroutineContext::get_current() { + None => { + // If there is no async context or we haven't entered it, + // we can still directly run a future that doesn't block + // inline. + run_immediate(future) + } + Some(context) => unsafe { context.as_ref().expect("valid context pointer") } + .block_on_future(Box::pin(future)) + .map_err(AsyncRuntimeError::RuntimeError), + } + }) +} + +thread_local! { + static CURRENT_CONTEXT: RefCell> = const { RefCell::new(Vec::new()) }; +} + +struct CoroutineContext { + yielder: *const Yielder, +} + +impl CoroutineContext { + fn new(yielder: &Yielder) -> Self { + Self { + yielder: yielder as *const _, + } + } + + fn enter(&self) { + CURRENT_CONTEXT.with(|cell| { + let mut borrow = cell.borrow_mut(); + + // Push this coroutine on top of the active stack. + borrow.push(self as *const _); + }) + } + + // Note: we don't use a drop-style guard here on purpose; if a panic + // happens while a coroutine is running, CURRENT_CONTEXT will be in + // an inconsistent state. corosensei will unwind all coroutine stacks + // anyway, and if we had a guard that would get dropped and try to + // leave its context, it'd panic again at the assert_eq! below. + fn leave(&self) { + CURRENT_CONTEXT.with(|cell| { + let mut borrow = cell.borrow_mut(); + + // Pop this coroutine from the active stack. + assert_eq!( + borrow.pop(), + Some(self as *const _), + "Active coroutine stack corrupted" + ); + }); + } + + fn get_current() -> Option<*const Self> { + CURRENT_CONTEXT.with(|cell| cell.borrow().last().copied()) + } + + fn block_on_future(&self, future: HostFuture) -> Result, RuntimeError> { + // Leave the coroutine context since we're yielding back to the + // parent stack, and will be inactive until the future is ready. + self.leave(); + + let yielder = unsafe { self.yielder.as_ref().expect("yielder pointer valid") }; + let result = match yielder.suspend(AsyncYield(future)) { + AsyncResume::HostFutureReady(result) => result, + AsyncResume::Start => unreachable!("coroutine resumed without start"), + }; + + // Once the future is ready, we restore the current coroutine + // context. + self.enter(); + + result + } +} + +fn run_immediate( + future: impl Future, RuntimeError>> + 'static, +) -> Result, AsyncRuntimeError> { + let waker = futures::task::noop_waker(); + let mut cx = Context::from_waker(&waker); + let mut future = Box::pin(future); + match future.as_mut().poll(&mut cx) { + Poll::Ready(result) => result.map_err(AsyncRuntimeError::RuntimeError), + Poll::Pending => Err(AsyncRuntimeError::YieldOutsideAsyncContext), + } +} diff --git a/lib/api/src/backend/sys/entities/engine.rs b/lib/api/src/backend/sys/entities/engine.rs index dee040f955..53648e7049 100644 --- a/lib/api/src/backend/sys/entities/engine.rs +++ b/lib/api/src/backend/sys/entities/engine.rs @@ -4,7 +4,7 @@ use std::{path::Path, sync::Arc}; use shared_buffer::OwnedBuffer; pub use wasmer_compiler::{Artifact, BaseTunables, Engine, EngineBuilder, Tunables}; -use wasmer_types::{target::Target, DeserializeError, Features, HashAlgorithm}; +use wasmer_types::{DeserializeError, Features, HashAlgorithm, target::Target}; use crate::{BackendEngine, BackendModule}; @@ -153,11 +153,9 @@ impl NativeEngineExt for crate::engine::Engine { file_ref: &Path, ) -> Result { let file = std::fs::File::open(file_ref)?; - let artifact = Arc::new(Artifact::deserialize_unchecked( - self.as_sys(), - OwnedBuffer::from_file(&file) - .map_err(|e| DeserializeError::Generic(format!("{e:?}")))?, - )?); + let buffer = OwnedBuffer::from_file(&file) + .map_err(|e| DeserializeError::Generic(format!("{e:?}")))?; + let artifact = unsafe { Arc::new(Artifact::deserialize_unchecked(self.as_sys(), buffer)?) }; Ok(crate::Module(BackendModule::Sys( super::module::Module::from_artifact(artifact), ))) @@ -168,11 +166,9 @@ impl NativeEngineExt for crate::engine::Engine { file_ref: &Path, ) -> Result { let file = std::fs::File::open(file_ref)?; - let artifact = Arc::new(Artifact::deserialize( - self.as_sys(), - OwnedBuffer::from_file(&file) - .map_err(|e| DeserializeError::Generic(format!("{e:?}")))?, - )?); + let buffer = OwnedBuffer::from_file(&file) + .map_err(|e| DeserializeError::Generic(format!("{e:?}")))?; + let artifact = unsafe { Arc::new(Artifact::deserialize(self.as_sys(), buffer)?) }; Ok(crate::Module(BackendModule::Sys( super::module::Module::from_artifact(artifact), ))) diff --git a/lib/api/src/backend/sys/entities/exception.rs b/lib/api/src/backend/sys/entities/exception.rs index 751184cd8d..32c3d2e2c4 100644 --- a/lib/api/src/backend/sys/entities/exception.rs +++ b/lib/api/src/backend/sys/entities/exception.rs @@ -2,85 +2,97 @@ use std::any::Any; use wasmer_types::{TagType, Type}; -use wasmer_vm::StoreHandle; +use wasmer_vm::{StoreHandle, StoreId}; use crate::{ - sys::vm::{VMException, VMExceptionRef}, - AsStoreMut, AsStoreRef, Tag, Value, + AsStoreMut, AsStoreRef, BackendTag, Tag, Value, + sys::vm::{VMExceptionObj, VMExceptionRef}, }; #[derive(Debug, Clone, PartialEq, Eq)] -/// A WebAssembly `exception` in the `sys` runtime. +/// A WebAssembly `exnref` in the `sys` runtime. pub(crate) struct Exception { - pub(crate) handle: VMException, + exnref: wasmer_vm::VMExceptionRef, } -unsafe impl Send for Exception {} -unsafe impl Sync for Exception {} - impl Exception { - /// Create a new [`Exception`]. - pub fn new(store: &mut impl AsStoreMut, tag: Tag, payload: &[Value]) -> Self { - todo!() - } -} + /// Creates a new exception with the given tag and payload, and also creates + /// a reference to it, returning the reference. + #[allow(irrefutable_let_patterns)] + pub fn new(store: &mut impl AsStoreMut, tag: &crate::sys::tag::Tag, payload: &[Value]) -> Self { + if !tag.is_from_store(store) { + panic!("cannot create Exception with Tag from another Store"); + } -#[derive(Debug, Clone)] -#[repr(transparent)] -/// A WebAssembly `extern ref` in the `sys` runtime. -pub(crate) struct ExceptionRef { - handle: StoreHandle, -} + let store_objects = store.as_store_ref().objects().as_sys(); + let store_id = store_objects.id(); -impl ExceptionRef { - /// Make a new extern reference - pub fn new(store: &mut impl AsStoreMut, value: T) -> Self - where - T: Any + Send + Sync + 'static + Sized, - { - Self { - handle: crate::backend::sys::store::StoreHandle::new( - store.objects_mut().as_sys_mut(), - wasmer_vm::VMExceptionObj::new(value), - ), + let tag_ty = tag.handle.get(store_objects).signature.params(); + + if tag_ty.len() != payload.len() { + panic!("payload length mismatch"); } + + let values = payload + .iter() + .enumerate() + .map(|(i, v)| { + if v.ty() != tag_ty[i] { + panic!("payload type mismatch"); + } + v.as_raw(store) + }) + .collect::>() + .into_boxed_slice(); + + let ctx = store.objects_mut().as_sys_mut(); + let exception = wasmer_vm::VMExceptionObj::new(tag.handle.internal_handle(), values); + let exn_handle = wasmer_vm::StoreHandle::new(ctx, exception); + let exnref = wasmer_vm::VMExceptionRef(exn_handle); + + Self { exnref } } - /// Try to downcast to the given value. - pub fn downcast<'a, T>(&self, store: &'a impl AsStoreRef) -> Option<&'a T> - where - T: Any + Send + Sync + 'static + Sized, - { - self.handle - .get(store.as_store_ref().objects().as_sys()) - .as_ref() - .downcast_ref::() + pub fn exnref(&self) -> wasmer_vm::VMExceptionRef { + self.exnref.clone() } - /// Create a [`VMExceptionRef`] from [`Self`]. - pub(crate) fn vm_exceptionref(&self) -> VMExceptionRef { - wasmer_vm::VMExceptionRef(self.handle.internal_handle()) + pub fn from_exnref(exnref: wasmer_vm::VMExceptionRef) -> Self { + Self { exnref } } - /// Create an instance of [`Self`] from a [`VMExceptionRef`]. - pub(crate) unsafe fn from_vm_exceptionref( - store: &mut impl AsStoreMut, - vm_exceptionref: VMExceptionRef, - ) -> Self { - Self { - handle: StoreHandle::from_internal(store.objects_mut().id(), vm_exceptionref.0), + pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { + self.exnref.0.store_id() == store.as_store_ref().objects().id() + } + + pub fn tag(&self, store: &impl AsStoreRef) -> crate::sys::tag::Tag { + if !self.is_from_store(store) { + panic!("Exception is from another Store"); + } + let ctx = store.as_store_ref().objects().as_sys(); + let exception = self.exnref.0.get(ctx); + let tag_handle = exception.tag(); + crate::sys::tag::Tag { + handle: unsafe { StoreHandle::from_internal(ctx.id(), tag_handle) }, } } - /// Checks whether this `ExceptionRef` can be used with the given context. - /// - /// Primitive (`i32`, `i64`, etc) and null funcref/exceptionref values are not - /// tied to a context and can be freely shared between contexts. - /// - /// exceptionref and funcref values are tied to a context and can only be used - /// with that context. - pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { - self.handle.store_id() == store.as_store_ref().objects().id() + pub fn payload(&self, store: &mut impl AsStoreMut) -> Vec { + if !self.is_from_store(store) { + panic!("Exception is from another Store"); + } + let ctx = store.as_store_ref().objects().as_sys(); + let exception = self.exnref.0.get(ctx); + let params_ty = exception.tag().get(ctx).signature.params().to_vec(); + let payload_ptr = exception.payload(); + + assert_eq!(params_ty.len(), payload_ptr.len()); + + params_ty + .iter() + .zip(unsafe { payload_ptr.as_ref().iter() }) + .map(|(ty, raw)| unsafe { Value::from_raw(store, *ty, *raw) }) + .collect() } } diff --git a/lib/api/src/backend/sys/entities/external.rs b/lib/api/src/backend/sys/entities/external.rs index b014029b2e..ac1cc3ad1a 100644 --- a/lib/api/src/backend/sys/entities/external.rs +++ b/lib/api/src/backend/sys/entities/external.rs @@ -48,7 +48,7 @@ impl ExternRef { vm_externref: VMExternRef, ) -> Self { Self { - handle: StoreHandle::from_internal(store.objects_mut().id(), vm_externref.0), + handle: unsafe { StoreHandle::from_internal(store.objects_mut().id(), vm_externref.0) }, } } diff --git a/lib/api/src/backend/sys/entities/function/env.rs b/lib/api/src/backend/sys/entities/function/env.rs index 362804a593..db823169b8 100644 --- a/lib/api/src/backend/sys/entities/function/env.rs +++ b/lib/api/src/backend/sys/entities/function/env.rs @@ -1,11 +1,13 @@ use std::{any::Any, fmt::Debug, marker::PhantomData}; +#[cfg(feature = "experimental-async")] +use crate::{AsStoreAsync, StoreAsync, StoreAsyncReadLock, StoreAsyncWriteLock}; use crate::{ + Store, StoreContext, StoreInner, StoreMut, StorePtrWrapper, store::{AsStoreMut, AsStoreRef, StoreRef}, - StoreMut, }; -use wasmer_vm::{StoreHandle, StoreObject, StoreObjects, VMFunctionEnvironment}; +use wasmer_vm::{StoreHandle, StoreId, StoreObject, StoreObjects, VMFunctionEnvironment}; #[derive(Debug)] #[repr(transparent)] @@ -16,12 +18,9 @@ pub struct FunctionEnv { marker: PhantomData, } -impl FunctionEnv { +impl FunctionEnv { /// Make a new FunctionEnv - pub fn new(store: &mut impl AsStoreMut, value: T) -> Self - where - T: Any + Send + 'static + Sized, - { + pub fn new(store: &mut impl AsStoreMut, value: T) -> Self { Self { handle: StoreHandle::new( store.as_store_mut().objects_mut().as_sys_mut(), @@ -31,18 +30,6 @@ impl FunctionEnv { } } - /// Get the data as reference - pub fn as_ref<'a>(&self, store: &'a impl AsStoreRef) -> &'a T - where - T: Any + Send + 'static + Sized, - { - self.handle - .get(store.as_store_ref().objects().as_sys()) - .as_ref() - .downcast_ref::() - .unwrap() - } - #[allow(dead_code)] // This function is only used in js pub(crate) fn from_handle(handle: StoreHandle) -> Self { Self { @@ -51,28 +38,33 @@ impl FunctionEnv { } } + /// Convert it into a `FunctionEnvMut` + pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut<'_, T> { + FunctionEnvMut { + store_mut: store.as_store_mut(), + func_env: self, + } + } +} + +impl FunctionEnv { + /// Get the data as reference + pub fn as_ref<'a>(&self, store: &'a impl AsStoreRef) -> &'a T { + self.handle + .get(store.as_store_ref().objects().as_sys()) + .as_ref() + .downcast_ref::() + .unwrap() + } + /// Get the data as mutable - pub fn as_mut<'a>(&self, store: &'a mut impl AsStoreMut) -> &'a mut T - where - T: Any + Send + 'static + Sized, - { + pub fn as_mut<'a>(&self, store: &'a mut impl AsStoreMut) -> &'a mut T { self.handle .get_mut(store.objects_mut().as_sys_mut()) .as_mut() .downcast_mut::() .unwrap() } - - /// Convert it into a `FunctionEnvMut` - pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut - where - T: Any + Send + 'static + Sized, - { - FunctionEnvMut { - store_mut: store.as_store_mut(), - func_env: self, - } - } } impl crate::FunctionEnv { @@ -165,7 +157,7 @@ impl FunctionEnvMut<'_, T> { } /// Borrows a new mutable reference of both the attached Store and host state - pub fn data_and_store_mut(&mut self) -> (&mut T, StoreMut) { + pub fn data_and_store_mut(&mut self) -> (&mut T, StoreMut<'_>) { let data = self.func_env.as_mut(&mut self.store_mut) as *mut T; // telling the borrow check to close his eyes here // this is still relatively safe to do as func_env are @@ -174,6 +166,16 @@ impl FunctionEnvMut<'_, T> { let data = unsafe { &mut *data }; (data, self.store_mut.as_store_mut()) } + + /// Returns a [`StoreAsync`] if the current + /// context is asynchronous. The store will be locked since + /// it's already active in the current context, but can be used + /// to spawn new coroutines via + /// [`Function::call_async`](crate::Function::call_async). + #[cfg(feature = "experimental-async")] + pub fn as_store_async(&self) -> Option { + self.store_mut.as_store_async() + } } impl AsStoreRef for FunctionEnvMut<'_, T> { @@ -207,3 +209,205 @@ impl From> for crate::FunctionEnv { Self(crate::BackendFunctionEnv::Sys(value)) } } + +/// A shared handle to a [`FunctionEnv`], suitable for use +/// in async imports. +#[cfg(feature = "experimental-async")] +pub struct AsyncFunctionEnvMut { + pub(crate) store: AsyncFunctionEnvMutStore, + pub(crate) func_env: FunctionEnv, +} + +// We need to let async functions that *don't suspend* run +// in a sync context. To that end, `AsyncFunctionEnvMut` +// must be able to be constructed without an actual +// StoreAsync instance, hence this enum. +#[cfg(feature = "experimental-async")] +pub(crate) enum AsyncFunctionEnvMutStore { + Async(StoreAsync), + Sync(StorePtrWrapper), +} + +/// A read-only handle to the [`FunctionEnv`] in an [`AsyncFunctionEnvMut`]. +#[cfg(feature = "experimental-async")] +pub struct AsyncFunctionEnvHandle { + read_lock: StoreAsyncReadLock, + pub(crate) func_env: FunctionEnv, +} + +/// A mutable handle to the [`FunctionEnv`] in an [`AsyncFunctionEnvMut`]. +#[cfg(feature = "experimental-async")] +pub struct AsyncFunctionEnvHandleMut { + write_lock: StoreAsyncWriteLock, + pub(crate) func_env: FunctionEnv, +} + +#[cfg(feature = "experimental-async")] +impl Debug for AsyncFunctionEnvMut +where + T: Send + Debug + 'static, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.store { + AsyncFunctionEnvMutStore::Sync(ptr) => self.func_env.as_ref(&ptr.as_ref()).fmt(f), + AsyncFunctionEnvMutStore::Async(store) => match store.inner.try_read() { + Some(read_lock) => self.func_env.as_ref(&read_lock).fmt(f), + None => write!(f, "AsyncFunctionEnvMut {{ }}"), + }, + } + } +} + +#[cfg(feature = "experimental-async")] +impl AsyncFunctionEnvMut { + pub(crate) fn store_id(&self) -> StoreId { + match &self.store { + AsyncFunctionEnvMutStore::Sync(ptr) => ptr.as_ref().objects().id(), + AsyncFunctionEnvMutStore::Async(store) => store.id, + } + } + + /// Waits for a store lock and returns a read-only handle to the + /// function environment. + pub async fn read(&self) -> AsyncFunctionEnvHandle { + let read_lock = match &self.store { + AsyncFunctionEnvMutStore::Async(store) => store.read_lock().await, + + // We can never acquire a store lock in a sync context + AsyncFunctionEnvMutStore::Sync(_) => futures::future::pending().await, + }; + + AsyncFunctionEnvHandle { + read_lock, + func_env: self.func_env.clone(), + } + } + + /// Waits for a store lock and returns a mutable handle to the + /// function environment. + pub async fn write(&self) -> AsyncFunctionEnvHandleMut { + let write_lock = match &self.store { + AsyncFunctionEnvMutStore::Async(store) => store.write_lock().await, + + // We can never acquire a store lock in a sync context + AsyncFunctionEnvMutStore::Sync(_) => futures::future::pending().await, + }; + + AsyncFunctionEnvHandleMut { + write_lock, + func_env: self.func_env.clone(), + } + } + + /// Borrows a new immmutable reference + pub fn as_ref(&self) -> FunctionEnv { + self.func_env.clone() + } + + /// Borrows a new mutable reference + pub fn as_mut(&mut self) -> Self { + self.clone() + } + + /// Creates an [`AsStoreAsync`] from this [`AsyncFunctionEnvMut`]. + pub fn as_store_async(&self) -> impl AsStoreAsync + 'static { + match &self.store { + AsyncFunctionEnvMutStore::Sync(_) => { + panic!("Cannot build a StoreAsync within a sync context") + } + AsyncFunctionEnvMutStore::Async(store) => StoreAsync { + id: store.id, + inner: store.inner.clone(), + }, + } + } +} + +#[cfg(feature = "experimental-async")] +impl Clone for AsyncFunctionEnvMut { + fn clone(&self) -> Self { + Self { + store: self.store.clone(), + func_env: self.func_env.clone(), + } + } +} + +#[cfg(feature = "experimental-async")] +impl Clone for AsyncFunctionEnvMutStore { + fn clone(&self) -> Self { + match self { + Self::Async(store) => Self::Async(StoreAsync { + id: store.id, + inner: store.inner.clone(), + }), + Self::Sync(ptr) => Self::Sync(ptr.clone()), + } + } +} + +#[cfg(feature = "experimental-async")] +impl AsyncFunctionEnvHandle { + /// Returns a reference to the host state in this function environment. + pub fn data(&self) -> &T { + self.func_env.as_ref(&self.read_lock) + } + + /// Returns both the host state and the attached StoreRef + pub fn data_and_store(&self) -> (&T, &impl AsStoreRef) { + (self.data(), &self.read_lock) + } +} + +#[cfg(feature = "experimental-async")] +impl AsStoreRef for AsyncFunctionEnvHandle { + fn as_store_ref(&self) -> StoreRef<'_> { + AsStoreRef::as_store_ref(&self.read_lock) + } +} + +#[cfg(feature = "experimental-async")] +impl AsyncFunctionEnvHandleMut { + /// Returns a mutable reference to the host state in this function environment. + pub fn data_mut(&mut self) -> &mut T { + self.func_env.as_mut(&mut self.write_lock) + } + + /// Returns both the host state and the attached StoreMut + pub fn data_and_store_mut(&mut self) -> (&mut T, &mut impl AsStoreMut) { + let data = self.data_mut() as *mut T; + // Wisdom of the ancients: + // telling the borrow check to close his eyes here + // this is still relatively safe to do as func_env are + // stored in a specific vec of Store, separate from the other objects + // and not really directly accessible with the StoreMut + let data = unsafe { &mut *data }; + (data, &mut self.write_lock) + } + + /// Borrows a new [`FunctionEnvMut`] from this [`AsyncFunctionEnvHandleMut`]. + pub fn as_function_env_mut(&mut self) -> FunctionEnvMut<'_, T> { + FunctionEnvMut { + store_mut: self.write_lock.as_store_mut(), + func_env: self.func_env.clone(), + } + } +} + +#[cfg(feature = "experimental-async")] +impl AsStoreRef for AsyncFunctionEnvHandleMut { + fn as_store_ref(&self) -> StoreRef<'_> { + AsStoreRef::as_store_ref(&self.write_lock) + } +} + +#[cfg(feature = "experimental-async")] +impl AsStoreMut for AsyncFunctionEnvHandleMut { + fn as_store_mut(&mut self) -> StoreMut<'_> { + AsStoreMut::as_store_mut(&mut self.write_lock) + } + + fn objects_mut(&mut self) -> &mut crate::StoreObjects { + AsStoreMut::objects_mut(&mut self.write_lock) + } +} diff --git a/lib/api/src/backend/sys/entities/function/mod.rs b/lib/api/src/backend/sys/entities/function/mod.rs index e032cb5c6f..04a364f9bf 100644 --- a/lib/api/src/backend/sys/entities/function/mod.rs +++ b/lib/api/src/backend/sys/entities/function/mod.rs @@ -3,21 +3,34 @@ pub(crate) mod env; pub(crate) mod typed; +#[cfg(feature = "experimental-async")] use crate::{ + AsStoreAsync, AsyncFunctionEnvMut, BackendAsyncFunctionEnvMut, StoreAsync, + entities::function::async_host::{AsyncFunctionEnv, AsyncHostFunction}, + sys::{ + async_runtime::{AsyncRuntimeError, block_on_host_future, call_function_async}, + function::env::AsyncFunctionEnvMutStore, + }, +}; +use crate::{ + BackendFunction, FunctionEnv, FunctionEnvMut, FunctionType, HostFunction, RuntimeError, + StoreContext, StoreInner, Value, WithEnv, WithoutEnv, backend::sys::{engine::NativeEngineExt, vm::VMFunctionCallback}, entities::store::{AsStoreMut, AsStoreRef, StoreMut}, utils::{FromToNativeWasmType, IntoResult, NativeWasmTypeInto, WasmTypeList}, vm::{VMExtern, VMExternFunction}, - BackendFunction, FunctionEnv, FunctionEnvMut, FunctionType, HostFunction, RuntimeError, - StoreInner, Value, WithEnv, WithoutEnv, }; use std::panic::{self, AssertUnwindSafe}; -use std::{cell::UnsafeCell, cmp::max, ffi::c_void}; -use wasmer_types::{NativeWasmType, RawValue}; +use std::{ + cell::UnsafeCell, cmp::max, error::Error, ffi::c_void, future::Future, marker::PhantomData, + pin::Pin, sync::Arc, +}; +use wasmer_types::{NativeWasmType, RawValue, StoreId}; use wasmer_vm::{ - on_host_stack, raise_user_trap, resume_panic, wasmer_call_trampoline, MaybeInstanceOwned, - StoreHandle, VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMFuncRef, - VMFunction, VMFunctionBody, VMFunctionContext, VMFunctionKind, VMTrampoline, + MaybeInstanceOwned, StoreHandle, Trap, TrapCode, VMCallerCheckedAnyfunc, VMContext, + VMDynamicFunctionContext, VMFuncRef, VMFunction, VMFunctionBody, VMFunctionContext, + VMFunctionKind, VMTrampoline, on_host_stack, raise_lib_trap, raise_user_trap, resume_panic, + wasmer_call_trampoline, }; #[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))] @@ -50,46 +63,39 @@ impl Function { let function_type = ty.into(); let func_ty = function_type.clone(); let func_env = env.clone().into_sys(); - let raw_store = store.as_store_mut().as_raw() as *mut u8; - let wrapper = move |values_vec: *mut RawValue| -> Result<(), RuntimeError> { + let store_id = store.objects_mut().id(); + let wrapper = move |values_vec: *mut RawValue| -> HostCallOutcome { unsafe { - let mut store = StoreMut::from_raw(raw_store as *mut StoreInner); + let mut store_wrapper = unsafe { StoreContext::get_current(store_id) }; + let mut store_mut = store_wrapper.as_mut(); let mut args = Vec::with_capacity(func_ty.params().len()); for (i, ty) in func_ty.params().iter().enumerate() { args.push(Value::from_raw( - &mut store, + &mut store_mut, *ty, values_vec.add(i).read_unaligned(), )); } - let store_mut = StoreMut::from_raw(raw_store as *mut StoreInner); let env = env::FunctionEnvMut { store_mut, func_env: func_env.clone(), } .into(); - let returns = func(env, &args)?; - - // We need to dynamically check that the returns - // match the expected types, as well as expected length. - let return_types = returns.iter().map(|ret| ret.ty()); - if return_types.ne(func_ty.results().iter().copied()) { - return Err(RuntimeError::new(format!( - "Dynamic function returned wrong signature. Expected {:?} but got {:?}", - func_ty.results(), - returns.iter().map(|ret| ret.ty()) - ))); - } - for (i, ret) in returns.iter().enumerate() { - values_vec.add(i).write_unaligned(ret.as_raw(&store)); + let sig = func_ty.clone(); + let result = func(env, &args); + HostCallOutcome::Ready { + func_ty: sig, + result, } } - Ok(()) }; let mut host_data = Box::new(VMDynamicFunctionContext { address: std::ptr::null(), - ctx: DynamicFunction { func: wrapper }, + ctx: DynamicFunction { + func: wrapper, + store_id, + }, }); host_data.address = host_data.ctx.func_body_ptr(); @@ -98,7 +104,7 @@ impl Function { // generated dynamic trampoline. let func_ptr = std::ptr::null() as VMFunctionCallback; let type_index = store - .as_store_mut() + .as_store_ref() .engine() .as_sys() .register_signature(&function_type); @@ -120,7 +126,122 @@ impl Function { host_data, }; Self { - handle: StoreHandle::new(store.as_store_mut().objects_mut().as_sys_mut(), vm_function), + handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function), + } + } + + #[cfg(feature = "experimental-async")] + pub(crate) fn new_async(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self + where + FT: Into, + F: Fn(&[Value]) -> Fut + 'static, + Fut: Future, RuntimeError>> + 'static, + { + let env = FunctionEnv::new(store, ()); + let wrapped = move |_env: AsyncFunctionEnvMut<()>, values: &[Value]| func(values); + Self::new_with_env_async(store, &env, ty, wrapped) + } + + #[cfg(feature = "experimental-async")] + pub(crate) fn new_with_env_async( + store: &mut impl AsStoreMut, + env: &FunctionEnv, + ty: FT, + func: F, + ) -> Self + where + FT: Into, + F: Fn(AsyncFunctionEnvMut, &[Value]) -> Fut + 'static, + Fut: Future, RuntimeError>> + 'static, + { + let function_type = ty.into(); + let func_ty = function_type.clone(); + let func_env = env.clone().into_sys(); + let store_id = store.objects_mut().id(); + let wrapper = move |values_vec: *mut RawValue| -> HostCallOutcome { + unsafe { + let mut context = StoreContext::try_get_current_async(store_id); + let mut store_mut = match &mut context { + crate::GetStoreAsyncGuardResult::Ok(wrapper) => StoreMut { + inner: wrapper.guard.as_mut().unwrap(), + }, + crate::GetStoreAsyncGuardResult::NotAsync(ptr) => ptr.as_mut(), + crate::GetStoreAsyncGuardResult::NotInstalled => { + panic!("No store context installed on this thread") + } + }; + let id = store_mut.as_store_ref().objects().id(); + let mut args = Vec::with_capacity(func_ty.params().len()); + + for (i, ty) in func_ty.params().iter().enumerate() { + args.push(Value::from_raw( + &mut store_mut, + *ty, + values_vec.add(i).read_unaligned(), + )); + } + let store_async = match context { + crate::GetStoreAsyncGuardResult::Ok(wrapper) => { + AsyncFunctionEnvMutStore::Async(StoreAsync { + id, + inner: crate::LocalRwLockWriteGuard::lock_handle( + wrapper.guard.as_mut().unwrap(), + ), + }) + } + crate::GetStoreAsyncGuardResult::NotAsync(ptr) => { + AsyncFunctionEnvMutStore::Sync(ptr) + } + crate::GetStoreAsyncGuardResult::NotInstalled => unreachable!(), + }; + let env = crate::AsyncFunctionEnvMut(crate::BackendAsyncFunctionEnvMut::Sys( + env::AsyncFunctionEnvMut { + store: store_async, + func_env: func_env.clone(), + }, + )); + let sig = func_ty.clone(); + let future = func(env, &args); + HostCallOutcome::Future { + func_ty: sig, + future: Box::pin(future), + } + } + }; + let mut host_data = Box::new(VMDynamicFunctionContext { + address: std::ptr::null(), + ctx: DynamicFunction { + func: wrapper, + store_id, + }, + }); + host_data.address = host_data.ctx.func_body_ptr(); + + let func_ptr = std::ptr::null() as VMFunctionCallback; + let type_index = store + .as_store_ref() + .engine() + .as_sys() + .register_signature(&function_type); + let vmctx = VMFunctionContext { + host_env: host_data.as_ref() as *const _ as *mut c_void, + }; + let call_trampoline = host_data.ctx.call_trampoline_address(); + let anyfunc = VMCallerCheckedAnyfunc { + func_ptr, + type_index, + vmctx, + call_trampoline, + }; + + let vm_function = VMFunction { + anyfunc: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc))), + kind: VMFunctionKind::Dynamic, + signature: function_type, + host_data, + }; + Self { + handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function), } } @@ -134,14 +255,14 @@ impl Function { let env = FunctionEnv::new(store, ()); let func_ptr = func.function_callback_sys().into_sys(); let host_data = Box::new(StaticFunction { - raw_store: store.as_store_mut().as_raw() as *mut u8, + store_id: store.objects_mut().id(), env, func, }); let function_type = FunctionType::new(Args::wasm_types(), Rets::wasm_types()); let type_index = store - .as_store_mut() + .as_store_ref() .engine() .as_sys() .register_signature(&function_type); @@ -164,10 +285,117 @@ impl Function { host_data, }; Self { - handle: StoreHandle::new(store.as_store_mut().objects_mut().as_sys_mut(), vm_function), + handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function), } } + #[cfg(feature = "experimental-async")] + pub(crate) fn new_typed_async(store: &mut impl AsStoreMut, func: F) -> Self + where + Args: WasmTypeList + 'static, + Rets: WasmTypeList + 'static, + F: AsyncHostFunction<(), Args, Rets, WithoutEnv> + 'static, + { + let env = FunctionEnv::new(store, ()); + let signature = FunctionType::new(Args::wasm_types(), Rets::wasm_types()); + let args_sig = Arc::new(signature.clone()); + let results_sig = Arc::new(signature.clone()); + let func = Arc::new(func); + Self::new_with_env_async( + store, + &env, + signature, + move |mut env_mut, + values| + -> Pin, RuntimeError>>>> { + let sys_env = match env_mut.0 { + BackendAsyncFunctionEnvMut::Sys(ref mut sys_env) => sys_env, + _ => panic!("Not a sys backend"), + }; + let mut store_mut_wrapper = + unsafe { StoreContext::get_current(sys_env.store_id()) }; + let mut store_mut = store_mut_wrapper.as_mut(); + let args_sig = args_sig.clone(); + let results_sig = results_sig.clone(); + let func = func.clone(); + let args = + match typed_args_from_values::(&mut store_mut, args_sig.as_ref(), values) + { + Ok(args) => args, + Err(err) => return Box::pin(async { Err(err) }), + }; + drop(store_mut_wrapper); + let future = func.as_ref().call_async(AsyncFunctionEnv::new(), args); + Box::pin(async move { + let typed_result = future.await?; + let mut store_mut = env_mut.write().await; + typed_results_to_values::( + &mut store_mut.as_store_mut(), + results_sig.as_ref(), + typed_result, + ) + }) + }, + ) + } + + #[cfg(feature = "experimental-async")] + pub(crate) fn new_typed_with_env_async( + store: &mut impl AsStoreMut, + env: &FunctionEnv, + func: F, + ) -> Self + where + T: 'static, + F: AsyncHostFunction + 'static, + Args: WasmTypeList + 'static, + Rets: WasmTypeList + 'static, + { + let signature = FunctionType::new(Args::wasm_types(), Rets::wasm_types()); + let args_sig = Arc::new(signature.clone()); + let results_sig = Arc::new(signature.clone()); + let func = Arc::new(func); + Self::new_with_env_async( + store, + env, + signature, + move |mut env_mut, + values| + -> Pin, RuntimeError>>>> { + let sys_env = match env_mut.0 { + BackendAsyncFunctionEnvMut::Sys(ref mut sys_env) => sys_env, + _ => panic!("Not a sys backend"), + }; + let mut store_mut_wrapper = + unsafe { StoreContext::get_current(sys_env.store_id()) }; + let mut store_mut = store_mut_wrapper.as_mut(); + let args_sig = args_sig.clone(); + let results_sig = results_sig.clone(); + let func = func.clone(); + let args = + match typed_args_from_values::(&mut store_mut, args_sig.as_ref(), values) + { + Ok(args) => args, + Err(err) => return Box::pin(async { Err(err) }), + }; + drop(store_mut_wrapper); + let env_mut_clone = env_mut.as_mut(); + let future = func + .as_ref() + .call_async(AsyncFunctionEnv::with_env(env_mut), args); + Box::pin(async move { + let typed_result = future.await?; + let mut store_mut = env_mut_clone.write().await; + typed_results_to_values::( + &mut store_mut.as_store_mut(), + results_sig.as_ref(), + typed_result, + ) + }) + }, + ) + } + pub(crate) fn new_typed_with_env( store: &mut impl AsStoreMut, env: &FunctionEnv, @@ -180,14 +408,14 @@ impl Function { { let func_ptr = func.function_callback_sys().into_sys(); let host_data = Box::new(StaticFunction { - raw_store: store.as_store_mut().as_raw() as *mut u8, + store_id: store.objects_mut().id(), env: env.as_sys().clone().into(), func, }); let function_type = FunctionType::new(Args::wasm_types(), Rets::wasm_types()); let type_index = store - .as_store_mut() + .as_store_ref() .engine() .as_sys() .register_signature(&function_type); @@ -210,7 +438,7 @@ impl Function { host_data, }; Self { - handle: StoreHandle::new(store.as_store_mut().objects_mut().as_sys_mut(), vm_function), + handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function), } } @@ -284,15 +512,25 @@ impl Function { ) -> Result<(), RuntimeError> { // Call the trampoline. let result = { + let store_id = store.objects_mut().id(); + // Safety: the store context is uninstalled before we return, and the + // store mut is valid for the duration of the call. + let store_install_guard = + unsafe { StoreContext::ensure_installed(store.as_store_mut().inner as *mut _) }; + let mut r; // TODO: This loop is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451 loop { let storeref = store.as_store_ref(); let vm_function = self.handle.get(storeref.objects().as_sys()); let config = storeref.engine().tunables().vmconfig(); + let signal_handler = storeref.signal_handler(); r = unsafe { + // Safety: This is the intended use-case for StoreContext::pause, as + // documented in the function's doc comments. + let pause_guard = StoreContext::pause(store_id); wasmer_call_trampoline( - store.as_store_ref().signal_handler(), + signal_handler, config, vm_function.anyfunc.as_ptr().as_ref().vmctx, trampoline, @@ -317,8 +555,12 @@ impl Function { } break; } + + drop(store_install_guard); + r }; + if let Err(error) = result { return Err(error.into()); } @@ -345,7 +587,7 @@ impl Function { ) -> Result, RuntimeError> { let trampoline = unsafe { self.handle - .get(store.as_store_ref().objects().as_sys()) + .get(store.objects_mut().as_sys()) .anyfunc .as_ptr() .as_ref() @@ -356,6 +598,18 @@ impl Function { Ok(results.into_boxed_slice()) } + #[cfg(feature = "experimental-async")] + #[allow(clippy::type_complexity)] + pub(crate) fn call_async( + &self, + store: &impl AsStoreAsync, + params: Vec, + ) -> Pin, RuntimeError>> + 'static>> { + let function = self.clone(); + let store = store.store(); + Box::pin(call_function_async(function, store, params)) + } + #[doc(hidden)] #[allow(missing_docs)] pub(crate) fn call_raw( @@ -365,7 +619,7 @@ impl Function { ) -> Result, RuntimeError> { let trampoline = unsafe { self.handle - .get(store.as_store_ref().objects().as_sys()) + .get(store.objects_mut().as_sys()) .anyfunc .as_ptr() .as_ref() @@ -385,12 +639,15 @@ impl Function { } pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self { - let signature = store - .as_store_ref() - .engine() - .as_sys() - .lookup_signature(funcref.0.as_ref().type_index) - .expect("Signature not found in store"); + let signature = { + let anyfunc = unsafe { funcref.0.as_ref() }; + store + .as_store_mut() + .engine() + .as_sys() + .lookup_signature(anyfunc.type_index) + .expect("Signature not found in store") + }; let vm_function = VMFunction { anyfunc: MaybeInstanceOwned::Instance(funcref.0), signature, @@ -407,10 +664,7 @@ impl Function { pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternFunction) -> Self { Self { handle: unsafe { - StoreHandle::from_internal( - store.as_store_ref().objects().id(), - vm_extern.into_sys(), - ) + StoreHandle::from_internal(store.objects_mut().id(), vm_extern.into_sys()) }, } } @@ -425,24 +679,170 @@ impl Function { } } +// We want to keep as much logic as possible on the host stack, +// since the WASM stack may be out of memory. In that scenario, +// throwing exceptions won't work since libunwind requires +// considerable stack space to do its magic, but everything else +// should work. +enum InvocationResult { + Success(T), + Exception(crate::Exception), + Trap(Box), + YieldOutsideAsyncContext, +} + +fn to_invocation_result(result: Result) -> InvocationResult +where + E: Error + 'static, +{ + match result { + Ok(value) => InvocationResult::Success(value), + Err(trap) => { + let dyn_err_ref = &trap as &dyn Error; + if let Some(runtime_error) = dyn_err_ref.downcast_ref::() + && let Some(exception) = runtime_error.to_exception() + { + return InvocationResult::Exception(exception); + } + InvocationResult::Trap(Box::new(trap)) + } + } +} + +fn write_dynamic_results( + store_id: StoreId, + func_ty: &FunctionType, + returns: Vec, + values_vec: *mut RawValue, +) -> Result<(), RuntimeError> { + let mut store_wrapper = unsafe { StoreContext::get_current(store_id) }; + let mut store = store_wrapper.as_mut(); + let return_types = returns.iter().map(|ret| ret.ty()); + if return_types.ne(func_ty.results().iter().copied()) { + return Err(RuntimeError::new(format!( + "Dynamic function returned wrong signature. Expected {:?} but got {:?}", + func_ty.results(), + returns.iter().map(|ret| ret.ty()) + ))); + } + for (i, ret) in returns.iter().enumerate() { + unsafe { + values_vec.add(i).write_unaligned(ret.as_raw(&store)); + } + } + Ok(()) +} + +fn finalize_dynamic_call( + store_id: StoreId, + func_ty: FunctionType, + values_vec: *mut RawValue, + result: Result, RuntimeError>, +) -> Result<(), RuntimeError> { + match result { + Ok(values) => write_dynamic_results(store_id, &func_ty, values, values_vec), + Err(err) => Err(err), + } +} + +fn typed_args_from_values( + store: &mut StoreMut, + func_ty: &FunctionType, + values: &[Value], +) -> Result +where + Args: WasmTypeList, +{ + if values.len() != func_ty.params().len() { + return Err(RuntimeError::new( + "typed host function received wrong number of parameters", + )); + } + let mut raw_array = Args::empty_array(); + for ((slot, value), expected_ty) in raw_array + .as_mut() + .iter_mut() + .zip(values.iter()) + .zip(func_ty.params().iter()) + { + debug_assert_eq!( + value.ty(), + *expected_ty, + "wasm should only call host functions with matching signatures" + ); + *slot = value.as_raw(store); + } + unsafe { Ok(Args::from_array(store, raw_array)) } +} + +fn typed_results_to_values( + store: &mut StoreMut, + func_ty: &FunctionType, + rets: Rets, +) -> Result, RuntimeError> +where + Rets: WasmTypeList, +{ + let mut raw_array = unsafe { rets.into_array(store) }; + let mut values = Vec::with_capacity(func_ty.results().len()); + for (raw, ty) in raw_array.as_mut().iter().zip(func_ty.results().iter()) { + unsafe { + values.push(Value::from_raw(store, *ty, *raw)); + } + } + Ok(values) +} + +pub(crate) enum HostCallOutcome { + Ready { + func_ty: FunctionType, + result: Result, RuntimeError>, + }, + #[cfg(feature = "experimental-async")] + Future { + func_ty: FunctionType, + future: Pin, RuntimeError>>>>, + }, +} + /// Host state for a dynamic function. pub(crate) struct DynamicFunction { func: F, + store_id: StoreId, } impl DynamicFunction where - F: Fn(*mut RawValue) -> Result<(), RuntimeError> + 'static, + F: Fn(*mut RawValue) -> HostCallOutcome + 'static, { // This function wraps our func, to make it compatible with the // reverse trampoline signature - unsafe extern "C" fn func_wrapper( + unsafe extern "C-unwind" fn func_wrapper( this: &mut VMDynamicFunctionContext, values_vec: *mut RawValue, ) { let result = on_host_stack(|| { - panic::catch_unwind(AssertUnwindSafe(|| { - (this.ctx.func)(values_vec).map_err(Box::new) + panic::catch_unwind(AssertUnwindSafe(|| match (this.ctx.func)(values_vec) { + HostCallOutcome::Ready { func_ty, result } => to_invocation_result( + finalize_dynamic_call(this.ctx.store_id, func_ty, values_vec, result), + ), + #[cfg(feature = "experimental-async")] + HostCallOutcome::Future { func_ty, future } => { + let awaited = block_on_host_future(future); + let result = match awaited { + Ok(value) => Ok(value), + Err(AsyncRuntimeError::RuntimeError(e)) => Err(e), + Err(AsyncRuntimeError::YieldOutsideAsyncContext) => { + return InvocationResult::YieldOutsideAsyncContext; + } + }; + to_invocation_result(finalize_dynamic_call( + this.ctx.store_id, + func_ty, + values_vec, + result, + )) + } })) }); @@ -450,9 +850,23 @@ where // AS WE ARE IN THE WASM STACK, NOT ON THE HOST ONE. // See: https://github.com/wasmerio/wasmer/pull/5700 match result { - Ok(Ok(())) => {} - Ok(Err(trap)) => raise_user_trap(trap), - Err(panic) => resume_panic(panic), + Ok(InvocationResult::Success(())) => {} + Ok(InvocationResult::Exception(exception)) => unsafe { + // Note: can't acquire a proper ref-counted context ref here, since we can switch + // away from the WASM stack at any time. + // Safety: The pointer is only used for the duration of the call to `throw`. + let mut store_wrapper = StoreContext::get_current_transient(this.ctx.store_id); + let mut store = store_wrapper.as_mut().unwrap(); + wasmer_vm::libcalls::throw( + store.objects.as_sys(), + exception.vm_exceptionref().as_sys().to_u32_exnref(), + ) + }, + Ok(InvocationResult::Trap(trap)) => unsafe { raise_user_trap(trap) }, + Ok(InvocationResult::YieldOutsideAsyncContext) => unsafe { + raise_lib_trap(Trap::lib(TrapCode::YieldOutsideAsyncContext)) + }, + Err(panic) => unsafe { resume_panic(panic) }, } } @@ -471,8 +885,10 @@ where ) { // The VMFunctionCallback is null here: it is only filled in later // by the engine linker. - let dynamic_function = &mut *(vmctx as *mut VMDynamicFunctionContext); - Self::func_wrapper(dynamic_function, args); + unsafe { + let dynamic_function = &mut *(vmctx as *mut VMDynamicFunctionContext); + Self::func_wrapper(dynamic_function, args); + } } } @@ -480,7 +896,7 @@ where /// [`crate::Function::new_typed`] and /// [`crate::Function::new_typed_with_env`] to learn more. pub(crate) struct StaticFunction { - pub(crate) raw_store: *mut u8, + pub(crate) store_id: StoreId, pub(crate) env: FunctionEnv, pub(crate) func: F, } @@ -521,20 +937,23 @@ macro_rules! impl_host_function { /// This is a function that wraps the real host /// function. Its address will be used inside the /// runtime. - unsafe extern "C" fn func_wrapper<$( $x, )* Rets, RetsAsResult, Func>( env: &StaticFunction, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct + unsafe extern "C-unwind" fn func_wrapper<$( $x, )* Rets, RetsAsResult, Func>( env: &StaticFunction, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct where $( $x: FromToNativeWasmType, )* Rets: WasmTypeList, RetsAsResult: IntoResult, Func: Fn($( $x , )*) -> RetsAsResult + 'static, { - let mut store = StoreMut::from_raw(env.raw_store as *mut _); let result = on_host_stack(|| { panic::catch_unwind(AssertUnwindSafe(|| { + let mut store_wrapper = unsafe { StoreContext::get_current(env.store_id) }; + let mut store = store_wrapper.as_mut(); $( - let $x = FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x)); + let $x = unsafe { + FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x)) + }; )* - (env.func)($($x),* ).into_result().map_err(Box::new) + to_invocation_result((env.func)($($x),* ).into_result()) })) }); @@ -542,9 +961,30 @@ macro_rules! impl_host_function { // AS WE ARE IN THE WASM STACK, NOT ON THE HOST ONE. // See: https://github.com/wasmerio/wasmer/pull/5700 match result { - Ok(Ok(result)) => return result.into_c_struct(&mut store), - Ok(Err(trap)) => raise_user_trap(trap), - Err(panic) => resume_panic(panic) , + Ok(InvocationResult::Success(result)) => unsafe { + // Note: can't acquire a proper ref-counted context ref here, since we can switch + // away from the WASM stack at any time. + // Safety: The pointer is only used for the duration of the call to `into_c_struct`. + let mut store_wrapper = StoreContext::get_current_transient(env.store_id); + let mut store = store_wrapper.as_mut().unwrap(); + return result.into_c_struct(store); + }, + Ok(InvocationResult::Exception(exception)) => unsafe { + // Note: can't acquire a proper ref-counted context ref here, since we can switch + // away from the WASM stack at any time. + // Safety: The pointer is only used for the duration of the call to `throw`. + let mut store_wrapper = StoreContext::get_current_transient(env.store_id); + let mut store = store_wrapper.as_mut().unwrap(); + wasmer_vm::libcalls::throw( + store.objects.as_sys(), + exception.vm_exceptionref().as_sys().to_u32_exnref() + ) + } + Ok(InvocationResult::Trap(trap)) => unsafe { raise_user_trap(trap) }, + Ok(InvocationResult::YieldOutsideAsyncContext) => unsafe { + raise_lib_trap(Trap::lib(TrapCode::YieldOutsideAsyncContext)) + }, + Err(panic) => unsafe { resume_panic(panic) }, } } @@ -563,15 +1003,17 @@ macro_rules! impl_host_function { body: crate::backend::sys::vm::VMFunctionCallback, args: *mut RawValue, ) { - let body: unsafe extern "C" fn(vmctx: *mut crate::backend::sys::vm::VMContext, $( $x: <$x::Native as NativeWasmType>::Abi, )*) -> Rets::CStruct = std::mem::transmute(body); let mut _n = 0; - $( - let $x = *args.add(_n).cast(); - _n += 1; - )* - let results = body(vmctx, $( $x ),*); - Rets::write_c_struct_to_ptr(results, args); + unsafe { + let body: unsafe extern "C" fn(vmctx: *mut crate::backend::sys::vm::VMContext, $( $x: <$x::Native as NativeWasmType>::Abi, )*) -> Rets::CStruct = std::mem::transmute(body); + $( + let $x = *args.add(_n).cast(); + _n += 1; + )* + let results = body(vmctx, $( $x ),*); + Rets::write_c_struct_to_ptr(results, args); + } } call_trampoline::<$( $x, )* Rets> as _ @@ -585,26 +1027,27 @@ macro_rules! impl_host_function { /// This is a function that wraps the real host /// function. Its address will be used inside the /// runtime. - unsafe extern "C" fn func_wrapper( env: &StaticFunction, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct + unsafe extern "C-unwind" fn func_wrapper( env: &StaticFunction, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct where $( $x: FromToNativeWasmType, )* Rets: WasmTypeList, RetsAsResult: IntoResult, Func: Fn(FunctionEnvMut, $( $x , )*) -> RetsAsResult + 'static, { - - let mut store = StoreMut::from_raw(env.raw_store as *mut _); let result = wasmer_vm::on_host_stack(|| { panic::catch_unwind(AssertUnwindSafe(|| { + let mut store_wrapper = unsafe { StoreContext::get_current(env.store_id) }; + let mut store = store_wrapper.as_mut(); $( - let $x = FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x)); + let $x = unsafe { + FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x)) + }; )* - let store_mut = StoreMut::from_raw(env.raw_store as *mut _); let f_env = crate::backend::sys::function::env::FunctionEnvMut { - store_mut, + store_mut: store, func_env: env.env.as_sys().clone(), }.into(); - (env.func)(f_env, $($x),* ).into_result().map_err(Box::new) + to_invocation_result((env.func)(f_env, $($x),* ).into_result()) })) }); @@ -612,9 +1055,30 @@ macro_rules! impl_host_function { // AS WE ARE IN THE WASM STACK, NOT ON THE HOST ONE. // See: https://github.com/wasmerio/wasmer/pull/5700 match result { - Ok(Ok(result)) => return result.into_c_struct(&mut store), - Ok(Err(trap)) => raise_user_trap(trap), - Err(panic) => resume_panic(panic), + Ok(InvocationResult::Success(result)) => unsafe { + // Note: can't acquire a proper ref-counted context ref here, since we can switch + // away from the WASM stack at any time. + // Safety: The pointer is only used for the duration of the call to `into_c_struct`. + let mut store_wrapper = StoreContext::get_current_transient(env.store_id); + let mut store = store_wrapper.as_mut().unwrap(); + return result.into_c_struct(store); + }, + Ok(InvocationResult::Exception(exception)) => unsafe { + // Note: can't acquire a proper ref-counted context ref here, since we can switch + // away from the WASM stack at any time. + // Safety: The pointer is only used for the duration of the call to `throw`. + let mut store_wrapper = StoreContext::get_current_transient(env.store_id); + let mut store = store_wrapper.as_mut().unwrap(); + wasmer_vm::libcalls::throw( + store.objects.as_sys(), + exception.vm_exceptionref().as_sys().to_u32_exnref() + ) + } + Ok(InvocationResult::Trap(trap)) => unsafe { raise_user_trap(trap) }, + Ok(InvocationResult::YieldOutsideAsyncContext) => unsafe { + raise_lib_trap(Trap::lib(TrapCode::YieldOutsideAsyncContext)) + }, + Err(panic) => unsafe { resume_panic(panic) }, } } func_wrapper::< T, $( $x, )* Rets, RetsAsResult, Func > as _ @@ -630,15 +1094,18 @@ macro_rules! impl_host_function { body: crate::backend::sys::vm::VMFunctionCallback, args: *mut RawValue, ) { - let body: unsafe extern "C" fn(vmctx: *mut crate::backend::sys::vm::VMContext, $( $x: <$x::Native as NativeWasmType>::Abi, )*) -> Rets::CStruct = std::mem::transmute(body); - let mut _n = 0; - $( - let $x = *args.add(_n).cast(); - _n += 1; - )* + unsafe { + let body: unsafe extern "C" fn(vmctx: *mut crate::backend::sys::vm::VMContext, $( $x: <$x::Native as NativeWasmType>::Abi, )*) -> Rets::CStruct = std::mem::transmute(body); + let mut _n = 0; + $( + let $x = *args.add(_n).cast(); + _n += 1; + )* - let results = body(vmctx, $( $x ),*); - Rets::write_c_struct_to_ptr(results, args); + let results = body(vmctx, $( $x ),*); + + Rets::write_c_struct_to_ptr(results, args); + } } call_trampoline::<$( $x, )* Rets> as _ diff --git a/lib/api/src/backend/sys/entities/function/typed.rs b/lib/api/src/backend/sys/entities/function/typed.rs index 53f5f9c1a1..8616234ca9 100644 --- a/lib/api/src/backend/sys/entities/function/typed.rs +++ b/lib/api/src/backend/sys/entities/function/typed.rs @@ -1,7 +1,13 @@ use crate::backend::sys::engine::NativeEngineExt; -use crate::store::{AsStoreMut, AsStoreRef}; -use crate::{FromToNativeWasmType, NativeWasmTypeInto, RuntimeError, TypedFunction, WasmTypeList}; -use wasmer_types::RawValue; +use crate::{ + FromToNativeWasmType, Function, NativeWasmTypeInto, RuntimeError, StoreContext, TypedFunction, + Value, WasmTypeList, + store::{AsStoreMut, AsStoreRef}, +}; +#[cfg(feature = "experimental-async")] +use crate::{StoreAsync, store::AsStoreAsync}; +use std::future::Future; +use wasmer_types::{FunctionType, RawValue, Type}; macro_rules! impl_native_traits { ( $( $x:ident ),* ) => { @@ -46,11 +52,20 @@ macro_rules! impl_native_traits { rets_list.as_mut() }; + let store_id = store.objects_mut().id(); + // Install the store into the store context + let store_install_guard = unsafe { + StoreContext::ensure_installed(store.as_store_mut().inner as *mut _) + }; + let mut r; loop { let storeref = store.as_store_ref(); let config = storeref.engine().tunables().vmconfig(); r = unsafe { + // Safety: This is the intended use-case for StoreContext::pause, as + // documented in the function's doc comments. + let pause_guard = StoreContext::pause(store_id); wasmer_vm::wasmer_call_trampoline( store.as_store_ref().signal_handler(), config, @@ -71,6 +86,9 @@ macro_rules! impl_native_traits { } break; } + + drop(store_install_guard); + r?; let num_rets = rets_list.len(); @@ -99,6 +117,38 @@ macro_rules! impl_native_traits { // Ok(Rets::from_c_struct(results)) } + /// Call the typed func asynchronously. + #[allow(unused_mut)] + #[allow(clippy::too_many_arguments)] + #[cfg(feature = "experimental-async")] + pub(crate) fn call_async_sys( + func: Function, + store: StoreAsync, + $( $x: $x, )* + ) -> impl Future> + 'static + where + $( $x: FromToNativeWasmType + 'static, )* + { + async move { + let mut write = store.write_lock().await; + let func_ty = func.ty(&mut write); + let mut params_raw = [ $( $x.to_native().into_raw(&mut write) ),* ]; + let mut params_values = Vec::with_capacity(params_raw.len()); + { + for (raw, ty) in params_raw.iter().zip(func_ty.params()) { + unsafe { + params_values.push(Value::from_raw(&mut write, *ty, *raw)); + } + } + } + drop(write); + + let results = func.call_async(&store, params_values).await?; + let mut write = store.write_lock().await; + convert_results::(&mut write, func_ty, &results) + } + } + #[doc(hidden)] #[allow(missing_docs)] #[allow(unused_mut)] @@ -128,11 +178,20 @@ macro_rules! impl_native_traits { rets_list.as_mut() }; + let store_id = store.objects_mut().id(); + // Install the store into the store context + let store_install_guard = unsafe { + StoreContext::ensure_installed(store.as_store_mut().inner as *mut _) + }; + let mut r; loop { let storeref = store.as_store_ref(); let config = storeref.engine().tunables().vmconfig(); r = unsafe { + // Safety: This is the intended use-case for StoreContext::pause, as + // documented in the function's doc comments. + let pause_guard = StoreContext::pause(store_id); wasmer_vm::wasmer_call_trampoline( store.as_store_ref().signal_handler(), config, @@ -154,6 +213,9 @@ macro_rules! impl_native_traits { } break; } + + drop(store_install_guard); + r?; let num_rets = rets_list.len(); @@ -200,9 +262,15 @@ impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15 +); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16 +); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17 +); impl_native_traits!( A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18 ); @@ -212,3 +280,27 @@ impl_native_traits!( impl_native_traits!( A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20 ); + +fn convert_results( + store: &mut impl AsStoreMut, + ty: FunctionType, + results: &[Value], +) -> Result +where + Rets: WasmTypeList, +{ + if results.len() != ty.results().len() { + return Err(RuntimeError::new("result arity mismatch")); + } + let mut raw_array = Rets::empty_array(); + for ((slot, value_ty), value) in raw_array + .as_mut() + .iter_mut() + .zip(ty.results().iter()) + .zip(results.iter()) + { + debug_assert_eq!(value.ty(), *value_ty); + *slot = value.as_raw(store); + } + unsafe { Ok(Rets::from_array(store, raw_array)) } +} diff --git a/lib/api/src/backend/sys/entities/global.rs b/lib/api/src/backend/sys/entities/global.rs index 893db3f47a..8d3b8754e9 100644 --- a/lib/api/src/backend/sys/entities/global.rs +++ b/lib/api/src/backend/sys/entities/global.rs @@ -59,7 +59,7 @@ impl Global { if !val.is_from_store(store) { return Err(RuntimeError::new("cross-`Store` values are not supported")); } - let global = self.handle.get_mut(store.objects_mut()); + let global = self.handle.get_mut(store.objects_mut().as_sys_mut()); if global.ty().mutability != Mutability::Var { return Err(RuntimeError::new("Attempted to set an immutable global")); } diff --git a/lib/api/src/backend/sys/entities/instance.rs b/lib/api/src/backend/sys/entities/instance.rs index 0219939529..15edc83407 100644 --- a/lib/api/src/backend/sys/entities/instance.rs +++ b/lib/api/src/backend/sys/entities/instance.rs @@ -1,8 +1,8 @@ //! Data types, functions and traits for `sys` runtime's `Instance` implementation. use crate::{ - error::InstantiationError, exports::Exports, imports::Imports, module::Module, - store::AsStoreMut, Extern, + Extern, error::InstantiationError, exports::Exports, imports::Imports, module::Module, + store::AsStoreMut, }; use wasmer_vm::{StoreHandle, VMInstance}; @@ -14,22 +14,6 @@ pub struct Instance { _handle: StoreHandle, } -#[cfg(test)] -mod send_test { - use super::*; - - // Only here to statically ensure that `Instance` is `Send`. - // Will fail to compile otherwise. - #[allow(dead_code)] - fn instance_is_send(inst: Instance) { - fn is_send(t: impl Send) { - let _ = t; - } - - is_send(inst); - } -} - impl From for InstantiationError { fn from(other: wasmer_compiler::InstantiationError) -> Self { match other { @@ -105,3 +89,19 @@ impl crate::BackendInstance { } } } + +#[cfg(test)] +mod send_test { + use super::*; + + // Only here to statically ensure that `Instance` is `Send`. + // Will fail to compile otherwise. + #[allow(dead_code)] + fn instance_is_send(inst: Instance) { + fn is_send(t: impl Send) { + let _ = t; + } + + is_send(inst); + } +} diff --git a/lib/api/src/backend/sys/entities/memory/mod.rs b/lib/api/src/backend/sys/entities/memory/mod.rs index faa2a51d38..ed16d22095 100644 --- a/lib/api/src/backend/sys/entities/memory/mod.rs +++ b/lib/api/src/backend/sys/entities/memory/mod.rs @@ -11,11 +11,11 @@ use wasmer_types::{MemoryType, Pages}; use wasmer_vm::{LinearMemory, MemoryError, StoreHandle, ThreadConditionsHandle, VMMemory}; use crate::{ + BackendMemory, MemoryAccessError, backend::sys::entities::{engine::NativeEngineExt, memory::MemoryView}, entities::store::{AsStoreMut, AsStoreRef}, location::{MemoryLocation, SharedMemoryOps}, vm::{VMExtern, VMExternMemory}, - BackendMemory, MemoryAccessError, }; pub(crate) mod view; @@ -147,12 +147,7 @@ impl SharedMemoryOps for ThreadConditionsHandle { let count = self .upgrade() .ok_or(crate::AtomicsError::Unimplemented)? - .do_notify( - wasmer_vm::NotifyLocation { - address: dst.address, - }, - count, - ); + .do_notify(dst.address, count); Ok(count) } @@ -161,20 +156,25 @@ impl SharedMemoryOps for ThreadConditionsHandle { dst: MemoryLocation, timeout: Option, ) -> Result { - self.upgrade() - .ok_or(crate::AtomicsError::Unimplemented)? - .do_wait( - wasmer_vm::NotifyLocation { - address: dst.address, - }, - timeout, - ) - .map_err(|e| match e { - wasmer_vm::WaiterError::Unimplemented => crate::AtomicsError::Unimplemented, - wasmer_vm::WaiterError::TooManyWaiters => crate::AtomicsError::TooManyWaiters, - wasmer_vm::WaiterError::AtomicsDisabled => crate::AtomicsError::AtomicsDisabled, - _ => crate::AtomicsError::Unimplemented, - }) + // Safety: `ExpectedValue::None` has no safety requirements. + unsafe { + self.upgrade() + .ok_or(crate::AtomicsError::Unimplemented)? + .do_wait( + wasmer_vm::NotifyLocation { + memory_base: std::ptr::null_mut(), + address: dst.address, + }, + wasmer_vm::ExpectedValue::None, + timeout, + ) + .map_err(|e| match e { + wasmer_vm::WaiterError::Unimplemented => crate::AtomicsError::Unimplemented, + wasmer_vm::WaiterError::TooManyWaiters => crate::AtomicsError::TooManyWaiters, + wasmer_vm::WaiterError::AtomicsDisabled => crate::AtomicsError::AtomicsDisabled, + _ => crate::AtomicsError::Unimplemented, + }) + } } fn disable_atomics(&self) -> Result<(), MemoryError> { @@ -284,52 +284,63 @@ impl MemoryBuffer<'_> { unsafe fn volatile_memcpy_read(mut src: *const u8, mut dst: *mut u8, mut len: usize) { #[inline] unsafe fn copy_one(src: &mut *const u8, dst: &mut *mut u8, len: &mut usize) { - #[repr(packed)] + #[repr(C, packed)] struct Unaligned(T); - let val = (*src as *const Unaligned).read_volatile(); - (*dst as *mut Unaligned).write(val); - *src = src.add(mem::size_of::()); - *dst = dst.add(mem::size_of::()); - *len -= mem::size_of::(); - } - while len >= 8 { - copy_one::(&mut src, &mut dst, &mut len); - } - if len >= 4 { - copy_one::(&mut src, &mut dst, &mut len); - } - if len >= 2 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { + let val = (*src as *const Unaligned).read_volatile(); + (*dst as *mut Unaligned).write(val); + + *src = src.add(mem::size_of::()); + *dst = dst.add(mem::size_of::()); + *len -= mem::size_of::(); + } } - if len >= 1 { - copy_one::(&mut src, &mut dst, &mut len); + + unsafe { + while len >= 8 { + copy_one::(&mut src, &mut dst, &mut len); + } + if len >= 4 { + copy_one::(&mut src, &mut dst, &mut len); + } + if len >= 2 { + copy_one::(&mut src, &mut dst, &mut len); + } + if len >= 1 { + copy_one::(&mut src, &mut dst, &mut len); + } } } #[inline] unsafe fn volatile_memcpy_write(mut src: *const u8, mut dst: *mut u8, mut len: usize) { #[inline] unsafe fn copy_one(src: &mut *const u8, dst: &mut *mut u8, len: &mut usize) { - #[repr(packed)] + #[repr(C, packed)] struct Unaligned(T); - let val = (*src as *const Unaligned).read(); - (*dst as *mut Unaligned).write_volatile(val); - *src = src.add(mem::size_of::()); - *dst = dst.add(mem::size_of::()); - *len -= mem::size_of::(); - } - while len >= 8 { - copy_one::(&mut src, &mut dst, &mut len); - } - if len >= 4 { - copy_one::(&mut src, &mut dst, &mut len); - } - if len >= 2 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { + let val = (*src as *const Unaligned).read(); + (*dst as *mut Unaligned).write_volatile(val); + *src = src.add(mem::size_of::()); + *dst = dst.add(mem::size_of::()); + *len -= mem::size_of::(); + } } - if len >= 1 { - copy_one::(&mut src, &mut dst, &mut len); + + unsafe { + while len >= 8 { + copy_one::(&mut src, &mut dst, &mut len); + } + if len >= 4 { + copy_one::(&mut src, &mut dst, &mut len); + } + if len >= 2 { + copy_one::(&mut src, &mut dst, &mut len); + } + if len >= 1 { + copy_one::(&mut src, &mut dst, &mut len); + } } } diff --git a/lib/api/src/backend/sys/entities/memory/view.rs b/lib/api/src/backend/sys/entities/memory/view.rs index 9fb4e04c77..e68c9b81e5 100644 --- a/lib/api/src/backend/sys/entities/memory/view.rs +++ b/lib/api/src/backend/sys/entities/memory/view.rs @@ -1,5 +1,5 @@ -use crate::store::AsStoreRef; use crate::MemoryAccessError; +use crate::store::AsStoreRef; use std::marker::PhantomData; use std::mem::MaybeUninit; use std::slice; @@ -67,7 +67,7 @@ impl<'a> MemoryView<'a> { /// function that writes to the memory or by resizing the memory. #[doc(hidden)] pub unsafe fn data_unchecked(&self) -> &[u8] { - self.data_unchecked_mut() + unsafe { self.data_unchecked_mut() } } /// Retrieve a mutable slice of the memory contents. @@ -82,7 +82,7 @@ impl<'a> MemoryView<'a> { #[allow(clippy::mut_from_ref)] #[doc(hidden)] pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] { - slice::from_raw_parts_mut(self.buffer.base, self.buffer.len) + unsafe { slice::from_raw_parts_mut(self.buffer.base, self.buffer.len) } } /// Returns the size (in [`Pages`]) of the `Memory`. diff --git a/lib/api/src/backend/sys/entities/module.rs b/lib/api/src/backend/sys/entities/module.rs index b2a4d63d97..cd12fd60c1 100644 --- a/lib/api/src/backend/sys/entities/module.rs +++ b/lib/api/src/backend/sys/entities/module.rs @@ -10,8 +10,9 @@ use wasmer_types::{ }; use crate::{ + AsStoreMut, AsStoreRef, BackendModule, IntoBytes, StoreContext, backend::sys::entities::engine::NativeEngineExt, engine::AsEngineRef, - error::InstantiationError, vm::VMInstance, AsStoreMut, AsStoreRef, BackendModule, IntoBytes, + error::InstantiationError, vm::VMInstance, }; #[derive(Clone, PartialEq, Eq)] @@ -88,11 +89,14 @@ impl Module { bytes: impl IntoBytes, ) -> Result { let bytes = bytes.into_bytes(); - let artifact = engine - .as_engine_ref() - .engine() - .as_sys() - .deserialize_unchecked(bytes.into())?; + + let artifact = unsafe { + engine + .as_engine_ref() + .engine() + .as_sys() + .deserialize_unchecked(bytes.into())? + }; Ok(Self::from_artifact(artifact)) } @@ -102,11 +106,13 @@ impl Module { bytes: impl IntoBytes, ) -> Result { let bytes = bytes.into_bytes(); - let artifact = engine - .as_engine_ref() - .engine() - .as_sys() - .deserialize(bytes.into())?; + let artifact = unsafe { + engine + .as_engine_ref() + .engine() + .as_sys() + .deserialize(bytes.into())? + }; Ok(Self::from_artifact(artifact)) } @@ -114,11 +120,13 @@ impl Module { engine: &impl AsEngineRef, path: impl AsRef, ) -> Result { - let artifact = engine - .as_engine_ref() - .engine() - .as_sys() - .deserialize_from_file_unchecked(path.as_ref())?; + let artifact = unsafe { + engine + .as_engine_ref() + .engine() + .as_sys() + .deserialize_from_file_unchecked(path.as_ref())? + }; Ok(Self::from_artifact(artifact)) } @@ -126,11 +134,13 @@ impl Module { engine: &impl AsEngineRef, path: impl AsRef, ) -> Result { - let artifact = engine - .as_engine_ref() - .engine() - .as_sys() - .deserialize_from_file(path.as_ref())?; + let artifact = unsafe { + engine + .as_engine_ref() + .engine() + .as_sys() + .deserialize_from_file(path.as_ref())? + }; Ok(Self::from_artifact(artifact)) } @@ -157,6 +167,7 @@ impl Module { } let signal_handler = store.as_store_ref().signal_handler(); let mut store_mut = store.as_store_mut(); + let store_ptr = store_mut.inner as *mut _; let (engine, objects) = store_mut.engine_and_objects_mut(); let config = engine.tunables().vmconfig(); unsafe { @@ -169,6 +180,9 @@ impl Module { objects.as_sys_mut(), )?; + let store_id = objects.id(); + let store_install_guard = StoreContext::ensure_installed(store_ptr); + // After the instance handle is created, we need to initialize // the data, call the start function and so. However, if any // of this steps traps, we still need to keep the instance alive @@ -177,6 +191,8 @@ impl Module { self.artifact .finish_instantiation(config, signal_handler, &mut instance_handle)?; + drop(store_install_guard); + Ok(VMInstance::Sys(instance_handle)) } } diff --git a/lib/api/src/backend/sys/entities/store/mod.rs b/lib/api/src/backend/sys/entities/store/mod.rs index 43a171eb3d..2763b2c08c 100644 --- a/lib/api/src/backend/sys/entities/store/mod.rs +++ b/lib/api/src/backend/sys/entities/store/mod.rs @@ -1,8 +1,8 @@ //! Data types, functions and traits for `sys` runtime's `Store` implementation. -use crate::entities::engine::{AsEngineRef, Engine, EngineRef}; use crate::BackendStore; -use wasmer_vm::init_traps; +use crate::entities::engine::{AsEngineRef, Engine, EngineRef}; use wasmer_vm::TrapHandlerFn; +use wasmer_vm::init_traps; pub use wasmer_vm::{StoreHandle, StoreObjects}; mod obj; @@ -70,18 +70,6 @@ impl NativeStoreExt for Store { } } -impl NativeStoreExt for crate::Store { - fn set_trap_handler(&mut self, handler: Option>>) { - self.inner.store.as_sys_mut().set_trap_handler(handler) - } - - /// The signal handler - #[inline] - fn signal_handler(&self) -> Option<*const TrapHandlerFn<'static>> { - self.inner.store.as_sys().signal_handler() - } -} - impl crate::BackendStore { /// Consume [`self`] into [`crate::backend::sys::store::Store`]. pub fn into_sys(self) -> crate::backend::sys::store::Store { @@ -111,25 +99,3 @@ impl crate::BackendStore { matches!(self, Self::Sys(_)) } } - -impl crate::Store { - /// Consume [`self`] into [`crate::backend::sys::store::Store`]. - pub(crate) fn into_sys(self) -> crate::backend::sys::store::Store { - self.inner.store.into_sys() - } - - /// Convert a reference to [`self`] into a reference [`crate::backend::sys::store::Store`]. - pub(crate) fn as_sys(&self) -> &crate::backend::sys::store::Store { - self.inner.store.as_sys() - } - - /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::sys::store::Store`]. - pub(crate) fn as_sys_mut(&mut self) -> &mut crate::backend::sys::store::Store { - self.inner.store.as_sys_mut() - } - - /// Return true if [`self`] is a store from the `sys` runtime. - pub fn is_sys(&self) -> bool { - self.inner.store.is_sys() - } -} diff --git a/lib/api/src/backend/sys/entities/store/obj.rs b/lib/api/src/backend/sys/entities/store/obj.rs index ba90370dc1..0bb27b8967 100644 --- a/lib/api/src/backend/sys/entities/store/obj.rs +++ b/lib/api/src/backend/sys/entities/store/obj.rs @@ -27,50 +27,3 @@ impl crate::StoreObjects { } } } - -//pub trait GetStoreObjects { -// /// Return a mutable reference to [`wasmer_vm::StoreObjects`] and a reference to the current -// /// engine. -// fn engine_and_objects_mut( -// &mut self, -// ) -> (&crate::Engine, &mut crate::backend::sys::store::StoreObjects); -// -// /// Return a mutable reference to [`wasmer_vm::StoreObjects`]. -// fn objects_mut(&mut self) -> &mut crate::backend::sys::store::StoreObjects; -//} -// -//impl GetStoreObjects for crate::StoreInner { -// fn objects_mut(&mut self) -> &mut crate::backend::sys::store::StoreObjects { -// self.objects.as_sys_mut() -// } -// -// fn engine_and_objects_mut( -// &mut self, -// ) -> (&crate::Engine, &mut crate::backend::sys::store::StoreObjects) { -// match (&mut self.objects, &self.store) { -// (crate::StoreObjects::Sys(o), crate::BackendStore::Sys(s)) => (&s.engine, o), -// _ => panic!("Not a `sys` store!"), -// } -// } -//} -// -//impl GetStoreObjects for T { -// fn objects_mut<'a>(&'a mut self) -> &'a mut crate::backend::sys::store::StoreObjects { -// match self.as_store_mut().inner.objects { -// crate::StoreObjects::Sys(ref mut s) => s, -// _ => panic!("Not a `sys` store!"), -// } -// } -// -// fn engine_and_objects_mut( -// &mut self, -// ) -> (&crate::Engine, &mut crate::backend::sys::store::StoreObjects) { -// let mut store = self.as_store_mut(); -// match (&mut store.inner.objects, &store.inner.store) { -// (crate::StoreObjects::Sys(ref mut o), crate::BackendStore::Sys(ref s)) => { -// (&s.engine, o) -// } -// _ => panic!("Not a `sys` store!"), -// } -// } -//} diff --git a/lib/api/src/backend/sys/entities/table.rs b/lib/api/src/backend/sys/entities/table.rs index 6888da892d..88cd08ae0d 100644 --- a/lib/api/src/backend/sys/entities/table.rs +++ b/lib/api/src/backend/sys/entities/table.rs @@ -1,10 +1,10 @@ //! Data types, functions and traits for `sys` runtime's `Table` implementation. use crate::{ + BackendTable, ExternRef, Function, Value, backend::sys::entities::engine::NativeEngineExt, entities::store::{AsStoreMut, AsStoreRef}, error::RuntimeError, vm::{VMExtern, VMExternTable}, - BackendTable, ExternRef, Function, Value, }; use wasmer_types::TableType; use wasmer_vm::{StoreHandle, TableElement, Trap, VMTable}; @@ -199,16 +199,16 @@ impl crate::Table { /// Convert a reference to [`self`] into a reference [`crate::backend::sys::table::Table`]. pub fn as_sys(&self) -> &crate::backend::sys::table::Table { - match self.0 { - BackendTable::Sys(ref s) => s, + match &self.0 { + BackendTable::Sys(s) => s, _ => panic!("Not a `sys` table!"), } } /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::sys::table::Table`]. pub fn as_sys_mut(&mut self) -> &mut crate::backend::sys::table::Table { - match self.0 { - BackendTable::Sys(ref mut s) => s, + match &mut self.0 { + BackendTable::Sys(s) => s, _ => panic!("Not a `sys` table!"), } } @@ -226,7 +226,7 @@ impl crate::BackendTable { /// Convert a reference to [`self`] into a reference [`crate::backend::sys::table::Table`]. pub fn as_sys(&self) -> &crate::backend::sys::table::Table { match self { - Self::Sys(ref s) => s, + Self::Sys(s) => s, _ => panic!("Not a `sys` table!"), } } @@ -234,7 +234,7 @@ impl crate::BackendTable { /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::sys::table::Table`]. pub fn as_sys_mut(&mut self) -> &mut crate::backend::sys::table::Table { match self { - Self::Sys(ref mut s) => s, + Self::Sys(s) => s, _ => panic!("Not a `sys` table!"), } } diff --git a/lib/api/src/backend/sys/entities/tag.rs b/lib/api/src/backend/sys/entities/tag.rs index 8f1de9b06a..5845251343 100644 --- a/lib/api/src/backend/sys/entities/tag.rs +++ b/lib/api/src/backend/sys/entities/tag.rs @@ -3,9 +3,9 @@ use wasmer_types::{FunctionType, TagType, Type}; use wasmer_vm::StoreHandle; use crate::{ + AsStoreMut, AsStoreRef, sys::vm::VMTag, vm::{VMExtern, VMExternTag}, - AsStoreMut, AsStoreRef, }; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/lib/api/src/backend/sys/error.rs b/lib/api/src/backend/sys/error.rs index e8ced176cd..950c7b021d 100644 --- a/lib/api/src/backend/sys/error.rs +++ b/lib/api/src/backend/sys/error.rs @@ -1,5 +1,5 @@ use crate::LinkError; -use wasmer_vm::Trap; +use wasmer_vm::{Trap, VMExceptionRef}; impl From for LinkError { fn from(other: wasmer_compiler::LinkError) -> Self { diff --git a/lib/api/src/backend/sys/mod.rs b/lib/api/src/backend/sys/mod.rs index ab009c0dc2..4e8ea874b7 100644 --- a/lib/api/src/backend/sys/mod.rs +++ b/lib/api/src/backend/sys/mod.rs @@ -1,5 +1,7 @@ //! Data types, functions and traits for the `sys` runtime. +#[cfg(feature = "experimental-async")] +pub(crate) mod async_runtime; pub(crate) mod entities; pub(crate) mod error; pub(crate) mod tunables; @@ -11,17 +13,17 @@ pub use tunables::*; #[cfg(feature = "compiler")] pub use wasmer_compiler::{ - wasmparser, CompilerConfig, FunctionMiddleware, MiddlewareReaderState, ModuleMiddleware, + CompilerConfig, FunctionMiddleware, MiddlewareReaderState, ModuleMiddleware, wasmparser, }; pub use wasmer_compiler::{Artifact, EngineBuilder, Features, Tunables}; -pub use wasmer_types::target::{Architecture, CpuFeature, OperatingSystem, Target, Triple}; pub use wasmer_types::MiddlewareError; +pub use wasmer_types::target::{Architecture, CpuFeature, OperatingSystem, Target, Triple}; #[cfg(feature = "cranelift")] pub use wasmer_compiler_cranelift::{Cranelift, CraneliftOptLevel}; #[cfg(feature = "llvm")] -pub use wasmer_compiler_llvm::{LLVMOptLevel, LLVM}; +pub use wasmer_compiler_llvm::{LLVM, LLVMOptLevel}; #[cfg(feature = "singlepass")] pub use wasmer_compiler_singlepass::Singlepass; diff --git a/lib/api/src/backend/sys/tunables.rs b/lib/api/src/backend/sys/tunables.rs index 018ee72b0a..232de0c60a 100644 --- a/lib/api/src/backend/sys/tunables.rs +++ b/lib/api/src/backend/sys/tunables.rs @@ -6,9 +6,9 @@ pub use wasmer_compiler::BaseTunables; #[cfg(test)] mod tests { use super::*; + use crate::TableType; #[allow(unused)] use crate::sys::NativeEngineExt; - use crate::TableType; use std::cell::UnsafeCell; use std::ptr::NonNull; use wasmer_compiler::Tunables; @@ -198,9 +198,9 @@ mod tests { let memory = VMTinyMemory::new().unwrap(); // now, it's important to update vm_definition_location with the memory information! let mut ptr = vm_definition_location; - let md = ptr.as_mut(); + let md = unsafe { ptr.as_mut() }; let unsafecell = memory.memory_definition.as_ref().unwrap(); - let def = unsafecell.get().as_ref().unwrap(); + let def = unsafe { unsafecell.get().as_ref().unwrap() }; md.base = def.base; md.current_length = def.current_length; Ok(memory.into()) @@ -221,7 +221,7 @@ mod tests { style: &TableStyle, vm_definition_location: NonNull, ) -> Result { - VMTable::from_definition(ty, style, vm_definition_location) + unsafe { VMTable::from_definition(ty, style, vm_definition_location) } } // Will use a minimum stack size of 8kb, not the 1Mb default @@ -258,7 +258,7 @@ mod tests { fn check_custom_tunables() -> Result<(), Box> { #[cfg(feature = "wat")] use crate::wat2wasm; - use crate::{imports, Engine, Instance, Memory, Module, Store}; + use crate::{Engine, Instance, Memory, Module, Store, imports}; let wasm_bytes = wat2wasm( br#"(module @@ -315,7 +315,7 @@ mod tests { ))] #[allow(clippy::print_stdout)] fn check_small_stack() -> Result<(), Box> { - use crate::{imports, wat2wasm, Engine, Instance, Module, Store}; + use crate::{Engine, Instance, Module, Store, imports, wat2wasm}; use wasmer_compiler_singlepass::Singlepass; // This test needs Singlepass compiler // because Cranelift will optimize the webassembly file diff --git a/lib/api/src/backend/sys/vm.rs b/lib/api/src/backend/sys/vm.rs index ee1816d0f8..6e13d34a26 100644 --- a/lib/api/src/backend/sys/vm.rs +++ b/lib/api/src/backend/sys/vm.rs @@ -3,9 +3,6 @@ use crate::entities::{Function, Global, Memory, Table, Tag}; use crate::store::AsStoreMut; pub use wasmer_vm::*; -// No EH for now. -pub(crate) type VMException = (); - /// The type of extern tables in the `sys` VM. pub type VMExternTable = InternalStoreHandle; /// diff --git a/lib/api/src/backend/v8/entities/engine.rs b/lib/api/src/backend/v8/entities/engine.rs index 5e5e44de7c..73acd9b2a3 100644 --- a/lib/api/src/backend/v8/entities/engine.rs +++ b/lib/api/src/backend/v8/entities/engine.rs @@ -1,10 +1,10 @@ //! Data types, functions and traits for `sys` runtime's `Engine` implementation. use crate::{ - backend::v8::bindings::{wasm_engine_delete, wasm_engine_new, wasm_engine_t}, BackendEngine, + backend::v8::bindings::{wasm_engine_delete, wasm_engine_new, wasm_engine_t}, }; use std::sync::Arc; -use wasmer_types::{target::Target, Features}; +use wasmer_types::{Features, target::Target}; // A handle to an engine, which we want to unsafely mark as Sync. struct EngineCapsule(*mut wasm_engine_t); @@ -114,9 +114,9 @@ impl crate::Engine { impl From for crate::Engine { fn from(value: Engine) -> Self { - crate::Engine { + Self { be: BackendEngine::V8(value), - id: crate::Engine::atomic_next_engine_id(), + id: Self::atomic_next_engine_id(), } } } diff --git a/lib/api/src/backend/v8/entities/exception.rs b/lib/api/src/backend/v8/entities/exception.rs index 7923ab57c9..2a11939501 100644 --- a/lib/api/src/backend/v8/entities/exception.rs +++ b/lib/api/src/backend/v8/entities/exception.rs @@ -4,8 +4,8 @@ use std::any::Any; use wasmer_types::{TagType, Type}; use crate::{ - v8::vm::{VMException, VMExceptionRef}, AsStoreMut, AsStoreRef, Tag, Value, + v8::vm::{VMException, VMExceptionRef}, }; use super::store::StoreHandle; @@ -22,42 +22,6 @@ unsafe impl Sync for Exception {} impl Exception { /// Create a new [`Exception`]. pub fn new(store: &mut impl AsStoreMut, tag: Tag, payload: &[Value]) -> Self { - todo!() - } -} - -#[derive(Debug, Clone)] -#[repr(transparent)] -/// A WebAssembly `extern ref` in `v8`. -pub(crate) struct ExceptionRef; - -impl ExceptionRef { - pub fn new(_store: &mut impl AsStoreMut, _value: T) -> Self - where - T: Any + Send + Sync + 'static + Sized, - { - unimplemented!("ExceptionRef is not yet supported in v8"); - } - - pub fn downcast<'a, T>(&self, _store: &'a impl AsStoreRef) -> Option<&'a T> - where - T: Any + Send + Sync + 'static + Sized, - { - unimplemented!("ExceptionRef is not yet supported in v8"); - } - - pub(crate) fn vm_exceptionref(&self) -> VMExceptionRef { - unimplemented!("ExceptionRef is not yet supported in v8"); - } - - pub(crate) unsafe fn from_vm_exceptionref( - _store: &mut impl AsStoreMut, - _vm_exceptionref: VMExceptionRef, - ) -> Self { - unimplemented!("ExceptionRef is not yet supported in v8"); - } - - pub fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { - true + unimplemented!("Exception handling is not yet supported in v8"); } } diff --git a/lib/api/src/backend/v8/entities/function/env.rs b/lib/api/src/backend/v8/entities/function/env.rs index efaf1ab7a2..cff3675a38 100644 --- a/lib/api/src/backend/v8/entities/function/env.rs +++ b/lib/api/src/backend/v8/entities/function/env.rs @@ -1,9 +1,9 @@ use std::{any::Any, fmt::Debug, marker::PhantomData}; use crate::{ + StoreMut, store::{AsStoreMut, AsStoreRef, StoreRef}, v8::{store::StoreHandle, vm::VMFunctionEnvironment}, - StoreMut, }; #[derive(Debug)] @@ -62,7 +62,7 @@ impl FunctionEnv { } /// Convert it into a `FunctionEnvMut` - pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut + pub fn into_mut<'a>(self, store: &'a mut impl AsStoreMut) -> FunctionEnvMut<'a, T> where T: Any + Send + 'static + Sized, { @@ -137,7 +137,7 @@ impl FunctionEnvMut<'_, T> { } /// Borrows a new mutable reference of both the attached Store and host state - pub fn data_and_store_mut(&mut self) -> (&mut T, StoreMut) { + pub fn data_and_store_mut<'a>(&'a mut self) -> (&'a mut T, StoreMut<'a>) { let data = self.func_env.as_mut(&mut self.store_mut) as *mut T; // telling the borrow check to close his eyes here // this is still relatively safe to do as func_env are @@ -208,6 +208,6 @@ impl<'a, T> From> for crate::FunctionEnvMut<'a, T> { impl From> for crate::FunctionEnv { fn from(value: FunctionEnv) -> Self { - crate::FunctionEnv(crate::BackendFunctionEnv::V8(value)) + Self(crate::BackendFunctionEnv::V8(value)) } } diff --git a/lib/api/src/backend/v8/entities/function/mod.rs b/lib/api/src/backend/v8/entities/function/mod.rs index 67278428d3..fd5fe497e6 100644 --- a/lib/api/src/backend/v8/entities/function/mod.rs +++ b/lib/api/src/backend/v8/entities/function/mod.rs @@ -6,15 +6,15 @@ use std::{ }; use crate::{ + AsStoreMut, AsStoreRef, BackendFunction, BackendFunctionEnvMut, BackendTrap, + FromToNativeWasmType, FunctionEnv, FunctionEnvMut, IntoResult, NativeWasmType, + NativeWasmTypeInto, RuntimeError, StoreMut, Value, WasmTypeList, WithEnv, WithoutEnv, v8::{ bindings::*, utils::convert::{IntoCApiType, IntoCApiValue, IntoWasmerType, IntoWasmerValue}, vm::{VMFuncRef, VMFunction, VMFunctionCallback, VMFunctionEnvironment}, }, vm::{VMExtern, VMExternFunction}, - AsStoreMut, AsStoreRef, BackendFunction, BackendFunctionEnvMut, BackendTrap, - FromToNativeWasmType, FunctionEnv, FunctionEnvMut, IntoResult, NativeWasmType, - NativeWasmTypeInto, RuntimeError, StoreMut, Value, WasmTypeList, WithEnv, WithoutEnv, }; use super::{super::error::Trap, check_isolate, store::StoreHandle}; @@ -91,9 +91,9 @@ impl Function { let params = fn_ty.params(); let mut param_types = params - .into_iter() + .iter() .map(|param| { - let kind = param.into_ct(); + let kind = (*param).into_ct(); unsafe { wasm_valtype_new(kind) } }) .collect::>(); @@ -106,9 +106,9 @@ impl Function { let results = fn_ty.results(); let mut result_types = results - .into_iter() + .iter() .map(|param| { - let kind = param.into_ct(); + let kind = (*param).into_ct(); unsafe { wasm_valtype_new(kind) } }) .collect::>(); @@ -152,7 +152,7 @@ impl Function { panic!("failed when creating new typed function"); } - Function { + Self { handle: wasm_function, } } @@ -166,9 +166,9 @@ impl Function { { check_isolate(store); let mut param_types = Args::wasm_types() - .into_iter() + .iter() .map(|param| { - let kind = param.into_ct(); + let kind = (*param).into_ct(); unsafe { wasm_valtype_new(kind) } }) .collect::>(); @@ -180,9 +180,9 @@ impl Function { }; let mut result_types = Rets::wasm_types() - .into_iter() + .iter() .map(|param| { - let kind = param.into_ct(); + let kind = (*param).into_ct(); unsafe { wasm_valtype_new(kind) } }) .collect::>(); @@ -224,7 +224,7 @@ impl Function { panic!("failed when creating new typed function"); } - Function { + Self { handle: wasm_function, } } @@ -242,9 +242,9 @@ impl Function { { check_isolate(store); let mut param_types = Args::wasm_types() - .into_iter() + .iter() .map(|param| { - let kind = param.into_ct(); + let kind = (*param).into_ct(); unsafe { wasm_valtype_new(kind) } }) .collect::>(); @@ -256,9 +256,9 @@ impl Function { }; let mut result_types = Rets::wasm_types() - .into_iter() + .iter() .map(|param| { - let kind = param.into_ct(); + let kind = (*param).into_ct(); unsafe { wasm_valtype_new(kind) } }) .collect::>(); @@ -304,7 +304,7 @@ impl Function { panic!("failed when creating new typed function"); } - Function { + Self { handle: wasm_function, } } @@ -355,17 +355,15 @@ impl Function { let store_mut = store.as_store_mut(); // let wasm_func_param_arity(self.handle) - let mut args = { - unsafe { - let mut wasm_params = params - .into_iter() - .map(|v| IntoCApiValue::into_cv(v.clone())) - .collect::>() - .into_boxed_slice(); - let mut vec = Default::default(); - wasm_val_vec_new(&mut vec, wasm_params.len(), wasm_params.as_ptr()); - vec - } + let mut args = unsafe { + let mut wasm_params = params + .iter() + .map(|v| IntoCApiValue::into_cv(v.clone())) + .collect::>() + .into_boxed_slice(); + let mut vec = Default::default(); + wasm_val_vec_new(&mut vec, wasm_params.len(), wasm_params.as_ptr()); + vec }; let size = unsafe { wasm_func_result_arity(self.handle) }; @@ -392,7 +390,7 @@ impl Function { break; } Ok(wasmer_types::OnCalledAction::Trap(trap)) => { - return Err(RuntimeError::user(trap)) + return Err(RuntimeError::user(trap)); } Err(trap) => return Err(RuntimeError::user(trap)), } @@ -404,14 +402,15 @@ impl Function { return Err(Into::::into(trap).into()); } - unsafe { + let values = unsafe { let results = std::ptr::slice_from_raw_parts(results.data, results.size); - return Ok((*results) - .into_iter() + (*results) + .iter() .map(|v| IntoWasmerValue::into_wv(*v)) .collect::>() - .into_boxed_slice()); - } + .into_boxed_slice() + }; + Ok(values) } pub(crate) fn from_vm_extern(_store: &mut impl AsStoreMut, internal: VMExternFunction) -> Self { @@ -457,15 +456,18 @@ where { let r: *mut (FunctionCallbackEnv<'_, F>) = env as _; - let mut store = (*r).store.as_store_mut(); - let env_handle = (*r).env_handle.as_ref().unwrap().clone(); + let mut store = unsafe { (*r).store.as_store_mut() }; + let env_handle = unsafe { (*r).env_handle.as_ref().unwrap().clone() }; let mut fn_env = env::FunctionEnv::from_handle(env_handle).into_mut(&mut store); - let func: &F = &(*r).func; + let func: &F = unsafe { &(*r).func }; let mut wasmer_args = vec![]; + let args_ptr = unsafe { (*args).data }; + let args_len = unsafe { (*args).size }; - for i in 0..(*args).size { - wasmer_args.push((*(*args).data.wrapping_add(i)).into_wv().clone()); + for i in 0..args_len { + let value = unsafe { (*args_ptr.wrapping_add(i)).into_wv().clone() }; + wasmer_args.push(value); } let result = panic::catch_unwind(AssertUnwindSafe(|| unsafe { @@ -479,13 +481,18 @@ where .map(IntoCApiValue::into_cv) .collect(); - if c_results.len() != (*rets).size { - panic!("when calling host function: number of observed results differ from wanted results") + let rets_size = unsafe { (*rets).size }; + if c_results.len() != rets_size { + panic!( + "when calling host function: number of observed results differ from wanted results" + ) } + let rets_ptr = unsafe { (*rets).data }; unsafe { - for i in 0..(*rets).size { - *((*rets).data.wrapping_add(i)) = c_results[i] + let rets_slice = std::slice::from_raw_parts_mut(rets_ptr, rets_size); + for (dst, value) in rets_slice.iter_mut().zip(&c_results) { + *dst = *value; } } @@ -503,7 +510,7 @@ where } } - return fn_callback::; + fn_callback:: } impl std::fmt::Debug for Function { @@ -555,7 +562,7 @@ macro_rules! impl_host_function { Rets: WasmTypeList, RetsAsResult: IntoResult, Func: Fn($( $x , )*) -> RetsAsResult + 'static, - { + { unsafe { let mut r: *mut crate::backend::v8::function::FunctionCallbackEnv = unsafe {std::mem::transmute(env)}; let store = &mut (*r).store.as_store_mut(); let mut i = 0; @@ -609,7 +616,7 @@ macro_rules! impl_host_function { unimplemented!("host function panicked"); } } - } + }} func_wrapper::< $( $x, )* Rets, RetsAsResult, Func> as _ } @@ -625,7 +632,7 @@ macro_rules! impl_host_function { RetsAsResult: IntoResult, T: Send + 'static, Func: Fn(FunctionEnvMut<'_, T>, $( $x , )*) -> RetsAsResult + 'static, - { + { unsafe { let r: *mut (crate::backend::v8::function::FunctionCallbackEnv<'_, Func>) = env as _; let store = &mut (*r).store.as_store_mut(); @@ -678,7 +685,7 @@ macro_rules! impl_host_function { Err(e) => { unimplemented!("host function panicked"); } } - } + }} func_wrapper::< $( $x, )* Rets, RetsAsResult, Func, T> as _ } diff --git a/lib/api/src/backend/v8/entities/function/typed.rs b/lib/api/src/backend/v8/entities/function/typed.rs index ffbe1e9a97..092b8c7316 100644 --- a/lib/api/src/backend/v8/entities/function/typed.rs +++ b/lib/api/src/backend/v8/entities/function/typed.rs @@ -11,9 +11,9 @@ use std::iter::FromIterator; use crate::{ - backend::v8::{bindings::*, error::Trap, function::Function, utils::convert::*}, AsStoreMut, FromToNativeWasmType, NativeWasmType, NativeWasmTypeInto, RuntimeError, TypedFunction, Value, WasmTypeList, + backend::v8::{bindings::*, error::Trap, function::Function, utils::convert::*}, }; use wasmer_types::RawValue; @@ -133,9 +133,15 @@ impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15 +); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16 +); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17 +); impl_native_traits!( A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18 ); diff --git a/lib/api/src/backend/v8/entities/global.rs b/lib/api/src/backend/v8/entities/global.rs index 796047081e..35a80fb853 100644 --- a/lib/api/src/backend/v8/entities/global.rs +++ b/lib/api/src/backend/v8/entities/global.rs @@ -2,6 +2,7 @@ use wasmer_types::{GlobalType, Mutability}; use crate::{ + AsStoreMut, AsStoreRef, RuntimeError, Value, v8::{ bindings::{ self, wasm_global_as_extern, wasm_global_get, wasm_global_new, wasm_global_set, @@ -12,7 +13,6 @@ use crate::{ vm::VMGlobal, }, vm::{VMExtern, VMExternGlobal}, - AsStoreMut, AsStoreRef, RuntimeError, Value, }; use super::check_isolate; diff --git a/lib/api/src/backend/v8/entities/instance.rs b/lib/api/src/backend/v8/entities/instance.rs index 3d337a6447..02afbfb94f 100644 --- a/lib/api/src/backend/v8/entities/instance.rs +++ b/lib/api/src/backend/v8/entities/instance.rs @@ -2,8 +2,8 @@ use std::sync::Arc; use crate::{ - backend::v8::bindings::*, v8::error::Trap, vm::VMExtern, AsStoreMut, AsStoreRef, Exports, - Extern, Imports, InstantiationError, Module, + AsStoreMut, AsStoreRef, Exports, Extern, Imports, InstantiationError, Module, + backend::v8::bindings::*, v8::error::Trap, vm::VMExtern, }; use super::check_isolate; @@ -15,6 +15,7 @@ unsafe impl Send for InstanceHandle {} unsafe impl Sync for InstanceHandle {} impl InstanceHandle { + #[allow(clippy::result_large_err, clippy::unnecessary_mut_passed)] fn new( store: *mut wasm_store_t, module: *mut wasm_shared_module_t, @@ -46,7 +47,7 @@ impl InstanceHandle { return Err(InstantiationError::Start(trap.into())); } - Ok(InstanceHandle(instance)) + Ok(Self(instance)) } fn get_exports(&self, mut store: &mut impl AsStoreMut, module: &Module) -> Exports { @@ -61,20 +62,19 @@ impl InstanceHandle { unsafe { std::slice::from_raw_parts(exports.data, exports.size) }; let exports_ty = module.exports().collect::>(); - let exports = exports_ty + exports_ty .iter() - .zip(wasm_exports.into_iter()) + .zip(wasm_exports.iter()) .map(|(export_type, wasm_export)| { let name = export_type.name(); let mut store = store.as_store_mut(); - let extern_type = export_type.ty(); + let _extern_type = export_type.ty(); // Annotation is here to prevent spurious IDE warnings. let extern_ = Extern::from_vm_extern(&mut store, VMExtern::V8(*wasm_export)); (name.to_string(), extern_) }) - .collect::(); - exports + .collect::() } } impl Drop for InstanceHandle { @@ -90,6 +90,7 @@ pub struct Instance { } impl Instance { + #[allow(clippy::result_large_err)] pub(crate) fn new( store: &mut impl AsStoreMut, module: &Module, @@ -98,18 +99,19 @@ impl Instance { check_isolate(store); let mut store = store.as_store_mut(); - let externs = module + let externs: Vec<_> = module .imports() .map(|import_ty| { imports .get_export(import_ty.module(), import_ty.name()) - .expect(format!("Export {import_ty:?} not found").as_str()) + .unwrap_or_else(|| panic!("Export {import_ty:?} not found")) }) .collect::>(); - return Self::new_by_index(&mut store, module, &externs); + Self::new_by_index(&mut store, module, &externs) } + #[allow(clippy::result_large_err)] pub(crate) fn new_by_index( store: &mut impl AsStoreMut, module: &Module, diff --git a/lib/api/src/backend/v8/entities/memory/mod.rs b/lib/api/src/backend/v8/entities/memory/mod.rs index c78874df5d..d73bc99f04 100644 --- a/lib/api/src/backend/v8/entities/memory/mod.rs +++ b/lib/api/src/backend/v8/entities/memory/mod.rs @@ -6,10 +6,10 @@ pub use wasmer_types::MemoryError; use wasmer_types::{MemoryType, Pages, WASM_PAGE_SIZE}; use crate::{ + AsStoreMut, AsStoreRef, BackendMemory, MemoryAccessError, shared::SharedMemory, v8::{bindings::*, vm::VMMemory}, vm::{VMExtern, VMExternMemory}, - AsStoreMut, AsStoreRef, BackendMemory, MemoryAccessError, }; pub(crate) mod view; @@ -188,7 +188,7 @@ impl Memory { /// can be put into a new store pub fn try_clone(&self, store: &impl AsStoreRef) -> Result { check_isolate(store); - Ok(self.handle.clone()) + Ok(self.handle) } /// Copying the memory will actually copy all the bytes in the memory to @@ -319,26 +319,36 @@ impl<'a> MemoryBuffer<'a> { unsafe fn volatile_memcpy_read(mut src: *const u8, mut dst: *mut u8, mut len: usize) { #[inline] unsafe fn copy_one(src: &mut *const u8, dst: &mut *mut u8, len: &mut usize) { - #[repr(packed)] + #[repr(C, packed)] struct Unaligned(T); - let val = (*src as *const Unaligned).read_volatile(); - (*dst as *mut Unaligned).write(val); - *src = src.add(std::mem::size_of::()); - *dst = dst.add(std::mem::size_of::()); - *len -= std::mem::size_of::(); + unsafe { + let val = (*src as *const Unaligned).read_volatile(); + (*dst as *mut Unaligned).write(val); + *src = src.add(std::mem::size_of::()); + *dst = dst.add(std::mem::size_of::()); + *len -= std::mem::size_of::(); + } } while len >= 8 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { + copy_one::(&mut src, &mut dst, &mut len); + } } if len >= 4 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { + copy_one::(&mut src, &mut dst, &mut len); + } } if len >= 2 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { + copy_one::(&mut src, &mut dst, &mut len); + } } if len >= 1 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { + copy_one::(&mut src, &mut dst, &mut len); + } } } @@ -346,26 +356,36 @@ unsafe fn volatile_memcpy_read(mut src: *const u8, mut dst: *mut u8, mut len: us unsafe fn volatile_memcpy_write(mut src: *const u8, mut dst: *mut u8, mut len: usize) { #[inline] unsafe fn copy_one(src: &mut *const u8, dst: &mut *mut u8, len: &mut usize) { - #[repr(packed)] + #[repr(C, packed)] struct Unaligned(T); - let val = (*src as *const Unaligned).read(); - (*dst as *mut Unaligned).write_volatile(val); - *src = src.add(std::mem::size_of::()); - *dst = dst.add(std::mem::size_of::()); - *len -= std::mem::size_of::(); + unsafe { + let val = (*src as *const Unaligned).read(); + (*dst as *mut Unaligned).write_volatile(val); + *src = src.add(std::mem::size_of::()); + *dst = dst.add(std::mem::size_of::()); + *len -= std::mem::size_of::(); + } } while len >= 8 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { + copy_one::(&mut src, &mut dst, &mut len); + } } if len >= 4 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { + copy_one::(&mut src, &mut dst, &mut len); + } } if len >= 2 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { + copy_one::(&mut src, &mut dst, &mut len); + } } if len >= 1 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { + copy_one::(&mut src, &mut dst, &mut len); + } } } diff --git a/lib/api/src/backend/v8/entities/memory/view.rs b/lib/api/src/backend/v8/entities/memory/view.rs index a4be3e93ed..3d516c178c 100644 --- a/lib/api/src/backend/v8/entities/memory/view.rs +++ b/lib/api/src/backend/v8/entities/memory/view.rs @@ -4,9 +4,9 @@ use wasmer_types::Pages; use super::{Memory, MemoryBuffer}; use crate::{ + AsStoreRef, MemoryAccessError, backend::v8::bindings::{wasm_memory_data, wasm_memory_data_size, wasm_memory_size}, v8::bindings::wasm_memory_t, - AsStoreRef, MemoryAccessError, }; /// A WebAssembly `memory` view. @@ -25,7 +25,7 @@ impl<'a> MemoryView<'a> { pub(crate) fn new(memory: &Memory, store: &'a (impl AsStoreRef + ?Sized)) -> Self { let c_memory: *mut wasm_memory_t = memory.handle; - let len = unsafe { wasm_memory_data_size(c_memory as _).try_into().unwrap() }; + let len = unsafe { wasm_memory_data_size(c_memory as _) }; let base: *mut u8 = unsafe { wasm_memory_data(c_memory as _) as _ }; let size = unsafe { wasm_memory_size(c_memory as _) }; @@ -62,7 +62,7 @@ impl<'a> MemoryView<'a> { /// function that writes to the memory or by resizing the memory. #[doc(hidden)] pub unsafe fn data_unchecked(&self) -> &[u8] { - self.data_unchecked_mut() + unsafe { self.data_unchecked_mut() } } /// Retrieve a mutable slice of the memory contents. @@ -77,7 +77,7 @@ impl<'a> MemoryView<'a> { #[allow(clippy::mut_from_ref)] #[doc(hidden)] pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] { - std::slice::from_raw_parts_mut(self.buffer.base, self.buffer.len) + unsafe { std::slice::from_raw_parts_mut(self.buffer.base, self.buffer.len) } } /// Returns the size (in [`Pages`]) of the `Memory`. diff --git a/lib/api/src/backend/v8/entities/mod.rs b/lib/api/src/backend/v8/entities/mod.rs index 9cb3801d8c..d2e8801def 100644 --- a/lib/api/src/backend/v8/entities/mod.rs +++ b/lib/api/src/backend/v8/entities/mod.rs @@ -10,11 +10,13 @@ pub(crate) mod store; pub(crate) mod table; pub(crate) mod tag; -pub(self) fn check_isolate(store: &impl crate::AsStoreRef) { +fn check_isolate(store: &impl crate::AsStoreRef) { let store = store.as_store_ref(); let v8_store = store.inner.store.as_v8(); if v8_store.thread_id != std::thread::current().id() { - panic!("Fatal error (v8): current thread is different from the thread the store was created in!"); + panic!( + "Fatal error (v8): current thread is different from the thread the store was created in!" + ); } } diff --git a/lib/api/src/backend/v8/entities/module.rs b/lib/api/src/backend/v8/entities/module.rs index 6a965dad43..87db4d5332 100644 --- a/lib/api/src/backend/v8/entities/module.rs +++ b/lib/api/src/backend/v8/entities/module.rs @@ -2,8 +2,8 @@ use std::{path::Path, sync::Arc}; use crate::{ - backend::v8::bindings::*, v8::utils::convert::IntoWasmerExternType, AsEngineRef, BackendModule, - IntoBytes, Store, + AsEngineRef, BackendModule, IntoBytes, Store, backend::v8::bindings::*, + v8::utils::convert::IntoWasmerExternType, }; use bytes::Bytes; @@ -49,20 +49,20 @@ impl ModuleHandle { let inner = unsafe { wasm_module_new(store.as_v8().inner, &bytes as *const _) }; if inner.is_null() { - return Err(CompileError::Validate(format!( - "Failed to create V8 module: null module reference returned from V8" - ))); + return Err(CompileError::Validate( + "Failed to create V8 module: null module reference returned from V8".to_string(), + )); } let inner = unsafe { wasm_module_share(inner) }; if inner.is_null() { - return Err(CompileError::Validate(format!( - "Failed to create V8 module: null module reference returned from V8" - ))); + return Err(CompileError::Validate( + "Failed to create V8 module: null module reference returned from V8".to_string(), + )); } - Ok(ModuleHandle { + Ok(Self { v8_shared_module_handle: inner, orig_store: store, }) @@ -78,20 +78,21 @@ impl ModuleHandle { let store = Store::new(engine.clone()); let inner = unsafe { wasm_module_deserialize(store.as_v8().inner, &bytes as *const _) }; if inner.is_null() { - return Err(CompileError::Validate(format!( + return Err(CompileError::Validate( "Failed to deserialize V8 module: null module reference returned from V8" - ))); + .to_string(), + )); } let inner = unsafe { wasm_module_share(inner) }; if inner.is_null() { - return Err(CompileError::Validate(format!( - "Failed to create V8 module: null module reference returned from V8" - ))); + return Err(CompileError::Validate( + "Failed to create V8 module: null module reference returned from V8".to_string(), + )); } - Ok(ModuleHandle { + Ok(Self { v8_shared_module_handle: inner, orig_store: store, }) @@ -151,6 +152,7 @@ impl Module { unsafe { Self::from_binary_unchecked(engine, binary) } } + #[allow(clippy::arc_with_non_send_sync)] #[tracing::instrument(skip(engine, binary))] pub(crate) unsafe fn from_binary_unchecked( engine: &impl AsEngineRef, @@ -212,6 +214,7 @@ impl Module { Ok(data.into()) } + #[allow(clippy::arc_with_non_send_sync)] pub unsafe fn deserialize_unchecked( engine: &impl AsEngineRef, bytes: impl IntoBytes, @@ -235,7 +238,7 @@ impl Module { engine: &impl AsEngineRef, bytes: impl IntoBytes, ) -> Result { - Self::deserialize_unchecked(engine, bytes) + unsafe { Self::deserialize_unchecked(engine, bytes) } } pub unsafe fn deserialize_from_file_unchecked( @@ -243,7 +246,7 @@ impl Module { path: impl AsRef, ) -> Result { let bytes = std::fs::read(path.as_ref())?; - Self::deserialize_unchecked(engine, bytes) + unsafe { Self::deserialize_unchecked(engine, bytes) } } pub unsafe fn deserialize_from_file( @@ -251,7 +254,7 @@ impl Module { path: impl AsRef, ) -> Result { let bytes = std::fs::read(path.as_ref())?; - Self::deserialize(engine, bytes) + unsafe { Self::deserialize(engine, bytes) } } pub fn set_name(&mut self, name: &str) -> bool { diff --git a/lib/api/src/backend/v8/entities/store/mod.rs b/lib/api/src/backend/v8/entities/store/mod.rs index 2bf988dde7..c821e8e871 100644 --- a/lib/api/src/backend/v8/entities/store/mod.rs +++ b/lib/api/src/backend/v8/entities/store/mod.rs @@ -2,9 +2,9 @@ use std::thread::ThreadId; use crate::{ + AsStoreRef, BackendStore, StoreRef, backend::v8::bindings::{wasm_store_delete, wasm_store_new, wasm_store_t}, engine::{AsEngineRef, Engine, EngineRef}, - AsStoreRef, BackendStore, StoreRef, }; mod obj; @@ -29,7 +29,7 @@ impl Store { pub(crate) fn new(engine: crate::engine::Engine) -> Self { let inner: *mut wasm_store_t = unsafe { wasm_store_new(engine.as_v8().inner.engine) }; let thread_id = std::thread::current().id(); - Store { + Self { inner, engine, thread_id, diff --git a/lib/api/src/backend/v8/entities/store/obj.rs b/lib/api/src/backend/v8/entities/store/obj.rs index 6f69a2d99f..fbfb0dd901 100644 --- a/lib/api/src/backend/v8/entities/store/obj.rs +++ b/lib/api/src/backend/v8/entities/store/obj.rs @@ -1,8 +1,8 @@ use std::{fmt, marker::PhantomData, num::NonZeroUsize}; use crate::{ - backend::v8::vm::{VMFunctionEnvironment, VMGlobal}, AsStoreMut, + backend::v8::vm::{VMFunctionEnvironment, VMGlobal}, }; pub use wasmer_types::StoreId; @@ -11,7 +11,7 @@ impl crate::StoreObjects { /// Consume [`self`] into [`crate::backend::v8::store::StoreObjects`]. pub fn into_v8(self) -> crate::backend::v8::store::StoreObjects { match self { - crate::StoreObjects::V8(s) => s, + Self::V8(s) => s, _ => panic!("Not a `v8` store!"), } } @@ -19,7 +19,7 @@ impl crate::StoreObjects { /// Convert a reference to [`self`] into a reference [`crate::backend::v8::store::StoreObjects`]. pub fn as_v8(&self) -> &crate::backend::v8::store::StoreObjects { match self { - crate::StoreObjects::V8(s) => s, + Self::V8(s) => s, _ => panic!("Not a `v8` store!"), } } @@ -27,7 +27,7 @@ impl crate::StoreObjects { /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::v8::store::StoreObjects`]. pub fn as_v8_mut(&mut self) -> &mut crate::backend::v8::store::StoreObjects { match self { - crate::StoreObjects::V8(s) => s, + Self::V8(s) => s, _ => panic!("Not a `v8` store!"), } } @@ -107,7 +107,7 @@ impl StoreObjects { } /// Return an immutable iterator over all globals - pub fn iter_globals(&self) -> core::slice::Iter { + pub fn iter_globals<'a>(&'a self) -> core::slice::Iter<'a, VMGlobal> { self.globals.iter() } diff --git a/lib/api/src/backend/v8/entities/table.rs b/lib/api/src/backend/v8/entities/table.rs index 30ff4465cb..d3053c221c 100644 --- a/lib/api/src/backend/v8/entities/table.rs +++ b/lib/api/src/backend/v8/entities/table.rs @@ -2,13 +2,13 @@ use wasmer_types::TableType; use crate::{ + AsStoreMut, AsStoreRef, BackendTable, RuntimeError, Value, v8::{ bindings::{self, *}, utils::convert::{IntoCApiType, IntoCApiValue, IntoWasmerType, IntoWasmerValue}, vm::VMTable, }, vm::{VMExtern, VMExternTable}, - AsStoreMut, AsStoreRef, BackendTable, RuntimeError, Value, }; use super::check_isolate; @@ -28,10 +28,7 @@ impl Table { let limits = Box::into_raw(Box::new(wasm_limits_t { min: ty.minimum, - max: match ty.maximum { - Some(v) => v, - None => 0, - }, + max: ty.maximum.unwrap_or_default(), shared: false, })); @@ -125,7 +122,7 @@ impl Table { _ => { return Err(RuntimeError::new(format!( "Could not grow table due to unsupported init value type: {val:?} " - ))) + ))); } }; @@ -162,7 +159,7 @@ impl Table { _ => { return Err(RuntimeError::new(format!( "Could not grow table due to unsupported init value type: {init:?} " - ))) + ))); } }; if !wasm_table_grow(self.handle, delta, init) { @@ -210,16 +207,16 @@ impl crate::Table { /// Convert a reference to [`self`] into a reference [`crate::backend::v8::table::Table`]. pub fn as_v8(&self) -> &crate::backend::v8::table::Table { - match self.0 { - BackendTable::V8(ref s) => s, + match &self.0 { + BackendTable::V8(s) => s, _ => panic!("Not a `v8` table!"), } } /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::v8::table::Table`]. pub fn as_v8_mut(&mut self) -> &mut crate::backend::v8::table::Table { - match self.0 { - BackendTable::V8(ref mut s) => s, + match &mut self.0 { + BackendTable::V8(s) => s, _ => panic!("Not a `v8` table!"), } } @@ -237,7 +234,7 @@ impl crate::BackendTable { /// Convert a reference to [`self`] into a reference [`crate::backend::v8::table::Table`]. pub fn as_v8(&self) -> &crate::backend::v8::table::Table { match self { - Self::V8(ref s) => s, + Self::V8(s) => s, _ => panic!("Not a `v8` table!"), } } @@ -245,7 +242,7 @@ impl crate::BackendTable { /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::v8::table::Table`]. pub fn as_v8_mut(&mut self) -> &mut crate::backend::v8::table::Table { match self { - Self::V8(ref mut s) => s, + Self::V8(s) => s, _ => panic!("Not a `v8` table!"), } } diff --git a/lib/api/src/backend/v8/entities/tag.rs b/lib/api/src/backend/v8/entities/tag.rs index bc2aeeb9f7..2672dfc323 100644 --- a/lib/api/src/backend/v8/entities/tag.rs +++ b/lib/api/src/backend/v8/entities/tag.rs @@ -2,13 +2,13 @@ use wasmer_types::{TagType, Type}; use crate::{ + AsStoreMut, AsStoreRef, v8::{ bindings::*, utils::convert::{IntoCApiType, IntoWasmerType}, vm::VMTag, }, vm::{VMExtern, VMExternTag}, - AsStoreMut, AsStoreRef, }; use super::check_isolate; diff --git a/lib/api/src/backend/v8/error.rs b/lib/api/src/backend/v8/error.rs index 7f9b26e98a..6065ffea37 100644 --- a/lib/api/src/backend/v8/error.rs +++ b/lib/api/src/backend/v8/error.rs @@ -1,9 +1,12 @@ use std::{ error::Error, - ffi::{c_char, CStr}, + ffi::{CStr, c_char}, }; -use crate::{v8::bindings::*, AsStoreMut}; +use crate::{ + AsStoreMut, + v8::{bindings::*, vm::VMExceptionRef}, +}; #[derive(Debug)] enum InnerTrap { @@ -53,19 +56,30 @@ impl Trap { } } + /// Returns true if the `Trap` is an exception + pub fn is_exception(&self) -> bool { + false + } + + /// If the `Trap` is an uncaught exception, returns it. + pub fn to_exception_ref(&self) -> Option { + None + } + + #[allow(clippy::unnecessary_mut_passed)] pub unsafe fn into_wasm_trap(self, store: &mut impl AsStoreMut) -> *mut wasm_trap_t { match self.inner { InnerTrap::CApi(t) => t, InnerTrap::User(err) => { let err_ptr = Box::leak(Box::new(err)); - let mut data = std::mem::zeroed(); + let mut data = unsafe { std::mem::zeroed() }; // let x = format!("") let s1 = format!("🐛{err_ptr:p}"); let _s = s1.into_bytes().into_boxed_slice(); - wasm_byte_vec_new(&mut data, _s.len(), _s.as_ptr() as _); + unsafe { wasm_byte_vec_new(&mut data, _s.len(), _s.as_ptr() as _) }; std::mem::forget(_s); let store = store.as_store_mut(); - wasm_trap_new(store.inner.store.as_v8().inner, &mut data) + unsafe { wasm_trap_new(store.inner.store.as_v8().inner, &mut data) } } } } @@ -82,8 +96,8 @@ impl Trap { impl From<*mut wasm_trap_t> for Trap { fn from(value: *mut wasm_trap_t) -> Self { let message = unsafe { - let mut message = std::mem::zeroed(); - wasm_trap_message(value, &mut message); + let mut message = unsafe { std::mem::zeroed() }; + unsafe { wasm_trap_message(value, &mut message) }; CStr::from_ptr(message.data as *const c_char) .to_str() @@ -94,10 +108,8 @@ impl From<*mut wasm_trap_t> for Trap { let ptr_str = message.replace("Exception: 🐛", ""); let ptr: Box = unsafe { let r = ptr_str.trim_start_matches("0x"); - std::ptr::read( - (usize::from_str_radix(&r, 16).unwrap() - as *const Box), - ) + std::ptr::read(usize::from_str_radix(r, 16).unwrap() + as *const Box) }; Self { @@ -146,6 +158,6 @@ impl From for crate::RuntimeError { return trap.downcast::().unwrap(); } - crate::RuntimeError::new_from_source(crate::BackendTrap::V8(trap), vec![], None) + Self::new_from_source(crate::BackendTrap::V8(trap), vec![], None) } } diff --git a/lib/api/src/backend/v8/utils/convert.rs b/lib/api/src/backend/v8/utils/convert.rs index d7540b264a..126fd34dad 100644 --- a/lib/api/src/backend/v8/utils/convert.rs +++ b/lib/api/src/backend/v8/utils/convert.rs @@ -2,11 +2,11 @@ use wasmer_types::{ExternType, FunctionType, Mutability, Type}; /// Utilities to convert between `v8` and `wasmer` values use crate::{ + BackendFunction, Function, Value, v8::{ bindings::{self, *}, function, }, - BackendFunction, Function, Value, }; pub trait IntoCApiValue { @@ -17,41 +17,41 @@ pub trait IntoCApiValue { impl IntoCApiValue for Value { fn into_cv(self) -> wasm_val_t { match self { - Value::I32(val) => wasm_val_t { + Self::I32(val) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_I32 as _, of: wasm_val_t__bindgen_ty_1 { i32_: val }, }, - Value::I64(val) => wasm_val_t { + Self::I64(val) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_I64 as _, of: wasm_val_t__bindgen_ty_1 { i64_: val }, }, - Value::F32(val) => wasm_val_t { + Self::F32(val) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_F32 as _, of: wasm_val_t__bindgen_ty_1 { f32_: val }, }, - Value::F64(val) => wasm_val_t { + Self::F64(val) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_F64 as _, of: wasm_val_t__bindgen_ty_1 { f64_: val }, }, - Value::FuncRef(Some(val)) => wasm_val_t { + Self::FuncRef(Some(val)) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_FUNCREF as _, of: wasm_val_t__bindgen_ty_1 { ref_: unsafe { wasm_func_as_ref(val.as_v8().handle) }, }, }, - Value::FuncRef(None) => wasm_val_t { + Self::FuncRef(None) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_FUNCREF as _, of: wasm_val_t__bindgen_ty_1 { ref_: unsafe { wasm_func_as_ref(std::ptr::null_mut()) }, }, }, - Value::ExternRef(_) => panic!( + Self::ExternRef(_) => panic!( "Creating host values from guest ExternRefs is not currently supported in V8." ), - Value::ExceptionRef(_) => { + Self::ExceptionRef(_) => { panic!("Creating host values from guest V128s is not currently supported in V8.") } - Value::V128(_) => { + Self::V128(_) => { panic!("Creating host values from guest V128s is not currently supported in V8.") } } @@ -110,14 +110,14 @@ pub trait IntoCApiType { impl IntoCApiType for Type { fn into_ct(self) -> wasm_valkind_t { match self as _ { - Type::I32 => bindings::wasm_valkind_enum_WASM_I32 as _, - Type::I64 => bindings::wasm_valkind_enum_WASM_I64 as _, - Type::F32 => bindings::wasm_valkind_enum_WASM_F32 as _, - Type::F64 => bindings::wasm_valkind_enum_WASM_F64 as _, - Type::FuncRef => bindings::wasm_valkind_enum_WASM_FUNCREF as _, - Type::ExternRef => bindings::wasm_valkind_enum_WASM_EXTERNREF as _, - Type::V128 => panic!("v8 currently does not support V128 types"), - Type::ExceptionRef => panic!("v8 currently does not support exnrefs"), + Self::I32 => bindings::wasm_valkind_enum_WASM_I32 as _, + Self::I64 => bindings::wasm_valkind_enum_WASM_I64 as _, + Self::F32 => bindings::wasm_valkind_enum_WASM_F32 as _, + Self::F64 => bindings::wasm_valkind_enum_WASM_F64 as _, + Self::FuncRef => bindings::wasm_valkind_enum_WASM_FUNCREF as _, + Self::ExternRef => bindings::wasm_valkind_enum_WASM_EXTERNREF as _, + Self::V128 => panic!("v8 currently does not support V128 types"), + Self::ExceptionRef => panic!("v8 currently does not support exnrefs"), } } } @@ -150,13 +150,13 @@ pub trait IntoWasmerExternType { impl IntoWasmerExternType for wasm_externtype_t { unsafe fn into_wextt(mut self) -> Result { - (&self as *const wasm_externtype_t).into_wextt() + unsafe { (&self as *const Self).into_wextt() } } } impl IntoWasmerExternType for *mut wasm_externtype_t { unsafe fn into_wextt(self) -> Result { - (self as *const wasm_externtype_t).into_wextt() + unsafe { (self as *const wasm_externtype_t).into_wextt() } } } diff --git a/lib/api/src/backend/v8/vm/mod.rs b/lib/api/src/backend/v8/vm/mod.rs index 4c11590ec9..7c798c2589 100644 --- a/lib/api/src/backend/v8/vm/mod.rs +++ b/lib/api/src/backend/v8/vm/mod.rs @@ -38,6 +38,7 @@ pub(crate) type VMInstance = *mut wasm_instance_t; pub(crate) type VMExternObj = (); pub(crate) type VMConfig = (); +#[allow(clippy::not_unsafe_ptr_arg_deref, clippy::unnecessary_mut_passed)] impl crate::VMExternToExtern for VMExtern { fn to_extern(self, store: &mut impl AsStoreMut) -> Extern { let kind = unsafe { wasm_extern_kind(&mut *self) }; @@ -132,7 +133,7 @@ impl VMFuncRef { } } -pub(crate) struct VMExceptionRef(*mut wasm_ref_t); +pub struct VMExceptionRef(*mut wasm_ref_t); impl VMExceptionRef { /// Converts the `VMExceptionRef` into a `RawValue`. pub fn into_raw(self) -> RawValue { diff --git a/lib/api/src/backend/wamr/entities/engine.rs b/lib/api/src/backend/wamr/entities/engine.rs index 6e30b96cf3..27fc6301fd 100644 --- a/lib/api/src/backend/wamr/entities/engine.rs +++ b/lib/api/src/backend/wamr/entities/engine.rs @@ -1,10 +1,10 @@ //! Data types, functions and traits for `wamr` runtime's `Engine` implementation. use crate::{ - backend::wamr::bindings::{wasm_engine_delete, wasm_engine_new, wasm_engine_t}, BackendEngine, + backend::wamr::bindings::{wasm_engine_delete, wasm_engine_new, wasm_engine_t}, }; use std::sync::Arc; -use wasmer_types::{target::Target, Features}; +use wasmer_types::{Features, target::Target}; #[derive(Debug)] pub(crate) struct CApiEngine { @@ -86,8 +86,8 @@ impl crate::Engine { /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::wamr::engine::Engine`]. pub fn as_wamr_mut(&mut self) -> &mut crate::backend::wamr::engine::Engine { - match self.be { - BackendEngine::Wamr(ref mut s) => s, + match &mut self.be { + BackendEngine::Wamr(s) => s, _ => panic!("Not a `wamr` engine!"), } } @@ -100,9 +100,9 @@ impl crate::Engine { impl From for crate::Engine { fn from(value: Engine) -> Self { - crate::Engine { + Self { be: BackendEngine::Wamr(value), - id: crate::Engine::atomic_next_engine_id(), + id: Self::atomic_next_engine_id(), } } } diff --git a/lib/api/src/backend/wamr/entities/exception.rs b/lib/api/src/backend/wamr/entities/exception.rs index 437511562a..ef1db7b6a8 100644 --- a/lib/api/src/backend/wamr/entities/exception.rs +++ b/lib/api/src/backend/wamr/entities/exception.rs @@ -4,8 +4,8 @@ use std::any::Any; use wasmer_types::{TagType, Type}; use crate::{ - wamr::vm::{VMException, VMExceptionRef}, AsStoreMut, AsStoreRef, Tag, Value, + wamr::vm::{VMException, VMExceptionRef}, }; use super::store::StoreHandle; @@ -22,42 +22,6 @@ unsafe impl Sync for Exception {} impl Exception { /// Create a new [`Exception`]. pub fn new(store: &mut impl AsStoreMut, tag: Tag, payload: &[Value]) -> Self { - todo!() - } -} - -#[derive(Debug, Clone)] -#[repr(transparent)] -/// A WebAssembly `extern ref` in `wamr`. -pub(crate) struct ExceptionRef; - -impl ExceptionRef { - pub fn new(_store: &mut impl AsStoreMut, _value: T) -> Self - where - T: Any + Send + Sync + 'static + Sized, - { - unimplemented!("ExceptionRef is not yet supported in wamr"); - } - - pub fn downcast<'a, T>(&self, _store: &'a impl AsStoreRef) -> Option<&'a T> - where - T: Any + Send + Sync + 'static + Sized, - { - unimplemented!("ExceptionRef is not yet supported in wamr"); - } - - pub(crate) fn vm_exceptionref(&self) -> VMExceptionRef { - unimplemented!("ExceptionRef is not yet supported in wamr"); - } - - pub(crate) unsafe fn from_vm_exceptionref( - _store: &mut impl AsStoreMut, - _vm_exceptionref: VMExceptionRef, - ) -> Self { - unimplemented!("ExceptionRef is not yet supported in wamr"); - } - - pub fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { - true + unimplemented!("Exception handling is not yet supported in wamr"); } } diff --git a/lib/api/src/backend/wamr/entities/function/env.rs b/lib/api/src/backend/wamr/entities/function/env.rs index 266022b205..9614a6f1a6 100644 --- a/lib/api/src/backend/wamr/entities/function/env.rs +++ b/lib/api/src/backend/wamr/entities/function/env.rs @@ -1,9 +1,9 @@ use std::{any::Any, fmt::Debug, marker::PhantomData}; use crate::{ + StoreMut, store::{AsStoreMut, AsStoreRef, StoreRef}, wamr::{store::StoreHandle, vm::VMFunctionEnvironment}, - StoreMut, }; #[derive(Debug)] @@ -62,7 +62,7 @@ impl FunctionEnv { } /// Convert it into a `FunctionEnvMut` - pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut + pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut<'_, T> where T: Any + Send + 'static + Sized, { @@ -137,7 +137,7 @@ impl FunctionEnvMut<'_, T> { } /// Borrows a new mutable reference of both the attached Store and host state - pub fn data_and_store_mut(&mut self) -> (&mut T, StoreMut) { + pub fn data_and_store_mut(&mut self) -> (&mut T, StoreMut<'_>) { let data = self.func_env.as_mut(&mut self.store_mut) as *mut T; // telling the borrow check to close his eyes here // this is still relatively safe to do as func_env are @@ -185,16 +185,16 @@ impl crate::FunctionEnv { /// Convert a reference to [`self`] into a reference to [`crate::backend::wamr::function::env::FunctionEnv`]. pub fn as_wamr(&self) -> &FunctionEnv { - match self.0 { - crate::BackendFunctionEnv::Wamr(ref s) => s, + match &self.0 { + crate::BackendFunctionEnv::Wamr(s) => s, _ => panic!("Not a `wamr` function env!"), } } /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::wamr::function::env::FunctionEnv`]. pub fn as_wamr_mut(&mut self) -> &mut FunctionEnv { - match self.0 { - crate::BackendFunctionEnv::Wamr(ref mut s) => s, + match &mut self.0 { + crate::BackendFunctionEnv::Wamr(s) => s, _ => panic!("Not a `wamr` function env!"), } } @@ -202,12 +202,12 @@ impl crate::FunctionEnv { impl<'a, T> From> for crate::FunctionEnvMut<'a, T> { fn from(value: FunctionEnvMut<'a, T>) -> Self { - crate::FunctionEnvMut(crate::BackendFunctionEnvMut::Wamr(value)) + Self(crate::BackendFunctionEnvMut::Wamr(value)) } } impl From> for crate::FunctionEnv { fn from(value: FunctionEnv) -> Self { - crate::FunctionEnv(crate::BackendFunctionEnv::Wamr(value)) + Self(crate::BackendFunctionEnv::Wamr(value)) } } diff --git a/lib/api/src/backend/wamr/entities/function/mod.rs b/lib/api/src/backend/wamr/entities/function/mod.rs index 3e4bbf6605..903cbad702 100644 --- a/lib/api/src/backend/wamr/entities/function/mod.rs +++ b/lib/api/src/backend/wamr/entities/function/mod.rs @@ -7,15 +7,15 @@ use std::{ }; use crate::{ + AsStoreMut, AsStoreRef, BackendFunction, BackendFunctionEnvMut, BackendTrap, + FromToNativeWasmType, FunctionEnv, FunctionEnvMut, IntoResult, NativeWasmType, + NativeWasmTypeInto, RuntimeError, StoreMut, Value, WasmTypeList, WithEnv, WithoutEnv, vm::{VMExtern, VMExternFunction}, wamr::{ bindings::*, utils::convert::{IntoCApiType, IntoCApiValue, IntoWasmerType, IntoWasmerValue}, vm::{VMFuncRef, VMFunction, VMFunctionCallback, VMFunctionEnvironment}, }, - AsStoreMut, AsStoreRef, BackendFunction, BackendFunctionEnvMut, BackendTrap, - FromToNativeWasmType, FunctionEnv, FunctionEnvMut, IntoResult, NativeWasmType, - NativeWasmTypeInto, RuntimeError, StoreMut, Value, WasmTypeList, WithEnv, WithoutEnv, }; use super::{super::error::Trap, store::StoreHandle}; @@ -90,7 +90,8 @@ impl Function { let params = fn_ty.params(); let mut param_types = params - .into_iter() + .iter() + .cloned() .map(|param| { let kind = param.into_ct(); unsafe { wasm_valtype_new(kind) } @@ -105,7 +106,8 @@ impl Function { let results = fn_ty.results(); let mut result_types = results - .into_iter() + .iter() + .cloned() .map(|param| { let kind = param.into_ct(); unsafe { wasm_valtype_new(kind) } @@ -151,7 +153,7 @@ impl Function { panic!("failed when creating new typed function"); } - Function { + Self { handle: wasm_function, } } @@ -163,8 +165,10 @@ impl Function { Args: WasmTypeList, Rets: WasmTypeList, { - let mut param_types = Args::wasm_types() - .into_iter() + let arg_types = Args::wasm_types(); + let mut param_types = arg_types + .iter() + .cloned() .map(|param| { let kind = param.into_ct(); unsafe { wasm_valtype_new(kind) } @@ -177,8 +181,10 @@ impl Function { vec }; - let mut result_types = Rets::wasm_types() - .into_iter() + let ret_types = Rets::wasm_types(); + let mut result_types = ret_types + .iter() + .cloned() .map(|param| { let kind = param.into_ct(); unsafe { wasm_valtype_new(kind) } @@ -222,7 +228,7 @@ impl Function { panic!("failed when creating new typed function"); } - Function { + Self { handle: wasm_function, } } @@ -238,8 +244,10 @@ impl Function { Rets: WasmTypeList, T: Send + 'static, { - let mut param_types = Args::wasm_types() - .into_iter() + let env_arg_types = Args::wasm_types(); + let mut param_types = env_arg_types + .iter() + .cloned() .map(|param| { let kind = param.into_ct(); unsafe { wasm_valtype_new(kind) } @@ -252,8 +260,10 @@ impl Function { vec }; - let mut result_types = Rets::wasm_types() - .into_iter() + let env_ret_types = Rets::wasm_types(); + let mut result_types = env_ret_types + .iter() + .cloned() .map(|param| { let kind = param.into_ct(); unsafe { wasm_valtype_new(kind) } @@ -301,7 +311,7 @@ impl Function { panic!("failed when creating new typed function"); } - Function { + Self { handle: wasm_function, } } @@ -350,17 +360,16 @@ impl Function { let store_mut = store.as_store_mut(); // let wasm_func_param_arity(self.handle) - let mut args = { - unsafe { - let mut wasm_params = params - .into_iter() - .map(|v| IntoCApiValue::into_cv(v.clone())) - .collect::>() - .into_boxed_slice(); - let mut vec = Default::default(); - wasm_val_vec_new(&mut vec, wasm_params.len(), wasm_params.as_ptr()); - vec - } + let mut args = unsafe { + let mut wasm_params = params + .iter() + .cloned() + .map(IntoCApiValue::into_cv) + .collect::>() + .into_boxed_slice(); + let mut vec = Default::default(); + wasm_val_vec_new(&mut vec, wasm_params.len(), wasm_params.as_ptr()); + vec }; let size = unsafe { wasm_func_result_arity(self.handle) }; @@ -387,7 +396,7 @@ impl Function { break; } Ok(wasmer_types::OnCalledAction::Trap(trap)) => { - return Err(RuntimeError::user(trap)) + return Err(RuntimeError::user(trap)); } Err(trap) => return Err(RuntimeError::user(trap)), } @@ -399,14 +408,12 @@ impl Function { return Err(Into::::into(trap).into()); } - unsafe { - let results = std::ptr::slice_from_raw_parts(results.data, results.size); - return Ok((*results) - .into_iter() - .map(|v| IntoWasmerValue::into_wv(*v)) - .collect::>() - .into_boxed_slice()); - } + let results_slice = unsafe { std::slice::from_raw_parts(results.data, results.size) }; + Ok(results_slice + .iter() + .map(|v| IntoWasmerValue::into_wv(*v)) + .collect::>() + .into_boxed_slice()) } pub(crate) fn from_vm_extern(_store: &mut impl AsStoreMut, internal: VMExternFunction) -> Self { @@ -452,15 +459,16 @@ where { let r: *mut (FunctionCallbackEnv<'_, F>) = env as _; - let mut store = (*r).store.as_store_mut(); - let env_handle = (*r).env_handle.as_ref().unwrap().clone(); + let mut store = unsafe { (*r).store.as_store_mut() }; + let env_handle = unsafe { (*r).env_handle.as_ref().unwrap().clone() }; let mut fn_env = env::FunctionEnv::from_handle(env_handle).into_mut(&mut store); - let func: &F = &(*r).func; + let func: &F = unsafe { &(*r).func }; let mut wasmer_args = vec![]; - for i in 0..(*args).size { - wasmer_args.push((*(*args).data.wrapping_add(i)).into_wv().clone()); + for i in 0..unsafe { (*args).size } { + let arg = unsafe { &*(*args).data.wrapping_add(i) }; + wasmer_args.push(arg.into_wv().clone()); } let result = panic::catch_unwind(AssertUnwindSafe(|| unsafe { @@ -474,13 +482,16 @@ where .map(IntoCApiValue::into_cv) .collect(); - if c_results.len() != (*rets).size { - panic!("when calling host function: number of observed results differ from wanted results") + let expected_size = unsafe { (*rets).size }; + if c_results.len() != expected_size { + panic!( + "when calling host function: number of observed results differ from wanted results" + ) } unsafe { - for i in 0..(*rets).size { - *((*rets).data.wrapping_add(i)) = c_results[i] + for (i, value) in c_results.iter().enumerate() { + *(*rets).data.wrapping_add(i) = *value; } } @@ -498,7 +509,7 @@ where } } - return fn_callback::; + fn_callback:: } impl std::fmt::Debug for Function { @@ -518,16 +529,16 @@ impl crate::Function { /// Convert a reference to [`self`] into a reference to [`crate::backend::wamr::function::Function`]. pub fn as_wamr(&self) -> &crate::backend::wamr::function::Function { - match self.0 { - BackendFunction::Wamr(ref s) => s, + match &self.0 { + BackendFunction::Wamr(s) => s, _ => panic!("Not a `wamr` function!"), } } /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::wamr::function::Function`]. pub fn as_wamr_mut(&mut self) -> &mut crate::backend::wamr::function::Function { - match self.0 { - BackendFunction::Wamr(ref mut s) => s, + match &mut self.0 { + BackendFunction::Wamr(s) => s, _ => panic!("Not a `wamr` function!"), } } @@ -551,43 +562,48 @@ macro_rules! impl_host_function { RetsAsResult: IntoResult, Func: Fn($( $x , )*) -> RetsAsResult + 'static, { - let mut r: *mut crate::backend::wamr::function::FunctionCallbackEnv = unsafe {std::mem::transmute(env)}; - let store = &mut (*r).store.as_store_mut(); + let r: *mut crate::backend::wamr::function::FunctionCallbackEnv = env as _; + let mut store = unsafe { (*r).store.as_store_mut() }; let mut i = 0; $( - let c_arg = (*(*args).data.wrapping_add(i)).clone(); + let c_arg = unsafe { (*(*args).data.wrapping_add(i)).clone() }; let wasmer_arg = c_arg.into_wv(); - let raw_arg : RawValue = wasmer_arg.as_raw(store); - let $x : $x = FromToNativeWasmType::from_native($x::Native::from_raw(store, raw_arg)); + let raw_arg : RawValue = wasmer_arg.as_raw(&mut store); + let native_value = unsafe { $x::Native::from_raw(&mut store, raw_arg) }; + let $x : $x = FromToNativeWasmType::from_native(native_value); i += 1; )* - let result = panic::catch_unwind(AssertUnwindSafe(|| unsafe { - ((*r).func)( $( $x, )* ).into_result() + let func = unsafe { &(*r).func }; + let result = panic::catch_unwind(AssertUnwindSafe(|| { + func( $( $x, )* ).into_result() })); match result { Ok(Ok(result)) => { let types = Rets::wasm_types(); - let mut native_results = result.into_array(store); + let mut native_results = unsafe { result.into_array(&mut store) }; let native_results = native_results.as_mut(); - let native_results: Vec = native_results.into_iter().enumerate() - .map(|(i, r)| Value::from_raw(store, types[i], r.clone())) + let native_results: Vec = native_results + .iter_mut() + .enumerate() + .map(|(i, r)| unsafe { Value::from_raw(&mut store, types[i], r.clone()) }) .collect(); let mut c_results: Vec = native_results.into_iter().map(IntoCApiValue::into_cv).collect(); - if c_results.len() != (*results).size { + let expected_size = unsafe { (*results).size }; + if c_results.len() != expected_size { panic!("when calling host function: number of observed results differ from wanted results") } unsafe { - for i in 0..(*results).size { - *((*results).data.wrapping_add(i)) = c_results[i] + for (i, value) in c_results.iter().enumerate() { + *(*results).data.wrapping_add(i) = *value; } } @@ -596,7 +612,7 @@ macro_rules! impl_host_function { Ok(Err(e)) => { let trap = crate::backend::wamr::error::Trap::user(Box::new(e)); - unsafe { trap.into_wasm_trap(store) } + unsafe { trap.into_wasm_trap(&mut store) } // unimplemented!("host function panicked"); }, @@ -623,45 +639,53 @@ macro_rules! impl_host_function { { let r: *mut (crate::backend::wamr::function::FunctionCallbackEnv<'_, Func>) = env as _; - let store = &mut (*r).store.as_store_mut(); + let mut store = unsafe { (*r).store.as_store_mut() }; let mut i = 0; $( - let c_arg = (*(*args).data.wrapping_add(i)).clone(); + let c_arg = unsafe { (*(*args).data.wrapping_add(i)).clone() }; let wasmer_arg = c_arg.into_wv(); - let raw_arg : RawValue = wasmer_arg.as_raw(store); - let $x : $x = FromToNativeWasmType::from_native($x::Native::from_raw(store, raw_arg)); + let raw_arg : RawValue = wasmer_arg.as_raw(&mut store); + let native_value = unsafe { $x::Native::from_raw(&mut store, raw_arg) }; + let $x : $x = FromToNativeWasmType::from_native(native_value); i += 1; )* - let env_handle = (*r).env_handle.as_ref().unwrap().clone(); - let mut fn_env = crate::backend::wamr::function::env::FunctionEnv::from_handle(env_handle).into_mut(store); - let func: &Func = &(*r).func; + let env_handle = unsafe { (*r).env_handle.as_ref().unwrap().clone() }; + let mut fn_env = crate::backend::wamr::function::env::FunctionEnv::from_handle(env_handle).into_mut(&mut store); + let func: &Func = unsafe { &(*r).func }; - let result = panic::catch_unwind(AssertUnwindSafe(|| unsafe { - ((*r).func)(BackendFunctionEnvMut::Wamr(fn_env).into(), $( $x, )* ).into_result() + let result = panic::catch_unwind(AssertUnwindSafe(|| { + func(BackendFunctionEnvMut::Wamr(fn_env).into(), $( $x, )* ).into_result() })); match result { Ok(Ok(result)) => { let types = Rets::wasm_types(); - let mut native_results = result.into_array(store); + let mut native_results = unsafe { result.into_array(&mut store) }; let native_results = native_results.as_mut(); - let native_results: Vec = native_results.into_iter().enumerate().map(|(i, r)| Value::from_raw(store, types[i], r.clone())).collect(); + let native_results: Vec = native_results + .iter_mut() + .enumerate() + .map(|(i, r)| unsafe { + Value::from_raw(&mut store, types[i], r.clone()) + }) + .collect(); let mut c_results: Vec = native_results.into_iter().map(IntoCApiValue::into_cv).collect(); - if c_results.len() != (*results).size { + let expected_size = unsafe { (*results).size }; + if c_results.len() != expected_size { panic!("when calling host function: number of observed results differ from wanted results") } unsafe { - for i in 0..(*results).size { - *((*results).data.wrapping_add(i)) = c_results[i] + for (i, value) in c_results.iter().enumerate() { + *(*results).data.wrapping_add(i) = *value; } } @@ -669,7 +693,7 @@ macro_rules! impl_host_function { unsafe { std::ptr::null_mut() } }, - Ok(Err(e)) => { let trap = crate::backend::wamr::error::Trap::user(Box::new(e)); unsafe { trap.into_wasm_trap(store) } }, + Ok(Err(e)) => { let trap = crate::backend::wamr::error::Trap::user(Box::new(e)); unsafe { trap.into_wasm_trap(&mut store) } }, Err(e) => { unimplemented!("host function panicked"); } } diff --git a/lib/api/src/backend/wamr/entities/function/typed.rs b/lib/api/src/backend/wamr/entities/function/typed.rs index c40acd82cb..388db3d690 100644 --- a/lib/api/src/backend/wamr/entities/function/typed.rs +++ b/lib/api/src/backend/wamr/entities/function/typed.rs @@ -11,9 +11,9 @@ use std::iter::FromIterator; use crate::{ - backend::wamr::{bindings::*, error::Trap, function::Function, utils::convert::*}, AsStoreMut, FromToNativeWasmType, NativeWasmType, NativeWasmTypeInto, RuntimeError, TypedFunction, Value, WasmTypeList, + backend::wamr::{bindings::*, error::Trap, function::Function, utils::convert::*}, }; use wasmer_types::RawValue; @@ -133,9 +133,15 @@ impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15 +); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16 +); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17 +); impl_native_traits!( A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18 ); diff --git a/lib/api/src/backend/wamr/entities/global.rs b/lib/api/src/backend/wamr/entities/global.rs index 51ae7c87ae..7d7efd9c1b 100644 --- a/lib/api/src/backend/wamr/entities/global.rs +++ b/lib/api/src/backend/wamr/entities/global.rs @@ -2,6 +2,7 @@ use wasmer_types::{GlobalType, Mutability}; use crate::{ + AsStoreMut, AsStoreRef, RuntimeError, Value, vm::{VMExtern, VMExternGlobal}, wamr::{ bindings::{ @@ -12,7 +13,6 @@ use crate::{ utils::convert::{IntoCApiType, IntoCApiValue, IntoWasmerType, IntoWasmerValue}, vm::VMGlobal, }, - AsStoreMut, AsStoreRef, RuntimeError, Value, }; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/lib/api/src/backend/wamr/entities/instance.rs b/lib/api/src/backend/wamr/entities/instance.rs index 30a61b39d0..188c5bccb4 100644 --- a/lib/api/src/backend/wamr/entities/instance.rs +++ b/lib/api/src/backend/wamr/entities/instance.rs @@ -3,8 +3,8 @@ use std::sync::Arc; use crate::entities::external::VMExternToExtern; use crate::{ - backend::wamr::bindings::*, vm::VMExtern, wamr::error::Trap, AsStoreMut, AsStoreRef, Exports, - Extern, Imports, InstantiationError, Module, + AsStoreMut, AsStoreRef, Exports, Extern, Imports, InstantiationError, Module, + backend::wamr::bindings::*, vm::VMExtern, wamr::error::Trap, }; #[derive(PartialEq, Eq)] @@ -14,6 +14,7 @@ unsafe impl Send for InstanceHandle {} unsafe impl Sync for InstanceHandle {} impl InstanceHandle { + #[allow(clippy::result_large_err)] fn new( store: *mut wasm_store_t, module: *mut wasm_module_t, @@ -40,7 +41,7 @@ impl InstanceHandle { std::mem::forget(externs); - wasm_instance_new(store, module, &mut imports, &mut trap) + wasm_instance_new(store, module, &imports, &mut trap) }; if instance.is_null() { @@ -48,7 +49,7 @@ impl InstanceHandle { return Err(InstantiationError::Start(trap.into())); } - Ok(InstanceHandle(instance)) + Ok(Self(instance)) } fn get_exports(&self, mut store: &mut impl AsStoreMut, module: &Module) -> Exports { @@ -66,7 +67,6 @@ impl InstanceHandle { } else { unsafe { std::slice::from_raw_parts(c_api_externs.data, c_api_externs.size) }.to_vec() }; - let c_api_externs = c_api_externs.to_vec(); let mut exports = unsafe { let mut vec = Default::default(); wasm_module_exports(module.as_wamr().handle.inner, &mut vec); @@ -86,7 +86,7 @@ impl InstanceHandle { let c_api_exports: Exports = c_api_exports .into_iter() - .zip(c_api_externs.into_iter()) + .zip(c_api_externs) .map(|(export, ext)| unsafe { let name = wasm_exporttype_name(export); let name = std::slice::from_raw_parts((*name).data as *const u8, (*name).size); @@ -104,10 +104,7 @@ impl InstanceHandle { for e in module_exports { let ext: Extern = c_api_exports .get::(e.name()) - .expect(&format!( - "c_api_exports: {c_api_exports:?} (name: {})", - e.name() - )) + .unwrap_or_else(|_| panic!("c_api_exports: {c_api_exports:?} (name: {})", e.name())) .clone(); exports.insert(e.name().to_string(), ext); } @@ -128,6 +125,7 @@ pub struct Instance { } impl Instance { + #[allow(clippy::result_large_err)] pub(crate) fn new( store: &mut impl AsStoreMut, module: &Module, @@ -148,9 +146,10 @@ impl Instance { let mut store_from_module = wamr_module.handle.store.lock().unwrap(); let mut store = store_from_module.as_store_mut(); - return Self::new_by_index(&mut store, module, &externs); + Self::new_by_index(&mut store, module, &externs) } + #[allow(clippy::result_large_err)] pub(crate) fn new_by_index( store: &mut impl AsStoreMut, module: &Module, diff --git a/lib/api/src/backend/wamr/entities/memory/mod.rs b/lib/api/src/backend/wamr/entities/memory/mod.rs index c6d2eec24f..ecd177f4d4 100644 --- a/lib/api/src/backend/wamr/entities/memory/mod.rs +++ b/lib/api/src/backend/wamr/entities/memory/mod.rs @@ -7,10 +7,10 @@ pub use wasmer_types::MemoryError; use wasmer_types::{MemoryType, Pages, WASM_PAGE_SIZE}; use crate::{ + AsStoreMut, AsStoreRef, BackendMemory, MemoryAccessError, shared::SharedMemory, vm::{VMExtern, VMExternMemory}, wamr::{bindings::*, vm::VMMemory}, - AsStoreMut, AsStoreRef, BackendMemory, MemoryAccessError, }; pub(crate) mod view; @@ -152,7 +152,7 @@ impl Memory { /// Cloning memory will create another reference to the same memory that /// can be put into a new store pub fn try_clone(&self, _store: &impl AsStoreRef) -> Result { - Ok(self.handle.clone()) + Ok(self.handle) } /// Copying the memory will actually copy all the bytes in the memory to @@ -280,26 +280,26 @@ impl<'a> MemoryBuffer<'a> { unsafe fn volatile_memcpy_read(mut src: *const u8, mut dst: *mut u8, mut len: usize) { #[inline] unsafe fn copy_one(src: &mut *const u8, dst: &mut *mut u8, len: &mut usize) { - #[repr(packed)] + #[repr(C, packed)] struct Unaligned(T); - let val = (*src as *const Unaligned).read_volatile(); - (*dst as *mut Unaligned).write(val); - *src = src.add(std::mem::size_of::()); - *dst = dst.add(std::mem::size_of::()); + let val = unsafe { (*src as *const Unaligned).read_volatile() }; + unsafe { (*dst as *mut Unaligned).write(val) }; + *src = unsafe { src.add(std::mem::size_of::()) }; + *dst = unsafe { dst.add(std::mem::size_of::()) }; *len -= std::mem::size_of::(); } while len >= 8 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } if len >= 4 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } if len >= 2 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } if len >= 1 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } } @@ -307,26 +307,26 @@ unsafe fn volatile_memcpy_read(mut src: *const u8, mut dst: *mut u8, mut len: us unsafe fn volatile_memcpy_write(mut src: *const u8, mut dst: *mut u8, mut len: usize) { #[inline] unsafe fn copy_one(src: &mut *const u8, dst: &mut *mut u8, len: &mut usize) { - #[repr(packed)] + #[repr(C, packed)] struct Unaligned(T); - let val = (*src as *const Unaligned).read(); - (*dst as *mut Unaligned).write_volatile(val); - *src = src.add(std::mem::size_of::()); - *dst = dst.add(std::mem::size_of::()); + let val = unsafe { (*src as *const Unaligned).read() }; + unsafe { (*dst as *mut Unaligned).write_volatile(val) }; + *src = unsafe { src.add(std::mem::size_of::()) }; + *dst = unsafe { dst.add(std::mem::size_of::()) }; *len -= std::mem::size_of::(); } while len >= 8 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } if len >= 4 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } if len >= 2 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } if len >= 1 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } } @@ -341,16 +341,16 @@ impl crate::Memory { /// Convert a reference to [`self`] into a reference to [`crate::backend::wamr::memory::Memory`]. pub fn as_wamr(&self) -> &crate::backend::wamr::memory::Memory { - match self.0 { - BackendMemory::Wamr(ref s) => s, + match &self.0 { + BackendMemory::Wamr(s) => s, _ => panic!("Not a `wamr` memory!"), } } /// Convert a mutable reference to [`self`] into a mutable reference to [`crate::backend::wamr::memory::Memory`]. pub fn as_wamr_mut(&mut self) -> &mut crate::backend::wamr::memory::Memory { - match self.0 { - BackendMemory::Wamr(ref mut s) => s, + match &mut self.0 { + BackendMemory::Wamr(s) => s, _ => panic!("Not a `wamr` memory!"), } } diff --git a/lib/api/src/backend/wamr/entities/memory/view.rs b/lib/api/src/backend/wamr/entities/memory/view.rs index 206c1a0f15..e9678e8753 100644 --- a/lib/api/src/backend/wamr/entities/memory/view.rs +++ b/lib/api/src/backend/wamr/entities/memory/view.rs @@ -4,9 +4,9 @@ use wasmer_types::Pages; use super::{Memory, MemoryBuffer}; use crate::{ + AsStoreRef, MemoryAccessError, backend::wamr::bindings::{wasm_memory_data, wasm_memory_data_size, wasm_memory_size}, wamr::bindings::wasm_memory_t, - AsStoreRef, MemoryAccessError, }; /// A WebAssembly `memory` view. @@ -25,7 +25,7 @@ impl<'a> MemoryView<'a> { pub(crate) fn new(memory: &Memory, store: &'a (impl AsStoreRef + ?Sized)) -> Self { let c_memory: *mut wasm_memory_t = memory.handle; - let len = unsafe { wasm_memory_data_size(c_memory as _).try_into().unwrap() }; + let len = unsafe { wasm_memory_data_size(c_memory as _) }; let base: *mut u8 = unsafe { wasm_memory_data(c_memory as _) as _ }; let size = unsafe { wasm_memory_size(c_memory as _) }; @@ -62,7 +62,7 @@ impl<'a> MemoryView<'a> { /// function that writes to the memory or by resizing the memory. #[doc(hidden)] pub unsafe fn data_unchecked(&self) -> &[u8] { - self.data_unchecked_mut() + unsafe { self.data_unchecked_mut() } } /// Retrieve a mutable slice of the memory contents. @@ -77,7 +77,7 @@ impl<'a> MemoryView<'a> { #[allow(clippy::mut_from_ref)] #[doc(hidden)] pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] { - std::slice::from_raw_parts_mut(self.buffer.base, self.buffer.len) + unsafe { std::slice::from_raw_parts_mut(self.buffer.base, self.buffer.len) } } /// Returns the size (in [`Pages`]) of the `Memory`. diff --git a/lib/api/src/backend/wamr/entities/module.rs b/lib/api/src/backend/wamr/entities/module.rs index 0b12f36c54..830c7d8709 100644 --- a/lib/api/src/backend/wamr/entities/module.rs +++ b/lib/api/src/backend/wamr/entities/module.rs @@ -1,7 +1,7 @@ //! Data types, functions and traits for `wamr`'s `Module` implementation. use std::{path::Path, sync::Arc}; -use crate::{backend::wamr::bindings::*, AsEngineRef, BackendModule, IntoBytes}; +use crate::{AsEngineRef, BackendModule, IntoBytes, backend::wamr::bindings::*}; use bytes::Bytes; use wasmer_types::{ @@ -14,6 +14,9 @@ pub(crate) struct ModuleHandle { pub(crate) store: std::sync::Mutex, } +unsafe impl Send for ModuleHandle {} +unsafe impl Sync for ModuleHandle {} + impl PartialEq for ModuleHandle { fn eq(&self, other: &Self) -> bool { self.inner == other.inner @@ -40,10 +43,10 @@ impl ModuleHandle { let store = std::sync::Mutex::new(store); if inner.is_null() { - return Err(CompileError::Validate(format!("module is null"))); + return Err(CompileError::Validate("module is null".to_string())); } - Ok(ModuleHandle { inner, store }) + Ok(Self { inner, store }) } } impl Drop for ModuleHandle { @@ -118,24 +121,23 @@ impl Module { } pub fn serialize(&self) -> Result { - return self.raw_bytes.clone().ok_or(SerializeError::Generic( + self.raw_bytes.clone().ok_or(SerializeError::Generic( "Not able to serialize module".to_string(), - )); + )) } pub unsafe fn deserialize_unchecked( engine: &impl AsEngineRef, bytes: impl IntoBytes, ) -> Result { - Self::deserialize(engine, bytes) + unsafe { Self::deserialize(engine, bytes) } } pub unsafe fn deserialize( engine: &impl AsEngineRef, bytes: impl IntoBytes, ) -> Result { - return Self::from_binary(engine, &bytes.into_bytes()) - .map_err(|e| DeserializeError::Compiler(e)); + Self::from_binary(engine, &bytes.into_bytes()).map_err(DeserializeError::Compiler) } pub unsafe fn deserialize_from_file_unchecked( @@ -143,7 +145,7 @@ impl Module { path: impl AsRef, ) -> Result { let bytes = std::fs::read(path.as_ref())?; - Self::deserialize_unchecked(engine, bytes) + unsafe { Self::deserialize_unchecked(engine, bytes) } } pub unsafe fn deserialize_from_file( @@ -151,7 +153,7 @@ impl Module { path: impl AsRef, ) -> Result { let bytes = std::fs::read(path.as_ref())?; - Self::deserialize(engine, bytes) + unsafe { Self::deserialize(engine, bytes) } } pub fn set_name(&mut self, name: &str) -> bool { @@ -190,16 +192,16 @@ impl crate::Module { /// Convert a reference to [`self`] into a reference [`crate::backend::wamr::module::Module`]. pub fn as_wamr(&self) -> &crate::backend::wamr::module::Module { - match self.0 { - BackendModule::Wamr(ref s) => s, + match &self.0 { + BackendModule::Wamr(s) => s, _ => panic!("Not a `wamr` module!"), } } /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::wamr::module::Module`]. pub fn as_wamr_mut(&mut self) -> &mut crate::backend::wamr::module::Module { - match self.0 { - BackendModule::Wamr(ref mut s) => s, + match &mut self.0 { + BackendModule::Wamr(s) => s, _ => panic!("Not a `wamr` module!"), } } diff --git a/lib/api/src/backend/wamr/entities/store/mod.rs b/lib/api/src/backend/wamr/entities/store/mod.rs index 2e556e16bf..cc18d07cc8 100644 --- a/lib/api/src/backend/wamr/entities/store/mod.rs +++ b/lib/api/src/backend/wamr/entities/store/mod.rs @@ -1,8 +1,8 @@ //! Data types, functions and traits for `wamr`'s `Store` implementation. use crate::{ + AsStoreRef, BackendStore, StoreRef, backend::wamr::bindings::{wasm_store_delete, wasm_store_new, wasm_store_t}, engine::{AsEngineRef, Engine, EngineRef}, - AsStoreRef, BackendStore, StoreRef, }; mod obj; @@ -25,7 +25,7 @@ impl std::fmt::Debug for Store { impl Store { pub(crate) fn new(engine: crate::engine::Engine) -> Self { let inner: *mut wasm_store_t = unsafe { wasm_store_new(engine.as_wamr().inner.engine) }; - Store { inner, engine } + Self { inner, engine } } pub(crate) fn engine(&self) -> &Engine { diff --git a/lib/api/src/backend/wamr/entities/store/obj.rs b/lib/api/src/backend/wamr/entities/store/obj.rs index 9c35d5fa57..bf24fb7a34 100644 --- a/lib/api/src/backend/wamr/entities/store/obj.rs +++ b/lib/api/src/backend/wamr/entities/store/obj.rs @@ -1,8 +1,8 @@ use std::{fmt, marker::PhantomData, num::NonZeroUsize}; use crate::{ - backend::wamr::vm::{VMFunctionEnvironment, VMGlobal}, AsStoreMut, + backend::wamr::vm::{VMFunctionEnvironment, VMGlobal}, }; pub use wasmer_types::StoreId; @@ -11,7 +11,7 @@ impl crate::StoreObjects { /// Consume [`self`] into [`crate::backend::wamr::store::StoreObjects`]. pub fn into_wamr(self) -> crate::backend::wamr::store::StoreObjects { match self { - crate::StoreObjects::Wamr(s) => s, + Self::Wamr(s) => s, _ => panic!("Not a `wamr` store!"), } } @@ -19,7 +19,7 @@ impl crate::StoreObjects { /// Convert a reference to [`self`] into a reference [`crate::backend::wamr::store::StoreObjects`]. pub fn as_wamr(&self) -> &crate::backend::wamr::store::StoreObjects { match self { - crate::StoreObjects::Wamr(s) => s, + Self::Wamr(s) => s, _ => panic!("Not a `wamr` store!"), } } @@ -27,7 +27,7 @@ impl crate::StoreObjects { /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::wamr::store::StoreObjects`]. pub fn as_wamr_mut(&mut self) -> &mut crate::backend::wamr::store::StoreObjects { match self { - crate::StoreObjects::Wamr(s) => s, + Self::Wamr(s) => s, _ => panic!("Not a `wamr` store!"), } } @@ -107,7 +107,7 @@ impl StoreObjects { } /// Return an immutable iterator over all globals - pub fn iter_globals(&self) -> core::slice::Iter { + pub fn iter_globals(&self) -> core::slice::Iter<'_, VMGlobal> { self.globals.iter() } diff --git a/lib/api/src/backend/wamr/entities/table.rs b/lib/api/src/backend/wamr/entities/table.rs index 79b05764d4..740b5df373 100644 --- a/lib/api/src/backend/wamr/entities/table.rs +++ b/lib/api/src/backend/wamr/entities/table.rs @@ -2,13 +2,13 @@ use wasmer_types::TableType; use crate::{ + AsStoreMut, AsStoreRef, BackendKind, BackendTable, RuntimeError, Value, vm::{VMExtern, VMExternTable}, wamr::{ bindings::{self, *}, utils::convert::{IntoCApiType, IntoCApiValue, IntoWasmerType, IntoWasmerValue}, vm::VMTable, }, - AsStoreMut, AsStoreRef, BackendKind, BackendTable, RuntimeError, Value, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -26,10 +26,7 @@ impl Table { let limits = Box::into_raw(Box::new(wasm_limits_t { min: ty.minimum, - max: match ty.maximum { - Some(v) => v, - None => 0, - }, + max: ty.maximum.unwrap_or_default(), })); unsafe { wasm_tabletype_new(valtype, limits) } @@ -116,7 +113,7 @@ impl Table { _ => { return Err(RuntimeError::new(format!( "Could not grow table due to unsupported init value type: {val:?} " - ))) + ))); } }; @@ -148,7 +145,7 @@ impl Table { _ => { return Err(RuntimeError::new(format!( "Could not grow table due to unsupported init value type: {init:?} " - ))) + ))); } }; if !wasm_table_grow(self.handle, delta, init) { @@ -192,16 +189,16 @@ impl crate::Table { /// Convert a reference to [`self`] into a reference [`crate::backend::wamr::table::Table`]. pub fn as_wamr(&self) -> &crate::backend::wamr::table::Table { - match self.0 { - BackendTable::Wamr(ref s) => s, + match &self.0 { + BackendTable::Wamr(s) => s, _ => panic!("Not a `wamr` table!"), } } /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::wamr::table::Table`]. pub fn as_wamr_mut(&mut self) -> &mut crate::backend::wamr::table::Table { - match self.0 { - BackendTable::Wamr(ref mut s) => s, + match &mut self.0 { + BackendTable::Wamr(s) => s, _ => panic!("Not a `wamr` table!"), } } @@ -219,7 +216,7 @@ impl crate::BackendTable { /// Convert a reference to [`self`] into a reference [`crate::backend::wamr::table::Table`]. pub fn as_wamr(&self) -> &crate::backend::wamr::table::Table { match self { - Self::Wamr(ref s) => s, + Self::Wamr(s) => s, _ => panic!("Not a `wamr` table!"), } } @@ -227,7 +224,7 @@ impl crate::BackendTable { /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::wamr::table::Table`]. pub fn as_wamr_mut(&mut self) -> &mut crate::backend::wamr::table::Table { match self { - Self::Wamr(ref mut s) => s, + Self::Wamr(s) => s, _ => panic!("Not a `wamr` table!"), } } diff --git a/lib/api/src/backend/wamr/entities/tag.rs b/lib/api/src/backend/wamr/entities/tag.rs index d7daa2274f..def86e2c94 100644 --- a/lib/api/src/backend/wamr/entities/tag.rs +++ b/lib/api/src/backend/wamr/entities/tag.rs @@ -2,9 +2,9 @@ use wasmer_types::{TagType, Type}; use crate::{ + AsStoreMut, AsStoreRef, vm::{VMExtern, VMExternTag}, wamr::vm::VMTag, - AsStoreMut, AsStoreRef, }; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/lib/api/src/backend/wamr/error.rs b/lib/api/src/backend/wamr/error.rs index 4d1b7790d5..5d80a671e3 100644 --- a/lib/api/src/backend/wamr/error.rs +++ b/lib/api/src/backend/wamr/error.rs @@ -1,9 +1,12 @@ use std::{ error::Error, - ffi::{c_char, CStr}, + ffi::{CStr, c_char}, }; -use crate::{wamr::bindings::*, AsStoreMut}; +use crate::{ + AsStoreMut, + wamr::{bindings::*, vm::VMExceptionRef}, +}; #[derive(Debug)] enum InnerTrap { @@ -52,19 +55,29 @@ impl Trap { } } + /// Returns true if the `Trap` is an exception + pub fn is_exception(&self) -> bool { + false + } + + /// If the `Trap` is an uncaught exception, returns it. + pub fn to_exception_ref(&self) -> Option { + None + } + pub unsafe fn into_wasm_trap(self, store: &mut impl AsStoreMut) -> *mut wasm_trap_t { match self.inner { InnerTrap::CApi(t) => t, InnerTrap::User(err) => { let err_ptr = Box::leak(Box::new(err)); - let mut data = std::mem::zeroed(); + let mut data = unsafe { std::mem::zeroed() }; // let x = format!("") - let s1 = format!("🐛{:p}", err_ptr); + let s1 = format!("🐛{err_ptr:p}"); let _s = s1.into_bytes().into_boxed_slice(); - wasm_byte_vec_new(&mut data, _s.len(), _s.as_ptr() as _); + unsafe { wasm_byte_vec_new(&mut data, _s.len(), _s.as_ptr() as _) }; std::mem::forget(_s); let store = store.as_store_mut(); - wasm_trap_new(store.inner.store.as_wamr().inner, &mut data) + unsafe { wasm_trap_new(store.inner.store.as_wamr().inner, &data) } } } } @@ -89,16 +102,13 @@ impl From<*mut wasm_trap_t> for Trap { .unwrap() }; - println!("{message}"); - if message.starts_with("Exception: 🐛") { let ptr_str = message.replace("Exception: 🐛", ""); let ptr: Box = unsafe { let r = ptr_str.trim_start_matches("0x"); - std::ptr::read( - (usize::from_str_radix(&r, 16).unwrap() - as *const Box), - ) + let raw_ptr = usize::from_str_radix(r, 16).unwrap() + as *const Box; + std::ptr::read(raw_ptr) }; Self { @@ -124,18 +134,19 @@ impl std::error::Error for Trap { impl std::fmt::Display for Trap { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &self.inner { - InnerTrap::User(e) => write!(f, "{}", e), + InnerTrap::User(e) => write!(f, "{e}"), InnerTrap::CApi(value) => { // let message: wasm_message_t; // wasm_trap_message(value, &mut message); - let mut out = unsafe { + let message = unsafe { let mut vec: wasm_byte_vec_t = Default::default(); wasm_byte_vec_new_empty(&mut vec); - &mut vec as *mut _ + let out = &mut vec as *mut _; + wasm_trap_message(*value, out); + let cstr = CStr::from_ptr((*out).data); + cstr.to_str().unwrap().to_string() }; - unsafe { wasm_trap_message(*value, out) }; - let cstr = unsafe { CStr::from_ptr((*out).data) }; - write!(f, "wasm-c-api trap: {}", cstr.to_str().unwrap()) + write!(f, "wasm-c-api trap: {message}") } } } @@ -144,18 +155,19 @@ impl std::fmt::Display for Trap { impl std::fmt::Debug for Trap { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &self.inner { - InnerTrap::User(e) => write!(f, "{}", e), + InnerTrap::User(e) => write!(f, "{e}"), InnerTrap::CApi(value) => { // let message: wasm_message_t; // wasm_trap_message(value, &mut message); - let mut out = unsafe { + let message = unsafe { let mut vec: wasm_byte_vec_t = Default::default(); wasm_byte_vec_new_empty(&mut vec); - &mut vec as *mut _ + let out = &mut vec as *mut _; + wasm_trap_message(*value, out); + let cstr = CStr::from_ptr((*out).data); + cstr.to_str().unwrap().to_string() }; - unsafe { wasm_trap_message(*value, out) }; - let cstr = unsafe { CStr::from_ptr((*out).data) }; - write!(f, "wasm-c-api trap: {}", cstr.to_str().unwrap()) + write!(f, "wasm-c-api trap: {message}") } } } @@ -167,6 +179,6 @@ impl From for crate::RuntimeError { return trap.downcast::().unwrap(); } - crate::RuntimeError::new_from_source(crate::BackendTrap::Wamr(trap), vec![], None) + Self::new_from_source(crate::BackendTrap::Wamr(trap), vec![], None) } } diff --git a/lib/api/src/backend/wamr/utils/convert.rs b/lib/api/src/backend/wamr/utils/convert.rs index 484baeba3e..8aa8c39369 100644 --- a/lib/api/src/backend/wamr/utils/convert.rs +++ b/lib/api/src/backend/wamr/utils/convert.rs @@ -1,5 +1,6 @@ /// Utilities to convert between `wamr` and `wasmer` values use crate::{ + BackendFunction, Function, Value, wamr::{ bindings::{ self, wasm_func_as_ref, wasm_val_t, wasm_val_t__bindgen_ty_1, wasm_valkind_t, @@ -7,7 +8,6 @@ use crate::{ }, function, }, - BackendFunction, Function, Value, }; use wasmer_types::Type; @@ -19,47 +19,47 @@ pub trait IntoCApiValue { impl IntoCApiValue for Value { fn into_cv(self) -> wasm_val_t { match self { - Value::I32(val) => wasm_val_t { + Self::I32(val) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_I32 as _, _paddings: Default::default(), of: wasm_val_t__bindgen_ty_1 { i32_: val }, }, - Value::I64(val) => wasm_val_t { + Self::I64(val) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_I64 as _, _paddings: Default::default(), of: wasm_val_t__bindgen_ty_1 { i64_: val }, }, - Value::F32(val) => wasm_val_t { + Self::F32(val) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_F32 as _, _paddings: Default::default(), of: wasm_val_t__bindgen_ty_1 { f32_: val }, }, - Value::F64(val) => wasm_val_t { + Self::F64(val) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_F64 as _, _paddings: Default::default(), of: wasm_val_t__bindgen_ty_1 { f64_: val }, }, - Value::FuncRef(Some(val)) => wasm_val_t { + Self::FuncRef(Some(val)) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_FUNCREF as _, _paddings: Default::default(), of: wasm_val_t__bindgen_ty_1 { ref_: unsafe { wasm_func_as_ref(val.as_wamr().handle) }, }, }, - Value::FuncRef(None) => wasm_val_t { + Self::FuncRef(None) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_FUNCREF as _, _paddings: Default::default(), of: wasm_val_t__bindgen_ty_1 { ref_: unsafe { wasm_func_as_ref(std::ptr::null_mut()) }, }, }, - Value::ExternRef(_) => panic!( + Self::ExternRef(_) => panic!( "Creating host values from guest ExternRefs is not currently supported in wamr ." ), - Value::ExceptionRef(_) => { + Self::ExceptionRef(_) => { panic!("Creating host values from guest V128s is not currently supported in wamr.") } - Value::V128(_) => { + Self::V128(_) => { panic!("Creating host values from guest V128s is not currently supported in wamr.") } } @@ -119,14 +119,14 @@ pub trait IntoCApiType { impl IntoCApiType for Type { fn into_ct(self) -> wasm_valkind_t { match self as _ { - Type::I32 => bindings::wasm_valkind_enum_WASM_I32 as _, - Type::I64 => bindings::wasm_valkind_enum_WASM_I64 as _, - Type::F32 => bindings::wasm_valkind_enum_WASM_F32 as _, - Type::F64 => bindings::wasm_valkind_enum_WASM_F64 as _, - Type::FuncRef => bindings::wasm_valkind_enum_WASM_FUNCREF as _, - Type::ExternRef => bindings::wasm_valkind_enum_WASM_EXTERNREF as _, - Type::V128 => bindings::wasm_valkind_enum_WASM_V128 as _, - Type::ExceptionRef => panic!("v8 currently does not support exnrefs"), + Self::I32 => bindings::wasm_valkind_enum_WASM_I32 as _, + Self::I64 => bindings::wasm_valkind_enum_WASM_I64 as _, + Self::F32 => bindings::wasm_valkind_enum_WASM_F32 as _, + Self::F64 => bindings::wasm_valkind_enum_WASM_F64 as _, + Self::FuncRef => bindings::wasm_valkind_enum_WASM_FUNCREF as _, + Self::ExternRef => bindings::wasm_valkind_enum_WASM_EXTERNREF as _, + Self::V128 => bindings::wasm_valkind_enum_WASM_V128 as _, + Self::ExceptionRef => panic!("v8 currently does not support exnrefs"), } } } diff --git a/lib/api/src/backend/wamr/vm/mod.rs b/lib/api/src/backend/wamr/vm/mod.rs index 01e04abdd4..87ccd91e9a 100644 --- a/lib/api/src/backend/wamr/vm/mod.rs +++ b/lib/api/src/backend/wamr/vm/mod.rs @@ -11,6 +11,7 @@ use super::{ table::Table, }; use crate::{AsStoreMut, BackendFunction, BackendGlobal, BackendMemory, BackendTable, Extern}; +use std::ptr::NonNull; use wasmer_types::RawValue; pub use super::error::Trap; @@ -45,11 +46,14 @@ pub(crate) type VMConfig = (); impl crate::VMExternToExtern for VMExtern { fn to_extern(self, store: &mut impl AsStoreMut) -> Extern { - let kind = unsafe { wasm_extern_kind(&mut *self) }; + let ptr = + NonNull::new(self).expect("The wasm-c-api returned a null pointer for wasm_extern_t"); + let raw = ptr.as_ptr(); + let kind = unsafe { wasm_extern_kind(raw as *const _) }; match kind as u32 { 0 => { - let func = unsafe { wasm_extern_as_func(&mut *self) }; + let func = unsafe { wasm_extern_as_func(raw) }; if func.is_null() { panic!("The wasm-c-api reported extern as function, but is not"); } @@ -59,7 +63,7 @@ impl crate::VMExternToExtern for VMExtern { )) } 1 => { - let global = unsafe { wasm_extern_as_global(&mut *self) }; + let global = unsafe { wasm_extern_as_global(raw) }; if global.is_null() { panic!("The wasm-c-api reported extern as a global, but is not"); } @@ -69,7 +73,7 @@ impl crate::VMExternToExtern for VMExtern { )) } 2 => { - let table = unsafe { wasm_extern_as_table(&mut *self) }; + let table = unsafe { wasm_extern_as_table(raw) }; if table.is_null() { panic!("The wasm-c-api reported extern as a table, but is not"); } @@ -79,7 +83,7 @@ impl crate::VMExternToExtern for VMExtern { )) } 3 => { - let memory = unsafe { wasm_extern_as_memory(&mut *self) }; + let memory = unsafe { wasm_extern_as_memory(raw) }; if memory.is_null() { panic!("The wasm-c-api reported extern as a table, but is not"); } diff --git a/lib/api/src/backend/wasmi/entities/engine.rs b/lib/api/src/backend/wasmi/entities/engine.rs index 896d40fce3..a3e9054769 100644 --- a/lib/api/src/backend/wasmi/entities/engine.rs +++ b/lib/api/src/backend/wasmi/entities/engine.rs @@ -1,10 +1,10 @@ //! Data types, functions and traits for `wasmi` runtime's `Engine` implementation. use crate::{ - backend::wasmi::bindings::{wasm_engine_delete, wasm_engine_new, wasm_engine_t}, BackendEngine, + backend::wasmi::bindings::{wasm_engine_delete, wasm_engine_new, wasm_engine_t}, }; use std::sync::Arc; -use wasmer_types::{target::Target, Features}; +use wasmer_types::{Features, target::Target}; #[derive(Debug)] pub(crate) struct CApiEngine { @@ -86,8 +86,8 @@ impl crate::Engine { /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::wasmi::engine::Engine`]. pub fn as_wasmi_mut(&mut self) -> &mut crate::backend::wasmi::engine::Engine { - match self.be { - BackendEngine::Wasmi(ref mut s) => s, + match &mut self.be { + BackendEngine::Wasmi(s) => s, _ => panic!("Not a `wasmi` engine!"), } } @@ -100,9 +100,9 @@ impl crate::Engine { impl From for crate::Engine { fn from(value: Engine) -> Self { - crate::Engine { + Self { be: BackendEngine::Wasmi(value), - id: crate::Engine::atomic_next_engine_id(), + id: Self::atomic_next_engine_id(), } } } diff --git a/lib/api/src/backend/wasmi/entities/exception.rs b/lib/api/src/backend/wasmi/entities/exception.rs index 4ae913cfa0..1de3579564 100644 --- a/lib/api/src/backend/wasmi/entities/exception.rs +++ b/lib/api/src/backend/wasmi/entities/exception.rs @@ -4,8 +4,8 @@ use std::any::Any; use wasmer_types::{TagType, Type}; use crate::{ - wasmi::vm::{VMException, VMExceptionRef}, AsStoreMut, AsStoreRef, Tag, Value, + wasmi::vm::{VMException, VMExceptionRef}, }; use super::store::StoreHandle; @@ -22,42 +22,6 @@ unsafe impl Sync for Exception {} impl Exception { /// Create a new [`Exception`]. pub fn new(store: &mut impl AsStoreMut, tag: Tag, payload: &[Value]) -> Self { - todo!() - } -} - -#[derive(Debug, Clone)] -#[repr(transparent)] -/// A WebAssembly `extern ref` in `wasmi`. -pub(crate) struct ExceptionRef; - -impl ExceptionRef { - pub fn new(_store: &mut impl AsStoreMut, _value: T) -> Self - where - T: Any + Send + Sync + 'static + Sized, - { - unimplemented!("ExceptionRef is not yet supported in wasmi"); - } - - pub fn downcast<'a, T>(&self, _store: &'a impl AsStoreRef) -> Option<&'a T> - where - T: Any + Send + Sync + 'static + Sized, - { - unimplemented!("ExceptionRef is not yet supported in wasmi"); - } - - pub(crate) fn vm_exceptionref(&self) -> VMExceptionRef { - unimplemented!("ExceptionRef is not yet supported in wasmi"); - } - - pub(crate) unsafe fn from_vm_exceptionref( - _store: &mut impl AsStoreMut, - _vm_exceptionref: VMExceptionRef, - ) -> Self { - unimplemented!("ExceptionRef is not yet supported in wasmi"); - } - - pub fn is_from_store(&self, _store: &impl AsStoreRef) -> bool { - true + unimplemented!("Exception handling is not yet supported in wasmi"); } } diff --git a/lib/api/src/backend/wasmi/entities/function/env.rs b/lib/api/src/backend/wasmi/entities/function/env.rs index c5062e897e..04e691d96d 100644 --- a/lib/api/src/backend/wasmi/entities/function/env.rs +++ b/lib/api/src/backend/wasmi/entities/function/env.rs @@ -1,9 +1,9 @@ use std::{any::Any, fmt::Debug, marker::PhantomData}; use crate::{ + StoreMut, store::{AsStoreMut, AsStoreRef, StoreRef}, wasmi::{store::StoreHandle, vm::VMFunctionEnvironment}, - StoreMut, }; #[derive(Debug)] @@ -62,7 +62,7 @@ impl FunctionEnv { } /// Convert it into a `FunctionEnvMut` - pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut + pub fn into_mut<'a>(self, store: &'a mut impl AsStoreMut) -> FunctionEnvMut<'a, T> where T: Any + Send + 'static + Sized, { @@ -137,7 +137,7 @@ impl FunctionEnvMut<'_, T> { } /// Borrows a new mutable reference of both the attached Store and host state - pub fn data_and_store_mut(&mut self) -> (&mut T, StoreMut) { + pub fn data_and_store_mut<'a>(&'a mut self) -> (&'a mut T, StoreMut<'a>) { let data = self.func_env.as_mut(&mut self.store_mut) as *mut T; // telling the borrow check to close his eyes here // this is still relatively safe to do as func_env are @@ -185,16 +185,16 @@ impl crate::FunctionEnv { /// Convert a reference to [`self`] into a reference to [`crate::backend::wasmi::function::env::FunctionEnv`]. pub fn as_wasmi(&self) -> &FunctionEnv { - match self.0 { - crate::BackendFunctionEnv::Wasmi(ref s) => s, + match &self.0 { + crate::BackendFunctionEnv::Wasmi(s) => s, _ => panic!("Not a `wasmi` function env!"), } } /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::wasmi::function::env::FunctionEnv`]. pub fn as_wasmi_mut(&mut self) -> &mut FunctionEnv { - match self.0 { - crate::BackendFunctionEnv::Wasmi(ref mut s) => s, + match &mut self.0 { + crate::BackendFunctionEnv::Wasmi(s) => s, _ => panic!("Not a `wasmi` function env!"), } } @@ -202,12 +202,12 @@ impl crate::FunctionEnv { impl<'a, T> From> for crate::FunctionEnvMut<'a, T> { fn from(value: FunctionEnvMut<'a, T>) -> Self { - crate::FunctionEnvMut(crate::BackendFunctionEnvMut::Wasmi(value)) + Self(crate::BackendFunctionEnvMut::Wasmi(value)) } } impl From> for crate::FunctionEnv { fn from(value: FunctionEnv) -> Self { - crate::FunctionEnv(crate::BackendFunctionEnv::Wasmi(value)) + Self(crate::BackendFunctionEnv::Wasmi(value)) } } diff --git a/lib/api/src/backend/wasmi/entities/function/mod.rs b/lib/api/src/backend/wasmi/entities/function/mod.rs index fef411bce7..7526fd56b2 100644 --- a/lib/api/src/backend/wasmi/entities/function/mod.rs +++ b/lib/api/src/backend/wasmi/entities/function/mod.rs @@ -7,15 +7,15 @@ use std::{ }; use crate::{ + AsStoreMut, AsStoreRef, BackendFunction, BackendFunctionEnvMut, BackendTrap, + FromToNativeWasmType, FunctionEnv, FunctionEnvMut, IntoResult, NativeWasmType, + NativeWasmTypeInto, RuntimeError, StoreMut, Value, WasmTypeList, WithEnv, WithoutEnv, vm::{VMExtern, VMExternFunction}, wasmi::{ bindings::*, utils::convert::{IntoCApiType, IntoCApiValue, IntoWasmerType, IntoWasmerValue}, vm::{VMFuncRef, VMFunction, VMFunctionCallback, VMFunctionEnvironment}, }, - AsStoreMut, AsStoreRef, BackendFunction, BackendFunctionEnvMut, BackendTrap, - FromToNativeWasmType, FunctionEnv, FunctionEnvMut, IntoResult, NativeWasmType, - NativeWasmTypeInto, RuntimeError, StoreMut, Value, WasmTypeList, WithEnv, WithoutEnv, }; use super::{super::error::Trap, store::StoreHandle}; @@ -90,9 +90,9 @@ impl Function { let params = fn_ty.params(); let mut param_types = params - .into_iter() + .iter() .map(|param| { - let kind = param.into_ct(); + let kind = (*param).into_ct(); unsafe { wasm_valtype_new(kind) } }) .collect::>(); @@ -105,9 +105,9 @@ impl Function { let results = fn_ty.results(); let mut result_types = results - .into_iter() + .iter() .map(|param| { - let kind = param.into_ct(); + let kind = (*param).into_ct(); unsafe { wasm_valtype_new(kind) } }) .collect::>(); @@ -151,7 +151,7 @@ impl Function { panic!("failed when creating new typed function"); } - Function { + Self { handle: wasm_function, } } @@ -164,9 +164,9 @@ impl Function { Rets: WasmTypeList, { let mut param_types = Args::wasm_types() - .into_iter() + .iter() .map(|param| { - let kind = param.into_ct(); + let kind = (*param).into_ct(); unsafe { wasm_valtype_new(kind) } }) .collect::>(); @@ -178,9 +178,9 @@ impl Function { }; let mut result_types = Rets::wasm_types() - .into_iter() + .iter() .map(|param| { - let kind = param.into_ct(); + let kind = (*param).into_ct(); unsafe { wasm_valtype_new(kind) } }) .collect::>(); @@ -225,7 +225,7 @@ impl Function { panic!("failed when creating new typed function"); } - Function { + Self { handle: wasm_function, } } @@ -242,9 +242,9 @@ impl Function { T: Send + 'static, { let mut param_types = Args::wasm_types() - .into_iter() + .iter() .map(|param| { - let kind = param.into_ct(); + let kind = (*param).into_ct(); unsafe { wasm_valtype_new(kind) } }) .collect::>(); @@ -256,9 +256,9 @@ impl Function { }; let mut result_types = Rets::wasm_types() - .into_iter() + .iter() .map(|param| { - let kind = param.into_ct(); + let kind = (*param).into_ct(); unsafe { wasm_valtype_new(kind) } }) .collect::>(); @@ -307,7 +307,7 @@ impl Function { panic!("failed when creating new typed function"); } - Function { + Self { handle: wasm_function, } } @@ -359,7 +359,7 @@ impl Function { let mut args = { unsafe { let mut wasm_params = params - .into_iter() + .iter() .map(|v| IntoCApiValue::into_cv(v.clone())) .collect::>() .into_boxed_slice(); @@ -394,7 +394,7 @@ impl Function { break; } Ok(wasmer_types::OnCalledAction::Trap(trap)) => { - return Err(RuntimeError::user(trap)) + return Err(RuntimeError::user(trap)); } Err(trap) => return Err(RuntimeError::user(trap)), } @@ -406,14 +406,15 @@ impl Function { return Err(Into::::into(trap).into()); } - unsafe { + let values = unsafe { let results = std::ptr::slice_from_raw_parts(results.data, results.size); - return Ok((*results) - .into_iter() + (*results) + .iter() .map(|v| IntoWasmerValue::into_wv(*v)) .collect::>() - .into_boxed_slice()); - } + .into_boxed_slice() + }; + Ok(values) } pub(crate) fn from_vm_extern(_store: &mut impl AsStoreMut, internal: VMExternFunction) -> Self { @@ -459,15 +460,18 @@ where { let r: *mut (FunctionCallbackEnv<'_, F>) = env as _; - let mut store = (*r).store.as_store_mut(); - let env_handle = (*r).env_handle.as_ref().unwrap().clone(); + let mut store = unsafe { (*r).store.as_store_mut() }; + let env_handle = unsafe { (*r).env_handle.as_ref().unwrap().clone() }; let mut fn_env = env::FunctionEnv::from_handle(env_handle).into_mut(&mut store); - let func: &F = &(*r).func; + let func: &F = unsafe { &(*r).func }; let mut wasmer_args = vec![]; + let args_ptr = unsafe { (*args).data }; + let args_len = unsafe { (*args).size }; - for i in 0..(*args).size { - wasmer_args.push((*(*args).data.wrapping_add(i)).into_wv().clone()); + for i in 0..args_len { + let value = unsafe { (*args_ptr.wrapping_add(i)).into_wv().clone() }; + wasmer_args.push(value); } let result = panic::catch_unwind(AssertUnwindSafe(|| unsafe { @@ -481,13 +485,18 @@ where .map(IntoCApiValue::into_cv) .collect(); - if c_results.len() != (*rets).size { - panic!("when calling host function: number of observed results differ from wanted results") + let rets_size = unsafe { (*rets).size }; + if c_results.len() != rets_size { + panic!( + "when calling host function: number of observed results differ from wanted results" + ) } + let rets_ptr = unsafe { (*rets).data }; unsafe { - for i in 0..(*rets).size { - *((*rets).data.wrapping_add(i)) = c_results[i] + let rets_slice = std::slice::from_raw_parts_mut(rets_ptr, rets_size); + for (dst, value) in rets_slice.iter_mut().zip(&c_results) { + *dst = *value; } } @@ -505,7 +514,7 @@ where } } - return fn_callback::; + fn_callback:: } impl std::fmt::Debug for Function { @@ -525,16 +534,16 @@ impl crate::Function { /// Convert a reference to [`self`] into a reference to [`crate::backend::wasmi::function::Function`]. pub fn as_wasmi(&self) -> &crate::backend::wasmi::function::Function { - match self.0 { - BackendFunction::Wasmi(ref s) => s, + match &self.0 { + BackendFunction::Wasmi(s) => s, _ => panic!("Not a `wasmi` function!"), } } /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::wasmi::function::Function`]. pub fn as_wasmi_mut(&mut self) -> &mut crate::backend::wasmi::function::Function { - match self.0 { - BackendFunction::Wasmi(ref mut s) => s, + match &mut self.0 { + BackendFunction::Wasmi(s) => s, _ => panic!("Not a `wasmi` function!"), } } @@ -558,43 +567,49 @@ macro_rules! impl_host_function { RetsAsResult: IntoResult, Func: Fn($( $x , )*) -> RetsAsResult + 'static, { - let mut r: *mut crate::backend::wasmi::function::FunctionCallbackEnv = unsafe {std::mem::transmute(env)}; - let store = &mut (*r).store.as_store_mut(); + let mut r: *mut crate::backend::wasmi::function::FunctionCallbackEnv = unsafe { std::mem::transmute(env) }; + let store = unsafe { &mut (*r).store.as_store_mut() }; let mut i = 0; + let args_ptr = unsafe { (*args).data }; $( - let c_arg = (*(*args).data.wrapping_add(i)).clone(); + let c_arg = unsafe { (*args_ptr.wrapping_add(i)).clone() }; let wasmer_arg = c_arg.into_wv(); let raw_arg : RawValue = wasmer_arg.as_raw(store); - let $x : $x = FromToNativeWasmType::from_native($x::Native::from_raw(store, raw_arg)); + let native_value = unsafe { $x::Native::from_raw(store, raw_arg) }; + let $x : $x = FromToNativeWasmType::from_native(native_value); i += 1; )* + let func = unsafe { &(*r).func }; let result = panic::catch_unwind(AssertUnwindSafe(|| unsafe { - ((*r).func)( $( $x, )* ).into_result() + (func)( $( $x, )* ).into_result() })); match result { Ok(Ok(result)) => { let types = Rets::wasm_types(); - let mut native_results = result.into_array(store); + let mut native_results = unsafe { result.into_array(store) }; let native_results = native_results.as_mut(); - let native_results: Vec = native_results.into_iter().enumerate() - .map(|(i, r)| Value::from_raw(store, types[i], r.clone())) + let native_results: Vec = native_results.iter().enumerate() + .map(|(i, r)| unsafe { Value::from_raw(store, types[i], r.clone()) }) .collect(); let mut c_results: Vec = native_results.into_iter().map(IntoCApiValue::into_cv).collect(); - - if c_results.len() != (*results).size { + let results_len = unsafe { (*results).size }; + if c_results.len() != results_len { panic!("when calling host function: number of observed results differ from wanted results") } + let results_ptr = unsafe { (*results).data }; unsafe { - for i in 0..(*results).size { - *((*results).data.wrapping_add(i)) = c_results[i] + let results_slice = + std::slice::from_raw_parts_mut(results_ptr, results_len); + for (dst, value) in results_slice.iter_mut().zip(&c_results) { + *dst = *value; } } @@ -630,47 +645,51 @@ macro_rules! impl_host_function { { let r: *mut (crate::backend::wasmi::function::FunctionCallbackEnv<'_, Func>) = env as _; - let store = &mut (*r).store.as_store_mut(); + let store = unsafe { &mut (*r).store.as_store_mut() }; let mut i = 0; + let args_ptr = unsafe { (*args).data }; $( - let c_arg = (*(*args).data.wrapping_add(i)).clone(); + let c_arg = unsafe { (*args_ptr.wrapping_add(i)).clone() }; let wasmer_arg = c_arg.into_wv(); let raw_arg : RawValue = wasmer_arg.as_raw(store); - let $x : $x = FromToNativeWasmType::from_native($x::Native::from_raw(store, raw_arg)); + let native_value = unsafe { $x::Native::from_raw(store, raw_arg) }; + let $x : $x = FromToNativeWasmType::from_native(native_value); i += 1; )* - let env_handle = (*r).env_handle.as_ref().unwrap().clone(); + let env_handle = unsafe { (*r).env_handle.as_ref().unwrap().clone() }; let mut fn_env = crate::backend::wasmi::function::env::FunctionEnv::from_handle(env_handle).into_mut(store); - let func: &Func = &(*r).func; + let func: &Func = unsafe { &(*r).func }; let result = panic::catch_unwind(AssertUnwindSafe(|| unsafe { - ((*r).func)(BackendFunctionEnvMut::Wasmi(fn_env).into(), $( $x, )* ).into_result() + (func)(BackendFunctionEnvMut::Wasmi(fn_env).into(), $( $x, )* ).into_result() })); match result { Ok(Ok(result)) => { let types = Rets::wasm_types(); - let mut native_results = result.into_array(store); + let mut native_results = unsafe { result.into_array(store) }; let native_results = native_results.as_mut(); - let native_results: Vec = native_results.into_iter().enumerate().map(|(i, r)| Value::from_raw(store, types[i], r.clone())).collect(); + let native_results: Vec = native_results.iter().enumerate().map(|(i, r)| unsafe { Value::from_raw(store, types[i], r.clone()) }).collect(); let mut c_results: Vec = native_results.into_iter().map(IntoCApiValue::into_cv).collect(); - - if c_results.len() != (*results).size { + let results_len = unsafe { (*results).size }; + if c_results.len() != results_len { panic!("when calling host function: number of observed results differ from wanted results") } + let results_ptr = unsafe { (*results).data }; unsafe { - for i in 0..(*results).size { - *((*results).data.wrapping_add(i)) = c_results[i] + let results_slice = + std::slice::from_raw_parts_mut(results_ptr, results_len); + for (dst, value) in results_slice.iter_mut().zip(&c_results) { + *dst = *value; } - } unsafe { std::ptr::null_mut() } diff --git a/lib/api/src/backend/wasmi/entities/function/typed.rs b/lib/api/src/backend/wasmi/entities/function/typed.rs index d4f4806768..63972edfd9 100644 --- a/lib/api/src/backend/wasmi/entities/function/typed.rs +++ b/lib/api/src/backend/wasmi/entities/function/typed.rs @@ -11,9 +11,9 @@ use std::iter::FromIterator; use crate::{ - backend::wasmi::{bindings::*, error::Trap, function::Function, utils::convert::*}, AsStoreMut, FromToNativeWasmType, NativeWasmType, NativeWasmTypeInto, RuntimeError, TypedFunction, Value, WasmTypeList, + backend::wasmi::{bindings::*, error::Trap, function::Function, utils::convert::*}, }; use wasmer_types::RawValue; @@ -131,9 +131,15 @@ impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15 +); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16 +); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17 +); impl_native_traits!( A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18 ); diff --git a/lib/api/src/backend/wasmi/entities/global.rs b/lib/api/src/backend/wasmi/entities/global.rs index 3304083423..393bb61e78 100644 --- a/lib/api/src/backend/wasmi/entities/global.rs +++ b/lib/api/src/backend/wasmi/entities/global.rs @@ -2,6 +2,7 @@ use wasmer_types::{GlobalType, Mutability}; use crate::{ + AsStoreMut, AsStoreRef, RuntimeError, Value, vm::{VMExtern, VMExternGlobal}, wasmi::{ bindings::{ @@ -12,7 +13,6 @@ use crate::{ utils::convert::{IntoCApiType, IntoCApiValue, IntoWasmerType, IntoWasmerValue}, vm::VMGlobal, }, - AsStoreMut, AsStoreRef, RuntimeError, Value, }; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/lib/api/src/backend/wasmi/entities/instance.rs b/lib/api/src/backend/wasmi/entities/instance.rs index 5b3bcc14e2..72765dc3e5 100644 --- a/lib/api/src/backend/wasmi/entities/instance.rs +++ b/lib/api/src/backend/wasmi/entities/instance.rs @@ -2,9 +2,9 @@ use std::sync::Arc; use crate::{ + AsStoreMut, AsStoreRef, Exports, Extern, Imports, InstantiationError, Module, backend::wasmi::bindings::*, entities::external::VMExternToExtern, vm::VMExtern, - wasmi::error::Trap, AsStoreMut, AsStoreRef, Exports, Extern, Imports, InstantiationError, - Module, + wasmi::error::Trap, }; #[derive(PartialEq, Eq)] @@ -14,6 +14,7 @@ unsafe impl Send for InstanceHandle {} unsafe impl Sync for InstanceHandle {} impl InstanceHandle { + #[allow(clippy::result_large_err, clippy::unnecessary_mut_passed)] fn new( store: *mut wasm_store_t, module: *mut wasm_module_t, @@ -48,7 +49,7 @@ impl InstanceHandle { return Err(InstantiationError::Start(trap.into())); } - Ok(InstanceHandle(instance)) + Ok(Self(instance)) } fn get_exports(&self, mut store: &mut impl AsStoreMut, module: &Module) -> Exports { @@ -77,7 +78,7 @@ impl InstanceHandle { let c_api_exports: Exports = c_api_exports .into_iter() - .zip(c_api_externs.into_iter()) + .zip(c_api_externs) .map(|(export, ext)| unsafe { let name = wasm_exporttype_name(export); let name = std::slice::from_raw_parts((*name).data as *const u8, (*name).size); @@ -110,6 +111,7 @@ pub struct Instance { } impl Instance { + #[allow(clippy::result_large_err)] pub(crate) fn new( store: &mut impl AsStoreMut, module: &Module, @@ -124,9 +126,10 @@ impl Instance { }) .collect::>(); - return Self::new_by_index(store, module, &externs); + Self::new_by_index(store, module, &externs) } + #[allow(clippy::result_large_err)] pub(crate) fn new_by_index( store: &mut impl AsStoreMut, module: &Module, diff --git a/lib/api/src/backend/wasmi/entities/memory/mod.rs b/lib/api/src/backend/wasmi/entities/memory/mod.rs index f7c0c64b60..db0858db64 100644 --- a/lib/api/src/backend/wasmi/entities/memory/mod.rs +++ b/lib/api/src/backend/wasmi/entities/memory/mod.rs @@ -7,10 +7,10 @@ pub use wasmer_types::MemoryError; use wasmer_types::{MemoryType, Pages, WASM_PAGE_SIZE}; use crate::{ + AsStoreMut, AsStoreRef, BackendMemory, MemoryAccessError, shared::SharedMemory, vm::{VMExtern, VMExternMemory}, wasmi::{bindings::*, vm::VMMemory}, - AsStoreMut, AsStoreRef, BackendMemory, MemoryAccessError, }; pub(crate) mod view; @@ -167,7 +167,7 @@ impl Memory { /// Cloning memory will create another reference to the same memory that /// can be put into a new store pub fn try_clone(&self, _store: &impl AsStoreRef) -> Result { - Ok(self.handle.clone()) + Ok(self.handle) } /// Copying the memory will actually copy all the bytes in the memory to @@ -295,26 +295,28 @@ impl<'a> MemoryBuffer<'a> { unsafe fn volatile_memcpy_read(mut src: *const u8, mut dst: *mut u8, mut len: usize) { #[inline] unsafe fn copy_one(src: &mut *const u8, dst: &mut *mut u8, len: &mut usize) { - #[repr(packed)] + #[repr(C, packed)] struct Unaligned(T); - let val = (*src as *const Unaligned).read_volatile(); - (*dst as *mut Unaligned).write(val); - *src = src.add(std::mem::size_of::()); - *dst = dst.add(std::mem::size_of::()); - *len -= std::mem::size_of::(); + unsafe { + let val = (*src as *const Unaligned).read_volatile(); + (*dst as *mut Unaligned).write(val); + *src = src.add(std::mem::size_of::()); + *dst = dst.add(std::mem::size_of::()); + *len -= std::mem::size_of::(); + } } while len >= 8 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } if len >= 4 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } if len >= 2 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } if len >= 1 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } } @@ -322,26 +324,28 @@ unsafe fn volatile_memcpy_read(mut src: *const u8, mut dst: *mut u8, mut len: us unsafe fn volatile_memcpy_write(mut src: *const u8, mut dst: *mut u8, mut len: usize) { #[inline] unsafe fn copy_one(src: &mut *const u8, dst: &mut *mut u8, len: &mut usize) { - #[repr(packed)] + #[repr(C, packed)] struct Unaligned(T); - let val = (*src as *const Unaligned).read(); - (*dst as *mut Unaligned).write_volatile(val); - *src = src.add(std::mem::size_of::()); - *dst = dst.add(std::mem::size_of::()); - *len -= std::mem::size_of::(); + unsafe { + let val = (*src as *const Unaligned).read(); + (*dst as *mut Unaligned).write_volatile(val); + *src = src.add(std::mem::size_of::()); + *dst = dst.add(std::mem::size_of::()); + *len -= std::mem::size_of::(); + } } while len >= 8 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } if len >= 4 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } if len >= 2 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } if len >= 1 { - copy_one::(&mut src, &mut dst, &mut len); + unsafe { copy_one::(&mut src, &mut dst, &mut len) }; } } @@ -356,16 +360,16 @@ impl crate::Memory { /// Convert a reference to [`self`] into a reference to [`crate::backend::wasmi::memory::Memory`]. pub fn as_wasmi(&self) -> &crate::backend::wasmi::memory::Memory { - match self.0 { - BackendMemory::Wasmi(ref s) => s, + match &self.0 { + BackendMemory::Wasmi(s) => s, _ => panic!("Not a `wasmi` memory!"), } } /// Convert a mutable reference to [`self`] into a mutable reference to [`crate::backend::wasmi::memory::Memory`]. pub fn as_wasmi_mut(&mut self) -> &mut crate::backend::wasmi::memory::Memory { - match self.0 { - BackendMemory::Wasmi(ref mut s) => s, + match &mut self.0 { + BackendMemory::Wasmi(s) => s, _ => panic!("Not a `wasmi` memory!"), } } diff --git a/lib/api/src/backend/wasmi/entities/memory/view.rs b/lib/api/src/backend/wasmi/entities/memory/view.rs index 51adca872b..90b17d6800 100644 --- a/lib/api/src/backend/wasmi/entities/memory/view.rs +++ b/lib/api/src/backend/wasmi/entities/memory/view.rs @@ -4,9 +4,9 @@ use wasmer_types::Pages; use super::{Memory, MemoryBuffer}; use crate::{ + AsStoreRef, MemoryAccessError, backend::wasmi::bindings::{wasm_memory_data, wasm_memory_data_size, wasm_memory_size}, wasmi::bindings::wasm_memory_t, - AsStoreRef, MemoryAccessError, }; /// A WebAssembly `memory` view. @@ -25,7 +25,7 @@ impl<'a> MemoryView<'a> { pub(crate) fn new(memory: &Memory, store: &'a (impl AsStoreRef + ?Sized)) -> Self { let c_memory: *mut wasm_memory_t = memory.handle; - let len = unsafe { wasm_memory_data_size(c_memory as _).try_into().unwrap() }; + let len = unsafe { wasm_memory_data_size(c_memory as _) }; let base: *mut u8 = unsafe { wasm_memory_data(c_memory as _) as _ }; let size = unsafe { wasm_memory_size(c_memory as _) }; @@ -62,7 +62,7 @@ impl<'a> MemoryView<'a> { /// function that writes to the memory or by resizing the memory. #[doc(hidden)] pub unsafe fn data_unchecked(&self) -> &[u8] { - self.data_unchecked_mut() + unsafe { std::slice::from_raw_parts(self.buffer.base as *const u8, self.buffer.len) } } /// Retrieve a mutable slice of the memory contents. @@ -77,7 +77,7 @@ impl<'a> MemoryView<'a> { #[allow(clippy::mut_from_ref)] #[doc(hidden)] pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] { - std::slice::from_raw_parts_mut(self.buffer.base, self.buffer.len) + unsafe { std::slice::from_raw_parts_mut(self.buffer.base, self.buffer.len) } } /// Returns the size (in [`Pages`]) of the `Memory`. diff --git a/lib/api/src/backend/wasmi/entities/module.rs b/lib/api/src/backend/wasmi/entities/module.rs index ad0aa9d39d..a0b5d98241 100644 --- a/lib/api/src/backend/wasmi/entities/module.rs +++ b/lib/api/src/backend/wasmi/entities/module.rs @@ -2,10 +2,10 @@ use std::{path::Path, sync::Arc}; use crate::{ + AsEngineRef, BackendModule, IntoBytes, backend::wasmi::bindings::{ wasm_byte_vec_t, wasm_module_delete, wasm_module_new, wasm_module_t, }, - AsEngineRef, BackendModule, IntoBytes, }; use bytes::Bytes; @@ -42,10 +42,10 @@ impl ModuleHandle { let store = std::sync::Mutex::new(store); if inner.is_null() { - return Err(CompileError::Validate(format!("module is null"))); + return Err(CompileError::Validate("module is null".to_string())); } - Ok(ModuleHandle { inner, store }) + Ok(Self { inner, store }) } } impl Drop for ModuleHandle { @@ -74,6 +74,7 @@ impl Module { unsafe { Self::from_binary_unchecked(_engine, binary) } } + #[allow(clippy::arc_with_non_send_sync)] pub(crate) unsafe fn from_binary_unchecked( engine: &impl AsEngineRef, binary: &[u8], @@ -103,24 +104,23 @@ impl Module { } pub fn serialize(&self) -> Result { - return self.raw_bytes.clone().ok_or(SerializeError::Generic( + self.raw_bytes.clone().ok_or(SerializeError::Generic( "Not able to serialize module".to_string(), - )); + )) } pub unsafe fn deserialize_unchecked( engine: &impl AsEngineRef, bytes: impl IntoBytes, ) -> Result { - Self::deserialize(engine, bytes) + unsafe { Self::deserialize(engine, bytes) } } pub unsafe fn deserialize( engine: &impl AsEngineRef, bytes: impl IntoBytes, ) -> Result { - return Self::from_binary(engine, &bytes.into_bytes()) - .map_err(|e| DeserializeError::Compiler(e)); + Self::from_binary(engine, &bytes.into_bytes()).map_err(DeserializeError::Compiler) } pub unsafe fn deserialize_from_file_unchecked( @@ -128,7 +128,7 @@ impl Module { path: impl AsRef, ) -> Result { let bytes = std::fs::read(path.as_ref())?; - Self::deserialize_unchecked(engine, bytes) + unsafe { Self::deserialize_unchecked(engine, bytes) } } pub unsafe fn deserialize_from_file( @@ -136,7 +136,7 @@ impl Module { path: impl AsRef, ) -> Result { let bytes = std::fs::read(path.as_ref())?; - Self::deserialize(engine, bytes) + unsafe { Self::deserialize(engine, bytes) } } pub fn set_name(&mut self, name: &str) -> bool { @@ -175,16 +175,16 @@ impl crate::Module { /// Convert a reference to [`self`] into a reference [`crate::backend::wasmi::module::Module`]. pub fn as_wasmi(&self) -> &crate::backend::wasmi::module::Module { - match self.0 { - BackendModule::Wasmi(ref s) => s, + match &self.0 { + BackendModule::Wasmi(s) => s, _ => panic!("Not a `wasmi` module!"), } } /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::wasmi::module::Module`]. pub fn as_wasmi_mut(&mut self) -> &mut crate::backend::wasmi::module::Module { - match self.0 { - BackendModule::Wasmi(ref mut s) => s, + match &mut self.0 { + BackendModule::Wasmi(s) => s, _ => panic!("Not a `wasmi` module!"), } } diff --git a/lib/api/src/backend/wasmi/entities/store/mod.rs b/lib/api/src/backend/wasmi/entities/store/mod.rs index f971d270e6..d27503ae74 100644 --- a/lib/api/src/backend/wasmi/entities/store/mod.rs +++ b/lib/api/src/backend/wasmi/entities/store/mod.rs @@ -1,8 +1,8 @@ //! Data types, functions and traits for `wasmi`'s `Store` implementation. use crate::{ + AsStoreRef, BackendStore, StoreRef, backend::wasmi::bindings::{wasm_store_delete, wasm_store_new, wasm_store_t}, engine::{AsEngineRef, Engine, EngineRef}, - AsStoreRef, BackendStore, StoreRef, }; mod obj; @@ -25,7 +25,7 @@ impl std::fmt::Debug for Store { impl Store { pub(crate) fn new(engine: crate::engine::Engine) -> Self { let inner: *mut wasm_store_t = unsafe { wasm_store_new(engine.as_wasmi().inner.engine) }; - Store { inner, engine } + Self { inner, engine } } pub(crate) fn engine(&self) -> &Engine { diff --git a/lib/api/src/backend/wasmi/entities/store/obj.rs b/lib/api/src/backend/wasmi/entities/store/obj.rs index e22eb78b18..3ee18e5bfe 100644 --- a/lib/api/src/backend/wasmi/entities/store/obj.rs +++ b/lib/api/src/backend/wasmi/entities/store/obj.rs @@ -1,8 +1,8 @@ use std::{fmt, marker::PhantomData, num::NonZeroUsize}; use crate::{ - backend::wasmi::vm::{VMFunctionEnvironment, VMGlobal}, AsStoreMut, + backend::wasmi::vm::{VMFunctionEnvironment, VMGlobal}, }; pub use wasmer_types::StoreId; @@ -11,7 +11,7 @@ impl crate::StoreObjects { /// Consume [`self`] into [`crate::backend::wasmi::store::StoreObjects`]. pub fn into_wasmi(self) -> crate::backend::wasmi::store::StoreObjects { match self { - crate::StoreObjects::Wasmi(s) => s, + Self::Wasmi(s) => s, _ => panic!("Not a `wasmi` store!"), } } @@ -19,7 +19,7 @@ impl crate::StoreObjects { /// Convert a reference to [`self`] into a reference [`crate::backend::wasmi::store::StoreObjects`]. pub fn as_wasmi(&self) -> &crate::backend::wasmi::store::StoreObjects { match self { - crate::StoreObjects::Wasmi(s) => s, + Self::Wasmi(s) => s, _ => panic!("Not a `wasmi` store!"), } } @@ -27,7 +27,7 @@ impl crate::StoreObjects { /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::wasmi::store::StoreObjects`]. pub fn as_wasmi_mut(&mut self) -> &mut crate::backend::wasmi::store::StoreObjects { match self { - crate::StoreObjects::Wasmi(s) => s, + Self::Wasmi(s) => s, _ => panic!("Not a `wasmi` store!"), } } @@ -107,7 +107,7 @@ impl StoreObjects { } /// Return an immutable iterator over all globals - pub fn iter_globals(&self) -> core::slice::Iter { + pub fn iter_globals<'a>(&'a self) -> core::slice::Iter<'a, VMGlobal> { self.globals.iter() } diff --git a/lib/api/src/backend/wasmi/entities/table.rs b/lib/api/src/backend/wasmi/entities/table.rs index 52bc54f695..cb8f3b354d 100644 --- a/lib/api/src/backend/wasmi/entities/table.rs +++ b/lib/api/src/backend/wasmi/entities/table.rs @@ -2,13 +2,13 @@ use wasmer_types::TableType; use crate::{ + AsStoreMut, AsStoreRef, BackendKind, BackendTable, RuntimeError, Value, vm::{VMExtern, VMExternTable}, wasmi::{ bindings::{self, *}, utils::convert::{IntoCApiType, IntoCApiValue, IntoWasmerType, IntoWasmerValue}, vm::VMTable, }, - AsStoreMut, AsStoreRef, BackendKind, BackendTable, RuntimeError, Value, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -26,10 +26,7 @@ impl Table { let limits = Box::into_raw(Box::new(wasm_limits_t { min: ty.minimum, - max: match ty.maximum { - Some(v) => v, - None => 0, - }, + max: ty.maximum.unwrap_or_default(), })); unsafe { wasm_tabletype_new(valtype, limits) } @@ -115,7 +112,7 @@ impl Table { _ => { return Err(RuntimeError::new(format!( "Could not grow table due to unsupported init value type: {val:?} " - ))) + ))); } }; @@ -147,7 +144,7 @@ impl Table { _ => { return Err(RuntimeError::new(format!( "Could not grow table due to unsupported init value type: {init:?} " - ))) + ))); } }; if !wasm_table_grow(self.handle, delta, init) { @@ -191,16 +188,16 @@ impl crate::Table { /// Convert a reference to [`self`] into a reference [`crate::backend::wasmi::table::Table`]. pub fn as_wasmi(&self) -> &crate::backend::wasmi::table::Table { - match self.0 { - BackendTable::Wasmi(ref s) => s, + match &self.0 { + BackendTable::Wasmi(s) => s, _ => panic!("Not a `wasmi` table!"), } } /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::wasmi::table::Table`]. pub fn as_wasmi_mut(&mut self) -> &mut crate::backend::wasmi::table::Table { - match self.0 { - BackendTable::Wasmi(ref mut s) => s, + match &mut self.0 { + BackendTable::Wasmi(s) => s, _ => panic!("Not a `wasmi` table!"), } } @@ -218,7 +215,7 @@ impl crate::BackendTable { /// Convert a reference to [`self`] into a reference [`crate::backend::wasmi::table::Table`]. pub fn as_wasmi(&self) -> &crate::backend::wasmi::table::Table { match self { - Self::Wasmi(ref s) => s, + Self::Wasmi(s) => s, _ => panic!("Not a `wasmi` table!"), } } @@ -226,7 +223,7 @@ impl crate::BackendTable { /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::wasmi::table::Table`]. pub fn as_wasmi_mut(&mut self) -> &mut crate::backend::wasmi::table::Table { match self { - Self::Wasmi(ref mut s) => s, + Self::Wasmi(s) => s, _ => panic!("Not a `wasmi` table!"), } } diff --git a/lib/api/src/backend/wasmi/entities/tag.rs b/lib/api/src/backend/wasmi/entities/tag.rs index 901c9ac4bb..277d0322ca 100644 --- a/lib/api/src/backend/wasmi/entities/tag.rs +++ b/lib/api/src/backend/wasmi/entities/tag.rs @@ -2,9 +2,9 @@ use wasmer_types::{TagType, Type}; use crate::{ + AsStoreMut, AsStoreRef, vm::{VMExtern, VMExternTag}, wasmi::vm::VMTag, - AsStoreMut, AsStoreRef, }; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/lib/api/src/backend/wasmi/error.rs b/lib/api/src/backend/wasmi/error.rs index 4c96960419..02f22e61ef 100644 --- a/lib/api/src/backend/wasmi/error.rs +++ b/lib/api/src/backend/wasmi/error.rs @@ -1,9 +1,12 @@ use std::{ error::Error, - ffi::{c_char, CStr}, + ffi::{CStr, c_char}, }; -use crate::{wasmi::bindings::*, AsStoreMut}; +use crate::{ + AsStoreMut, + wasmi::{bindings::*, vm::VMExceptionRef}, +}; #[derive(Debug)] enum InnerTrap { @@ -52,19 +55,31 @@ impl Trap { } } + /// Returns true if the `Trap` is an exception + pub fn is_exception(&self) -> bool { + false + } + + /// If the `Trap` is an uncaught exception, returns it. + pub fn to_exception_ref(&self) -> Option { + None + } + pub unsafe fn into_wasm_trap(self, store: &mut impl AsStoreMut) -> *mut wasm_trap_t { match self.inner { InnerTrap::CApi(t) => t, InnerTrap::User(err) => { let err_ptr = Box::leak(Box::new(err)); - let mut data = std::mem::zeroed(); + let mut data = unsafe { std::mem::zeroed() }; // let x = format!("") - let s1 = format!("🐛{:p}", err_ptr); + let s1 = format!("🐛{err_ptr:p}"); let _s = s1.into_bytes().into_boxed_slice(); - wasm_byte_vec_new(&mut data, _s.len(), _s.as_ptr() as _); + unsafe { + wasm_byte_vec_new(&mut data, _s.len(), _s.as_ptr() as _); + } std::mem::forget(_s); let store = store.as_store_mut(); - wasm_trap_new(store.inner.store.as_wasmi().inner, &mut data) + unsafe { wasm_trap_new(store.inner.store.as_wasmi().inner, &data) } } } } @@ -89,16 +104,12 @@ impl From<*mut wasm_trap_t> for Trap { .unwrap() }; - println!("{message}"); - if message.starts_with("Exception: 🐛") { let ptr_str = message.replace("Exception: 🐛", ""); let ptr: Box = unsafe { let r = ptr_str.trim_start_matches("0x"); - std::ptr::read( - (usize::from_str_radix(&r, 16).unwrap() - as *const Box), - ) + std::ptr::read(usize::from_str_radix(r, 16).unwrap() + as *const Box) }; Self { @@ -124,7 +135,7 @@ impl std::error::Error for Trap { impl std::fmt::Display for Trap { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &self.inner { - InnerTrap::User(e) => write!(f, "{}", e), + InnerTrap::User(e) => write!(f, "{e}"), InnerTrap::CApi(value) => { // let message: wasm_message_t; // wasm_trap_message(value, &mut message); @@ -144,7 +155,7 @@ impl std::fmt::Display for Trap { impl std::fmt::Debug for Trap { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &self.inner { - InnerTrap::User(e) => write!(f, "{}", e), + InnerTrap::User(e) => write!(f, "{e}"), InnerTrap::CApi(value) => { // let message: wasm_message_t; // wasm_trap_message(value, &mut message); @@ -167,6 +178,6 @@ impl From for crate::RuntimeError { return trap.downcast::().unwrap(); } - crate::RuntimeError::new_from_source(crate::BackendTrap::Wasmi(trap), vec![], None) + Self::new_from_source(crate::BackendTrap::Wasmi(trap), vec![], None) } } diff --git a/lib/api/src/backend/wasmi/utils/convert.rs b/lib/api/src/backend/wasmi/utils/convert.rs index 9c2746821e..a1d45fcddb 100644 --- a/lib/api/src/backend/wasmi/utils/convert.rs +++ b/lib/api/src/backend/wasmi/utils/convert.rs @@ -1,5 +1,6 @@ /// Utilities to convert between `wasmi` and `wasmer` values use crate::{ + BackendFunction, Function, Value, wasmi::{ bindings::{ self, wasm_func_as_ref, wasm_val_t, wasm_val_t__bindgen_ty_1, wasm_valkind_t, @@ -7,7 +8,6 @@ use crate::{ }, function, }, - BackendFunction, Function, Value, }; use wasmer_types::Type; @@ -19,37 +19,43 @@ pub trait IntoCApiValue { impl IntoCApiValue for Value { fn into_cv(self) -> wasm_val_t { match self { - Value::I32(val) => wasm_val_t { + Self::I32(val) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_I32 as _, of: wasm_val_t__bindgen_ty_1 { i32_: val }, }, - Value::I64(val) => wasm_val_t { + Self::I64(val) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_I64 as _, of: wasm_val_t__bindgen_ty_1 { i64_: val }, }, - Value::F32(val) => wasm_val_t { + Self::F32(val) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_F32 as _, of: wasm_val_t__bindgen_ty_1 { f32_: val }, }, - Value::F64(val) => wasm_val_t { + Self::F64(val) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_F64 as _, of: wasm_val_t__bindgen_ty_1 { f64_: val }, }, - Value::FuncRef(Some(val)) => wasm_val_t { + Self::FuncRef(Some(val)) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_FUNCREF as _, of: wasm_val_t__bindgen_ty_1 { ref_: unsafe { wasm_func_as_ref(val.as_wasmi().handle) }, }, }, - Value::FuncRef(None) => wasm_val_t { + Self::FuncRef(None) => wasm_val_t { kind: bindings::wasm_valkind_enum_WASM_FUNCREF as _, of: wasm_val_t__bindgen_ty_1 { ref_: unsafe { wasm_func_as_ref(std::ptr::null_mut()) }, }, }, - Value::ExternRef(_) => panic!("Creating host values from guest ExternRefs is not currently supported in wasmi.") , - Value::ExceptionRef(_) => panic!("Creating host values from guest ExceptionRefs is not currently supported in wasmi.") , - Value::V128(_) => panic!("Creating host values from guest V128s is not currently supported in wasmi."), + Self::ExternRef(_) => panic!( + "Creating host values from guest ExternRefs is not currently supported in wasmi." + ), + Self::ExceptionRef(_) => panic!( + "Creating host values from guest ExceptionRefs is not currently supported in wasmi." + ), + Self::V128(_) => { + panic!("Creating host values from guest V128s is not currently supported in wasmi.") + } } } } @@ -109,14 +115,14 @@ pub trait IntoCApiType { impl IntoCApiType for Type { fn into_ct(self) -> wasm_valkind_t { match self as _ { - Type::I32 => bindings::wasm_valkind_enum_WASM_I32 as _, - Type::I64 => bindings::wasm_valkind_enum_WASM_I64 as _, - Type::F32 => bindings::wasm_valkind_enum_WASM_F32 as _, - Type::F64 => bindings::wasm_valkind_enum_WASM_F64 as _, - Type::FuncRef => bindings::wasm_valkind_enum_WASM_FUNCREF as _, - Type::ExternRef => bindings::wasm_valkind_enum_WASM_EXTERNREF as _, - Type::V128 => panic!("wasmi does not support V128!"), - Type::ExceptionRef => panic!("wasmi does not support exnrefs!"), + Self::I32 => bindings::wasm_valkind_enum_WASM_I32 as _, + Self::I64 => bindings::wasm_valkind_enum_WASM_I64 as _, + Self::F32 => bindings::wasm_valkind_enum_WASM_F32 as _, + Self::F64 => bindings::wasm_valkind_enum_WASM_F64 as _, + Self::FuncRef => bindings::wasm_valkind_enum_WASM_FUNCREF as _, + Self::ExternRef => bindings::wasm_valkind_enum_WASM_EXTERNREF as _, + Self::V128 => panic!("wasmi does not support V128!"), + Self::ExceptionRef => panic!("wasmi does not support exnrefs!"), } } } diff --git a/lib/api/src/backend/wasmi/vm/mod.rs b/lib/api/src/backend/wasmi/vm/mod.rs index 43f490b86c..055785fb8f 100644 --- a/lib/api/src/backend/wasmi/vm/mod.rs +++ b/lib/api/src/backend/wasmi/vm/mod.rs @@ -44,12 +44,13 @@ pub(crate) type VMExternObj = (); pub(crate) type VMConfig = (); impl crate::VMExternToExtern for VMExtern { + #[allow(clippy::not_unsafe_ptr_arg_deref)] fn to_extern(self, store: &mut impl AsStoreMut) -> Extern { - let kind = unsafe { wasm_extern_kind(&mut *self) }; + let kind = unsafe { wasm_extern_kind(self) }; match kind as u32 { 0 => { - let func = unsafe { wasm_extern_as_func(&mut *self) }; + let func = unsafe { wasm_extern_as_func(self) }; if func.is_null() { panic!("The wasm-c-api reported extern as function, but is not"); } @@ -59,7 +60,7 @@ impl crate::VMExternToExtern for VMExtern { )) } 1 => { - let global = unsafe { wasm_extern_as_global(&mut *self) }; + let global = unsafe { wasm_extern_as_global(self) }; if global.is_null() { panic!("The wasm-c-api reported extern as a global, but is not"); } @@ -69,7 +70,7 @@ impl crate::VMExternToExtern for VMExtern { )) } 2 => { - let table = unsafe { wasm_extern_as_table(&mut *self) }; + let table = unsafe { wasm_extern_as_table(self) }; if table.is_null() { panic!("The wasm-c-api reported extern as a table, but is not"); } @@ -79,7 +80,7 @@ impl crate::VMExternToExtern for VMExtern { )) } 3 => { - let memory = unsafe { wasm_extern_as_memory(&mut *self) }; + let memory = unsafe { wasm_extern_as_memory(self) }; if memory.is_null() { panic!("The wasm-c-api reported extern as a table, but is not"); } @@ -127,7 +128,7 @@ impl VMFuncRef { } } -pub(crate) struct VMExceptionRef(*mut wasm_ref_t); +pub struct VMExceptionRef(*mut wasm_ref_t); impl VMExceptionRef { /// Converts the `VMExceptionRef` into a `RawValue`. pub fn into_raw(self) -> RawValue { diff --git a/lib/api/src/entities/engine/engine_ref.rs b/lib/api/src/entities/engine/engine_ref.rs index d33eb04860..8edaa93d54 100644 --- a/lib/api/src/entities/engine/engine_ref.rs +++ b/lib/api/src/entities/engine/engine_ref.rs @@ -61,7 +61,7 @@ where impl AsEngineRef for Engine { #[inline] - fn as_engine_ref(&self) -> EngineRef { + fn as_engine_ref(&self) -> EngineRef<'_> { EngineRef { inner: self } } } diff --git a/lib/api/src/entities/engine/inner.rs b/lib/api/src/entities/engine/inner.rs index 8c0326e1d6..f37af54f34 100644 --- a/lib/api/src/entities/engine/inner.rs +++ b/lib/api/src/entities/engine/inner.rs @@ -1,6 +1,6 @@ use bytes::Bytes; use std::{path::Path, sync::Arc}; -use wasmer_types::{target::Target, DeserializeError, Features}; +use wasmer_types::{DeserializeError, Features, target::Target}; #[cfg(feature = "sys")] use wasmer_compiler::Artifact; @@ -8,8 +8,8 @@ use wasmer_compiler::Artifact; use wasmer_compiler::CompilerConfig; use crate::{ - macros::backend::{gen_rt_ty, match_rt}, BackendKind, IntoBytes, Store, + macros::backend::{gen_rt_ty, match_rt}, }; gen_rt_ty!(Engine @derives Debug, Clone); @@ -44,7 +44,9 @@ impl BackendEngine { ) -> Result, DeserializeError> { match self { #[cfg(feature = "sys")] - Self::Sys(s) => s.deserialize_unchecked(bytes.into_bytes().to_owned().into()), + Self::Sys(s) => unsafe { + s.deserialize_unchecked(bytes.into_bytes().to_owned().into()) + }, _ => Err(DeserializeError::Generic( "The selected runtime does not support `deserialize_unchecked`".into(), )), @@ -66,7 +68,7 @@ impl BackendEngine { ) -> Result, DeserializeError> { match self { #[cfg(feature = "sys")] - Self::Sys(s) => s.deserialize(bytes.into_bytes().to_owned().into()), + Self::Sys(s) => unsafe { s.deserialize(bytes.into_bytes().to_owned().into()) }, _ => Err(DeserializeError::Generic( "The selected runtime does not support `deserialize`".into(), )), @@ -93,7 +95,7 @@ impl BackendEngine { ) -> Result, DeserializeError> { match self { #[cfg(feature = "sys")] - Self::Sys(s) => s.deserialize_from_file_unchecked(file_ref), + Self::Sys(s) => unsafe { s.deserialize_from_file_unchecked(file_ref) }, _ => Err(DeserializeError::Generic( "The selected runtime does not support `deserialize_from_file_unchecked`".into(), )), @@ -117,7 +119,7 @@ impl BackendEngine { ) -> Result, DeserializeError> { match self { #[cfg(feature = "sys")] - Self::Sys(s) => s.deserialize_from_file(file_ref), + Self::Sys(s) => unsafe { s.deserialize_from_file(file_ref) }, _ => Err(DeserializeError::Generic( "The selected runtime does not support `deserialize_from_file`".into(), )), diff --git a/lib/api/src/entities/engine/mod.rs b/lib/api/src/entities/engine/mod.rs index b28b250918..1537507a9d 100644 --- a/lib/api/src/entities/engine/mod.rs +++ b/lib/api/src/entities/engine/mod.rs @@ -3,8 +3,8 @@ use bytes::Bytes; use std::{path::Path, sync::Arc}; use wasmer_types::{ - target::{Target, UserCompilerOptimizations}, CompileError, DeserializeError, Features, + target::{Target, UserCompilerOptimizations}, }; #[cfg(feature = "sys")] @@ -186,7 +186,7 @@ impl Engine { &self, bytes: impl IntoBytes, ) -> Result, DeserializeError> { - self.be.deserialize_unchecked(bytes) + unsafe { self.be.deserialize_unchecked(bytes) } } #[cfg(all(feature = "sys", not(target_arch = "wasm32")))] @@ -198,7 +198,7 @@ impl Engine { /// Currently, only the `sys` engines support it, and only when the target /// architecture is not `wasm32`. unsafe fn deserialize(&self, bytes: impl IntoBytes) -> Result, DeserializeError> { - self.be.deserialize(bytes) + unsafe { self.be.deserialize(bytes) } } #[cfg(all(feature = "sys", not(target_arch = "wasm32")))] @@ -218,7 +218,7 @@ impl Engine { &self, file_ref: &Path, ) -> Result, DeserializeError> { - self.be.deserialize_from_file_unchecked(file_ref) + unsafe { self.be.deserialize_from_file_unchecked(file_ref) } } #[cfg(all(feature = "sys", not(target_arch = "wasm32")))] @@ -235,7 +235,7 @@ impl Engine { &self, file_ref: &Path, ) -> Result, DeserializeError> { - self.be.deserialize_from_file_unchecked(file_ref) + unsafe { self.be.deserialize_from_file_unchecked(file_ref) } } /// Add suggested optimizations to this engine. diff --git a/lib/api/src/entities/exception/exnref/inner.rs b/lib/api/src/entities/exception/exnref/inner.rs deleted file mode 100644 index 9940a78a2f..0000000000 --- a/lib/api/src/entities/exception/exnref/inner.rs +++ /dev/null @@ -1,135 +0,0 @@ -use std::any::Any; - -use crate::entities::store::{AsStoreMut, AsStoreRef}; -use crate::macros::backend::{gen_rt_ty, match_rt}; -use crate::vm::VMExceptionRef; -use crate::StoreRef; - -gen_rt_ty!(ExceptionRef @derives derive_more::From, Debug, Clone ; @path exception); - -impl BackendExceptionRef { - /// Make a new extern reference - pub fn new(store: &mut impl AsStoreMut, value: T) -> Self - where - T: Any + Send + Sync + 'static + Sized, - { - match &store.as_store_mut().inner.store { - #[cfg(feature = "sys")] - crate::BackendStore::Sys(s) => Self::Sys( - crate::backend::sys::entities::exception::ExceptionRef::new(store, value), - ), - #[cfg(feature = "wamr")] - crate::BackendStore::Wamr(s) => Self::Wamr( - crate::backend::wamr::entities::exception::ExceptionRef::new(store, value), - ), - #[cfg(feature = "wasmi")] - crate::BackendStore::Wasmi(s) => Self::Wasmi( - crate::backend::wasmi::entities::exception::ExceptionRef::new(store, value), - ), - #[cfg(feature = "v8")] - crate::BackendStore::V8(s) => Self::V8( - crate::backend::v8::entities::exception::ExceptionRef::new(store, value), - ), - #[cfg(feature = "js")] - crate::BackendStore::Js(s) => Self::Js( - crate::backend::js::entities::exception::ExceptionRef::new(store, value), - ), - #[cfg(feature = "jsc")] - crate::BackendStore::Jsc(s) => Self::Jsc( - crate::backend::jsc::entities::exception::ExceptionRef::new(store, value), - ), - } - } - - /// Try to downcast to the given value. - pub fn downcast<'a, T>(&self, store: &'a impl AsStoreRef) -> Option<&'a T> - where - T: Any + Send + Sync + 'static + Sized, - { - match_rt!(on self => r { - r.downcast::(store) - }) - } - - /// Create a [`VMExceptionRef`] from [`Self`]. - pub(crate) fn vm_exceptionref(&self) -> VMExceptionRef { - match self { - #[cfg(feature = "sys")] - Self::Sys(r) => VMExceptionRef::Sys(r.vm_exceptionref()), - #[cfg(feature = "wamr")] - Self::Wamr(r) => VMExceptionRef::Wamr(r.vm_exceptionref()), - #[cfg(feature = "wasmi")] - Self::Wasmi(r) => VMExceptionRef::Wasmi(r.vm_exceptionref()), - #[cfg(feature = "v8")] - Self::V8(r) => VMExceptionRef::V8(r.vm_exceptionref()), - #[cfg(feature = "js")] - Self::Js(r) => VMExceptionRef::Js(r.vm_exceptionref()), - #[cfg(feature = "jsc")] - Self::Jsc(r) => VMExceptionRef::Jsc(r.vm_exceptionref()), - } - } - - /// Create an instance of [`Self`] from a [`VMExceptionRef`]. - pub(crate) unsafe fn from_vm_exceptionref( - store: &mut impl AsStoreMut, - vm_externref: VMExceptionRef, - ) -> Self { - match &store.as_store_mut().inner.store { - #[cfg(feature = "sys")] - crate::BackendStore::Sys(_) => Self::Sys( - crate::backend::sys::entities::exception::ExceptionRef::from_vm_exceptionref( - store, - vm_externref.into_sys(), - ), - ), - #[cfg(feature = "wamr")] - crate::BackendStore::Wamr(_) => Self::Wamr( - crate::backend::wamr::entities::exception::ExceptionRef::from_vm_exceptionref( - store, - vm_externref.into_wamr(), - ), - ), - #[cfg(feature = "wasmi")] - crate::BackendStore::Wasmi(_) => Self::Wasmi( - crate::backend::wasmi::entities::exception::ExceptionRef::from_vm_exceptionref( - store, - vm_externref.into_wasmi(), - ), - ), - #[cfg(feature = "v8")] - crate::BackendStore::V8(_) => Self::V8( - crate::backend::v8::entities::exception::ExceptionRef::from_vm_exceptionref( - store, - vm_externref.into_v8(), - ), - ), - #[cfg(feature = "js")] - crate::BackendStore::Js(_) => Self::Js( - crate::backend::js::entities::exception::ExceptionRef::from_vm_exceptionref( - store, - vm_externref.into_js(), - ), - ), - #[cfg(feature = "jsc")] - crate::BackendStore::Jsc(_) => Self::Jsc( - crate::backend::jsc::entities::exception::ExceptionRef::from_vm_exceptionref( - store, - vm_externref.into_jsc(), - ), - ), - } - } - - /// Checks whether this `ExceptionRef` can be used with the given context. - /// - /// Primitive (`i32`, `i64`, etc) and null funcref/externref values are not - /// tied to a context and can be freely shared between contexts. - /// - /// Externref and funcref values are tied to a context and can only be used - /// with that context. - pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { - match_rt!(on self => r { - r.is_from_store(store) - }) - } -} diff --git a/lib/api/src/entities/exception/exnref/mod.rs b/lib/api/src/entities/exception/exnref/mod.rs deleted file mode 100644 index c1f8ca02e6..0000000000 --- a/lib/api/src/entities/exception/exnref/mod.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::any::Any; - -use crate::entities::store::{AsStoreMut, AsStoreRef}; -use crate::vm::{VMExceptionRef, VMExternRef}; -use crate::StoreRef; - -pub(crate) mod inner; -pub(crate) use inner::*; - -#[derive(Debug, Clone, derive_more::From)] -/// An opaque reference to some data. This reference can be passed through Wasm. -pub struct ExceptionRef(pub(crate) BackendExceptionRef); - -impl ExceptionRef { - /// Make a new extern reference - pub fn new(store: &mut impl AsStoreMut, value: T) -> Self - where - T: Any + Send + Sync + 'static + Sized, - { - Self(BackendExceptionRef::new(store, value)) - } - - /// Try to downcast to the given value. - pub fn downcast<'a, T>(&self, store: &'a impl AsStoreRef) -> Option<&'a T> - where - T: Any + Send + Sync + 'static + Sized, - { - self.0.downcast(store) - } - - /// Create a [`VMExceptionRef`] from [`Self`]. - pub(crate) fn vm_exceptionref(&self) -> VMExceptionRef { - self.0.vm_exceptionref() - } - - /// Create an instance of [`Self`] from a [`VMExceptionRef`]. - pub(crate) unsafe fn from_vm_exceptionref( - store: &mut impl AsStoreMut, - vm_externref: VMExceptionRef, - ) -> Self { - Self(BackendExceptionRef::from_vm_exceptionref( - store, - vm_externref, - )) - } - - /// Checks whether this `ExceptionRef` can be used with the given context. - /// - /// Primitive (`i32`, `i64`, etc) and null funcref/externref values are not - /// tied to a context and can be freely shared between contexts. - /// - /// Externref and funcref values are tied to a context and can only be used - /// with that context. - pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { - self.0.is_from_store(store) - } -} diff --git a/lib/api/src/entities/exception/inner.rs b/lib/api/src/entities/exception/inner.rs index 3b7c601050..08d0344ca3 100644 --- a/lib/api/src/entities/exception/inner.rs +++ b/lib/api/src/entities/exception/inner.rs @@ -1,7 +1,8 @@ +use crate::vm::VMExceptionRef; use crate::{ + AsStoreMut, AsStoreRef, BackendTag, ExportError, Exportable, Extern, Tag, Value, macros::backend::{gen_rt_ty, match_rt}, vm::{VMExtern, VMExternTag}, - AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, Tag, Value, }; /// A WebAssembly `global` instance. @@ -18,38 +19,72 @@ gen_rt_ty!(Exception impl BackendException { /// Create a new exception with the given tag type and payload. #[inline] - pub fn new(store: &mut impl AsStoreMut, tag: Tag, payload: &[Value]) -> Self { + #[allow(irrefutable_let_patterns)] + pub fn new(store: &mut impl AsStoreMut, tag: &Tag, payload: &[Value]) -> Self { match &store.as_store_mut().inner.store { #[cfg(feature = "sys")] - crate::BackendStore::Sys(_) => Self::Sys( - crate::backend::sys::exception::Exception::new(store, tag, payload), - ), - #[cfg(feature = "wamr")] - crate::BackendStore::Wamr(_) => Self::Wamr( - crate::backend::wamr::exception::Exception::new(store, tag, payload), - ), - #[cfg(feature = "wasmi")] - crate::BackendStore::Wasmi(_) => Self::Wasmi( - crate::backend::wasmi::exception::Exception::new(store, tag, payload), - ), - #[cfg(feature = "v8")] - crate::BackendStore::V8(_) => Self::V8(crate::backend::v8::exception::Exception::new( - store, tag, payload, - )), - #[cfg(feature = "js")] - crate::BackendStore::Js(_) => Self::Js(crate::backend::js::exception::Exception::new( - store, tag, payload, - )), - #[cfg(feature = "jsc")] - crate::BackendStore::Jsc(_) => Self::Jsc( - crate::backend::jsc::exception::Exception::new(store, tag, payload), - ), + crate::BackendStore::Sys(_) => { + let BackendTag::Sys(tag) = &tag.0 else { + panic!("cannot create Exception with Tag from another backend"); + }; + + Self::Sys(crate::backend::sys::exception::Exception::new( + store, tag, payload, + )) + } + _ => unimplemented!("new is only implemented for the sys backend"), } } /// Checks whether this `Exception` can be used with the given store. #[inline] pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { - todo!() + match self { + #[cfg(feature = "sys")] + Self::Sys(s) => s.is_from_store(store), + _ => unimplemented!("is_from_store is only implemented for the sys backend"), + } + } + + /// Gets the exception tag. + #[inline] + pub fn tag(&self, store: &impl AsStoreRef) -> Tag { + match self { + #[cfg(feature = "sys")] + Self::Sys(s) => Tag(BackendTag::Sys(s.tag(store))), + _ => unimplemented!("tag is only implemented for the sys backend"), + } + } + + /// Gets the exception payload values. + #[inline] + pub fn payload(&self, store: &mut impl AsStoreMut) -> Vec { + match self { + #[cfg(feature = "sys")] + Self::Sys(s) => s.payload(store), + _ => unimplemented!("payload is only implemented for the sys backend"), + } + } + + /// Get the `VMExceptionRef` corresponding to this `Exception`. + #[inline] + pub fn vm_exceptionref(&self) -> VMExceptionRef { + match self { + #[cfg(feature = "sys")] + Self::Sys(s) => VMExceptionRef::Sys(s.exnref()), + _ => unimplemented!("vm_exceptionref is only implemented for the sys backend"), + } + } + + /// Creates a new `Exception` from a `VMExceptionRef`. + #[inline] + pub fn from_vm_exceptionref(exnref: VMExceptionRef) -> Self { + match exnref { + #[cfg(feature = "sys")] + VMExceptionRef::Sys(s) => { + Self::Sys(crate::backend::sys::exception::Exception::from_exnref(s)) + } + _ => unimplemented!("from_vm_exceptionref is only implemented for the sys backend"), + } } } diff --git a/lib/api/src/entities/exception/mod.rs b/lib/api/src/entities/exception/mod.rs index 47c562df4e..abdc15acf7 100644 --- a/lib/api/src/entities/exception/mod.rs +++ b/lib/api/src/entities/exception/mod.rs @@ -1,13 +1,10 @@ -pub(crate) mod exnref; -pub use exnref::*; - pub(crate) mod inner; pub(crate) use inner::*; use wasmer_types::{TagType, Type}; use crate::{ - vm::{VMExtern, VMExternTag}, AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, Tag, Value, + vm::{VMExceptionRef, VMExtern, VMExternTag}, }; /// A WebAssembly `exception` instance. @@ -21,13 +18,34 @@ use crate::{ pub struct Exception(pub(crate) BackendException); impl Exception { - /// Create a new exception with the given tag type and payload. - pub fn new(store: &mut impl AsStoreMut, tag: Tag, payload: &[Value]) -> Self { + /// Create a new exception with the given tag and payload, and also creates + /// a reference to it, returning the reference. + pub fn new(store: &mut impl AsStoreMut, tag: &Tag, payload: &[Value]) -> Self { Self(BackendException::new(store, tag, payload)) } - /// Checks whether this `Exception` comes from the given store. + /// Check whether this `Exception` comes from the given store. pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { self.0.is_from_store(store) } + + /// Get the exception tag. + pub fn tag(&self, store: &impl AsStoreRef) -> Tag { + self.0.tag(store) + } + + /// Get the exception payload values. + pub fn payload(&self, store: &mut impl AsStoreMut) -> Vec { + self.0.payload(store) + } + + /// Get the `VMExceptionRef` corresponding to this `Exception`. + pub fn vm_exceptionref(&self) -> VMExceptionRef { + self.0.vm_exceptionref() + } + + /// Create an `Exception` from a `VMExceptionRef`. + pub fn from_vm_exceptionref(exnref: VMExceptionRef) -> Self { + Self(BackendException::from_vm_exceptionref(exnref)) + } } diff --git a/lib/api/src/entities/exports.rs b/lib/api/src/entities/exports.rs index 21a5f902d9..5bda72891d 100644 --- a/lib/api/src/entities/exports.rs +++ b/lib/api/src/entities/exports.rs @@ -175,7 +175,7 @@ impl Exports { } /// Get an iterator over the exports. - pub fn iter(&self) -> ExportsIterator> { + pub fn iter(&self) -> ExportsIterator<'_, indexmap::map::Iter<'_, String, Extern>> { ExportsIterator { iter: self.map.iter(), } diff --git a/lib/api/src/entities/external/extref/inner.rs b/lib/api/src/entities/external/extref/inner.rs index 124218aa89..9c974f7cda 100644 --- a/lib/api/src/entities/external/extref/inner.rs +++ b/lib/api/src/entities/external/extref/inner.rs @@ -1,9 +1,9 @@ use std::any::Any; +use crate::StoreRef; use crate::entities::store::{AsStoreMut, AsStoreRef}; use crate::macros::backend::{gen_rt_ty, match_rt}; use crate::vm::VMExternRef; -use crate::StoreRef; gen_rt_ty!(ExternRef @derives derive_more::From, Debug, Clone ; @path external); @@ -80,47 +80,47 @@ impl BackendExternRef { ) -> Self { match &store.as_store_mut().inner.store { #[cfg(feature = "sys")] - crate::BackendStore::Sys(_) => Self::Sys( + crate::BackendStore::Sys(_) => Self::Sys(unsafe { crate::backend::sys::entities::external::ExternRef::from_vm_externref( store, vm_externref.into_sys(), - ), - ), + ) + }), #[cfg(feature = "wamr")] - crate::BackendStore::Wamr(_) => Self::Wamr( + crate::BackendStore::Wamr(_) => Self::Wamr(unsafe { crate::backend::wamr::entities::external::ExternRef::from_vm_externref( store, vm_externref.into_wamr(), - ), - ), + ) + }), #[cfg(feature = "wasmi")] - crate::BackendStore::Wasmi(_) => Self::Wasmi( + crate::BackendStore::Wasmi(_) => Self::Wasmi(unsafe { crate::backend::wasmi::entities::external::ExternRef::from_vm_externref( store, vm_externref.into_wasmi(), - ), - ), + ) + }), #[cfg(feature = "v8")] - crate::BackendStore::V8(_) => Self::V8( + crate::BackendStore::V8(_) => Self::V8(unsafe { crate::backend::v8::entities::external::ExternRef::from_vm_externref( store, vm_externref.into_v8(), - ), - ), + ) + }), #[cfg(feature = "js")] - crate::BackendStore::Js(_) => Self::Js( + crate::BackendStore::Js(_) => Self::Js(unsafe { crate::backend::js::entities::external::ExternRef::from_vm_externref( store, vm_externref.into_js(), - ), - ), + ) + }), #[cfg(feature = "jsc")] - crate::BackendStore::Jsc(_) => Self::Jsc( + crate::BackendStore::Jsc(_) => Self::Jsc(unsafe { crate::backend::jsc::entities::external::ExternRef::from_vm_externref( store, vm_externref.into_jsc(), - ), - ), + ) + }), } } diff --git a/lib/api/src/entities/external/extref/mod.rs b/lib/api/src/entities/external/extref/mod.rs index 39c60d5d59..6257eb2c10 100644 --- a/lib/api/src/entities/external/extref/mod.rs +++ b/lib/api/src/entities/external/extref/mod.rs @@ -1,8 +1,8 @@ use std::any::Any; +use crate::StoreRef; use crate::entities::store::{AsStoreMut, AsStoreRef}; use crate::vm::VMExternRef; -use crate::StoreRef; pub(crate) mod inner; pub(crate) use inner::*; @@ -38,7 +38,7 @@ impl ExternRef { store: &mut impl AsStoreMut, vm_externref: VMExternRef, ) -> Self { - Self(BackendExternRef::from_vm_externref(store, vm_externref)) + Self(unsafe { BackendExternRef::from_vm_externref(store, vm_externref) }) } /// Checks whether this `ExternRef` can be used with the given context. diff --git a/lib/api/src/entities/external/mod.rs b/lib/api/src/entities/external/mod.rs index 77891b5b5f..7ee104f6eb 100644 --- a/lib/api/src/entities/external/mod.rs +++ b/lib/api/src/entities/external/mod.rs @@ -4,8 +4,8 @@ pub use extref::*; use wasmer_types::ExternType; use crate::{ - vm::VMExtern, AsStoreMut, AsStoreRef, ExportError, Exportable, Function, Global, Memory, Table, - Tag, + AsStoreMut, AsStoreRef, ExportError, Exportable, Function, Global, Memory, Table, Tag, + vm::VMExtern, }; /// Trait convert a VMExtern to a Extern diff --git a/lib/api/src/entities/function/async_host.rs b/lib/api/src/entities/function/async_host.rs new file mode 100644 index 0000000000..01702a9118 --- /dev/null +++ b/lib/api/src/entities/function/async_host.rs @@ -0,0 +1,178 @@ +use std::{future::Future, marker::PhantomData, pin::Pin}; + +use crate::{ + AsyncFunctionEnvMut, HostFunctionKind, RuntimeError, WasmTypeList, WithEnv, WithoutEnv, + utils::{FromToNativeWasmType, IntoResult}, +}; + +/// Wrapper conveying whether an async host function receives an environment. +pub enum AsyncFunctionEnv { + /// Used by host functions without an environment. + WithoutEnv(PhantomData<(T, Kind)>), + /// Used by host functions that capture an environment. + WithEnv(AsyncFunctionEnvMut), +} + +impl AsyncFunctionEnv { + /// Create an environment wrapper for functions without host state. + pub fn new() -> Self { + Self::WithoutEnv(PhantomData) + } +} + +impl AsyncFunctionEnv { + /// Create an environment wrapper carrying [`AsyncFunctionEnvMut`]. + pub fn with_env(env: AsyncFunctionEnvMut) -> Self { + Self::WithEnv(env) + } + + /// Extract the underlying [`AsyncFunctionEnvMut`]. + pub fn into_env(self) -> AsyncFunctionEnvMut { + match self { + Self::WithEnv(env) => env, + Self::WithoutEnv(_) => unreachable!("with-env async function called without env"), + } + } +} + +/// Async counterpart to [`HostFunction`](super::host::HostFunction). +pub trait AsyncHostFunction +where + Args: WasmTypeList + 'static, + Rets: WasmTypeList, + Kind: HostFunctionKind, +{ + /// Invoke the host function asynchronously. + fn call_async( + &self, + env: AsyncFunctionEnv, + args: Args, + ) -> Pin>>>; +} + +macro_rules! impl_async_host_function_without_env { + ( $( $x:ident ),* ) => { + impl<$( $x, )* Rets, RetsAsResult, F, Fut > AsyncHostFunction<(), ( $( $x ),* ), Rets, WithoutEnv> for F + where + F: Fn($( $x ),*) -> Fut + 'static, + Fut: Future + 'static, + RetsAsResult: IntoResult, + Rets: WasmTypeList, + ( $( $x ),* ): WasmTypeList + 'static, + $( $x: FromToNativeWasmType + 'static, )* + { + fn call_async( + &self, + _env: AsyncFunctionEnv<(), WithoutEnv>, + args: ( $( $x ),* ), + ) -> Pin>>> { + #[allow(non_snake_case)] + let ( $( $x ),* ) = args; + let fut = (self)( $( $x ),* ); + Box::pin(async move { + fut.await + .into_result() + .map_err(|err| RuntimeError::from_dyn(Box::new(err))) + }) + } + } + }; +} + +macro_rules! impl_async_host_function_with_env { + ( $( $x:ident ),* ) => { + impl<$( $x, )* Rets, RetsAsResult, T, F, Fut > AsyncHostFunction for F + where + T: 'static, + F: Fn(AsyncFunctionEnvMut, $( $x ),*) -> Fut + 'static, + Fut: Future + 'static, + RetsAsResult: IntoResult, + Rets: WasmTypeList, + ( $( $x ),* ): WasmTypeList + 'static, + $( $x: FromToNativeWasmType + 'static, )* + { + fn call_async( + &self, + env: AsyncFunctionEnv, + args: ( $( $x ),* ), + ) -> Pin>>> { + #[allow(non_snake_case)] + let ( $( $x ),* ) = args; + let fut = (self)(env.into_env(), $( $x ),* ); + Box::pin(async move { + fut.await + .into_result() + .map_err(|err| RuntimeError::from_dyn(Box::new(err))) + }) + } + } + }; +} + +impl_async_host_function_without_env!(); +impl_async_host_function_without_env!(A1); +impl_async_host_function_without_env!(A1, A2); +impl_async_host_function_without_env!(A1, A2, A3); +impl_async_host_function_without_env!(A1, A2, A3, A4); +impl_async_host_function_without_env!(A1, A2, A3, A4, A5); +impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6); +impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7); +impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7, A8); +impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9); +impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); +impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); +impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); +impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); +impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); +impl_async_host_function_without_env!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15 +); +impl_async_host_function_without_env!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16 +); +impl_async_host_function_without_env!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17 +); +impl_async_host_function_without_env!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18 +); +impl_async_host_function_without_env!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19 +); +impl_async_host_function_without_env!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20 +); + +impl_async_host_function_with_env!(); +impl_async_host_function_with_env!(A1); +impl_async_host_function_with_env!(A1, A2); +impl_async_host_function_with_env!(A1, A2, A3); +impl_async_host_function_with_env!(A1, A2, A3, A4); +impl_async_host_function_with_env!(A1, A2, A3, A4, A5); +impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6); +impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7); +impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7, A8); +impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9); +impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); +impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); +impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); +impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); +impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); +impl_async_host_function_with_env!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15 +); +impl_async_host_function_with_env!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16 +); +impl_async_host_function_with_env!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17 +); +impl_async_host_function_with_env!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18 +); +impl_async_host_function_with_env!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19 +); +impl_async_host_function_with_env!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20 +); diff --git a/lib/api/src/entities/function/env/inner.rs b/lib/api/src/entities/function/env/inner.rs index 62427e5108..e1b576623b 100644 --- a/lib/api/src/entities/function/env/inner.rs +++ b/lib/api/src/entities/function/env/inner.rs @@ -1,6 +1,8 @@ +#[cfg(feature = "experimental-async")] +use crate::AsStoreAsync; use crate::{ - macros::backend::match_rt, AsStoreMut, AsStoreRef, FunctionEnv, FunctionEnvMut, StoreMut, - StoreRef, + AsStoreMut, AsStoreRef, FunctionEnv, FunctionEnvMut, StoreMut, StoreRef, + macros::backend::match_rt, }; use std::{any::Any, marker::PhantomData}; @@ -85,11 +87,6 @@ impl BackendFunctionEnv { } } - //#[allow(dead_code)] // This function is only used in js - //pub(crate) fn from_handle(handle: StoreHandle) -> Self { - // todo!() - //} - /// Get the data as reference pub fn as_ref<'a>(&self, store: &'a impl AsStoreRef) -> &'a T where @@ -111,7 +108,7 @@ impl BackendFunctionEnv { } /// Convert it into a `FunctionEnvMut` - pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut + pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut<'_, T> where T: Any + Send + 'static + Sized, { @@ -127,6 +124,7 @@ pub enum BackendFunctionEnvMut<'a, T: 'a> { #[cfg(feature = "sys")] /// The function environment for the `sys` runtime. Sys(crate::backend::sys::function::env::FunctionEnvMut<'a, T>), + #[cfg(feature = "wamr")] /// The function environment for the `wamr` runtime. Wamr(crate::backend::wamr::function::env::FunctionEnvMut<'a, T>), @@ -134,6 +132,7 @@ pub enum BackendFunctionEnvMut<'a, T: 'a> { #[cfg(feature = "wasmi")] /// The function environment for the `wasmi` runtime. Wasmi(crate::backend::wasmi::function::env::FunctionEnvMut<'a, T>), + #[cfg(feature = "v8")] /// The function environment for the `v8` runtime. V8(crate::backend::v8::function::env::FunctionEnvMut<'a, T>), @@ -166,17 +165,17 @@ impl BackendFunctionEnvMut<'_, T> { pub fn as_ref(&self) -> FunctionEnv { match self { #[cfg(feature = "sys")] - Self::Sys(ref f) => BackendFunctionEnv::Sys(f.as_ref()).into(), + Self::Sys(f) => BackendFunctionEnv::Sys(f.as_ref()).into(), #[cfg(feature = "wamr")] - Self::Wamr(ref f) => BackendFunctionEnv::Wamr(f.as_ref()).into(), + Self::Wamr(f) => BackendFunctionEnv::Wamr(f.as_ref()).into(), #[cfg(feature = "wasmi")] - Self::Wasmi(ref f) => BackendFunctionEnv::Wasmi(f.as_ref()).into(), + Self::Wasmi(f) => BackendFunctionEnv::Wasmi(f.as_ref()).into(), #[cfg(feature = "v8")] - Self::V8(ref f) => BackendFunctionEnv::V8(f.as_ref()).into(), + Self::V8(f) => BackendFunctionEnv::V8(f.as_ref()).into(), #[cfg(feature = "js")] - Self::Js(ref f) => BackendFunctionEnv::Js(f.as_ref()).into(), + Self::Js(f) => BackendFunctionEnv::Js(f.as_ref()).into(), #[cfg(feature = "jsc")] - Self::Jsc(ref f) => BackendFunctionEnv::Jsc(f.as_ref()).into(), + Self::Jsc(f) => BackendFunctionEnv::Jsc(f.as_ref()).into(), } } @@ -184,32 +183,46 @@ impl BackendFunctionEnvMut<'_, T> { pub fn as_mut(&mut self) -> FunctionEnvMut<'_, T> { match self { #[cfg(feature = "sys")] - Self::Sys(ref mut f) => BackendFunctionEnvMut::Sys(f.as_mut()).into(), + Self::Sys(f) => BackendFunctionEnvMut::Sys(f.as_mut()).into(), #[cfg(feature = "wamr")] - Self::Wamr(ref mut f) => BackendFunctionEnvMut::Wamr(f.as_mut()).into(), + Self::Wamr(f) => BackendFunctionEnvMut::Wamr(f.as_mut()).into(), #[cfg(feature = "wasmi")] - Self::Wasmi(ref mut f) => BackendFunctionEnvMut::Wasmi(f.as_mut()).into(), + Self::Wasmi(f) => BackendFunctionEnvMut::Wasmi(f.as_mut()).into(), #[cfg(feature = "v8")] - Self::V8(ref mut f) => BackendFunctionEnvMut::V8(f.as_mut()).into(), + Self::V8(f) => BackendFunctionEnvMut::V8(f.as_mut()).into(), #[cfg(feature = "js")] - Self::Js(ref mut f) => BackendFunctionEnvMut::Js(f.as_mut()).into(), + Self::Js(f) => BackendFunctionEnvMut::Js(f.as_mut()).into(), #[cfg(feature = "jsc")] - Self::Jsc(ref mut f) => BackendFunctionEnvMut::Jsc(f.as_mut()).into(), + Self::Jsc(f) => BackendFunctionEnvMut::Jsc(f.as_mut()).into(), } } /// Borrows a new mutable reference of both the attached Store and host state - pub fn data_and_store_mut(&mut self) -> (&mut T, StoreMut) { + pub fn data_and_store_mut(&mut self) -> (&mut T, StoreMut<'_>) { match_rt!(on self => f { f.data_and_store_mut() }) } + + /// Creates an [`AsStoreAsync`] from this [`BackendFunctionEnvMut`] if the current + /// context is async. + #[cfg(feature = "experimental-async")] + pub fn as_store_async(&self) -> Option { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => f.as_store_async(), + #[cfg(feature = "sys")] + _ => unsupported_async_backend(), + #[cfg(not(feature = "sys"))] + _ => unsupported_async_backend::>(), + } + } } impl AsStoreRef for BackendFunctionEnvMut<'_, T> { fn as_store_ref(&self) -> StoreRef<'_> { - match_rt!(on &self => f { - f.as_store_ref() + match_rt!(on self => s { + s.as_store_ref() }) } } @@ -238,3 +251,344 @@ where }) } } + +/// A shared handle to a [`FunctionEnv`], suitable for use +/// in async imports. +#[derive(derive_more::From)] +#[cfg(feature = "experimental-async")] +pub enum BackendAsyncFunctionEnvMut { + #[cfg(feature = "sys")] + /// The function environment for the `sys` runtime. + Sys(crate::backend::sys::function::env::AsyncFunctionEnvMut), + #[cfg(any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ))] + /// Placeholder for unsupported backends. + Unsupported(PhantomData), +} + +/// A read-only handle to the [`FunctionEnv`] in an [`BackendAsyncFunctionEnvMut`]. +#[cfg(feature = "experimental-async")] +pub enum BackendAsyncFunctionEnvHandle { + #[cfg(feature = "sys")] + /// The function environment handle for the `sys` runtime. + Sys(crate::backend::sys::function::env::AsyncFunctionEnvHandle), + #[cfg(any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ))] + /// Placeholder for unsupported backends. + Unsupported(PhantomData), +} + +/// A mutable handle to the [`FunctionEnv`] in an [`BackendAsyncFunctionEnvMut`]. +#[cfg(feature = "experimental-async")] +pub enum BackendAsyncFunctionEnvHandleMut { + #[cfg(feature = "sys")] + /// The function environment handle for the `sys` runtime. + Sys(crate::backend::sys::function::env::AsyncFunctionEnvHandleMut), + #[cfg(any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ))] + /// Placeholder for unsupported backends. + Unsupported(PhantomData), +} + +#[cfg(feature = "experimental-async")] +impl BackendAsyncFunctionEnvMut { + /// Waits for a store lock and returns a read-only handle to the + /// function environment. + pub async fn read(&self) -> BackendAsyncFunctionEnvHandle { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => BackendAsyncFunctionEnvHandle::Sys(f.read().await), + #[cfg(any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ))] + _ => unsupported_async_backend(), + } + } + + /// Waits for a store lock and returns a mutable handle to the + /// function environment. + pub async fn write(&self) -> BackendAsyncFunctionEnvHandleMut { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => BackendAsyncFunctionEnvHandleMut::Sys(f.write().await), + #[cfg(any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ))] + _ => unsupported_async_backend(), + } + } + + /// Borrows a new immutable reference + pub fn as_ref(&self) -> BackendFunctionEnv { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => BackendFunctionEnv::Sys(f.as_ref()), + #[cfg(any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ))] + _ => unsupported_async_backend(), + } + } + + /// Borrows a new mutable reference + pub fn as_mut(&mut self) -> Self { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => Self::Sys(f.as_mut()), + #[cfg(any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ))] + _ => unsupported_async_backend(), + } + } + + /// Creates an [`AsStoreAsync`] from this [`BackendAsyncFunctionEnvMut`]. + pub fn as_store_async(&self) -> impl AsStoreAsync + 'static { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => f.as_store_async(), + #[cfg(all( + feature = "sys", + any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ) + ))] + _ => unsupported_async_backend(), + #[cfg(all( + not(feature = "sys"), + any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ) + ))] + _ => unsupported_async_backend::(), + } + } +} + +#[cfg(feature = "experimental-async")] +impl BackendAsyncFunctionEnvHandle { + /// Returns a reference to the host state in this function environment. + pub fn data(&self) -> &T { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => f.data(), + #[cfg(any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ))] + _ => unsupported_async_backend(), + } + } + + /// Returns both the host state and the attached StoreRef + pub fn data_and_store(&self) -> (&T, &impl AsStoreRef) { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => f.data_and_store(), + #[cfg(all( + feature = "sys", + any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ) + ))] + _ => unsupported_async_backend(), + #[cfg(all( + not(feature = "sys"), + any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ) + ))] + _ => unsupported_async_backend::<(&T, &StoreRef)>(), + } + } +} + +#[cfg(feature = "experimental-async")] +impl AsStoreRef for BackendAsyncFunctionEnvHandle { + fn as_store_ref(&self) -> StoreRef<'_> { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => AsStoreRef::as_store_ref(f), + #[cfg(any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ))] + _ => unsupported_async_backend(), + } + } +} + +#[cfg(feature = "experimental-async")] +impl BackendAsyncFunctionEnvHandleMut { + /// Returns a mutable reference to the host state in this function environment. + pub fn data_mut(&mut self) -> &mut T { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => f.data_mut(), + #[cfg(any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ))] + _ => unsupported_async_backend(), + } + } + + /// Returns both the host state and the attached StoreMut + pub fn data_and_store_mut(&mut self) -> (&mut T, &mut impl AsStoreMut) { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => f.data_and_store_mut(), + #[cfg(all( + feature = "sys", + any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ) + ))] + _ => unsupported_async_backend(), + #[cfg(all( + not(feature = "sys"), + any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ) + ))] + _ => unsupported_async_backend::<(&mut T, &mut crate::StoreMut)>(), + } + } + + /// Borrows a new [`BackendFunctionEnvMut`] from this + /// [`BackendAsyncFunctionEnvHandleMut`]. + pub fn as_function_env_mut(&mut self) -> BackendFunctionEnvMut<'_, T> { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => BackendFunctionEnvMut::Sys(f.as_function_env_mut()), + #[cfg(any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ))] + _ => unsupported_async_backend(), + } + } +} + +#[cfg(feature = "experimental-async")] +impl AsStoreRef for BackendAsyncFunctionEnvHandleMut { + fn as_store_ref(&self) -> StoreRef<'_> { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => AsStoreRef::as_store_ref(f), + #[cfg(any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ))] + _ => unsupported_async_backend(), + } + } +} + +#[cfg(feature = "experimental-async")] +impl AsStoreMut for BackendAsyncFunctionEnvHandleMut { + fn as_store_mut(&mut self) -> StoreMut<'_> { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => AsStoreMut::as_store_mut(f), + #[cfg(any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ))] + _ => unsupported_async_backend(), + } + } + + fn objects_mut(&mut self) -> &mut crate::StoreObjects { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => AsStoreMut::objects_mut(f), + #[cfg(any( + feature = "wamr", + feature = "wasmi", + feature = "v8", + feature = "js", + feature = "jsc" + ))] + _ => unsupported_async_backend(), + } + } +} + +#[cfg(feature = "experimental-async")] +fn unsupported_async_backend() -> T { + panic!("async functions are only supported with the `sys` backend"); +} diff --git a/lib/api/src/entities/function/env/mod.rs b/lib/api/src/entities/function/env/mod.rs index 5d24212e3b..41b49f942b 100644 --- a/lib/api/src/entities/function/env/mod.rs +++ b/lib/api/src/entities/function/env/mod.rs @@ -1,7 +1,9 @@ pub(crate) mod inner; pub(crate) use inner::*; -use crate::{macros::backend::match_rt, AsStoreMut, AsStoreRef, StoreMut, StoreRef}; +#[cfg(feature = "experimental-async")] +use crate::AsStoreAsync; +use crate::{AsStoreMut, AsStoreRef, StoreMut, StoreRef, macros::backend::match_rt}; use std::{any::Any, fmt::Debug, marker::PhantomData}; #[derive(Debug, derive_more::From)] @@ -46,7 +48,7 @@ impl FunctionEnv { } /// Convert it into a `FunctionEnvMut` - pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut + pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut<'_, T> where T: Any + Send + 'static + Sized, { @@ -80,9 +82,16 @@ impl FunctionEnvMut<'_, T> { } /// Borrows a new mutable reference of both the attached Store and host state - pub fn data_and_store_mut(&mut self) -> (&mut T, StoreMut) { + pub fn data_and_store_mut(&mut self) -> (&mut T, StoreMut<'_>) { self.0.data_and_store_mut() } + + /// Creates an [`AsStoreAsync`] from this [`FunctionEnvMut`] if the current + /// context is async. + #[cfg(feature = "experimental-async")] + pub fn as_store_async(&self) -> Option { + self.0.as_store_async() + } } impl AsStoreRef for FunctionEnvMut<'_, T> { @@ -109,3 +118,103 @@ where self.0.fmt(f) } } + +/// A shared handle to a [`FunctionEnv`], suitable for use +/// in async imports. +#[cfg(feature = "experimental-async")] +pub struct AsyncFunctionEnvMut(pub(crate) BackendAsyncFunctionEnvMut); + +/// A read-only handle to the [`FunctionEnv`] in an [`AsyncFunctionEnvMut`]. +#[cfg(feature = "experimental-async")] +pub struct AsyncFunctionEnvHandle(pub(crate) BackendAsyncFunctionEnvHandle); + +/// A mutable handle to the [`FunctionEnv`] in an [`AsyncFunctionEnvMut`]. +#[cfg(feature = "experimental-async")] +pub struct AsyncFunctionEnvHandleMut(pub(crate) BackendAsyncFunctionEnvHandleMut); + +#[cfg(feature = "experimental-async")] +impl AsyncFunctionEnvMut { + /// Waits for a store lock and returns a read-only handle to the + /// function environment. + pub async fn read(&self) -> AsyncFunctionEnvHandle { + AsyncFunctionEnvHandle(self.0.read().await) + } + + /// Waits for a store lock and returns a mutable handle to the + /// function environment. + pub async fn write(&self) -> AsyncFunctionEnvHandleMut { + AsyncFunctionEnvHandleMut(self.0.write().await) + } + + /// Borrows a new immmutable reference + pub fn as_ref(&self) -> FunctionEnv { + FunctionEnv(self.0.as_ref()) + } + + /// Borrows a new mutable reference + pub fn as_mut(&mut self) -> Self { + Self(self.0.as_mut()) + } + + /// Creates an [`AsStoreAsync`] from this [`AsyncFunctionEnvMut`]. + pub fn as_store_async(&self) -> impl AsStoreAsync + 'static { + self.0.as_store_async() + } +} + +#[cfg(feature = "experimental-async")] +impl AsyncFunctionEnvHandle { + /// Returns a reference to the host state in this function environment. + pub fn data(&self) -> &T { + self.0.data() + } + + /// Returns both the host state and the attached StoreRef + pub fn data_and_store(&self) -> (&T, &impl AsStoreRef) { + self.0.data_and_store() + } +} + +#[cfg(feature = "experimental-async")] +impl AsStoreRef for AsyncFunctionEnvHandle { + fn as_store_ref(&self) -> StoreRef<'_> { + AsStoreRef::as_store_ref(&self.0) + } +} + +#[cfg(feature = "experimental-async")] +impl AsyncFunctionEnvHandleMut { + /// Returns a mutable reference to the host state in this function environment. + pub fn data_mut(&mut self) -> &mut T { + self.0.data_mut() + } + + /// Returns both the host state and the attached StoreMut + pub fn data_and_store_mut(&mut self) -> (&mut T, &mut impl AsStoreMut) { + self.0.data_and_store_mut() + } + + /// Borrows a new [`FunctionEnvMut`] from this + /// [`AsyncFunctionEnvHandleMut`]. + pub fn as_function_env_mut(&mut self) -> FunctionEnvMut<'_, T> { + FunctionEnvMut(self.0.as_function_env_mut()) + } +} + +#[cfg(feature = "experimental-async")] +impl AsStoreRef for AsyncFunctionEnvHandleMut { + fn as_store_ref(&self) -> StoreRef<'_> { + AsStoreRef::as_store_ref(&self.0) + } +} + +#[cfg(feature = "experimental-async")] +impl AsStoreMut for AsyncFunctionEnvHandleMut { + fn as_store_mut(&mut self) -> StoreMut<'_> { + AsStoreMut::as_store_mut(&mut self.0) + } + + fn objects_mut(&mut self) -> &mut crate::StoreObjects { + AsStoreMut::objects_mut(&mut self.0) + } +} diff --git a/lib/api/src/entities/function/host/imp.rs b/lib/api/src/entities/function/host/imp.rs index db006b9cb2..5caa5b3342 100644 --- a/lib/api/src/entities/function/host/imp.rs +++ b/lib/api/src/entities/function/host/imp.rs @@ -1,8 +1,8 @@ use crate::{ - utils::{FromToNativeWasmType, IntoResult, NativeWasmTypeInto, WasmTypeList}, AsStoreMut, AsStoreRef, BackendFunctionEnv, BackendFunctionEnvMut, FunctionEnvMut, FunctionType, HostFunction, RuntimeError, StoreInner, StoreMut, StoreRef, Value, WithEnv, WithoutEnv, + utils::{FromToNativeWasmType, IntoResult, NativeWasmTypeInto, WasmTypeList}, }; use std::panic::{self, AssertUnwindSafe}; diff --git a/lib/api/src/entities/function/host/mod.rs b/lib/api/src/entities/function/host/mod.rs index aadc3555ad..b3dcb0023f 100644 --- a/lib/api/src/entities/function/host/mod.rs +++ b/lib/api/src/entities/function/host/mod.rs @@ -1,8 +1,8 @@ mod imp; use crate::{ - vm::{VMFunctionCallback, VMTrampoline}, BackendKind, WasmTypeList, + vm::{VMFunctionCallback, VMTrampoline}, }; /// The `HostFunction` trait represents the set of functions that diff --git a/lib/api/src/entities/function/inner.rs b/lib/api/src/entities/function/inner.rs index 76e4b09253..54bbf742dc 100644 --- a/lib/api/src/entities/function/inner.rs +++ b/lib/api/src/entities/function/inner.rs @@ -1,11 +1,15 @@ +use std::pin::Pin; + use wasmer_types::{FunctionType, RawValue}; +#[cfg(feature = "experimental-async")] +use crate::{AsStoreAsync, AsyncFunctionEnvMut, entities::function::async_host::AsyncHostFunction}; use crate::{ + AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, FunctionEnv, FunctionEnvMut, + HostFunction, StoreMut, StoreRef, TypedFunction, Value, WasmTypeList, WithEnv, WithoutEnv, error::RuntimeError, macros::backend::{gen_rt_ty, match_rt}, vm::{VMExtern, VMExternFunction, VMFuncRef}, - AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, FunctionEnv, FunctionEnvMut, - HostFunction, StoreMut, StoreRef, TypedFunction, Value, WasmTypeList, WithEnv, WithoutEnv, }; /// A WebAssembly `function` instance. @@ -247,6 +251,148 @@ impl BackendFunction { } } + /// Creates a new async host `Function` (dynamic) with the provided + /// signature. + /// + /// If you know the signature of the host function at compile time, + /// consider using [`Self::new_typed_async`] for less runtime overhead. + /// + /// The provided closure returns a future that resolves to the function results. + /// When invoked synchronously + /// (via [`Function::call`](crate::Function::call)) the future will run to + /// completion immediately, provided it doesn't suspend. When invoked through + /// [`Function::call_async`](crate::Function::call_async), the future may suspend + /// and resume as needed. + #[inline] + #[cfg(feature = "experimental-async")] + pub fn new_async(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self + where + FT: Into, + F: Fn(&[Value]) -> Fut + 'static, + Fut: Future, RuntimeError>> + 'static, + { + match &store.as_store_mut().inner.store { + #[cfg(feature = "sys")] + crate::BackendStore::Sys(_) => Self::Sys( + crate::backend::sys::entities::function::Function::new_async(store, ty, func), + ), + #[cfg(feature = "wamr")] + crate::BackendStore::Wamr(_) => unsupported_async_backend("wamr"), + #[cfg(feature = "wasmi")] + crate::BackendStore::Wasmi(_) => unsupported_async_backend("wasmi"), + #[cfg(feature = "v8")] + crate::BackendStore::V8(_) => unsupported_async_backend("v8"), + #[cfg(feature = "js")] + crate::BackendStore::Js(_) => unsupported_async_backend("js"), + #[cfg(feature = "jsc")] + crate::BackendStore::Jsc(_) => unsupported_async_backend("jsc"), + } + } + + /// Creates a new async host `Function` (dynamic) with the provided + /// signature and environment. + /// + /// If you know the signature of the host function at compile time, + /// consider using [`Self::new_typed_with_env_async`] for less runtime overhead. + /// + /// Takes an [`AsyncFunctionEnvMut`] that is passed into func. If + /// that is not required, [`Self::new_async`] might be an option as well. + #[inline] + #[cfg(feature = "experimental-async")] + pub fn new_with_env_async( + store: &mut impl AsStoreMut, + env: &FunctionEnv, + ty: FT, + func: F, + ) -> Self + where + FT: Into, + F: Fn(AsyncFunctionEnvMut, &[Value]) -> Fut + 'static, + Fut: Future, RuntimeError>> + 'static, + { + match &store.as_store_mut().inner.store { + #[cfg(feature = "sys")] + crate::BackendStore::Sys(_) => Self::Sys( + crate::backend::sys::entities::function::Function::new_with_env_async( + store, env, ty, func, + ), + ), + #[cfg(feature = "wamr")] + crate::BackendStore::Wamr(_) => unsupported_async_backend("wamr"), + #[cfg(feature = "wasmi")] + crate::BackendStore::Wasmi(_) => unsupported_async_backend("wasmi"), + #[cfg(feature = "v8")] + crate::BackendStore::V8(_) => unsupported_async_backend("v8"), + #[cfg(feature = "js")] + crate::BackendStore::Js(_) => unsupported_async_backend("js"), + #[cfg(feature = "jsc")] + crate::BackendStore::Jsc(_) => unsupported_async_backend("jsc"), + } + } + + /// Creates a new async host `Function` from a native typed function. + /// + /// The future can return either the raw result tuple or any type that implements + /// [`IntoResult`](crate::IntoResult) for the result tuple (e.g. `Result`). + #[inline] + #[cfg(feature = "experimental-async")] + pub fn new_typed_async(store: &mut impl AsStoreMut, func: F) -> Self + where + F: AsyncHostFunction<(), Args, Rets, WithoutEnv> + 'static, + Args: WasmTypeList + 'static, + Rets: WasmTypeList + 'static, + { + match &store.as_store_mut().inner.store { + #[cfg(feature = "sys")] + crate::BackendStore::Sys(_) => Self::Sys( + crate::backend::sys::entities::function::Function::new_typed_async(store, func), + ), + #[cfg(feature = "wamr")] + crate::BackendStore::Wamr(_) => unsupported_async_backend("wamr"), + #[cfg(feature = "wasmi")] + crate::BackendStore::Wasmi(_) => unsupported_async_backend("wasmi"), + #[cfg(feature = "v8")] + crate::BackendStore::V8(_) => unsupported_async_backend("v8"), + #[cfg(feature = "js")] + crate::BackendStore::Js(_) => unsupported_async_backend("js"), + #[cfg(feature = "jsc")] + crate::BackendStore::Jsc(_) => unsupported_async_backend("jsc"), + } + } + + /// Creates a new async host `Function` with an environment from a typed function. + #[inline] + #[cfg(feature = "experimental-async")] + pub fn new_typed_with_env_async( + store: &mut impl AsStoreMut, + env: &FunctionEnv, + func: F, + ) -> Self + where + F: AsyncHostFunction + 'static, + Args: WasmTypeList + 'static, + Rets: WasmTypeList + 'static, + { + match &store.as_store_mut().inner.store { + #[cfg(feature = "sys")] + crate::BackendStore::Sys(_) => Self::Sys( + crate::backend::sys::entities::function::Function::new_typed_with_env_async( + store, env, func, + ), + ), + #[cfg(feature = "wamr")] + crate::BackendStore::Wamr(_) => unsupported_async_backend("wamr"), + #[cfg(feature = "wasmi")] + crate::BackendStore::Wasmi(_) => unsupported_async_backend("wasmi"), + #[cfg(feature = "v8")] + crate::BackendStore::V8(_) => unsupported_async_backend("v8"), + #[cfg(feature = "js")] + crate::BackendStore::Js(_) => unsupported_async_backend("js"), + #[cfg(feature = "jsc")] + crate::BackendStore::Jsc(_) => unsupported_async_backend("jsc"), + } + } + /// Returns the [`FunctionType`] of the `Function`. /// /// # Example @@ -371,6 +517,29 @@ impl BackendFunction { }) } + #[cfg(feature = "experimental-async")] + #[allow(clippy::type_complexity)] + pub fn call_async( + &self, + store: &impl AsStoreAsync, + params: Vec, + ) -> Pin, RuntimeError>> + 'static>> { + match self { + #[cfg(feature = "sys")] + Self::Sys(f) => f.call_async(store, params), + #[cfg(feature = "wamr")] + Self::Wamr(_) => unsupported_async_future(), + #[cfg(feature = "wasmi")] + Self::Wasmi(_) => unsupported_async_future(), + #[cfg(feature = "v8")] + Self::V8(_) => unsupported_async_future(), + #[cfg(feature = "js")] + Self::Js(_) => unsupported_async_future(), + #[cfg(feature = "jsc")] + Self::Jsc(_) => unsupported_async_future(), + } + } + #[inline] pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef { match self { @@ -393,47 +562,47 @@ impl BackendFunction { pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self { match &store.as_store_mut().inner.store { #[cfg(feature = "sys")] - crate::BackendStore::Sys(s) => Self::Sys( + crate::BackendStore::Sys(s) => Self::Sys(unsafe { crate::backend::sys::entities::function::Function::from_vm_funcref( store, funcref.into_sys(), - ), - ), + ) + }), #[cfg(feature = "wamr")] - crate::BackendStore::Wamr(s) => Self::Wamr( + crate::BackendStore::Wamr(s) => Self::Wamr(unsafe { crate::backend::wamr::entities::function::Function::from_vm_funcref( store, funcref.into_wamr(), - ), - ), + ) + }), #[cfg(feature = "wasmi")] - crate::BackendStore::Wasmi(s) => Self::Wasmi( + crate::BackendStore::Wasmi(s) => Self::Wasmi(unsafe { crate::backend::wasmi::entities::function::Function::from_vm_funcref( store, funcref.into_wasmi(), - ), - ), + ) + }), #[cfg(feature = "v8")] - crate::BackendStore::V8(s) => Self::V8( + crate::BackendStore::V8(s) => Self::V8(unsafe { crate::backend::v8::entities::function::Function::from_vm_funcref( store, funcref.into_v8(), - ), - ), + ) + }), #[cfg(feature = "js")] - crate::BackendStore::Js(s) => Self::Js( + crate::BackendStore::Js(s) => Self::Js(unsafe { crate::backend::js::entities::function::Function::from_vm_funcref( store, funcref.into_js(), - ), - ), + ) + }), #[cfg(feature = "jsc")] - crate::BackendStore::Jsc(s) => Self::Jsc( + crate::BackendStore::Jsc(s) => Self::Jsc(unsafe { crate::backend::jsc::entities::function::Function::from_vm_funcref( store, funcref.into_jsc(), - ), - ), + ) + }), } } @@ -605,6 +774,23 @@ impl BackendFunction { } } +#[cold] +fn unsupported_async_backend(backend: &str) -> ! { + panic!( + "async host functions are only supported with the `sys` backend (attempted on {backend})" + ) +} + +#[allow(clippy::type_complexity)] +pub(super) fn unsupported_async_future<'a>() +-> Pin, RuntimeError>> + 'a>> { + Box::pin(async { + Err(RuntimeError::new( + "async calls are only supported with the `sys` backend", + )) + }) +} + impl<'a> Exportable<'a> for BackendFunction { fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { match _extern { diff --git a/lib/api/src/entities/function/mod.rs b/lib/api/src/entities/function/mod.rs index 1ff92ca609..32668df27a 100644 --- a/lib/api/src/entities/function/mod.rs +++ b/lib/api/src/entities/function/mod.rs @@ -10,13 +10,22 @@ pub use host::*; pub(crate) mod env; pub use env::*; +#[cfg(feature = "experimental-async")] +pub(crate) mod async_host; +#[cfg(feature = "experimental-async")] +pub use async_host::{AsyncFunctionEnv, AsyncHostFunction}; + +use std::{future::Future, pin::Pin}; + use wasmer_types::{FunctionType, RawValue}; +#[cfg(feature = "experimental-async")] +use crate::AsStoreAsync; use crate::{ - error::RuntimeError, - vm::{VMExtern, VMExternFunction, VMFuncRef}, AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef, TypedFunction, Value, WasmTypeList, + error::RuntimeError, + vm::{VMExtern, VMExternFunction, VMFuncRef}, }; /// A WebAssembly `function` instance. @@ -147,6 +156,78 @@ impl Function { Self(BackendFunction::new_typed_with_env(store, env, func)) } + /// Creates a new async host `Function` (dynamic) with the provided + /// signature. + /// + /// If you know the signature of the host function at compile time, + /// consider using [`Self::new_typed_async`] for less runtime overhead. + /// + /// The provided closure returns a future that resolves to the function results. + /// When invoked synchronously (via [`Function::call`]) the future will run to + /// completion immediately, provided it doesn't suspend. When invoked through + /// [`Function::call_async`], the future may suspend and resume as needed. + #[cfg(feature = "experimental-async")] + pub fn new_async(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self + where + FT: Into, + F: Fn(&[Value]) -> Fut + 'static, + Fut: Future, RuntimeError>> + 'static, + { + Self(BackendFunction::new_async(store, ty, func)) + } + + /// Creates a new async host `Function` (dynamic) with the provided + /// signature and environment. + /// + /// If you know the signature of the host function at compile time, + /// consider using [`Self::new_typed_with_env_async`] for less runtime overhead. + /// + /// Takes an [`AsyncFunctionEnvMut`] that is passed into func. If + /// that is not required, [`Self::new_async`] might be an option as well. + #[cfg(feature = "experimental-async")] + pub fn new_with_env_async( + store: &mut impl AsStoreMut, + env: &FunctionEnv, + ty: FT, + func: F, + ) -> Self + where + FT: Into, + F: Fn(AsyncFunctionEnvMut, &[Value]) -> Fut + 'static, + Fut: Future, RuntimeError>> + 'static, + { + Self(BackendFunction::new_with_env_async(store, env, ty, func)) + } + + /// Creates a new async host `Function` from a native typed function. + /// + /// The future can return either the raw result tuple or any type that implements + /// [`IntoResult`](crate::IntoResult) for the result tuple (e.g. `Result`). + #[cfg(feature = "experimental-async")] + pub fn new_typed_async(store: &mut impl AsStoreMut, func: F) -> Self + where + Rets: WasmTypeList + 'static, + Args: WasmTypeList + 'static, + F: AsyncHostFunction<(), Args, Rets, WithoutEnv> + 'static, + { + Self(BackendFunction::new_typed_async(store, func)) + } + + /// Creates a new async host `Function` with an environment from a typed function. + #[cfg(feature = "experimental-async")] + pub fn new_typed_with_env_async( + store: &mut impl AsStoreMut, + env: &FunctionEnv, + func: F, + ) -> Self + where + Rets: WasmTypeList + 'static, + Args: WasmTypeList + 'static, + F: AsyncHostFunction + 'static, + { + Self(BackendFunction::new_typed_with_env_async(store, env, func)) + } + /// Returns the [`FunctionType`] of the `Function`. /// /// # Example @@ -250,6 +331,22 @@ impl Function { self.0.call(store, params) } + /// Calls the function asynchronously. + /// + /// The returned future drives execution of the WebAssembly function on a + /// coroutine stack. Host functions created with [`Function::new_async`] may + /// suspend execution by awaiting futures, and their completion will resume + /// the Wasm instance according to the JSPI proposal. + #[must_use = "This function spawns a future that must be awaited to produce results"] + #[cfg(feature = "experimental-async")] + pub fn call_async( + &self, + store: &impl AsStoreAsync, + params: Vec, + ) -> impl Future, RuntimeError>> + 'static { + self.0.call_async(store, params) + } + #[doc(hidden)] #[allow(missing_docs)] pub fn call_raw( @@ -265,7 +362,7 @@ impl Function { } pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self { - Self(BackendFunction::from_vm_funcref(store, funcref)) + unsafe { Self(BackendFunction::from_vm_funcref(store, funcref)) } } /// Transform this WebAssembly function into a typed function. diff --git a/lib/api/src/entities/global/inner.rs b/lib/api/src/entities/global/inner.rs index 887864b205..bb867eeba4 100644 --- a/lib/api/src/entities/global/inner.rs +++ b/lib/api/src/entities/global/inner.rs @@ -1,10 +1,10 @@ use crate::{ + ExportError, Exportable, Extern, error::RuntimeError, macros::backend::{gen_rt_ty, match_rt}, store::{AsStoreMut, AsStoreRef, StoreMut, StoreRef}, value::Value, vm::{VMExtern, VMExternGlobal}, - ExportError, Exportable, Extern, }; use wasmer_types::{GlobalType, Mutability}; diff --git a/lib/api/src/entities/global/mod.rs b/lib/api/src/entities/global/mod.rs index 0cf479b7cc..93b3fc5025 100644 --- a/lib/api/src/entities/global/mod.rs +++ b/lib/api/src/entities/global/mod.rs @@ -1,9 +1,9 @@ use crate::{ + ExportError, Exportable, Extern, error::RuntimeError, store::{AsStoreMut, AsStoreRef, StoreMut, StoreRef}, value::Value, vm::{VMExtern, VMExternGlobal}, - ExportError, Exportable, Extern, }; use wasmer_types::{GlobalType, Mutability}; diff --git a/lib/api/src/entities/imports.rs b/lib/api/src/entities/imports.rs index d0bd6b19c5..2efb2f2606 100644 --- a/lib/api/src/entities/imports.rs +++ b/lib/api/src/entities/imports.rs @@ -1,7 +1,7 @@ //! The import module contains the implementation data structures and helper functions used to //! manipulate and access a wasm module's imports including memories, tables, globals, and //! functions. -use crate::{error::LinkError, Exports, Extern, Module}; +use crate::{Exports, Extern, Module, error::LinkError}; use std::collections::HashMap; use std::fmt; use wasmer_types::ImportError; @@ -130,11 +130,7 @@ impl Imports { .filter(|((ns, _), _)| ns == name) .map(|((_, name), e)| (name.clone(), e.clone())) .collect(); - if ret.is_empty() { - None - } else { - Some(ret) - } + if ret.is_empty() { None } else { Some(ret) } } /// Resolve and return a vector of imports in the order they are defined in the `module`'s source code. @@ -306,10 +302,10 @@ macro_rules! import_namespace { #[cfg(test)] mod test { - use crate::store::Store; - use crate::value::Value; use crate::Extern; use crate::Global; + use crate::store::Store; + use crate::value::Value; use wasmer_types::Type; #[test] diff --git a/lib/api/src/entities/instance.rs b/lib/api/src/entities/instance.rs index 0a2e7ac18b..761e160e9c 100644 --- a/lib/api/src/entities/instance.rs +++ b/lib/api/src/entities/instance.rs @@ -1,6 +1,6 @@ use crate::{ - error::InstantiationError, exports::Exports, imports::Imports, macros::backend::gen_rt_ty, - module::Module, store::AsStoreMut, Extern, + Extern, error::InstantiationError, exports::Exports, imports::Imports, + macros::backend::gen_rt_ty, module::Module, store::AsStoreMut, }; /// A WebAssembly Instance is a stateful, executable diff --git a/lib/api/src/entities/memory/buffer/inner.rs b/lib/api/src/entities/memory/buffer/inner.rs index 6823b331ba..4cc3c199d2 100644 --- a/lib/api/src/entities/memory/buffer/inner.rs +++ b/lib/api/src/entities/memory/buffer/inner.rs @@ -1,8 +1,8 @@ use std::{marker::PhantomData, mem::MaybeUninit}; use crate::{ - macros::backend::{gen_rt_ty, match_rt}, MemoryAccessError, + macros::backend::{gen_rt_ty, match_rt}, }; /// Underlying buffer for a memory. diff --git a/lib/api/src/entities/memory/inner.rs b/lib/api/src/entities/memory/inner.rs index f6ec7c471d..74dd52c960 100644 --- a/lib/api/src/entities/memory/inner.rs +++ b/lib/api/src/entities/memory/inner.rs @@ -2,9 +2,9 @@ use super::{shared::SharedMemory, view::*}; use wasmer_types::{MemoryError, MemoryType, Pages}; use crate::{ + AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef, macros::backend::{gen_rt_ty, match_rt}, vm::{VMExtern, VMExternMemory, VMMemory}, - AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef, }; gen_rt_ty!(Memory diff --git a/lib/api/src/entities/memory/mod.rs b/lib/api/src/entities/memory/mod.rs index 168aacc57d..e869b2fb70 100644 --- a/lib/api/src/entities/memory/mod.rs +++ b/lib/api/src/entities/memory/mod.rs @@ -2,8 +2,8 @@ pub use shared::SharedMemory; use wasmer_types::{MemoryError, MemoryType, Pages}; use crate::{ - vm::{VMExtern, VMExternMemory, VMMemory}, AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef, + vm::{VMExtern, VMExternMemory, VMMemory}, }; pub(crate) mod buffer; diff --git a/lib/api/src/entities/memory/shared.rs b/lib/api/src/entities/memory/shared.rs index 45a31eb8f4..9d7bac06c2 100644 --- a/lib/api/src/entities/memory/shared.rs +++ b/lib/api/src/entities/memory/shared.rs @@ -1,9 +1,9 @@ use wasmer_types::MemoryError; use crate::{ + Memory, error::AtomicsError, location::{MemoryLocation, SharedMemoryOps}, - Memory, }; /// A handle that exposes operations only relevant for shared memories. diff --git a/lib/api/src/entities/memory/view/inner.rs b/lib/api/src/entities/memory/view/inner.rs index 6297d6802a..c0ff910388 100644 --- a/lib/api/src/entities/memory/view/inner.rs +++ b/lib/api/src/entities/memory/view/inner.rs @@ -2,9 +2,9 @@ use std::{mem::MaybeUninit, ops::Range}; use wasmer_types::Pages; use crate::{ + AsStoreRef, Memory, MemoryAccessError, buffer::{BackendMemoryBuffer, MemoryBuffer}, macros::backend::{gen_rt_ty, match_rt}, - AsStoreRef, Memory, MemoryAccessError, }; /// A WebAssembly `memory` view. @@ -90,7 +90,7 @@ impl<'a> BackendMemoryView<'a> { #[inline] pub unsafe fn data_unchecked(&self) -> &[u8] { match_rt!(on self => s { - s.data_unchecked() + unsafe { s.data_unchecked() } }) } @@ -108,7 +108,7 @@ impl<'a> BackendMemoryView<'a> { #[inline] pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] { match_rt!(on self => s { - s.data_unchecked_mut() + unsafe { s.data_unchecked_mut() } }) } diff --git a/lib/api/src/entities/memory/view/mod.rs b/lib/api/src/entities/memory/view/mod.rs index 32e55ce4b1..8f16105dc5 100644 --- a/lib/api/src/entities/memory/view/mod.rs +++ b/lib/api/src/entities/memory/view/mod.rs @@ -1,7 +1,7 @@ use std::{mem::MaybeUninit, ops::Range}; use wasmer_types::Pages; -use crate::{buffer::MemoryBuffer, AsStoreRef, Memory, MemoryAccessError}; +use crate::{AsStoreRef, Memory, MemoryAccessError, buffer::MemoryBuffer}; pub(crate) mod inner; pub(crate) use inner::*; @@ -43,7 +43,7 @@ impl<'a> MemoryView<'a> { /// function that writes to the memory or by resizing the memory. #[doc(hidden)] pub unsafe fn data_unchecked(&self) -> &[u8] { - self.0.data_unchecked() + unsafe { self.0.data_unchecked() } } /// Retrieve a mutable slice of the memory contents. @@ -58,7 +58,7 @@ impl<'a> MemoryView<'a> { #[allow(clippy::mut_from_ref)] #[doc(hidden)] pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] { - self.0.data_unchecked_mut() + unsafe { self.0.data_unchecked_mut() } } /// Returns the size (in [`Pages`]) of the `Memory`. diff --git a/lib/api/src/entities/module/inner.rs b/lib/api/src/entities/module/inner.rs index 66afadc0ed..56b7c54278 100644 --- a/lib/api/src/entities/module/inner.rs +++ b/lib/api/src/entities/module/inner.rs @@ -13,9 +13,9 @@ use wasmer_types::{ }; use crate::{ + AsEngineRef, macros::backend::{gen_rt_ty, match_rt}, utils::IntoBytes, - AsEngineRef, }; /// A WebAssembly Module contains stateless WebAssembly @@ -115,44 +115,62 @@ impl BackendModule { ) -> Result { match engine.as_engine_ref().inner.be { #[cfg(feature = "sys")] - crate::BackendEngine::Sys(_) => Ok(Self::Sys( - crate::backend::sys::entities::module::Module::from_binary_unchecked( - engine, binary, - )?, - )), + crate::BackendEngine::Sys(_) => { + let module = unsafe { + crate::backend::sys::entities::module::Module::from_binary_unchecked( + engine, binary, + )? + }; + Ok(Self::Sys(module)) + } #[cfg(feature = "wamr")] - crate::BackendEngine::Wamr(_) => Ok(Self::Wamr( - crate::backend::wamr::entities::module::Module::from_binary_unchecked( - engine, binary, - )?, - )), + crate::BackendEngine::Wamr(_) => { + let module = unsafe { + crate::backend::wamr::entities::module::Module::from_binary_unchecked( + engine, binary, + )? + }; + Ok(Self::Wamr(module)) + } #[cfg(feature = "wasmi")] - crate::BackendEngine::Wasmi(_) => Ok(Self::Wasmi( - crate::backend::wasmi::entities::module::Module::from_binary_unchecked( - engine, binary, - )?, - )), + crate::BackendEngine::Wasmi(_) => { + let module = unsafe { + crate::backend::wasmi::entities::module::Module::from_binary_unchecked( + engine, binary, + )? + }; + Ok(Self::Wasmi(module)) + } #[cfg(feature = "v8")] - crate::BackendEngine::V8(_) => Ok(Self::V8( - crate::backend::v8::entities::module::Module::from_binary_unchecked( - engine, binary, - )?, - )), + crate::BackendEngine::V8(_) => { + let module = unsafe { + crate::backend::v8::entities::module::Module::from_binary_unchecked( + engine, binary, + )? + }; + Ok(Self::V8(module)) + } #[cfg(feature = "js")] - crate::BackendEngine::Js(_) => Ok(Self::Js( - crate::backend::js::entities::module::Module::from_binary_unchecked( - engine, binary, - )?, - )), + crate::BackendEngine::Js(_) => { + let module = unsafe { + crate::backend::js::entities::module::Module::from_binary_unchecked( + engine, binary, + )? + }; + Ok(Self::Js(module)) + } #[cfg(feature = "jsc")] - crate::BackendEngine::Jsc(_) => Ok(Self::Jsc( - crate::backend::jsc::entities::module::Module::from_binary_unchecked( - engine, binary, - )?, - )), + crate::BackendEngine::Jsc(_) => { + let module = unsafe { + crate::backend::jsc::entities::module::Module::from_binary_unchecked( + engine, binary, + )? + }; + Ok(Self::Jsc(module)) + } } } @@ -279,38 +297,60 @@ impl BackendModule { ) -> Result { match engine.as_engine_ref().inner.be { #[cfg(feature = "sys")] - crate::BackendEngine::Sys(_) => Ok(Self::Sys( - crate::backend::sys::entities::module::Module::deserialize_unchecked( - engine, bytes, - )?, - )), + crate::BackendEngine::Sys(_) => { + let module = unsafe { + crate::backend::sys::entities::module::Module::deserialize_unchecked( + engine, bytes, + )? + }; + Ok(Self::Sys(module)) + } #[cfg(feature = "wamr")] - crate::BackendEngine::Wamr(_) => Ok(Self::Wamr( - crate::backend::wamr::entities::module::Module::deserialize_unchecked( - engine, bytes, - )?, - )), + crate::BackendEngine::Wamr(_) => { + let module = unsafe { + crate::backend::wamr::entities::module::Module::deserialize_unchecked( + engine, bytes, + )? + }; + Ok(Self::Wamr(module)) + } #[cfg(feature = "wasmi")] - crate::BackendEngine::Wasmi(_) => Ok(Self::Wasmi( - crate::backend::wasmi::entities::module::Module::deserialize_unchecked( - engine, bytes, - )?, - )), + crate::BackendEngine::Wasmi(_) => { + let module = unsafe { + crate::backend::wasmi::entities::module::Module::deserialize_unchecked( + engine, bytes, + )? + }; + Ok(Self::Wasmi(module)) + } #[cfg(feature = "v8")] - crate::BackendEngine::V8(_) => Ok(Self::V8( - crate::backend::v8::entities::module::Module::deserialize_unchecked(engine, bytes)?, - )), + crate::BackendEngine::V8(_) => { + let module = unsafe { + crate::backend::v8::entities::module::Module::deserialize_unchecked( + engine, bytes, + )? + }; + Ok(Self::V8(module)) + } #[cfg(feature = "js")] - crate::BackendEngine::Js(_) => Ok(Self::Js( - crate::backend::js::entities::module::Module::deserialize_unchecked(engine, bytes)?, - )), + crate::BackendEngine::Js(_) => { + let module = unsafe { + crate::backend::js::entities::module::Module::deserialize_unchecked( + engine, bytes, + )? + }; + Ok(Self::Js(module)) + } #[cfg(feature = "jsc")] - crate::BackendEngine::Jsc(_) => Ok(Self::Jsc( - crate::backend::jsc::entities::module::Module::deserialize_unchecked( - engine, bytes, - )?, - )), + crate::BackendEngine::Jsc(_) => { + let module = unsafe { + crate::backend::jsc::entities::module::Module::deserialize_unchecked( + engine, bytes, + )? + }; + Ok(Self::Jsc(module)) + } } } @@ -346,30 +386,48 @@ impl BackendModule { ) -> Result { match engine.as_engine_ref().inner.be { #[cfg(feature = "sys")] - crate::BackendEngine::Sys(_) => Ok(Self::Sys( - crate::backend::sys::entities::module::Module::deserialize(engine, bytes)?, - )), + crate::BackendEngine::Sys(_) => { + let module = unsafe { + crate::backend::sys::entities::module::Module::deserialize(engine, bytes)? + }; + Ok(Self::Sys(module)) + } #[cfg(feature = "wamr")] - crate::BackendEngine::Wamr(_) => Ok(Self::Wamr( - crate::backend::wamr::entities::module::Module::deserialize(engine, bytes)?, - )), + crate::BackendEngine::Wamr(_) => { + let module = unsafe { + crate::backend::wamr::entities::module::Module::deserialize(engine, bytes)? + }; + Ok(Self::Wamr(module)) + } #[cfg(feature = "wasmi")] - crate::BackendEngine::Wasmi(_) => Ok(Self::Wasmi( - crate::backend::wasmi::entities::module::Module::deserialize(engine, bytes)?, - )), + crate::BackendEngine::Wasmi(_) => { + let module = unsafe { + crate::backend::wasmi::entities::module::Module::deserialize(engine, bytes)? + }; + Ok(Self::Wasmi(module)) + } #[cfg(feature = "v8")] - crate::BackendEngine::V8(_) => Ok(Self::V8( - crate::backend::v8::entities::module::Module::deserialize(engine, bytes)?, - )), + crate::BackendEngine::V8(_) => { + let module = unsafe { + crate::backend::v8::entities::module::Module::deserialize(engine, bytes)? + }; + Ok(Self::V8(module)) + } #[cfg(feature = "js")] - crate::BackendEngine::Js(_) => Ok(Self::Js( - crate::backend::js::entities::module::Module::deserialize(engine, bytes)?, - )), + crate::BackendEngine::Js(_) => { + let module = unsafe { + crate::backend::js::entities::module::Module::deserialize(engine, bytes)? + }; + Ok(Self::Js(module)) + } #[cfg(feature = "jsc")] - crate::BackendEngine::Jsc(_) => Ok(Self::Jsc( - crate::backend::jsc::entities::module::Module::deserialize(engine, bytes)?, - )), + crate::BackendEngine::Jsc(_) => { + let module = unsafe { + crate::backend::jsc::entities::module::Module::deserialize(engine, bytes)? + }; + Ok(Self::Jsc(module)) + } } } @@ -380,8 +438,8 @@ impl BackendModule { /// /// ```ignore /// # use wasmer::*; - /// # let mut store = Store::default(); /// # fn main() -> anyhow::Result<()> { + /// # let mut store = Store::default(); /// let module = Module::deserialize_from_file(&store, path)?; /// # Ok(()) /// # } @@ -397,34 +455,60 @@ impl BackendModule { ) -> Result { match engine.as_engine_ref().inner.be { #[cfg(feature = "sys")] - crate::BackendEngine::Sys(_) => Ok(Self::Sys( - crate::backend::sys::entities::module::Module::deserialize_from_file(engine, path)?, - )), + crate::BackendEngine::Sys(_) => { + let module = unsafe { + crate::backend::sys::entities::module::Module::deserialize_from_file( + engine, path, + )? + }; + Ok(Self::Sys(module)) + } #[cfg(feature = "wamr")] - crate::BackendEngine::Wamr(_) => Ok(Self::Wamr( - crate::backend::wamr::entities::module::Module::deserialize_from_file( - engine, path, - )?, - )), + crate::BackendEngine::Wamr(_) => { + let module = unsafe { + crate::backend::wamr::entities::module::Module::deserialize_from_file( + engine, path, + )? + }; + Ok(Self::Wamr(module)) + } #[cfg(feature = "wasmi")] - crate::BackendEngine::Wasmi(_) => Ok(Self::Wasmi( - crate::backend::wasmi::entities::module::Module::deserialize_from_file( - engine, path, - )?, - )), + crate::BackendEngine::Wasmi(_) => { + let module = unsafe { + crate::backend::wasmi::entities::module::Module::deserialize_from_file( + engine, path, + )? + }; + Ok(Self::Wasmi(module)) + } #[cfg(feature = "v8")] - crate::BackendEngine::V8(_) => Ok(Self::V8( - crate::backend::v8::entities::module::Module::deserialize_from_file(engine, path)?, - )), + crate::BackendEngine::V8(_) => { + let module = unsafe { + crate::backend::v8::entities::module::Module::deserialize_from_file( + engine, path, + )? + }; + Ok(Self::V8(module)) + } #[cfg(feature = "js")] - crate::BackendEngine::Js(_) => Ok(Self::Js( - crate::backend::js::entities::module::Module::deserialize_from_file(engine, path)?, - )), + crate::BackendEngine::Js(_) => { + let module = unsafe { + crate::backend::js::entities::module::Module::deserialize_from_file( + engine, path, + )? + }; + Ok(Self::Js(module)) + } #[cfg(feature = "jsc")] - crate::BackendEngine::Jsc(_) => Ok(Self::Jsc( - crate::backend::jsc::entities::module::Module::deserialize_from_file(engine, path)?, - )), + crate::BackendEngine::Jsc(_) => { + let module = unsafe { + crate::backend::jsc::entities::module::Module::deserialize_from_file( + engine, path, + )? + }; + Ok(Self::Jsc(module)) + } } } @@ -441,8 +525,8 @@ impl BackendModule { /// /// ```ignore /// # use wasmer::*; - /// # let mut store = Store::default(); /// # fn main() -> anyhow::Result<()> { + /// # let mut store = Store::default(); /// let module = Module::deserialize_from_file_unchecked(&store, path)?; /// # Ok(()) /// # } @@ -454,42 +538,60 @@ impl BackendModule { ) -> Result { match engine.as_engine_ref().inner.be { #[cfg(feature = "sys")] - crate::BackendEngine::Sys(_) => Ok(Self::Sys( - crate::backend::sys::entities::module::Module::deserialize_from_file_unchecked( - engine, path, - )?, - )), + crate::BackendEngine::Sys(_) => { + let module = unsafe { + crate::backend::sys::entities::module::Module::deserialize_from_file_unchecked( + engine, path, + )? + }; + Ok(Self::Sys(module)) + } #[cfg(feature = "wamr")] - crate::BackendEngine::Wamr(_) => Ok(Self::Wamr( - crate::backend::wamr::entities::module::Module::deserialize_from_file_unchecked( - engine, path, - )?, - )), + crate::BackendEngine::Wamr(_) => { + let module = unsafe { + crate::backend::wamr::entities::module::Module::deserialize_from_file_unchecked( + engine, path, + )? + }; + Ok(Self::Wamr(module)) + } #[cfg(feature = "wasmi")] - crate::BackendEngine::Wasmi(_) => Ok(Self::Wasmi( - crate::backend::wasmi::entities::module::Module::deserialize_from_file_unchecked( - engine, path, - )?, - )), + crate::BackendEngine::Wasmi(_) => { + let module = unsafe { + crate::backend::wasmi::entities::module::Module::deserialize_from_file_unchecked( + engine, path, + )? + }; + Ok(Self::Wasmi(module)) + } #[cfg(feature = "v8")] - crate::BackendEngine::V8(_) => Ok(Self::V8( - crate::backend::v8::entities::module::Module::deserialize_from_file_unchecked( - engine, path, - )?, - )), + crate::BackendEngine::V8(_) => { + let module = unsafe { + crate::backend::v8::entities::module::Module::deserialize_from_file_unchecked( + engine, path, + )? + }; + Ok(Self::V8(module)) + } #[cfg(feature = "js")] - crate::BackendEngine::Js(_) => Ok(Self::Js( - crate::backend::js::entities::module::Module::deserialize_from_file_unchecked( - engine, path, - )?, - )), + crate::BackendEngine::Js(_) => { + let module = unsafe { + crate::backend::js::entities::module::Module::deserialize_from_file_unchecked( + engine, path, + )? + }; + Ok(Self::Js(module)) + } #[cfg(feature = "jsc")] - crate::BackendEngine::Jsc(_) => Ok(Self::Jsc( - crate::backend::jsc::entities::module::Module::deserialize_from_file_unchecked( - engine, path, - )?, - )), + crate::BackendEngine::Jsc(_) => { + let module = unsafe { + crate::backend::jsc::entities::module::Module::deserialize_from_file_unchecked( + engine, path, + )? + }; + Ok(Self::Jsc(module)) + } } } diff --git a/lib/api/src/entities/module/mod.rs b/lib/api/src/entities/module/mod.rs index 1162d03172..daa3de0312 100644 --- a/lib/api/src/entities/module/mod.rs +++ b/lib/api/src/entities/module/mod.rs @@ -15,7 +15,7 @@ use wasmer_types::{ ModuleInfo, SerializeError, }; -use crate::{macros::backend::match_rt, utils::IntoBytes, AsEngineRef}; +use crate::{AsEngineRef, macros::backend::match_rt, utils::IntoBytes}; /// IO errors that can happen while compiling a [`Module`]. #[derive(Error, Debug)] @@ -142,7 +142,7 @@ impl Module { engine: &impl AsEngineRef, binary: &[u8], ) -> Result { - BackendModule::from_binary_unchecked(engine, binary).map(Self) + unsafe { BackendModule::from_binary_unchecked(engine, binary) }.map(Self) } /// Validates a new WebAssembly Module given the configuration @@ -234,7 +234,7 @@ impl Module { engine: &impl AsEngineRef, bytes: impl IntoBytes, ) -> Result { - BackendModule::deserialize_unchecked(engine, bytes).map(Self) + unsafe { BackendModule::deserialize_unchecked(engine, bytes) }.map(Self) } /// Deserializes a serialized Module binary into a `Module`. @@ -266,7 +266,7 @@ impl Module { engine: &impl AsEngineRef, bytes: impl IntoBytes, ) -> Result { - BackendModule::deserialize_unchecked(engine, bytes).map(Self) + unsafe { BackendModule::deserialize_unchecked(engine, bytes) }.map(Self) } /// Deserializes a serialized Module located in a `Path` into a `Module`. @@ -276,8 +276,8 @@ impl Module { /// /// ```ignore /// # use wasmer::*; - /// # let mut store = Store::default(); /// # fn main() -> anyhow::Result<()> { + /// # let mut store = Store::default(); /// let module = Module::deserialize_from_file(&store, path)?; /// # Ok(()) /// # } @@ -290,7 +290,7 @@ impl Module { engine: &impl AsEngineRef, path: impl AsRef, ) -> Result { - BackendModule::deserialize_from_file(engine, path).map(Self) + unsafe { BackendModule::deserialize_from_file(engine, path) }.map(Self) } /// Deserializes a serialized Module located in a `Path` into a `Module`. @@ -306,8 +306,8 @@ impl Module { /// /// ```ignore /// # use wasmer::*; - /// # let mut store = Store::default(); /// # fn main() -> anyhow::Result<()> { + /// # let mut store = Store::default(); /// let module = Module::deserialize_from_file_unchecked(&store, path)?; /// # Ok(()) /// # } @@ -316,7 +316,7 @@ impl Module { engine: &impl AsEngineRef, path: impl AsRef, ) -> Result { - BackendModule::deserialize_from_file_unchecked(engine, path).map(Self) + unsafe { BackendModule::deserialize_from_file_unchecked(engine, path) }.map(Self) } /// Returns the name of the current module. diff --git a/lib/api/src/entities/store/async_.rs b/lib/api/src/entities/store/async_.rs new file mode 100644 index 0000000000..fa557c174f --- /dev/null +++ b/lib/api/src/entities/store/async_.rs @@ -0,0 +1,160 @@ +use std::{fmt::Debug, marker::PhantomData}; + +use crate::{ + AsStoreMut, AsStoreRef, LocalRwLock, LocalRwLockReadGuard, LocalRwLockWriteGuard, Store, + StoreContext, StoreInner, StoreMut, StorePtrWrapper, StoreRef, +}; + +use wasmer_types::StoreId; + +/// A store that can be used to invoke +/// [`Function::call_async`](crate::Function::call_async). +pub struct StoreAsync { + pub(crate) id: StoreId, + // We use a box inside the RW lock because the StoreInner shouldn't be moved + pub(crate) inner: LocalRwLock>, +} + +impl StoreAsync { + pub(crate) fn from_context(id: StoreId) -> Option { + // Safety: we don't keep the guard around, it's just used to + // build a safe lock handle. + match unsafe { StoreContext::try_get_current_async(id) } { + crate::GetStoreAsyncGuardResult::Ok(guard) => Some(Self { + id, + inner: crate::LocalRwLockWriteGuard::lock_handle(unsafe { + guard.guard.as_ref().unwrap() + }), + }), + _ => None, + } + } + + /// Transform this [`StoreAsync`] back into a [`Store`] + /// if this is the only clone of it and is unlocked. + pub fn into_store(self) -> Result { + match self.inner.consume() { + Ok(unwrapped) => Ok(Store { inner: unwrapped }), + Err(lock) => Err(Self { + id: self.id, + inner: lock, + }), + } + } + + /// Acquire a read lock on the store. Panics if the store is + /// locked for writing. + pub fn read(&self) -> StoreAsyncReadLock { + if !StoreContext::is_empty() { + panic!("This method cannot be called from inside imported functions"); + } + + let store_ref = self + .inner + .try_read() + .expect("StoreAsync is locked for write"); + StoreAsyncReadLock { inner: store_ref } + } + + /// Acquire a write lock on the store. Panics if the store is + /// locked. + pub fn write(self) -> StoreAsyncWriteLock { + if !StoreContext::is_empty() { + panic!("This method cannot be called from inside imported functions"); + } + + let store_guard = self.inner.try_write().expect("StoreAsync is locked"); + StoreAsyncWriteLock { inner: store_guard } + } +} + +impl Debug for StoreAsync { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("StoreAsync").field("id", &self.id).finish() + } +} + +/// A trait for types that can be used with +/// [`Function::call_async`](crate::Function::call_async). +pub trait AsStoreAsync { + /// Returns a reference to the inner store. + fn store_ref(&self) -> &StoreAsync; + + /// Returns a copy of the store. + fn store(&self) -> StoreAsync { + let store = self.store_ref(); + StoreAsync { + id: store.id, + inner: store.inner.clone(), + } + } + + /// Returns the store id. + fn store_id(&self) -> StoreId { + self.store().id + } + + /// Acquires a read lock on the store. + fn read_lock(&self) -> impl Future { + StoreAsyncReadLock::acquire(self.store_ref()) + } + + /// Acquires a write lock on the store. + fn write_lock(&self) -> impl Future { + StoreAsyncWriteLock::acquire(self.store_ref()) + } +} + +impl AsStoreAsync for StoreAsync { + fn store_ref(&self) -> &StoreAsync { + self + } +} + +/// A read lock on an async store. +pub struct StoreAsyncReadLock { + pub(crate) inner: LocalRwLockReadGuard>, +} + +impl StoreAsyncReadLock { + pub(crate) async fn acquire(store: &StoreAsync) -> Self { + let store_ref = store.inner.read().await; + Self { inner: store_ref } + } +} + +impl AsStoreRef for StoreAsyncReadLock { + fn as_store_ref(&self) -> StoreRef<'_> { + StoreRef { inner: &self.inner } + } +} + +/// A write lock on an async store. +pub struct StoreAsyncWriteLock { + pub(crate) inner: LocalRwLockWriteGuard>, +} + +impl StoreAsyncWriteLock { + pub(crate) async fn acquire(store: &StoreAsync) -> Self { + let store_guard = store.inner.write().await; + Self { inner: store_guard } + } +} + +impl AsStoreRef for StoreAsyncWriteLock { + fn as_store_ref(&self) -> StoreRef<'_> { + StoreRef { inner: &self.inner } + } +} + +impl AsStoreMut for StoreAsyncWriteLock { + fn as_store_mut(&mut self) -> StoreMut<'_> { + StoreMut { + inner: &mut self.inner, + } + } + + fn objects_mut(&mut self) -> &mut super::StoreObjects { + &mut self.inner.objects + } +} diff --git a/lib/api/src/entities/store/context.rs b/lib/api/src/entities/store/context.rs new file mode 100644 index 0000000000..3c4285bf3b --- /dev/null +++ b/lib/api/src/entities/store/context.rs @@ -0,0 +1,459 @@ +//! Thread-local storage for storing the current store context, +//! i.e. the currently active [`Store`](crate::Store)(s). When +//! a function is called, a pointer to the [`StoreInner`] in placed +//! inside the store context so it can be retrieved when needed. +//! This lets code that needs access to the store get it with +//! just the store ID. +//! +//! The currently active store context can be a sync or async +//! context. +//! +//! For sync contexts, we just store a raw pointer +//! to the `StoreInner`, which is owned by the embedder's stack. +//! +//! For async contexts, we store a write guard taken from the +//! [`StoreAsync`](crate::StoreAsync); This achieves two goals: +//! * Makes the [`StoreAsync`](crate::StoreAsync) available +//! to whoever needs it, including when code needs to spawn +//! new coroutines +//! * Makes sure a write lock is held on the store as long as +//! the context is active, preventing other tasks from +//! accessing the store concurrently. +//! +//! We maintain a stack because it is technically possible to +//! have nested `Function::call` invocations that use different +//! stores, such as: +//! call(store1, func1) -> wasm code -> imported func -> +//! call(store2, func2) +//! +//! Note that this stack is maintained by both function +//! calls and the async_runtime to reflect the exact WASM +//! functions running on a given thread at any moment in +//! time. If a function suspends, its store context is +//! cleared and later reinstalled when it resumes. This lets +//! us use thread-local storage for the context without +//! requiring that async tasks are tied to specific threads. +//! +//! When something needs the "currently active" store context, +//! they will only look at the top entry in the stack. It is +//! always an error for code to try to access a store that's +//! "paused", i.e. not the top entry. This should be impossible +//! due to how the function call code is structured, but we +//! guard against it anyway. + +use std::{ + borrow::BorrowMut, + cell::{RefCell, UnsafeCell}, + mem::MaybeUninit, +}; + +#[cfg(feature = "experimental-async")] +use crate::LocalRwLockWriteGuard; + +use super::{AsStoreMut, AsStoreRef, StoreInner, StoreMut, StoreRef}; + +use wasmer_types::StoreId; + +enum StoreContextEntry { + Sync(*mut StoreInner), + + #[cfg(feature = "experimental-async")] + Async(LocalRwLockWriteGuard>), +} + +impl StoreContextEntry { + fn as_ptr(&self) -> *mut StoreInner { + match self { + Self::Sync(ptr) => *ptr, + #[cfg(feature = "experimental-async")] + Self::Async(guard) => &***guard as *const _ as *mut _, + } + } +} + +pub(crate) struct StoreContext { + id: StoreId, + + // StoreContexts can be used recursively when Function::call + // is used in an imported function. In the scenario, we're + // essentially passing a mutable borrow of the store into + // Function::call. However, entering the WASM code loses the + // reference, and it needs to be re-acquired from the + // StoreContext. This is why we use an UnsafeCell to allow + // multiple mutable references to the StoreMut; we do however + // keep track of how many borrows there are so we don't drop + // it prematurely. + borrow_count: u32, + entry: UnsafeCell, +} + +pub(crate) struct StorePtrWrapper { + store_ptr: *mut StoreInner, +} + +#[cfg(feature = "experimental-async")] +pub(crate) struct StoreAsyncGuardWrapper { + pub(crate) guard: *mut LocalRwLockWriteGuard>, +} + +pub(crate) struct StorePtrPauseGuard { + store_id: StoreId, + ptr: *mut StoreInner, + ref_count_decremented: bool, +} + +#[cfg(feature = "experimental-async")] +pub(crate) enum GetStoreAsyncGuardResult { + Ok(StoreAsyncGuardWrapper), + NotAsync(StorePtrWrapper), + NotInstalled, +} + +pub(crate) struct ForcedStoreInstallGuard { + store_id: StoreId, +} + +pub(crate) enum StoreInstallGuard { + Installed(StoreId), + NotInstalled, +} + +thread_local! { + static STORE_CONTEXT_STACK: RefCell> = const { RefCell::new(Vec::new()) }; +} + +impl StoreContext { + fn is_active(id: StoreId) -> bool { + STORE_CONTEXT_STACK.with(|cell| { + let stack = cell.borrow(); + stack.last().is_some_and(|ctx| ctx.id == id) + }) + } + + fn is_suspended(id: StoreId) -> bool { + !Self::is_active(id) + && STORE_CONTEXT_STACK.with(|cell| { + let stack = cell.borrow(); + stack.iter().rev().skip(1).any(|ctx| ctx.id == id) + }) + } + + fn install(id: StoreId, entry: StoreContextEntry) { + STORE_CONTEXT_STACK.with(|cell| { + let mut stack = cell.borrow_mut(); + stack.push(Self { + id, + borrow_count: 0, + entry: UnsafeCell::new(entry), + }); + }) + } + + /// Returns true if there are no active store context entries. + pub(crate) fn is_empty() -> bool { + STORE_CONTEXT_STACK.with(|cell| { + let stack = cell.borrow(); + stack.is_empty() + }) + } + + /// The write guard ensures this is the only reference to the store, + /// so installation can never fail. + #[cfg(feature = "experimental-async")] + pub(crate) fn install_async( + guard: LocalRwLockWriteGuard>, + ) -> ForcedStoreInstallGuard { + let store_id = guard.objects.id(); + Self::install(store_id, StoreContextEntry::Async(guard)); + ForcedStoreInstallGuard { store_id } + } + + /// Install the store context as sync if it is not already installed. + /// + /// # Safety + /// The pointer must be dereferenceable and remain valid until the + /// store context is uninstalled. + pub(crate) unsafe fn ensure_installed(store_ptr: *mut StoreInner) -> StoreInstallGuard { + let store_id = unsafe { store_ptr.as_ref().unwrap().objects.id() }; + if Self::is_active(store_id) { + let current_ptr = STORE_CONTEXT_STACK.with(|cell| { + let stack = cell.borrow(); + unsafe { stack.last().unwrap().entry.get().as_ref().unwrap().as_ptr() } + }); + assert_eq!(store_ptr, current_ptr, "Store context pointer mismatch"); + StoreInstallGuard::NotInstalled + } else { + Self::install(store_id, StoreContextEntry::Sync(store_ptr)); + StoreInstallGuard::Installed(store_id) + } + } + + /// "Pause" one borrow of the store context. + /// + /// # Safety + /// Code must ensure it does not use the StorePtrWrapper or + /// StoreAsyncGuardWrapper that it owns, or any StoreRef/StoreMut + /// derived from them, while the store context is paused. + /// + /// The safe, correct use-case for this method is to + /// pause the store context while executing WASM code, which + /// cannot use the store context directly. This allows an async + /// context to uninstall the store context when suspending if it's + /// called from a sync imported function. The imported function + /// will have borrowed the store context in its trampoline, which + /// will prevent the async context from uninstalling the store. + /// However, since the imported function passes a mutable borrow + /// of its store into `Function::call`, it will expect the store + /// to change before the call returns. + pub(crate) unsafe fn pause(id: StoreId) -> StorePtrPauseGuard { + STORE_CONTEXT_STACK.with(|cell| { + let mut stack = cell.borrow_mut(); + let top = stack + .last_mut() + .expect("No store context installed on this thread"); + assert_eq!(top.id, id, "Mismatched store context access"); + let ref_count_decremented = if top.borrow_count > 0 { + top.borrow_count -= 1; + true + } else { + false + }; + StorePtrPauseGuard { + store_id: id, + ptr: unsafe { top.entry.get().as_ref().unwrap().as_ptr() }, + ref_count_decremented, + } + }) + } + + /// Safety: This method lets you borrow multiple mutable references + /// to the currently active store context. The caller must ensure that: + /// * there is only one mutable reference alive, or + /// * all but one mutable reference are inaccessible and passed + /// into a function that lost the reference (e.g. into WASM code) + /// + /// The intended, valid use-case for this method is from within + /// imported function trampolines. + pub(crate) unsafe fn get_current(id: StoreId) -> StorePtrWrapper { + STORE_CONTEXT_STACK.with(|cell| { + let mut stack = cell.borrow_mut(); + let top = stack + .last_mut() + .expect("No store context installed on this thread"); + assert_eq!(top.id, id, "Mismatched store context access"); + top.borrow_count += 1; + StorePtrWrapper { + store_ptr: unsafe { top.entry.get().as_mut().unwrap().as_ptr() }, + } + }) + } + + /// Safety: In addition to the safety requirements of [`Self::get_current`], + /// the pointer returned from this function will become invalid if + /// the store context is changed in any way (via installing or uninstalling + /// a store context). The caller must ensure that the store context + /// remains unchanged as long as the pointer is being accessed. + pub(crate) unsafe fn get_current_transient(id: StoreId) -> *mut StoreInner { + STORE_CONTEXT_STACK.with(|cell| { + let mut stack = cell.borrow_mut(); + let top = stack + .last_mut() + .expect("No store context installed on this thread"); + assert_eq!(top.id, id, "Mismatched store context access"); + unsafe { top.entry.get().as_mut().unwrap().as_ptr() } + }) + } + + /// Safety: See [`Self::get_current`]. + pub(crate) unsafe fn try_get_current(id: StoreId) -> Option { + STORE_CONTEXT_STACK.with(|cell| { + let mut stack = cell.borrow_mut(); + let top = stack.last_mut()?; + if top.id != id { + return None; + } + top.borrow_count += 1; + Some(StorePtrWrapper { + store_ptr: unsafe { top.entry.get().as_mut().unwrap().as_ptr() }, + }) + }) + } + + /// Safety: See [`Self::get_current`]. + #[cfg(feature = "experimental-async")] + pub(crate) unsafe fn try_get_current_async(id: StoreId) -> GetStoreAsyncGuardResult { + STORE_CONTEXT_STACK.with(|cell| { + let mut stack = cell.borrow_mut(); + let Some(top) = stack.last_mut() else { + return GetStoreAsyncGuardResult::NotInstalled; + }; + if top.id != id { + return GetStoreAsyncGuardResult::NotInstalled; + } + top.borrow_count += 1; + match unsafe { top.entry.get().as_mut().unwrap() } { + StoreContextEntry::Async(guard) => { + GetStoreAsyncGuardResult::Ok(StoreAsyncGuardWrapper { + guard: guard as *mut _, + }) + } + StoreContextEntry::Sync(ptr) => { + GetStoreAsyncGuardResult::NotAsync(StorePtrWrapper { store_ptr: *ptr }) + } + } + }) + } +} + +impl StorePtrWrapper { + pub(crate) fn as_ref(&self) -> StoreRef<'_> { + // Safety: the store_mut is always initialized unless the StoreMutWrapper + // is dropped, at which point it's impossible to call this function + unsafe { self.store_ptr.as_ref().unwrap().as_store_ref() } + } + + pub(crate) fn as_mut(&mut self) -> StoreMut<'_> { + // Safety: the store_mut is always initialized unless the StoreMutWrapper + // is dropped, at which point it's impossible to call this function + unsafe { self.store_ptr.as_mut().unwrap().as_store_mut() } + } +} + +impl Clone for StorePtrWrapper { + fn clone(&self) -> Self { + STORE_CONTEXT_STACK.with(|cell| { + let mut stack = cell.borrow_mut(); + let top = stack + .last_mut() + .expect("No store context installed on this thread"); + match unsafe { top.entry.get().as_ref().unwrap() } { + StoreContextEntry::Sync(ptr) if *ptr == self.store_ptr => (), + _ => panic!("Mismatched store context access"), + } + top.borrow_count += 1; + Self { + store_ptr: self.store_ptr, + } + }) + } +} + +impl Drop for StorePtrWrapper { + fn drop(&mut self) { + if std::thread::panicking() { + return; + } + let id = self.as_mut().objects_mut().id(); + STORE_CONTEXT_STACK.with(|cell| { + let mut stack = cell.borrow_mut(); + let top = stack + .last_mut() + .expect("No store context installed on this thread"); + assert_eq!(top.id, id, "Mismatched store context reinstall"); + top.borrow_count -= 1; + }) + } +} + +#[cfg(feature = "experimental-async")] +impl Drop for StoreAsyncGuardWrapper { + fn drop(&mut self) { + if std::thread::panicking() { + return; + } + let id = unsafe { self.guard.as_ref().unwrap().objects.id() }; + STORE_CONTEXT_STACK.with(|cell| { + let mut stack = cell.borrow_mut(); + let top = stack + .last_mut() + .expect("No store context installed on this thread"); + assert_eq!(top.id, id, "Mismatched store context reinstall"); + top.borrow_count -= 1; + }) + } +} + +impl Drop for StoreInstallGuard { + fn drop(&mut self) { + if let Self::Installed(store_id) = self { + STORE_CONTEXT_STACK.with(|cell| { + let mut stack = cell.borrow_mut(); + match (stack.pop(), std::thread::panicking()) { + (Some(top), false) => { + assert_eq!(top.id, *store_id, "Mismatched store context uninstall"); + assert_eq!( + top.borrow_count, 0, + "Cannot uninstall store context while it is still borrowed" + ); + } + (Some(top), true) => { + // If we're panicking and there's a store ID mismatch, just + // put the store back in the hope that its own install guard + // take care of uninstalling it later. + if top.id != *store_id { + stack.push(top); + } + } + (None, false) => panic!("Store context stack underflow"), + (None, true) => { + // Nothing to do if we're panicking; panics can put the context + // in an invalid state, and we don't to cause another panic here. + } + } + }) + } + } +} + +impl Drop for ForcedStoreInstallGuard { + fn drop(&mut self) { + STORE_CONTEXT_STACK.with(|cell| { + let mut stack = cell.borrow_mut(); + match (stack.pop(), std::thread::panicking()) { + (Some(top), false) => { + assert_eq!(top.id, self.store_id, "Mismatched store context uninstall"); + assert_eq!( + top.borrow_count, 0, + "Cannot uninstall store context while it is still borrowed" + ); + } + (Some(top), true) => { + // If we're panicking and there's a store ID mismatch, just + // put the store back in the hope that its own install guard + // take care of uninstalling it later. + if top.id != self.store_id { + stack.push(top); + } + } + (None, false) => panic!("Store context stack underflow"), + (None, true) => { + // Nothing to do if we're panicking; panics can put the context + // in an invalid state, and we don't to cause another panic here. + } + } + }) + } +} + +impl Drop for StorePtrPauseGuard { + fn drop(&mut self) { + if std::thread::panicking() { + return; + } + STORE_CONTEXT_STACK.with(|cell| { + let mut stack = cell.borrow_mut(); + let top = stack + .last_mut() + .expect("No store context installed on this thread"); + assert_eq!(top.id, self.store_id, "Mismatched store context access"); + assert_eq!( + unsafe { top.entry.get().as_ref().unwrap() }.as_ptr(), + self.ptr, + "Mismatched store context access" + ); + if self.ref_count_decremented { + top.borrow_count += 1; + } + }) + } +} diff --git a/lib/api/src/entities/store/inner.rs b/lib/api/src/entities/store/inner.rs index c41bdbf7a8..c977b01acb 100644 --- a/lib/api/src/entities/store/inner.rs +++ b/lib/api/src/entities/store/inner.rs @@ -1,10 +1,10 @@ use crate::{ + AsStoreMut, AsStoreRef, StoreRef, entities::{ engine::{AsEngineRef, Engine}, store::{StoreMut, StoreObjects}, }, macros::backend::{gen_rt_ty, match_rt}, - AsStoreMut, }; #[cfg(feature = "sys")] @@ -29,6 +29,21 @@ impl std::fmt::Debug for StoreInner { } } +impl AsStoreRef for StoreInner { + fn as_store_ref(&self) -> StoreRef<'_> { + StoreRef { inner: self } + } +} +impl AsStoreMut for StoreInner { + fn as_store_mut(&mut self) -> StoreMut<'_> { + StoreMut { inner: self } + } + + fn objects_mut(&mut self) -> &mut StoreObjects { + &mut self.objects + } +} + /// Call handler for a store. // TODO: better documentation! pub type OnCalledHandler = Box< diff --git a/lib/api/src/entities/store/local_rwlock.rs b/lib/api/src/entities/store/local_rwlock.rs new file mode 100644 index 0000000000..8eb6c53a87 --- /dev/null +++ b/lib/api/src/entities/store/local_rwlock.rs @@ -0,0 +1,648 @@ +//! A single-threaded async-aware RwLock implementation. +//! +//! This module provides [`LocalRwLock`], which is similar to `async_lock::RwLock` +//! but optimized for single-threaded async runtimes. It avoids atomic operations +//! and is `!Send + !Sync`, making it more efficient when thread safety is not needed. +//! +//! Like `async_lock::RwLock`, it provides `read_rc()` and `write_rc()` methods +//! that allow callers to asynchronously wait for the lock to become available, +//! and return guards with `'static` lifetimes by holding an `Rc` to the lock. + +use std::cell::{Cell, RefCell, UnsafeCell}; +use std::future::Future; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; +use std::pin::Pin; +use std::rc::Rc; +use std::task::{Context, Poll, Waker}; + +/// The main lock type. +pub struct LocalRwLock { + inner: Rc>, +} + +struct LocalRwLockInner { + value: UnsafeCell, + state: Cell, + read_waiters: RefCell>>, + write_waiters: RefCell>>, +} + +#[derive(Clone, Copy, PartialEq, Debug)] +enum LockState { + Unlocked, + Reading(usize), // count of readers + Writing, +} + +impl LocalRwLock { + /// Creates a new `LocalRwLock` with the given value. + pub fn new(value: T) -> Self { + Self { + inner: Rc::new(LocalRwLockInner { + value: UnsafeCell::new(value), + state: Cell::new(LockState::Unlocked), + read_waiters: RefCell::new(Vec::new()), + write_waiters: RefCell::new(Vec::new()), + }), + } + } + + /// Acquires a read lock, waiting asynchronously if necessary. + /// + /// The returned guard holds an `Rc` clone, allowing it to have a `'static` lifetime. + pub fn read(&self) -> ReadFuture { + ReadFuture { + inner: self.inner.clone(), + waiter_index: Cell::new(None), + } + } + + /// Acquires a write lock, waiting asynchronously if necessary. + /// + /// The returned guard holds an `Rc` clone, allowing it to have a `'static` lifetime. + pub fn write(&self) -> WriteFuture { + WriteFuture { + inner: self.inner.clone(), + waiter_index: Cell::new(None), + } + } + + /// Attempts to acquire a read lock with a `'static` lifetime without waiting. + pub fn try_read(&self) -> Option> { + if self.inner.try_read() { + Some(LocalRwLockReadGuard { + inner: self.inner.clone(), + }) + } else { + None + } + } + + /// Attempts to acquire a write lock with a `'static` lifetime without waiting. + pub fn try_write(&self) -> Option> { + if self.inner.try_write() { + Some(LocalRwLockWriteGuard { + inner: self.inner.clone(), + }) + } else { + None + } + } + + /// Attempts to consume the lock if there are no active or waiting + /// readers or writers, and returns the inner value if successful. + pub fn consume(self) -> Result { + if self.inner.state.get() == LockState::Unlocked + && self.inner.read_waiters.borrow().is_empty() + && self.inner.write_waiters.borrow().is_empty() + { + match Rc::try_unwrap(self.inner) { + Ok(inner) => Ok(inner.value.into_inner()), + Err(rc) => Err(Self { inner: rc }), + } + } else { + Err(self) + } + } +} + +impl Clone for LocalRwLock { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + } + } +} + +impl LocalRwLockInner { + fn try_read(&self) -> bool { + match self.state.get() { + LockState::Unlocked => { + self.state.set(LockState::Reading(1)); + true + } + LockState::Reading(n) => { + self.state.set(LockState::Reading(n + 1)); + true + } + LockState::Writing => false, + } + } + + fn try_write(&self) -> bool { + match self.state.get() { + LockState::Unlocked => { + self.state.set(LockState::Writing); + true + } + _ => false, + } + } + + fn release_read(&self) { + match self.state.get() { + LockState::Reading(1) => { + self.state.set(LockState::Unlocked); + self.wake_waiters(); + } + LockState::Reading(n) if n > 1 => { + self.state.set(LockState::Reading(n - 1)); + } + _ => panic!("LocalRwLock: release_read called but not in Reading state"), + } + } + + fn release_write(&self) { + match self.state.get() { + LockState::Writing => { + self.state.set(LockState::Unlocked); + self.wake_waiters(); + } + _ => panic!("LocalRwLock: release_write called but not in Writing state"), + } + } + + fn wake_waiters(&self) { + // Wake writers first (priority) + let mut write_waiters = self.write_waiters.borrow_mut(); + let has_writers = write_waiters.iter().any(|w| w.is_some()); + + if has_writers { + // If there are waiting writers, only wake them (they need exclusive access) + for waker in write_waiters.drain(..).flatten() { + waker.wake(); + } + } else { + // No writers waiting, wake all readers (they can share the lock) + drop(write_waiters); // Release borrow before borrowing read_waiters + let mut read_waiters = self.read_waiters.borrow_mut(); + for waker in read_waiters.drain(..).flatten() { + waker.wake(); + } + } + } + + /// Shared polling logic for all futures. + /// Returns Poll::Ready(()) if the lock was acquired, Poll::Pending otherwise. + fn poll_lock( + &self, + waiter_index: &Cell>, + cx: &mut Context<'_>, + try_lock: impl FnOnce(&Self) -> bool, + is_write: bool, + ) -> Poll<()> { + if try_lock(self) { + // If we successfully acquired the lock, remove our waiter slot if we registered one + if let Some(index) = waiter_index.get() { + let waiters = if is_write { + &self.write_waiters + } else { + &self.read_waiters + }; + let mut waiters = waiters.borrow_mut(); + if index < waiters.len() { + waiters[index] = None; + } + } + return Poll::Ready(()); + } + + // Register or update our waker in the appropriate waiters list + let waiters = if is_write { + &self.write_waiters + } else { + &self.read_waiters + }; + let mut waiters = waiters.borrow_mut(); + + if let Some(index) = waiter_index.get() { + // We already have a slot, check if we need to update it + if index < waiters.len() { + if let Some(existing) = &waiters[index] { + if !existing.will_wake(cx.waker()) { + waiters[index] = Some(cx.waker().clone()); + } + } else { + waiters[index] = Some(cx.waker().clone()); + } + } else { + // Our slot was somehow removed, register a new one + let new_index = waiters.len(); + waiters.push(Some(cx.waker().clone())); + waiter_index.set(Some(new_index)); + } + } else { + // First time registering + let index = waiters.len(); + waiters.push(Some(cx.waker().clone())); + waiter_index.set(Some(index)); + } + + Poll::Pending + } + + /// Cleanup waiter slot on drop + fn cleanup_waiter(&self, waiter_index: &Cell>, is_write: bool) { + if let Some(index) = waiter_index.get() { + let waiters = if is_write { + &self.write_waiters + } else { + &self.read_waiters + }; + let mut waiters = waiters.borrow_mut(); + if index < waiters.len() { + waiters[index] = None; + } + } + } +} + +// Guards with 'static lifetime (Rc-like) + +/// A read guard with a `'static` lifetime, holding an `Rc` to the lock. +pub struct LocalRwLockReadGuard { + inner: Rc>, +} + +impl LocalRwLockReadGuard { + /// Rebuild a handle to the lock from this [`LocalRwLockReadGuard`]. + pub fn lock_handle(me: &Self) -> LocalRwLock { + LocalRwLock { + inner: me.inner.clone(), + } + } +} + +impl Deref for LocalRwLockReadGuard { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.inner.value.get() } + } +} + +impl Drop for LocalRwLockReadGuard { + fn drop(&mut self) { + self.inner.release_read(); + } +} + +/// A write guard with a `'static` lifetime, holding an `Rc` to the lock. +pub struct LocalRwLockWriteGuard { + inner: Rc>, +} + +impl LocalRwLockWriteGuard { + /// Rebuild a handle to the lock from this [`LocalRwLockWriteGuard`]. + pub fn lock_handle(me: &Self) -> LocalRwLock { + LocalRwLock { + inner: me.inner.clone(), + } + } +} + +impl Deref for LocalRwLockWriteGuard { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.inner.value.get() } + } +} + +impl DerefMut for LocalRwLockWriteGuard { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.inner.value.get() } + } +} + +impl Drop for LocalRwLockWriteGuard { + fn drop(&mut self) { + self.inner.release_write(); + } +} + +// Futures + +/// Future returned by `read_rc()`. +pub struct ReadFuture { + inner: Rc>, + waiter_index: Cell>, +} + +impl Future for ReadFuture { + type Output = LocalRwLockReadGuard; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + if self + .inner + .poll_lock(&self.waiter_index, cx, |inner| inner.try_read(), false) + .is_ready() + { + Poll::Ready(LocalRwLockReadGuard { + inner: self.inner.clone(), + }) + } else { + Poll::Pending + } + } +} + +impl Drop for ReadFuture { + fn drop(&mut self) { + self.inner.cleanup_waiter(&self.waiter_index, false); + } +} + +/// Future returned by `write_rc()`. +pub struct WriteFuture { + inner: Rc>, + waiter_index: Cell>, +} + +impl Future for WriteFuture { + type Output = LocalRwLockWriteGuard; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + if self + .inner + .poll_lock(&self.waiter_index, cx, |inner| inner.try_write(), true) + .is_ready() + { + Poll::Ready(LocalRwLockWriteGuard { + inner: self.inner.clone(), + }) + } else { + Poll::Pending + } + } +} + +impl Drop for WriteFuture { + fn drop(&mut self) { + self.inner.cleanup_waiter(&self.waiter_index, true); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_basic_read_write() { + let lock = LocalRwLock::new(42); + + // Can acquire read lock + let guard = lock.try_read().unwrap(); + assert_eq!(*guard, 42); + drop(guard); + + // Can acquire write lock + let mut guard = lock.try_write().unwrap(); + *guard = 100; + drop(guard); + + // Value was updated + let guard = lock.try_read().unwrap(); + assert_eq!(*guard, 100); + } + + #[test] + fn test_multiple_readers() { + let lock = LocalRwLock::new(42); + + let guard1 = lock.try_read().unwrap(); + let guard2 = lock.try_read().unwrap(); + let guard3 = lock.try_read().unwrap(); + + assert_eq!(*guard1, 42); + assert_eq!(*guard2, 42); + assert_eq!(*guard3, 42); + + // Cannot acquire write lock while readers exist + assert!(lock.try_write().is_none()); + + drop(guard1); + assert!(lock.try_write().is_none()); + + drop(guard2); + assert!(lock.try_write().is_none()); + + drop(guard3); + // Now we can acquire write lock + assert!(lock.try_write().is_some()); + } + + #[test] + fn test_exclusive_writer() { + let lock = LocalRwLock::new(42); + + let guard = lock.try_write().unwrap(); + + // Cannot acquire another write lock + assert!(lock.try_write().is_none()); + + // Cannot acquire read lock + assert!(lock.try_read().is_none()); + + drop(guard); + + // Now we can acquire locks again + assert!(lock.try_read().is_some()); + } + + #[test] + fn test_arc_guards() { + let lock = LocalRwLock::new(42); + + // Try read_rc + let guard = lock.try_read().unwrap(); + assert_eq!(*guard, 42); + drop(guard); + + // Try write_rc + let mut guard = lock.try_write().unwrap(); + *guard = 100; + drop(guard); + + let guard = lock.try_read().unwrap(); + assert_eq!(*guard, 100); + } + + #[test] + fn test_writer_priority() { + use std::sync::{Arc, Mutex}; + use std::task::{Poll, Wake}; + + // Custom waker that tracks when it's woken + struct TrackingWaker { + name: &'static str, + wake_order: Arc>>, + } + + impl Wake for TrackingWaker { + fn wake(self: Arc) { + self.wake_order.lock().unwrap().push(self.name); + } + } + + let lock = LocalRwLock::new(0); + let wake_order = Arc::new(Mutex::new(Vec::new())); + + // Acquire write lock + let write_guard = lock.try_write().unwrap(); + + // Create read and write futures that will need to wait + let mut read_future = Box::pin(lock.read()); + let mut write_future = Box::pin(lock.write()); + + // Create tracking wakers + let read_waker = Arc::new(TrackingWaker { + name: "reader", + wake_order: wake_order.clone(), + }) + .into(); + let mut read_cx = std::task::Context::from_waker(&read_waker); + + let write_waker = Arc::new(TrackingWaker { + name: "writer", + wake_order: wake_order.clone(), + }) + .into(); + let mut write_cx = std::task::Context::from_waker(&write_waker); + + // Poll both to register them as waiters + assert!(matches!( + write_future.as_mut().poll(&mut write_cx), + Poll::Pending + )); + assert!(matches!( + read_future.as_mut().poll(&mut read_cx), + Poll::Pending + )); + + // Verify they're in separate queues + assert_eq!( + lock.inner + .write_waiters + .borrow() + .iter() + .filter(|w| w.is_some()) + .count(), + 1 + ); + assert_eq!( + lock.inner + .read_waiters + .borrow() + .iter() + .filter(|w| w.is_some()) + .count(), + 1 + ); + + // No wakers called yet + assert_eq!(wake_order.lock().unwrap().len(), 0); + + // Release the write lock - this should wake waiters + drop(write_guard); + + // Verify ONLY writer was woken (not reader, since writer has priority) + let order = wake_order.lock().unwrap(); + assert_eq!( + order.len(), + 1, + "Only writer should be woken when writers are waiting" + ); + assert_eq!(order[0], "writer", "Writer should be woken, not reader"); + } + + #[test] + fn test_readers_woken_when_no_writers() { + use std::sync::{Arc, Mutex}; + use std::task::{Poll, Wake}; + + // Custom waker that tracks when it's woken + struct TrackingWaker { + name: String, + wake_order: Arc>>, + } + + impl Wake for TrackingWaker { + fn wake(self: Arc) { + self.wake_order.lock().unwrap().push(self.name.clone()); + } + } + + let lock = LocalRwLock::new(0); + let wake_order = Arc::new(Mutex::new(Vec::new())); + + // Acquire write lock + let write_guard = lock.try_write().unwrap(); + + // Create multiple read futures (no writers) + let mut read_future1 = Box::pin(lock.read()); + let mut read_future2 = Box::pin(lock.read()); + + // Create tracking wakers + let read_waker1 = Arc::new(TrackingWaker { + name: "reader1".to_string(), + wake_order: wake_order.clone(), + }) + .into(); + let mut read_cx1 = std::task::Context::from_waker(&read_waker1); + + let read_waker2 = Arc::new(TrackingWaker { + name: "reader2".to_string(), + wake_order: wake_order.clone(), + }) + .into(); + let mut read_cx2 = std::task::Context::from_waker(&read_waker2); + + // Poll both to register them as waiters + assert!(matches!( + read_future1.as_mut().poll(&mut read_cx1), + Poll::Pending + )); + assert!(matches!( + read_future2.as_mut().poll(&mut read_cx2), + Poll::Pending + )); + + // Verify they're in read queue + assert_eq!( + lock.inner + .read_waiters + .borrow() + .iter() + .filter(|w| w.is_some()) + .count(), + 2 + ); + assert_eq!( + lock.inner + .write_waiters + .borrow() + .iter() + .filter(|w| w.is_some()) + .count(), + 0 + ); + + // No wakers called yet + assert_eq!(wake_order.lock().unwrap().len(), 0); + + // Release the write lock - this should wake all readers since no writers are waiting + drop(write_guard); + + // Verify both readers were woken + let order = wake_order.lock().unwrap(); + assert_eq!( + order.len(), + 2, + "Both readers should be woken when no writers are waiting" + ); + assert!(order.contains(&"reader1".to_string())); + assert!(order.contains(&"reader2".to_string())); + } +} diff --git a/lib/api/src/entities/store/mod.rs b/lib/api/src/entities/store/mod.rs index cc403861f4..e1aee0709f 100644 --- a/lib/api/src/entities/store/mod.rs +++ b/lib/api/src/entities/store/mod.rs @@ -1,17 +1,39 @@ //! Defines the [`Store`] data type and various useful traits and data types to interact with a //! store. +/// Defines the [`AsStoreAsync`] trait and its supporting types. +#[cfg(feature = "experimental-async")] +mod async_; +#[cfg(feature = "experimental-async")] +pub use async_::*; + +/// Defines the [`StoreContext`] type. +mod context; + /// Defines the [`StoreInner`] data type. mod inner; /// Create temporary handles to engines. mod store_ref; + +/// Single-threaded async-aware RwLock. +#[cfg(feature = "experimental-async")] +mod local_rwlock; +#[cfg(feature = "experimental-async")] +pub(crate) use local_rwlock::*; + +use std::{ + boxed::Box, + ops::{Deref, DerefMut}, +}; + pub use store_ref::*; mod obj; pub use obj::*; use crate::{AsEngineRef, BackendEngine, Engine, EngineRef}; +pub(crate) use context::*; pub(crate) use inner::*; use wasmer_types::StoreId; @@ -108,6 +130,16 @@ impl Store { pub fn id(&self) -> StoreId { self.inner.objects.id() } + + #[cfg(feature = "experimental-async")] + /// Transforms this store into a [`StoreAsync`] which can be used + /// to invoke [`Function::call_async`](crate::Function::call_async). + pub fn into_async(self) -> StoreAsync { + StoreAsync { + id: self.id(), + inner: LocalRwLock::new(self.inner), + } + } } impl PartialEq for Store { diff --git a/lib/api/src/entities/store/obj.rs b/lib/api/src/entities/store/obj.rs index 8fa28ed5fe..215ec2b8a5 100644 --- a/lib/api/src/entities/store/obj.rs +++ b/lib/api/src/entities/store/obj.rs @@ -1,6 +1,6 @@ use wasmer_types::StoreId; -use crate::{macros::backend::match_rt, BackendStore}; +use crate::{BackendStore, macros::backend::match_rt}; /// Set of objects managed by a context. #[derive(Debug)] @@ -37,16 +37,16 @@ impl StoreObjects { pub fn same(a: &Self, b: &Self) -> bool { match (a, b) { #[cfg(feature = "sys")] - (Self::Sys(ref a), Self::Sys(ref b)) => a.id() == b.id(), + (Self::Sys(a), Self::Sys(b)) => a.id() == b.id(), #[cfg(feature = "wamr")] - (Self::Wamr(ref a), Self::Wamr(ref b)) => a.id() == b.id(), + (Self::Wamr(a), Self::Wamr(b)) => a.id() == b.id(), #[cfg(feature = "v8")] - (Self::V8(ref a), Self::V8(ref b)) => a.id() == b.id(), + (Self::V8(a), Self::V8(b)) => a.id() == b.id(), #[cfg(feature = "js")] - (Self::Js(ref a), Self::Js(ref b)) => a.id() == b.id(), + (Self::Js(a), Self::Js(b)) => a.id() == b.id(), #[cfg(feature = "jsc")] - (Self::Jsc(ref a), Self::Jsc(ref b)) => a.id() == b.id(), + (Self::Jsc(a), Self::Jsc(b)) => a.id() == b.id(), _ => panic!( "Incompatible `StoreObjects` instance: {}, {}!", diff --git a/lib/api/src/entities/store/store_ref.rs b/lib/api/src/entities/store/store_ref.rs index 1dae7b5ead..42ad59ec12 100644 --- a/lib/api/src/entities/store/store_ref.rs +++ b/lib/api/src/entities/store/store_ref.rs @@ -1,7 +1,9 @@ use std::ops::{Deref, DerefMut}; -use super::{inner::StoreInner, StoreObjects}; +use super::{StoreObjects, inner::StoreInner}; use crate::entities::engine::{AsEngineRef, Engine, EngineRef}; +#[cfg(feature = "experimental-async")] +use crate::{AsStoreAsync, StoreAsync}; use wasmer_types::{ExternType, OnCalledAction}; //use wasmer_vm::{StoreObjects, TrapHandlerFn}; @@ -63,7 +65,9 @@ impl StoreMut<'_> { #[allow(unused)] pub(crate) unsafe fn from_raw(raw: *mut StoreInner) -> Self { - Self { inner: &mut *raw } + Self { + inner: unsafe { &mut *raw }, + } } #[allow(unused)] @@ -88,6 +92,17 @@ impl StoreMut<'_> { pub trait AsStoreRef { /// Returns a `StoreRef` pointing to the underlying context. fn as_store_ref(&self) -> StoreRef<'_>; + + /// Returns a [`StoreAsync`] if the current + /// context is asynchronous. The store will be locked since + /// it's already active in the current context, but can be used + /// to spawn new coroutines via + /// [`Function::call_async`](crate::Function::call_async). + #[cfg(feature = "experimental-async")] + fn as_store_async(&self) -> Option { + let id = self.as_store_ref().inner.objects.id(); + StoreAsync::from_context(id) + } } /// Helper trait for a value that is convertible to a [`StoreMut`]. diff --git a/lib/api/src/entities/table/inner.rs b/lib/api/src/entities/table/inner.rs index 5cbe35b893..13e6f86e1d 100644 --- a/lib/api/src/entities/table/inner.rs +++ b/lib/api/src/entities/table/inner.rs @@ -1,11 +1,11 @@ use wasmer_types::TableType; use crate::{ + AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef, Value, error::RuntimeError, macros::backend::{gen_rt_ty, match_rt}, store::BackendStore, vm::{VMExtern, VMExternTable}, - AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef, Value, }; /// A WebAssembly `table` instance. /// @@ -254,7 +254,7 @@ mod test { ignore = "growing tables in v8 is not currently supported" )] fn table_grow_issue_3197() { - use crate::{imports, Instance, Module, Store, Table, TableType, Type, Value}; + use crate::{Instance, Module, Store, Table, TableType, Type, Value, imports}; const WAT: &str = r#"(module (table (import "env" "table") 100 funcref))"#; diff --git a/lib/api/src/entities/table/mod.rs b/lib/api/src/entities/table/mod.rs index 0ee1934df6..bcb05aa5e2 100644 --- a/lib/api/src/entities/table/mod.rs +++ b/lib/api/src/entities/table/mod.rs @@ -4,10 +4,10 @@ pub(crate) mod inner; pub(crate) use inner::*; use crate::{ + AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef, Value, error::RuntimeError, store::BackendStore, vm::{VMExtern, VMExternTable}, - AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef, Value, }; /// A WebAssembly `table` instance. @@ -135,7 +135,7 @@ mod test { ignore = "growing tables in v8 is not currently supported" )] fn table_grow_issue_3197() { - use crate::{imports, Instance, Module, Store, Table, TableType, Type, Value}; + use crate::{Instance, Module, Store, Table, TableType, Type, Value, imports}; const WAT: &str = r#"(module (table (import "env" "table") 100 funcref))"#; diff --git a/lib/api/src/entities/tag/inner.rs b/lib/api/src/entities/tag/inner.rs index 1a30f1ade0..5d05c4bbd1 100644 --- a/lib/api/src/entities/tag/inner.rs +++ b/lib/api/src/entities/tag/inner.rs @@ -1,9 +1,9 @@ use wasmer_types::{TagType, Type}; use crate::{ + AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, macros::backend::{gen_rt_ty, match_rt}, vm::{VMExtern, VMExternTag}, - AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, }; /// A WebAssembly `global` instance. diff --git a/lib/api/src/entities/tag/mod.rs b/lib/api/src/entities/tag/mod.rs index e670d0a4fa..794d0b5d9c 100644 --- a/lib/api/src/entities/tag/mod.rs +++ b/lib/api/src/entities/tag/mod.rs @@ -3,8 +3,8 @@ pub(crate) use inner::*; use wasmer_types::{TagType, Type}; use crate::{ - vm::{VMExtern, VMExternTag}, AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, + vm::{VMExtern, VMExternTag}, }; /// A WebAssembly `tag` instance. diff --git a/lib/api/src/entities/trap.rs b/lib/api/src/entities/trap.rs index 06af0c198e..8578b96051 100644 --- a/lib/api/src/entities/trap.rs +++ b/lib/api/src/entities/trap.rs @@ -1,6 +1,8 @@ use std::{any::Any, error::Error, fmt::Debug}; -use crate::{macros::backend::match_rt, RuntimeError}; +#[cfg(feature = "sys")] +use crate::BackendException; +use crate::{Exception, RuntimeError, macros::backend::match_rt}; /// An enumeration of all the trap kinds supported by the runtimes. #[derive(Debug, derive_more::From)] @@ -87,6 +89,45 @@ impl BackendTrap { s.is::() }) } + + /// Returns true if the trap is an exception + #[inline] + pub fn is_exception(&self) -> bool { + match_rt!(on self => s { + s.is_exception() + }) + } + + /// If the `Trap` is an uncaught exception, returns it. + #[inline] + pub fn to_exception(&self) -> Option { + match self { + #[cfg(feature = "sys")] + Self::Sys(s) => s + .to_exception_ref() + .map(|e| Exception::from_vm_exceptionref(crate::vm::VMExceptionRef::Sys(e))), + #[cfg(feature = "wamr")] + Self::Wamr(s) => s + .to_exception_ref() + .map(|e| Exception::from_vm_exceptionref(crate::vm::VMExceptionRef::Wamr(e))), + #[cfg(feature = "wasmi")] + Self::Wasmi(s) => s + .to_exception_ref() + .map(|e| Exception::from_vm_exceptionref(crate::vm::VMExceptionRef::Wasmi(e))), + #[cfg(feature = "v8")] + Self::V8(s) => s + .to_exception_ref() + .map(|e| Exception::from_vm_exceptionref(crate::vm::VMExceptionRef::V8(e))), + #[cfg(feature = "js")] + Self::Js(s) => s + .to_exception_ref() + .map(|e| Exception::from_vm_exceptionref(crate::vm::VMExceptionRef::Js(e))), + #[cfg(feature = "jsc")] + Self::Jsc(s) => s + .to_exception_ref() + .map(|e| Exception::from_vm_exceptionref(crate::vm::VMExceptionRef::Jsc(e))), + } + } } impl std::fmt::Display for BackendTrap { diff --git a/lib/api/src/entities/value.rs b/lib/api/src/entities/value.rs index 4ef22e45e4..06ec15ec82 100644 --- a/lib/api/src/entities/value.rs +++ b/lib/api/src/entities/value.rs @@ -1,9 +1,9 @@ use wasmer_types::{RawValue, Type}; use crate::{ - entities::{ExceptionRef, ExternRef, Function}, - vm::{VMExceptionRef, VMExternRef, VMFuncRef}, AsStoreRef, Tag, + entities::{Exception, ExternRef, Function}, + vm::{VMExceptionRef, VMExternRef, VMFuncRef}, }; /// WebAssembly computations manipulate values of basic value types: @@ -41,7 +41,7 @@ pub enum Value { FuncRef(Option), /// A nullable first-class reference to a WebAssembly exception. - ExceptionRef(Option), + ExceptionRef(Option), } macro_rules! accessors { @@ -97,7 +97,7 @@ impl Value { Self::F64(f64) => RawValue { f64 }, Self::V128(u128) => RawValue { u128 }, Self::ExceptionRef(Some(ref f)) => f.vm_exceptionref().into_raw(), - Self::ExceptionRef(None) => RawValue { funcref: 0 }, + Self::ExceptionRef(None) => RawValue { exnref: 0 }, Self::FuncRef(Some(ref f)) => f.vm_funcref(store).into_raw(), Self::FuncRef(None) => RawValue { funcref: 0 }, Self::ExternRef(Some(ref e)) => e.vm_externref().into_raw(), @@ -115,126 +115,136 @@ impl Value { raw: RawValue, ) -> Self { match ty { - Type::I32 => Self::I32(raw.i32), - Type::I64 => Self::I64(raw.i64), - Type::F32 => Self::F32(raw.f32), - Type::F64 => Self::F64(raw.f64), - Type::V128 => Self::V128(raw.u128), + Type::I32 => Self::I32(unsafe { raw.i32 }), + Type::I64 => Self::I64(unsafe { raw.i64 }), + Type::F32 => Self::F32(unsafe { raw.f32 }), + Type::F64 => Self::F64(unsafe { raw.f64 }), + Type::V128 => Self::V128(unsafe { raw.u128 }), Type::FuncRef => match store.as_store_ref().inner.store { #[cfg(feature = "sys")] - crate::BackendStore::Sys(_) => Self::FuncRef( - crate::backend::sys::vm::VMFuncRef::from_raw(raw) - .map(VMFuncRef::Sys) - .map(|f| Function::from_vm_funcref(store, f)), - ), + crate::BackendStore::Sys(_) => Self::FuncRef({ + unsafe { crate::backend::sys::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Sys) } + .map(|f| unsafe { Function::from_vm_funcref(store, f) }) + }), #[cfg(feature = "wamr")] - crate::BackendStore::Wamr(_) => Self::FuncRef( - crate::backend::wamr::vm::VMFuncRef::from_raw(raw) - .map(VMFuncRef::Wamr) - .map(|f| Function::from_vm_funcref(store, f)), - ), + crate::BackendStore::Wamr(_) => Self::FuncRef({ + unsafe { + crate::backend::wamr::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Wamr) + } + .map(|f| unsafe { Function::from_vm_funcref(store, f) }) + }), #[cfg(feature = "wasmi")] - crate::BackendStore::Wasmi(_) => Self::FuncRef( - crate::backend::wasmi::vm::VMFuncRef::from_raw(raw) - .map(VMFuncRef::Wasmi) - .map(|f| Function::from_vm_funcref(store, f)), - ), + crate::BackendStore::Wasmi(_) => Self::FuncRef({ + unsafe { + crate::backend::wasmi::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Wasmi) + } + .map(|f| unsafe { Function::from_vm_funcref(store, f) }) + }), #[cfg(feature = "v8")] - crate::BackendStore::V8(_) => Self::FuncRef( - crate::backend::v8::vm::VMFuncRef::from_raw(raw) - .map(VMFuncRef::V8) - .map(|f| Function::from_vm_funcref(store, f)), - ), + crate::BackendStore::V8(_) => Self::FuncRef({ + unsafe { crate::backend::v8::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::V8) } + .map(|f| unsafe { Function::from_vm_funcref(store, f) }) + }), #[cfg(feature = "js")] - crate::BackendStore::Js(_) => Self::FuncRef( - crate::backend::js::vm::VMFuncRef::from_raw(raw) - .map(VMFuncRef::Js) - .map(|f| Function::from_vm_funcref(store, f)), - ), + crate::BackendStore::Js(_) => Self::FuncRef({ + unsafe { crate::backend::js::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Js) } + .map(|f| unsafe { Function::from_vm_funcref(store, f) }) + }), #[cfg(feature = "jsc")] - crate::BackendStore::Jsc(_) => Self::FuncRef( - crate::backend::jsc::vm::VMFuncRef::from_raw(raw) - .map(VMFuncRef::Jsc) - .map(|f| Function::from_vm_funcref(store, f)), - ), + crate::BackendStore::Jsc(_) => Self::FuncRef({ + unsafe { crate::backend::jsc::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Jsc) } + .map(|f| unsafe { Function::from_vm_funcref(store, f) }) + }), }, Type::ExternRef => match store.as_store_ref().inner.store { #[cfg(feature = "sys")] - crate::BackendStore::Sys(_) => Self::ExternRef( - crate::backend::sys::vm::VMExternRef::from_raw(raw) - .map(VMExternRef::Sys) - .map(|f| ExternRef::from_vm_externref(store, f)), - ), + crate::BackendStore::Sys(_) => Self::ExternRef({ + unsafe { + crate::backend::sys::vm::VMExternRef::from_raw(raw).map(VMExternRef::Sys) + } + .map(|f| unsafe { ExternRef::from_vm_externref(store, f) }) + }), #[cfg(feature = "wamr")] - crate::BackendStore::Wamr(_) => Self::ExternRef( - crate::backend::wamr::vm::VMExternRef::from_raw(raw) - .map(VMExternRef::Wamr) - .map(|f| ExternRef::from_vm_externref(store, f)), - ), + crate::BackendStore::Wamr(_) => Self::ExternRef({ + unsafe { + crate::backend::wamr::vm::VMExternRef::from_raw(raw).map(VMExternRef::Wamr) + } + .map(|f| unsafe { ExternRef::from_vm_externref(store, f) }) + }), #[cfg(feature = "wasmi")] - crate::BackendStore::Wasmi(_) => Self::ExternRef( - crate::backend::wasmi::vm::VMExternRef::from_raw(raw) - .map(VMExternRef::Wasmi) - .map(|f| ExternRef::from_vm_externref(store, f)), - ), + crate::BackendStore::Wasmi(_) => Self::ExternRef({ + unsafe { + crate::backend::wasmi::vm::VMExternRef::from_raw(raw) + .map(VMExternRef::Wasmi) + } + .map(|f| unsafe { ExternRef::from_vm_externref(store, f) }) + }), #[cfg(feature = "v8")] - crate::BackendStore::V8(_) => Self::ExternRef( - crate::backend::v8::vm::VMExternRef::from_raw(raw) - .map(VMExternRef::V8) - .map(|f| ExternRef::from_vm_externref(store, f)), - ), + crate::BackendStore::V8(_) => Self::ExternRef({ + unsafe { + crate::backend::v8::vm::VMExternRef::from_raw(raw).map(VMExternRef::V8) + } + .map(|f| unsafe { ExternRef::from_vm_externref(store, f) }) + }), #[cfg(feature = "js")] - crate::BackendStore::Js(_) => Self::ExternRef( - crate::backend::js::vm::VMExternRef::from_raw(raw) - .map(VMExternRef::Js) - .map(|f| ExternRef::from_vm_externref(store, f)), - ), + crate::BackendStore::Js(_) => Self::ExternRef({ + unsafe { + crate::backend::js::vm::VMExternRef::from_raw(raw).map(VMExternRef::Js) + } + .map(|f| unsafe { ExternRef::from_vm_externref(store, f) }) + }), #[cfg(feature = "jsc")] - crate::BackendStore::Jsc(_) => Self::ExternRef( - crate::backend::jsc::vm::VMExternRef::from_raw(raw) - .map(VMExternRef::Jsc) - .map(|f| ExternRef::from_vm_externref(store, f)), - ), + crate::BackendStore::Jsc(_) => Self::ExternRef({ + unsafe { + crate::backend::jsc::vm::VMExternRef::from_raw(raw).map(VMExternRef::Jsc) + } + .map(|f| unsafe { ExternRef::from_vm_externref(store, f) }) + }), }, Type::ExceptionRef => match store.as_store_ref().inner.store { #[cfg(feature = "sys")] crate::BackendStore::Sys(_) => Self::ExceptionRef( - crate::backend::sys::vm::VMExceptionRef::from_raw(raw) - .map(VMExceptionRef::Sys) - .map(|f| ExceptionRef::from_vm_exceptionref(store, f)), + unsafe { + crate::backend::sys::vm::VMExceptionRef::from_raw( + store.objects_mut().id(), + raw, + ) + } + .map(VMExceptionRef::Sys) + .map(Exception::from_vm_exceptionref), ), #[cfg(feature = "wamr")] crate::BackendStore::Wamr(_) => Self::ExceptionRef( - crate::backend::wamr::vm::VMExceptionRef::from_raw(raw) + unsafe { crate::backend::wamr::vm::VMExceptionRef::from_raw(raw) } .map(VMExceptionRef::Wamr) - .map(|f| ExceptionRef::from_vm_exceptionref(store, f)), + .map(Exception::from_vm_exceptionref), ), #[cfg(feature = "wasmi")] crate::BackendStore::Wasmi(_) => Self::ExceptionRef( - crate::backend::wasmi::vm::VMExceptionRef::from_raw(raw) + unsafe { crate::backend::wasmi::vm::VMExceptionRef::from_raw(raw) } .map(VMExceptionRef::Wasmi) - .map(|f| ExceptionRef::from_vm_exceptionref(store, f)), + .map(Exception::from_vm_exceptionref), ), #[cfg(feature = "v8")] crate::BackendStore::V8(_) => Self::ExceptionRef( - crate::backend::v8::vm::VMExceptionRef::from_raw(raw) + unsafe { crate::backend::v8::vm::VMExceptionRef::from_raw(raw) } .map(VMExceptionRef::V8) - .map(|f| ExceptionRef::from_vm_exceptionref(store, f)), + .map(Exception::from_vm_exceptionref), ), #[cfg(feature = "js")] crate::BackendStore::Js(_) => Self::ExceptionRef( - crate::backend::js::vm::VMExceptionRef::from_raw(raw) + unsafe { crate::backend::js::vm::VMExceptionRef::from_raw(raw) } .map(VMExceptionRef::Js) - .map(|f| ExceptionRef::from_vm_exceptionref(store, f)), + .map(Exception::from_vm_exceptionref), ), #[cfg(feature = "jsc")] crate::BackendStore::Jsc(_) => Self::ExceptionRef( - crate::backend::jsc::vm::VMExceptionRef::from_raw(raw) + unsafe { crate::backend::jsc::vm::VMExceptionRef::from_raw(raw) } .map(VMExceptionRef::Jsc) - .map(|f| ExceptionRef::from_vm_exceptionref(store, f)), + .map(Exception::from_vm_exceptionref), ), }, } @@ -387,14 +397,14 @@ impl From> for Value { } } -impl From for Value { - fn from(val: ExceptionRef) -> Self { +impl From for Value { + fn from(val: Exception) -> Self { Self::ExceptionRef(Some(val)) } } -impl From> for Value { - fn from(val: Option) -> Self { +impl From> for Value { + fn from(val: Option) -> Self { Self::ExceptionRef(val) } } @@ -477,7 +487,7 @@ impl TryFrom for Option { } } -impl TryFrom for Option { +impl TryFrom for Option { type Error = &'static str; fn try_from(value: Value) -> Result { diff --git a/lib/api/src/error.rs b/lib/api/src/error.rs index 35400775b7..f80ffb67da 100644 --- a/lib/api/src/error.rs +++ b/lib/api/src/error.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use thiserror::Error; use wasmer_types::{FrameInfo, ImportError, TrapCode}; -use crate::BackendTrap as Trap; +use crate::{AsStoreMut, AsStoreRef, BackendTrap as Trap, Exception, Value}; /// The WebAssembly.LinkError object indicates an error during /// module instantiation (besides traps from the start function). @@ -18,9 +18,9 @@ pub enum LinkError { #[cfg_attr(feature = "std", error("Error while importing {0:?}.{1:?}: {2}"))] Import(String, String, ImportError), - /// A trap ocurred during linking. + /// A trap occurred during linking. #[cfg_attr(feature = "std", error("RuntimeError occurred during linking: {0}"))] - Trap(#[source] RuntimeError), + Trap(#[cfg_attr(feature = "std", source)] RuntimeError), /// Insufficient resources available for linking. #[cfg_attr(feature = "std", error("Insufficient resources: {0}"))] Resource(String), @@ -37,7 +37,7 @@ pub enum LinkError { #[derive(Debug, Clone)] #[cfg_attr(feature = "std", derive(Error))] pub enum InstantiationError { - /// A linking ocurred during instantiation. + /// A linking occurred during instantiation. #[cfg_attr(feature = "std", error(transparent))] Link(LinkError), @@ -153,6 +153,26 @@ impl RuntimeError { } } + /// Creates a `RuntimeError` containing an exception. + /// + /// If this error is returned from an imported function, the exception + /// will be thrown in the WebAssembly code instead of the usual trapping. + pub fn exception(ctx: &impl AsStoreRef, exception: Exception) -> Self { + let exnref = exception.vm_exceptionref(); + let store = ctx.as_store_ref(); + match store.inner.objects { + #[cfg(feature = "sys")] + crate::StoreObjects::Sys(ref store_objects) => { + crate::backend::sys::vm::Trap::uncaught_exception( + exnref.as_sys().clone(), + store_objects, + ) + .into() + } + _ => panic!("exceptions are only supported in the `sys` backend"), + } + } + /// Returns a reference the `message` stored in `Trap`. pub fn message(&self) -> String { if let Some(trap_code) = self.inner.trap_code { @@ -198,25 +218,32 @@ impl RuntimeError { pub fn is(&self) -> bool { self.inner.source.is::() } -} -impl std::fmt::Debug for RuntimeError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("RuntimeError") - .field("source", &self.inner.source) - .field("wasm_trace", &self.inner.wasm_trace) - .finish() + /// Returns true if the `RuntimeError` is an uncaught exception. + pub fn is_exception(&self) -> bool { + self.inner.source.is_exception() } -} -impl std::fmt::Display for RuntimeError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "RuntimeError: {}", self.message())?; - let trace = self.trace(); + /// If the `RuntimeError` is an uncaught exception, returns it. + pub fn to_exception(&self) -> Option { + self.inner.source.to_exception() + } + + /// Returns a displayable version of the `RuntimeError` that also shows exception payloads. + pub fn display<'a>(&'a self, store: &'a mut impl AsStoreMut) -> RuntimeErrorDisplay<'a> { + if let Some(exception) = self.to_exception() { + RuntimeErrorDisplay::Exception(exception.payload(store), self.trace()) + } else { + RuntimeErrorDisplay::Other(self) + } + } + + /// Write the WASM trace to the given formatter, if we have one. + pub fn write_trace(trace: &[FrameInfo], f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if trace.is_empty() { return Ok(()); } - for frame in self.trace().iter() { + for frame in trace.iter() { let name = frame.module_name(); let func_index = frame.func_index(); writeln!(f)?; @@ -238,6 +265,52 @@ impl std::fmt::Display for RuntimeError { } Ok(()) } + + pub(crate) fn from_dyn(err: Box) -> Self { + match err.downcast::() { + Ok(runtime_error) => *runtime_error, + Err(error) => Trap::user(error), + } + } +} + +impl std::fmt::Debug for RuntimeError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("RuntimeError") + .field("source", &self.inner.source) + .field("wasm_trace", &self.inner.wasm_trace) + .finish() + } +} + +impl std::fmt::Display for RuntimeError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "RuntimeError: {}", self.message())?; + Self::write_trace(self.trace(), f) + } +} + +/// A displayable version of the `RuntimeError` that also shows exception payloads. +pub enum RuntimeErrorDisplay<'a> { + /// The error is an uncaught exception, with its payload and trace. + Exception(Vec, &'a [FrameInfo]), + /// The error is not an exception, just display it. + Other(&'a RuntimeError), +} + +impl std::fmt::Display for RuntimeErrorDisplay<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + RuntimeErrorDisplay::Exception(payload, trace) => { + write!(f, "Uncaught exception")?; + if !payload.is_empty() { + write!(f, " with payload: {payload:?}")?; + } + RuntimeError::write_trace(trace, f) + } + RuntimeErrorDisplay::Other(err) => write!(f, "{err}"), + } + } } impl std::error::Error for RuntimeError { diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 3627094333..c85f05cfa0 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -72,11 +72,11 @@ //! //! * **Pluggable compilers** — A compiler is used by the engine to //! transform WebAssembly into executable code: -//! * [`wasmer-compiler-singlepass`] provides a fast compilation-time +//! * [`wasmer-compiler-singlepass`](https://docs.rs/wasmer-compiler-singlepass/) provides a fast compilation-time //! but an unoptimized runtime speed, -//! * [`wasmer-compiler-cranelift`] provides the right balance between +//! * [`wasmer-compiler-cranelift`](https://docs.rs/wasmer-compiler-cranelift/) provides the right balance between //! compilation-time and runtime performance, useful for development, -//! * [`wasmer-compiler-llvm`] provides a deeply optimized executable +//! * [`wasmer-compiler-llvm`](https://docs.rs/wasmer-compiler-llvm/) provides a deeply optimized executable //! code with the fastest runtime speed, ideal for production. //! //! * **Interpreters** - Wasmer supports interpeters such as [`wamr`] and [`wasmi`]. @@ -302,15 +302,15 @@ //! - `cranelift` #![cfg_attr(feature = "cranelift", doc = "(enabled),")] #![cfg_attr(not(feature = "cranelift"), doc = "(disabled),")] -//! enables Wasmer's [Cranelift compiler][wasmer-compiler-cranelift], +//! enables Wasmer's [`Cranelift` compiler](https://docs.rs/wasmer-compiler-cranelift), //! - `llvm` #![cfg_attr(feature = "llvm", doc = "(enabled),")] #![cfg_attr(not(feature = "llvm"), doc = "(disabled),")] -//! enables Wasmer's [LLVM compiler][wasmer-compiler-lvm], +//! enables Wasmer's [`LLVM` compiler](https://docs.rs/wasmer-compiler-llvm), //! - `singlepass` #![cfg_attr(feature = "singlepass", doc = "(enabled),")] #![cfg_attr(not(feature = "singlepass"), doc = "(disabled),")] -//! enables Wasmer's [Singlepass compiler][wasmer-compiler-singlepass], +//! enables Wasmer's [`Singlepass` compiler](https://docs.rs/wasmer-compiler-singlepass), //! - `wat` #![cfg_attr(feature = "wat", doc = "(enabled),")] #![cfg_attr(not(feature = "wat"), doc = "(disabled),")] @@ -428,7 +428,7 @@ mod utils; pub use utils::*; mod entities; -pub use entities::memory::{location::MemoryLocation, MemoryView}; +pub use entities::memory::{MemoryView, location::MemoryLocation}; pub use entities::*; mod error; @@ -439,11 +439,11 @@ pub use backend::*; mod vm; pub use wasmer_types::{ - is_wasm, Bytes, CompileError, DeserializeError, ExportIndex, ExportType, ExternType, FrameInfo, + Bytes, CompileError, DeserializeError, ExportIndex, ExportType, ExternType, FrameInfo, FunctionType, GlobalInit, GlobalType, ImportType, LocalFunctionIndex, MemoryError, MemoryStyle, MemoryType, Mutability, OnCalledAction, Pages, ParseCpuFeatureError, SerializeError, - TableStyle, TableType, TagKind, TagType, Type, ValueType, WasmError, WasmResult, - WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE, + TableStyle, TableType, TagKind, TagType, Type, ValueType, WASM_MAX_PAGES, WASM_MIN_PAGES, + WASM_PAGE_SIZE, WasmError, WasmResult, is_wasm, }; #[cfg(feature = "wasmparser")] diff --git a/lib/api/src/utils/macros/backend.rs b/lib/api/src/utils/macros/backend.rs index 32b77c23eb..5faf704495 100644 --- a/lib/api/src/utils/macros/backend.rs +++ b/lib/api/src/utils/macros/backend.rs @@ -37,6 +37,7 @@ macro_rules! gen_rt_ty { paste::paste! { $($(#[cfg_attr($if, $then)])*)? #[derive($($derive,)*)] + #[allow(clippy::large_enum_variant)] pub(crate) enum []$(<$lt>)? { #[cfg(feature = "sys")] /// The implementation from the `sys` backend. diff --git a/lib/api/src/utils/mem/access.rs b/lib/api/src/utils/mem/access.rs index 8b921b6aaa..71da1165b3 100644 --- a/lib/api/src/utils/mem/access.rs +++ b/lib/api/src/utils/mem/access.rs @@ -2,8 +2,8 @@ use std::mem::{self, MaybeUninit}; use std::slice; use crate::{ - utils::mem::{WasmRef, WasmSlice}, MemoryAccessError, + utils::mem::{WasmRef, WasmSlice}, }; pub(crate) enum SliceCow<'a, T> { @@ -118,10 +118,10 @@ where T: wasmer_types::ValueType, { fn drop(&mut self) { - if let SliceCow::Owned(buf, modified) = &self.buf { - if *modified { - self.slice.write_slice(buf.as_ref()).ok(); - } + if let SliceCow::Owned(buf, modified) = &self.buf + && *modified + { + self.slice.write_slice(buf.as_ref()).ok(); } } } @@ -191,10 +191,10 @@ where T: wasmer_types::ValueType, { fn drop(&mut self) { - if let RefCow::Owned(val, modified) = &self.buf { - if *modified { - self.ptr.write(*val).ok(); - } + if let RefCow::Owned(val, modified) = &self.buf + && *modified + { + self.ptr.write(*val).ok(); } } } diff --git a/lib/api/src/utils/mem/ptr.rs b/lib/api/src/utils/mem/ptr.rs index 257e2a1cb2..dcb089297d 100644 --- a/lib/api/src/utils/mem/ptr.rs +++ b/lib/api/src/utils/mem/ptr.rs @@ -2,8 +2,8 @@ use std::marker::PhantomData; use wasmer_types::{Memory32, Memory64, MemorySize, ValueType}; use crate::{ - access::WasmRefAccess, view::MemoryView, AsStoreRef, FromToNativeWasmType, MemoryAccessError, - NativeWasmTypeInto, WasmRef, WasmSlice, + AsStoreRef, FromToNativeWasmType, MemoryAccessError, NativeWasmTypeInto, WasmRef, WasmSlice, + access::WasmRefAccess, view::MemoryView, }; /// Alias for `WasmPtr. diff --git a/lib/api/src/utils/native/convert.rs b/lib/api/src/utils/native/convert.rs index e776ce6854..05c4a1b977 100644 --- a/lib/api/src/utils/native/convert.rs +++ b/lib/api/src/utils/native/convert.rs @@ -3,8 +3,8 @@ use wasmer_types::{RawValue, Type}; use crate::store::AsStoreRef; use crate::{ - vm::{VMExternRef, VMFuncRef}, ExternRef, Function, TypedFunction, + vm::{VMExternRef, VMFuncRef}, }; use std::error::Error; @@ -52,7 +52,7 @@ impl NativeWasmTypeInto for i32 { #[inline] unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { - raw.i32 + unsafe { raw.i32 } } } @@ -74,7 +74,7 @@ impl NativeWasmTypeInto for u32 { #[inline] unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { - raw.i32 as _ + unsafe { raw.i32 as _ } } } @@ -96,7 +96,7 @@ impl NativeWasmTypeInto for i64 { #[inline] unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { - raw.i64 + unsafe { raw.i64 } } } @@ -118,7 +118,7 @@ impl NativeWasmTypeInto for u64 { #[inline] unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { - raw.i64 as _ + unsafe { raw.i64 as _ } } } @@ -140,7 +140,7 @@ impl NativeWasmTypeInto for f32 { #[inline] unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { - raw.f32 + unsafe { raw.f32 } } } @@ -162,7 +162,7 @@ impl NativeWasmTypeInto for f64 { #[inline] unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { - raw.f64 + unsafe { raw.f64 } } } @@ -184,7 +184,7 @@ impl NativeWasmTypeInto for u128 { #[inline] unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: RawValue) -> Self { - raw.u128 + unsafe { raw.u128 } } } @@ -198,36 +198,36 @@ impl NativeWasmTypeInto for Option { unsafe fn from_abi(store: &mut impl AsStoreMut, abi: Self::Abi) -> Self { match store.as_store_ref().inner.store { #[cfg(feature = "sys")] - crate::BackendStore::Sys(_) => { + crate::BackendStore::Sys(_) => unsafe { wasmer_vm::VMExternRef::from_raw(RawValue { externref: abi }).map(VMExternRef::Sys) - } + }, #[cfg(feature = "wamr")] - crate::BackendStore::Wamr(_) => { + crate::BackendStore::Wamr(_) => unsafe { crate::backend::wamr::vm::VMExternRef::from_raw(RawValue { externref: abi }) .map(VMExternRef::Wamr) - } + }, #[cfg(feature = "wasmi")] - crate::BackendStore::Wasmi(_) => { + crate::BackendStore::Wasmi(_) => unsafe { crate::backend::wasmi::vm::VMExternRef::from_raw(RawValue { externref: abi }) .map(VMExternRef::Wasmi) - } + }, #[cfg(feature = "v8")] - crate::BackendStore::V8(_) => { + crate::BackendStore::V8(_) => unsafe { crate::backend::v8::vm::VMExternRef::from_raw(RawValue { externref: abi }) .map(VMExternRef::V8) - } + }, #[cfg(feature = "js")] - crate::BackendStore::Js(_) => { + crate::BackendStore::Js(_) => unsafe { crate::backend::js::vm::VMExternRef::from_raw(RawValue { externref: abi }) .map(VMExternRef::Js) - } + }, #[cfg(feature = "jsc")] - crate::BackendStore::Jsc(_) => { + crate::BackendStore::Jsc(_) => unsafe { crate::backend::jsc::vm::VMExternRef::from_raw(RawValue { externref: abi }) .map(VMExternRef::Jsc) - } + }, } - .map(|e| ExternRef::from_vm_externref(store, e)) + .map(|e| unsafe { ExternRef::from_vm_externref(store, e) }) } #[inline] @@ -244,31 +244,31 @@ impl NativeWasmTypeInto for Option { unsafe fn from_raw(store: &mut impl AsStoreMut, raw: RawValue) -> Self { match store.as_store_ref().inner.store { #[cfg(feature = "sys")] - crate::BackendStore::Sys(_) => { + crate::BackendStore::Sys(_) => unsafe { wasmer_vm::VMExternRef::from_raw(raw).map(VMExternRef::Sys) - } + }, #[cfg(feature = "wamr")] - crate::BackendStore::Wamr(_) => { + crate::BackendStore::Wamr(_) => unsafe { crate::backend::wamr::vm::VMExternRef::from_raw(raw).map(VMExternRef::Wamr) - } + }, #[cfg(feature = "wasmi")] - crate::BackendStore::Wasmi(_) => { + crate::BackendStore::Wasmi(_) => unsafe { crate::backend::wasmi::vm::VMExternRef::from_raw(raw).map(VMExternRef::Wasmi) - } + }, #[cfg(feature = "v8")] - crate::BackendStore::V8(_) => { + crate::BackendStore::V8(_) => unsafe { crate::backend::v8::vm::VMExternRef::from_raw(raw).map(VMExternRef::V8) - } + }, #[cfg(feature = "js")] - crate::BackendStore::Js(_) => { + crate::BackendStore::Js(_) => unsafe { crate::backend::js::vm::VMExternRef::from_raw(raw).map(VMExternRef::Js) - } + }, #[cfg(feature = "jsc")] - crate::BackendStore::Jsc(_) => { + crate::BackendStore::Jsc(_) => unsafe { crate::backend::jsc::vm::VMExternRef::from_raw(raw).map(VMExternRef::Jsc) - } + }, } - .map(|e| ExternRef::from_vm_externref(store, e)) + .map(|e| unsafe { ExternRef::from_vm_externref(store, e) }) } } @@ -292,36 +292,36 @@ impl NativeWasmTypeInto for Option { unsafe fn from_abi(store: &mut impl AsStoreMut, abi: Self::Abi) -> Self { match store.as_store_ref().inner.store { #[cfg(feature = "sys")] - crate::BackendStore::Sys(_) => { + crate::BackendStore::Sys(_) => unsafe { wasmer_vm::VMFuncRef::from_raw(RawValue { funcref: abi }).map(VMFuncRef::Sys) - } + }, #[cfg(feature = "wamr")] - crate::BackendStore::Wamr(_) => { + crate::BackendStore::Wamr(_) => unsafe { crate::backend::wamr::vm::VMFuncRef::from_raw(RawValue { funcref: abi }) .map(VMFuncRef::Wamr) - } + }, #[cfg(feature = "wasmi")] - crate::BackendStore::Wasmi(_) => { + crate::BackendStore::Wasmi(_) => unsafe { crate::backend::wasmi::vm::VMFuncRef::from_raw(RawValue { funcref: abi }) .map(VMFuncRef::Wasmi) - } + }, #[cfg(feature = "v8")] - crate::BackendStore::V8(_) => { + crate::BackendStore::V8(_) => unsafe { crate::backend::v8::vm::VMFuncRef::from_raw(RawValue { funcref: abi }) .map(VMFuncRef::V8) - } + }, #[cfg(feature = "js")] - crate::BackendStore::Js(_) => { + crate::BackendStore::Js(_) => unsafe { crate::backend::js::vm::VMFuncRef::from_raw(RawValue { funcref: abi }) .map(VMFuncRef::Js) - } + }, #[cfg(feature = "jsc")] - crate::BackendStore::Jsc(_) => { + crate::BackendStore::Jsc(_) => unsafe { crate::backend::jsc::vm::VMFuncRef::from_raw(RawValue { funcref: abi }) .map(VMFuncRef::Jsc) - } + }, } - .map(|f| Function::from_vm_funcref(store, f)) + .map(|f| unsafe { Function::from_vm_funcref(store, f) }) } #[inline] @@ -340,29 +340,31 @@ impl NativeWasmTypeInto for Option { unsafe fn from_raw(store: &mut impl AsStoreMut, raw: RawValue) -> Self { match store.as_store_ref().inner.store { #[cfg(feature = "sys")] - crate::BackendStore::Sys(_) => wasmer_vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Sys), + crate::BackendStore::Sys(_) => unsafe { + wasmer_vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Sys) + }, #[cfg(feature = "wamr")] - crate::BackendStore::Wamr(_) => { + crate::BackendStore::Wamr(_) => unsafe { crate::backend::wamr::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Wamr) - } + }, #[cfg(feature = "wasmi")] - crate::BackendStore::Wasmi(_) => { + crate::BackendStore::Wasmi(_) => unsafe { crate::backend::wasmi::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Wasmi) - } + }, #[cfg(feature = "v8")] - crate::BackendStore::V8(_) => { + crate::BackendStore::V8(_) => unsafe { crate::backend::v8::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::V8) - } + }, #[cfg(feature = "js")] - crate::BackendStore::Js(_) => { + crate::BackendStore::Js(_) => unsafe { crate::backend::js::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Js) - } + }, #[cfg(feature = "jsc")] - crate::BackendStore::Jsc(_) => { + crate::BackendStore::Jsc(_) => unsafe { crate::backend::jsc::vm::VMFuncRef::from_raw(raw).map(VMFuncRef::Jsc) - } + }, } - .map(|f| Function::from_vm_funcref(store, f)) + .map(|f| unsafe { Function::from_vm_funcref(store, f) }) } } @@ -477,7 +479,7 @@ unsafe impl FromToNativeWasmType for Option { n } fn is_from_store(&self, store: &impl AsStoreRef) -> bool { - self.as_ref().map_or(true, |e| e.is_from_store(store)) + self.as_ref().is_none_or(|e| e.is_from_store(store)) } } @@ -491,7 +493,7 @@ unsafe impl FromToNativeWasmType for Option { n } fn is_from_store(&self, store: &impl AsStoreRef) -> bool { - self.as_ref().map_or(true, |f| f.is_from_store(store)) + self.as_ref().is_none_or(|f| f.is_from_store(store)) } } @@ -760,14 +762,18 @@ macro_rules! impl_wasmtypelist { // Build the tuple. ( $( - FromToNativeWasmType::from_native(NativeWasmTypeInto::from_raw(_store, $x)) + { + let native = unsafe { NativeWasmTypeInto::from_raw(_store, $x) }; + FromToNativeWasmType::from_native(native) + } ),* ) } #[allow(clippy::missing_safety_doc)] unsafe fn from_slice(store: &mut impl AsStoreMut, slice: &[RawValue]) -> Result { - Ok(Self::from_array(store, slice.try_into()?)) + let array = slice.try_into()?; + Ok(unsafe { Self::from_array(store, array) }) } #[allow(unused_mut)] @@ -800,7 +806,10 @@ macro_rules! impl_wasmtypelist { ( $( - FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(_store, $x)) + { + let native = unsafe { NativeWasmTypeInto::from_abi(_store, $x) }; + FromToNativeWasmType::from_native(native) + } ),* ) } @@ -826,7 +835,9 @@ macro_rules! impl_wasmtypelist { let mut _n = 0; $( - *_ptr.add(_n).cast() = $x; + unsafe { + *_ptr.add(_n).cast() = $x; + } _n += 1; )* } diff --git a/lib/api/src/utils/native/typed_func.rs b/lib/api/src/utils/native/typed_func.rs index 76ff59db95..546858309e 100644 --- a/lib/api/src/utils/native/typed_func.rs +++ b/lib/api/src/utils/native/typed_func.rs @@ -7,10 +7,13 @@ //! let add_one = instance.exports.get_function("function_name")?; //! let add_one_native: TypedFunction = add_one.native().unwrap(); //! ``` +#[cfg(feature = "experimental-async")] +use crate::AsStoreAsync; use crate::{ - store::AsStoreRef, AsStoreMut, BackendStore, FromToNativeWasmType, Function, - NativeWasmTypeInto, RuntimeError, WasmTypeList, + AsStoreMut, BackendStore, FromToNativeWasmType, Function, NativeWasmTypeInto, RuntimeError, + WasmTypeList, store::AsStoreRef, }; +use std::future::Future; use std::marker::PhantomData; use wasmer_types::RawValue; @@ -78,6 +81,45 @@ macro_rules! impl_native_traits { } } + /// Call the typed func asynchronously. + #[cfg(feature = "experimental-async")] + #[allow(unused_mut)] + #[allow(clippy::too_many_arguments)] + pub fn call_async( + &self, + store: &impl AsStoreAsync, + $( $x: $x, )* + ) -> impl Future> + Sized + 'static + where + $( $x: FromToNativeWasmType + 'static, )* + { + $( + let [] = $x; + )* + let store = store.store(); + let func = self.func.clone(); + async move { + let read_lock = store.read_lock().await; + match read_lock.as_store_ref().inner.store { + #[cfg(feature = "sys")] + BackendStore::Sys(_) => { + drop(read_lock); + Self::call_async_sys(func, store, $([]),*).await + } + #[cfg(feature = "wamr")] + BackendStore::Wamr(_) => async_backend_error(), + #[cfg(feature = "wasmi")] + BackendStore::Wasmi(_) => async_backend_error(), + #[cfg(feature = "v8")] + BackendStore::V8(_) => async_backend_error(), + #[cfg(feature = "js")] + BackendStore::Js(_) => async_backend_error(), + #[cfg(feature = "jsc")] + BackendStore::Jsc(_) => async_backend_error(), + } + } + } + #[doc(hidden)] #[allow(missing_docs)] #[allow(unused_mut)] @@ -118,9 +160,15 @@ impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); -impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15 +); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16 +); +impl_native_traits!( + A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17 +); impl_native_traits!( A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18 ); @@ -130,3 +178,9 @@ impl_native_traits!( impl_native_traits!( A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20 ); + +fn async_backend_error() -> Result { + Err(RuntimeError::new( + "async calls are only supported with the `sys` backend", + )) +} diff --git a/lib/api/src/utils/polyfill.rs b/lib/api/src/utils/polyfill.rs index 8b54de444b..412068d45d 100644 --- a/lib/api/src/utils/polyfill.rs +++ b/lib/api/src/utils/polyfill.rs @@ -373,7 +373,7 @@ pub fn wpreftype_to_type(ty: wasmparser::RefType) -> WasmResult { } else if ty.is_func_ref() { Ok(Type::FuncRef) } else { - Err(format!("Unsupported ref type: {:?}", ty)) + Err(format!("Unsupported ref type: {ty:?}")) } } diff --git a/lib/api/src/vm/impls.rs b/lib/api/src/vm/impls.rs index 29877545d1..ea80315092 100644 --- a/lib/api/src/vm/impls.rs +++ b/lib/api/src/vm/impls.rs @@ -55,6 +55,11 @@ impl VMExternRef { impl VMExceptionRef { /// Converts the `VMExternRef` into a `RawValue`. pub fn into_raw(self) -> RawValue { - todo!() + match self { + #[cfg(feature = "sys")] + Self::Sys(s) => s.into_raw(), + + _ => unimplemented!("VMExceptionRef::into_raw is only implemented for the sys backend"), + } } } diff --git a/lib/api/src/vm/mod.rs b/lib/api/src/vm/mod.rs index 01825f9ca5..131f848fbb 100644 --- a/lib/api/src/vm/mod.rs +++ b/lib/api/src/vm/mod.rs @@ -438,7 +438,6 @@ define_vm_like!(Trampoline); define_vm_like!(Function, Debug); define_vm_like!(Global, Debug); define_vm_like!(Tag, Debug); -define_vm_like!(Exception, Debug); define_vm_like!(Memory, Debug, @From); define_vm_like!(SharedMemory); define_vm_like!(Table, Debug); diff --git a/lib/api/tests/externals.rs b/lib/api/tests/externals.rs index 6a063f8d83..f59611a8c8 100644 --- a/lib/api/tests/externals.rs +++ b/lib/api/tests/externals.rs @@ -157,7 +157,7 @@ fn table_set() -> Result<(), String> { let v = v.unwrap(); let v = if let Value::ExternRef(Some(ext)) = v { - ext.downcast::(&mut store) + ext.downcast::(&store) } else { return Err("table.get does not match `ExternRef(Some(..))`!".into()); }; @@ -175,7 +175,7 @@ fn table_set() -> Result<(), String> { let v = v.unwrap(); let v = if let Value::ExternRef(Some(ext)) = v { - ext.downcast::(&mut store) + ext.downcast::(&store) } else { return Err("table.get does not match `ExternRef(Some(..))`!".into()); }; @@ -194,7 +194,7 @@ fn table_set() -> Result<(), String> { let v = v.unwrap(); let v = if let Value::ExternRef(Some(ext)) = v { - ext.downcast::(&mut store) + ext.downcast::(&store) } else { return Err("table.get does not match `ExternRef(Some(..))`!".into()); }; @@ -250,7 +250,7 @@ fn table_copy() -> Result<(), String> { fn memory_new() -> Result<(), String> { let mut store = Store::default(); let memory_type = MemoryType { - shared: if cfg!(feature = "wamr") { true } else { false }, + shared: cfg!(feature = "wamr"), minimum: Pages(0), maximum: Some(Pages(10)), }; diff --git a/lib/api/tests/jspi_async.rs b/lib/api/tests/jspi_async.rs new file mode 100644 index 0000000000..e4b1454240 --- /dev/null +++ b/lib/api/tests/jspi_async.rs @@ -0,0 +1,305 @@ +#![cfg(feature = "experimental-async")] + +use std::{cell::RefCell, sync::OnceLock}; + +use anyhow::Result; +use futures::future; +use wasmer::{ + AsyncFunctionEnvMut, Function, FunctionEnv, FunctionEnvMut, FunctionType, Instance, Module, + Store, StoreAsync, Type, TypedFunction, Value, imports, +}; +use wasmer_vm::TrapCode; + +#[derive(Default)] +struct DeltaState { + deltas: Vec, + index: usize, +} + +impl DeltaState { + fn next(&mut self) -> f64 { + let value = self.deltas.get(self.index).copied().unwrap_or(0.0); + self.index += 1; + value + } +} + +fn jspi_module() -> &'static [u8] { + static BYTES: OnceLock> = OnceLock::new(); + const JSPI_WAT: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../tests/examples/jspi.wat"); + BYTES.get_or_init(|| wat::parse_file(JSPI_WAT).expect("valid example module")) +} + +#[test] +fn async_state_updates_follow_jspi_example() -> Result<()> { + let wasm = jspi_module(); + let mut store = Store::default(); + let module = Module::new(&store, wasm)?; + + let init_state = Function::new_async( + &mut store, + FunctionType::new(vec![], vec![Type::F64]), + |_values| async move { + // Note: future::ready doesn't actually suspend. It's important + // to note that, while we're in an async import here, it's + // impossible to suspend during module instantiation, which is + // where this import is called. + // To see this in action, uncomment the following line: + // tokio::task::yield_now().await; + future::ready(()).await; + Ok(vec![Value::F64(1.0)]) + }, + ); + + let delta_env = FunctionEnv::new( + &mut store, + DeltaState { + deltas: vec![0.5, -1.0, 2.5], + index: 0, + }, + ); + let compute_delta = Function::new_with_env_async( + &mut store, + &delta_env, + FunctionType::new(vec![], vec![Type::F64]), + |env: AsyncFunctionEnvMut, _values| async move { + // Note: holding a lock across an await point prevents + // other coroutines from progressing, so it's a good + // idea to drop the lock before awaiting. + let delta = { + let mut env_write = env.write().await; + env_write.data_mut().next() + }; + // We can, however, actually suspend whenever + // `Function::call_async` is used to call WASM functions. + tokio::time::sleep(std::time::Duration::from_millis(10)).await; + Ok(vec![Value::F64(delta)]) + }, + ); + + let import_object = imports! { + "js" => { + "init_state" => init_state, + "compute_delta" => compute_delta, + } + }; + + let instance = Instance::new(&mut store, &module, &import_object)?; + let get_state = instance.exports.get_function("get_state")?; + let update_state = instance.exports.get_function("update_state")?; + + fn as_f64(values: &[Value]) -> f64 { + match &values[0] { + Value::F64(v) => *v, + other => panic!("expected f64 value, got {other:?}"), + } + } + + assert_eq!(as_f64(&get_state.call(&mut store, &[])?), 1.0); + + let step = |store: &StoreAsync, func: &wasmer::Function| -> Result { + let result = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(func.call_async(store, vec![]))?; + Ok(as_f64(&result)) + }; + + let store_async = store.into_async(); + + assert_eq!(step(&store_async, update_state)?, 1.5); + assert_eq!(step(&store_async, update_state)?, 0.5); + assert_eq!(step(&store_async, update_state)?, 3.0); + + Ok(()) +} + +#[test] +fn typed_async_host_and_calls_work() -> Result<()> { + let wasm = wat::parse_str( + r#" + (module + (import "host" "async_add" (func $async_add (param i32 i32) (result i32))) + (import "host" "async_double" (func $async_double (param i32) (result i32))) + (func (export "compute") (param i32) (result i32) + local.get 0 + i32.const 10 + call $async_add + local.get 0 + call $async_double + i32.add)) + "#, + )?; + + #[derive(Clone, Copy)] + struct AddBias { + bias: i32, + } + + let mut store = Store::default(); + let module = Module::new(&store, wasm)?; + + let add_env = FunctionEnv::new(&mut store, AddBias { bias: 5 }); + let async_add = Function::new_typed_with_env_async( + &mut store, + &add_env, + async move |env: AsyncFunctionEnvMut, a: i32, b: i32| { + let env_read = env.read().await; + let bias = env_read.data().bias; + tokio::task::yield_now().await; + a + b + bias + }, + ); + let async_double = Function::new_typed_async(&mut store, async move |value: i32| { + tokio::task::yield_now().await; + value * 2 + }); + + let import_object = imports! { + "host" => { + "async_add" => async_add, + "async_double" => async_double, + } + }; + + let instance = Instance::new(&mut store, &module, &import_object)?; + let compute: TypedFunction = + instance.exports.get_typed_function(&store, "compute")?; + + let store_async = store.into_async(); + + let result = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(compute.call_async(&store_async, 4))?; + assert_eq!(result, 27); + + Ok(()) +} + +#[test] +fn cannot_yield_when_not_in_async_context() -> Result<()> { + const WAT: &str = r#" + (module + (import "env" "yield_now" (func $yield_now)) + (func (export "yield_outside") + call $yield_now + ) + ) + "#; + let wasm = wat::parse_str(WAT).expect("valid WAT module"); + + let mut store = Store::default(); + let module = Module::new(&store, wasm)?; + + let yield_now = Function::new_async( + &mut store, + FunctionType::new(vec![], vec![]), + |_values| async move { + // Attempting to yield when not in an async context should trap. + tokio::task::yield_now().await; + Ok(vec![]) + }, + ); + + let import_object = imports! { + "env" => { + "yield_now" => yield_now, + } + }; + let instance = Instance::new(&mut store, &module, &import_object)?; + let yield_outside = instance.exports.get_function("yield_outside")?; + + let trap = yield_outside + .call(&mut store, &[]) + .expect_err("expected trap calling yield outside async context"); + + // TODO: wasm trace generation appears to be broken? + // assert!(!trap.trace().is_empty(), "should have a stack trace"); + let trap_code = trap.to_trap().expect("expected trap code"); + assert_eq!( + trap_code, + TrapCode::YieldOutsideAsyncContext, + "expected YieldOutsideAsyncContext trap code" + ); + + Ok(()) +} + +#[test] +fn nested_async_in_sync() -> Result<()> { + const WAT: &str = r#" + (module + (import "env" "sync" (func $sync (result i32))) + (import "env" "async" (func $async (result i32))) + (func (export "entry") (result i32) + call $sync + ) + (func (export "inner_async") (result i32) + call $async + ) + ) + "#; + let wasm = wat::parse_str(WAT).expect("valid WAT module"); + + let mut store = Store::default(); + let module = Module::new(&store, wasm)?; + + struct Env { + inner_async: RefCell>>, + } + let env = FunctionEnv::new( + &mut store, + Env { + inner_async: RefCell::new(None), + }, + ); + + let sync = Function::new_typed_with_env(&mut store, &env, |mut env: FunctionEnvMut| { + let (env, mut store) = env.data_and_store_mut(); + env.inner_async + .borrow() + .as_ref() + .expect("inner_async function to be set") + .call(&mut store) + .expect("inner async call to succeed") + }); + + let async_ = Function::new_typed_async(&mut store, async || { + tokio::task::yield_now().await; + 42 + }); + + let imports = imports! { + "env" => { + "sync" => sync, + "async" => async_, + } + }; + + let instance = Instance::new(&mut store, &module, &imports)?; + + let inner_async = instance + .exports + .get_typed_function::<(), i32>(&store, "inner_async") + .unwrap(); + env.as_mut(&mut store) + .inner_async + .borrow_mut() + .replace(inner_async); + + let entry = instance + .exports + .get_typed_function::<(), i32>(&store, "entry")?; + let result = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(entry.call_async(&store.into_async()))?; + + assert_eq!(result, 42); + + Ok(()) +} diff --git a/lib/api/tests/memory.rs b/lib/api/tests/memory.rs index c79b6eed8c..4119e75d3e 100644 --- a/lib/api/tests/memory.rs +++ b/lib/api/tests/memory.rs @@ -1,11 +1,8 @@ use std::sync::{ - atomic::{AtomicBool, Ordering}, Arc, + atomic::{AtomicBool, Ordering}, }; -use wasmer::{ - imports, Instance, Memory, MemoryAccessError, MemoryLocation, MemoryType, Module, Store, - WasmSlice, -}; +use wasmer::{Instance, Memory, MemoryLocation, MemoryType, Module, Store, imports}; #[test] #[cfg_attr(feature = "wamr", ignore = "wamr ignores import memories")] @@ -44,9 +41,11 @@ fn test_shared_memory_atomics_notify_send() { // Test basic notify. let mem2 = mem.clone(); - std::thread::spawn(move || loop { - if mem2.notify(MemoryLocation::new_32(10), 1).unwrap() > 0 { - break; + std::thread::spawn(move || { + loop { + if mem2.notify(MemoryLocation::new_32(10), 1).unwrap() > 0 { + break; + } } }); @@ -108,12 +107,12 @@ fn test_wasm_slice_issue_5444() { let _inst = Instance::new(&mut store, &module, &imports).unwrap(); let view = mem.view(&store); - let slice = WasmSlice::::new(&view, 1, 10).unwrap(); + let slice = wasmer::WasmSlice::::new(&view, 1, 10).unwrap(); let access = slice.access(); assert!(matches!( access.err(), - Some(MemoryAccessError::UnalignedPointerRead) + Some(wasmer::MemoryAccessError::UnalignedPointerRead) )) } diff --git a/lib/api/tests/module.rs b/lib/api/tests/module.rs index cdfdd7d75e..83296c136e 100644 --- a/lib/api/tests/module.rs +++ b/lib/api/tests/module.rs @@ -195,11 +195,11 @@ fn calling_host_functions_with_negative_values_works() -> Result<(), String> { "host" => { "host_func1" => Function::new_typed(&mut store, |p: u64| { println!("host_func1: Found number {p}"); - assert_eq!(p, u64::max_value()); + assert_eq!(p, u64::MAX); }), "host_func2" => Function::new_typed(&mut store, |p: u32| { println!("host_func2: Found number {p}"); - assert_eq!(p, u32::max_value()); + assert_eq!(p, u32::MAX); }), "host_func3" => Function::new_typed(&mut store, |p: i64| { println!("host_func3: Found number {p}"); @@ -215,7 +215,7 @@ fn calling_host_functions_with_negative_values_works() -> Result<(), String> { }), "host_func6" => Function::new_typed(&mut store, |p: u16| { println!("host_func6: Found number {p}"); - assert_eq!(p, u16::max_value()); + assert_eq!(p, u16::MAX); }), "host_func7" => Function::new_typed(&mut store, |p: i8| { println!("host_func7: Found number {p}"); @@ -223,7 +223,7 @@ fn calling_host_functions_with_negative_values_works() -> Result<(), String> { }), "host_func8" => Function::new_typed(&mut store, |p: u8| { println!("host_func8: Found number {p}"); - assert_eq!(p, u8::max_value()); + assert_eq!(p, u8::MAX); }), } }; diff --git a/lib/api/tests/reference_types.rs b/lib/api/tests/reference_types.rs index b014e6b2f4..3350873bfe 100644 --- a/lib/api/tests/reference_types.rs +++ b/lib/api/tests/reference_types.rs @@ -3,8 +3,8 @@ pub mod reference_types { use anyhow::Result; use macro_wasmer_universal_test::universal_test; - use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; + use std::sync::atomic::{AtomicBool, Ordering}; #[cfg(feature = "js")] use wasm_bindgen_test::*; use wasmer::*; diff --git a/lib/api/tests/simple_greenthread.rs b/lib/api/tests/simple_greenthread.rs new file mode 100644 index 0000000000..61f8e512be --- /dev/null +++ b/lib/api/tests/simple_greenthread.rs @@ -0,0 +1,275 @@ +#![cfg(feature = "experimental-async")] + +use std::collections::BTreeMap; +use std::sync::atomic::AtomicU32; +use std::sync::{Arc, RwLock}; + +use anyhow::Result; +use futures::task::LocalSpawnExt; +use futures::{FutureExt, channel::oneshot}; +use wasmer::{ + AsyncFunctionEnvMut, Function, FunctionEnv, FunctionEnvMut, FunctionType, Instance, Memory, + Module, RuntimeError, Store, Type, Value, imports, +}; + +struct GreenEnv { + logs: Vec, + memory: Option, + greenthreads: Arc>>, + current_greenthread_id: Arc>, + next_free_id: AtomicU32, + entrypoint: Option, + spawner: Option, +} + +// Required for carrying the spawner around. Safe because we don't do threads. +// It worked before with a thread-local! spawner, so this is equivalent. +// The thread-local version does not work with multiple tests +unsafe impl Send for GreenEnv {} +unsafe impl Sync for GreenEnv {} + +impl GreenEnv { + fn new() -> Self { + Self { + logs: Vec::new(), + memory: None, + greenthreads: Arc::new(RwLock::new(BTreeMap::new())), + current_greenthread_id: Arc::new(RwLock::new(0)), + next_free_id: AtomicU32::new(1), + entrypoint: None, + spawner: None, + } + } +} + +struct Greenthread { + entrypoint: Option, + resumer: Option>, +} + +impl Clone for Greenthread { + fn clone(&self) -> Self { + if self.resumer.is_some() { + panic!("Cannot clone a greenthread with a resumer"); + } + Self { + entrypoint: self.entrypoint, + resumer: None, + } + } +} + +async fn greenthread_new( + env: AsyncFunctionEnvMut, + entrypoint_data: u32, +) -> core::result::Result { + let async_store = env.as_store_async(); + let mut env_write = env.write().await; + let data = env_write.data_mut(); + let new_greenthread_id = data + .next_free_id + .fetch_add(1, std::sync::atomic::Ordering::SeqCst); + + let function = data.entrypoint.clone().expect("entrypoint set"); + let (sender, receiver) = oneshot::channel::<()>(); + + let new_greenthread = Greenthread { + entrypoint: Some(entrypoint_data), + resumer: Some(sender), + }; + + data.greenthreads + .write() + .unwrap() + .insert(new_greenthread_id, new_greenthread); + + let spawner = data.spawner.as_ref().expect("spawner set").clone(); + spawner + .spawn_local(async move { + receiver.await.unwrap(); + let resumer = function + .call_async(&async_store, vec![Value::I32(entrypoint_data as i32)]) + .await; + panic!("Greenthread function returned {:?}", resumer); + }) + .unwrap(); + + Ok(new_greenthread_id) +} + +async fn greenthread_switch(env: AsyncFunctionEnvMut, next_greenthread_id: u32) { + let (receiver, current_id_arc, current_greenthread_id) = { + let mut write_lock = env.write().await; + let data = write_lock.data_mut(); + + let current_greenthread_id = { + let mut current = data.current_greenthread_id.write().unwrap(); + let old = *current; + *current = next_greenthread_id; + old + }; + + if current_greenthread_id == next_greenthread_id { + panic!("Switching to self is not allowed"); + } + + let (sender, receiver) = oneshot::channel::<()>(); + + { + let mut greenthreads = data.greenthreads.write().unwrap(); + let this_one = greenthreads.get_mut(¤t_greenthread_id).unwrap(); + if this_one.resumer.is_some() { + panic!("Switching from a greenthread that is already switched out"); + } + this_one.resumer = Some(sender); + } + + { + let mut greenthreads = data.greenthreads.write().unwrap(); + let next_one = greenthreads.get_mut(&next_greenthread_id).unwrap(); + let Some(resumer) = next_one.resumer.take() else { + panic!("Switching to greenthread that has no resumer"); + }; + resumer.send(()).unwrap(); + } + let current_id_arc = data.current_greenthread_id.clone(); + + (receiver, current_id_arc, current_greenthread_id) + }; + + let _ = receiver.map(|_| ()).await; + + *current_id_arc.write().unwrap() = current_greenthread_id; +} + +fn run_greenthread_test(wat: &[u8]) -> Result> { + let mut store = Store::default(); + let module = Module::new(&store.engine(), wat)?; + + let env = FunctionEnv::new(&mut store, GreenEnv::new()); + + // log(ptr, len) + let log_fn = Function::new_with_env( + &mut store, + &env, + FunctionType::new(vec![Type::I32, Type::I32], vec![]), + |mut env: FunctionEnvMut, params: &[Value]| { + let ptr = params[0].unwrap_i32() as u32; + let len = params[1].unwrap_i32() as u32; + let (data, storemut) = env.data_and_store_mut(); + let memory = data.memory.as_ref().expect("memory set"); + let view = memory.view(&storemut); + let mut bytes = Vec::with_capacity(len as usize); + for i in ptr..ptr + len { + bytes.push(view.read_u8(i as u64).expect("in bounds")); + } + let s = String::from_utf8_lossy(&bytes).to_string(); + data.logs.push(s.trim_matches('\0').to_string()); + Ok(vec![]) + }, + ); + + let greenthread_new = Function::new_typed_with_env_async(&mut store, &env, greenthread_new); + + let greenthread_switch = + Function::new_typed_with_env_async(&mut store, &env, greenthread_switch); + + let import_object = imports! { + "test" => { + "log" => log_fn, + "greenthread_new" => greenthread_new, + "greenthread_switch" => greenthread_switch, + } + }; + + let instance = Instance::new(&mut store, &module, &import_object)?; + + let entrypoint = instance.exports.get_function("entrypoint")?.clone(); + env.as_mut(&mut store).entrypoint = Some(entrypoint); + + let memory = instance.exports.get_memory("memory")?.clone(); + env.as_mut(&mut store).memory = Some(memory); + + let main_fn = instance.exports.get_function("_main")?; + + let main_greenthread = Greenthread { + entrypoint: None, + resumer: None, + }; + + env.as_mut(&mut store) + .greenthreads + .write() + .unwrap() + .insert(0, main_greenthread); + + let mut localpool = futures::executor::LocalPool::new(); + let local_spawner = localpool.spawner(); + env.as_mut(&mut store).spawner = Some(local_spawner); + + let store_async = store.into_async(); + + localpool + .run_until(main_fn.call_async(&store_async, vec![])) + .unwrap(); + + // If there are no more clones of it, StoreAsync can also be + // turned back into a store. We need to drop the local pool + // first to drop the futures and their references to the store. + drop(localpool); + + let store = store_async.into_store().ok().unwrap(); + Ok(env.as_ref(&store).logs.clone()) +} + +#[cfg(not(target_arch = "wasm32"))] +#[test] +fn green_threads_switch_and_log_in_expected_order() -> Result<()> { + let logs = run_greenthread_test(include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../tests/examples/simple-greenthread.wat" + )))?; + + // Expected logs + let expected = [ + "[gr1] main -> test1", + "[gr2] test1 -> test2", + "[gr1] test1 <- test2", + "[gr2] test1 -> test2", + "[gr1] test1 <- test2", + "[main] main <- test1", + ]; + + assert_eq!(logs.len(), expected.len(),); + for (i, exp) in expected.iter().enumerate() { + assert_eq!(logs[i], *exp, "Log entry mismatch at index {i}: {:?}", logs); + } + + Ok(()) +} + +#[cfg(not(target_arch = "wasm32"))] +#[test] +fn green_threads_switch_main_crashed() -> Result<()> { + let logs = run_greenthread_test(include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../tests/examples/simple-greenthread2.wat" + )))?; + + // Expected logs + let expected = [ + "[main] switching to side", + "[side] switching to main", + "[main] switching to side", + "[side] switching to main", + "[main] returned", + ]; + + eprintln!("logs: {:?}", logs); + assert_eq!(logs.len(), expected.len()); + for (i, exp) in expected.iter().enumerate() { + assert_eq!(logs[i], *exp, "Log entry mismatch at index {i}: {:?}", logs); + } + + Ok(()) +} diff --git a/lib/api/tests/typed_functions.rs b/lib/api/tests/typed_functions.rs index 12e52d9b28..d746a1a95f 100644 --- a/lib/api/tests/typed_functions.rs +++ b/lib/api/tests/typed_functions.rs @@ -96,7 +96,7 @@ fn non_typed_functions_and_closures_with_no_env_work() -> anyhow::Result<()> { let instance = Instance::new(&mut store, &module, &import_object)?; let test: TypedFunction<(i32, i32, i32, i32, i32), i32> = - instance.exports.get_typed_function(&mut store, "test")?; + instance.exports.get_typed_function(&store, "test")?; let result = test.call(&mut store, 2, 3, 4, 5, 6)?; let manually_computed_result = 6 * (5 * (4 * (3 * 2 * 20) * 10 * 20)) * 10; @@ -165,7 +165,7 @@ fn holochain_typed_function() -> anyhow::Result<()> { // Execute the WASM function 'sum' let sum: TypedFunction<(i32, i32), i32> = - instance.exports.get_function("sum")?.typed(&mut store)?; + instance.exports.get_function("sum")?.typed(&store)?; let result = sum.call(&mut store, 1, 2)?; assert_eq!(result, 6); diff --git a/lib/backend-api/Cargo.toml b/lib/backend-api/Cargo.toml index 93fe18e216..e83f1999fe 100644 --- a/lib/backend-api/Cargo.toml +++ b/lib/backend-api/Cargo.toml @@ -25,27 +25,26 @@ reqwest = { workspace = true, default-features = false, features = ["json"] } anyhow.workspace = true serde.workspace = true serde_json.workspace = true -serde_path_to_error = "0.1.14" +serde_path_to_error.workspace = true time = { workspace = true, features = ["formatting", "parsing"] } tokio.workspace = true url = { workspace = true, features = ["serde"] } -futures = "0.3" -tracing.workspace = true -cynic = { version = "3.7.2", features = ["http-reqwest"] } -pin-project-lite = "0.2.10" -harsh = "0.2.2" -merge-streams = "0.1.2" - +futures.workspace = true +tracing = { workspace = true, default-features = true } +cynic = { workspace = true, features = ["http-reqwest"] } +pin-project-lite.workspace = true +harsh.workspace = true +merge-streams.workspace = true # Subscriptions. -graphql-ws-client = { version = "0.11.0", features = [ +graphql-ws-client = { workspace = true, features = [ "tungstenite", "client-cynic", ], optional = true } tokio-tungstenite = { workspace = true, features = [ "rustls-tls-native-roots", ], optional = true } -async-tungstenite = { version = "0.28.0", features = [ +async-tungstenite = { workspace = true, features = [ "tokio-runtime", "tokio-rustls-native-certs", ], optional = true } @@ -57,7 +56,7 @@ features = ["js"] [dev-dependencies] tokio = { workspace = true, features = ["macros", "rt"] } base64.workspace = true -uuid = { version = "1", features = ["v4"] } +uuid = { workspace = true, features = ["v4"] } [features] diff --git a/lib/backend-api/schema.graphql b/lib/backend-api/schema.graphql index 2fd6fbec6f..2fd388e697 100644 --- a/lib/backend-api/schema.graphql +++ b/lib/backend-api/schema.graphql @@ -46,6 +46,7 @@ type User implements Node & PackageOwner & Owner { globalName: String! globalId: ID! viewerCan(action: OwnerAction!): Boolean! + isPro: Boolean! avatar(size: Int = 80): String! limitState: LimitState! isViewer: Boolean! @@ -82,9 +83,10 @@ type User implements Node & PackageOwner & Owner { dashboardActivity(offset: Int, before: String, after: String, first: Int, last: Int): ActivityEventConnection! loginMethods: [LoginMethod!]! githubUser: SocialAuth - githubScopes: [String]! - githubRepositories: [GithubRepository]! - isPro: Boolean! + githubScopes: [String]! @deprecated(reason: "Please use github installations instead.") + githubRepositories: [GithubInstallationRepository]! @deprecated(reason: "Please use github installations instead.") + githubInstallationExists: Boolean! @deprecated(reason: "Please use github installations instead.") + githubInstallations: [GithubAppInstallation!] currentUsage( """List of app IDs. Usage gets filtered for the specific apps.""" appIds: [ID] @@ -92,7 +94,6 @@ type User implements Node & PackageOwner & Owner { """Optional time range filter.""" timeRange: TimeRangeInput ): OwnerUsageSummary - webhooks: [Webhook] } """Setup for backwards compatibility with existing frontends.""" @@ -107,11 +108,11 @@ enum OwnerAction { PUBLISH_PACKAGE } -"""An owner of a package.""" interface Owner { globalName: String! globalId: ID! viewerCan(action: OwnerAction!): Boolean! + isPro: Boolean! } """ @@ -244,6 +245,7 @@ type Namespace implements Node & PackageOwner & Owner { globalName: String! globalId: ID! viewerCan(action: OwnerAction!): Boolean! + isPro: Boolean! limitState: LimitState! avatar: String! packages(offset: Int, before: String, after: String, first: Int, last: Int): PackageConnection! @@ -272,7 +274,6 @@ type Namespace implements Node & PackageOwner & Owner { timeRange: TimeRangeInput ): [UsageMetric]! domains(offset: Int, before: String, after: String, first: Int, last: Int): DNSDomainConnection! - isPro: Boolean! billing: Billing currentUsage( """List of app IDs. Usage gets filtered for the specific apps.""" @@ -517,6 +518,7 @@ type PackageVersion implements Node & PackageReleaseInterface & PackageInstance javascriptlanguagebindingSet(offset: Int, before: String, after: String, first: Int, last: Int): PackageVersionNPMBindingConnection! pythonlanguagebindingSet(offset: Int, before: String, after: String, first: Int, last: Int): PackageVersionPythonBindingConnection! deployappversionSet(offset: Int, before: String, after: String, first: Int, last: Int): DeployAppVersionConnection! + packagerolloutSet(offset: Int, before: String, after: String, first: Int, last: Int): PackageRolloutConnection! piritaManifest: JSONString piritaOffsets: JSONString piritaVolumes: JSONString @@ -984,7 +986,8 @@ type DeployAppVersion implements Node { sourcePackage: Package! aggregateMetrics: AggregateMetrics! volumes: [AppVersionVolume] - gitSource: AutobuildRepository + gitSource: AutobuildRepository @deprecated(reason: "This field is deprecated and return null always.") + rolloutSource: Rollout favicon: URL screenshot(viewportSize: AppScreenshotViewportSize, appearance: AppScreenshotAppearance): URL isUploaded: Boolean! @@ -1004,6 +1007,7 @@ type DeployApp implements Node & Owner { globalName: String! globalId: ID! viewerCan(action: OwnerAction!): Boolean! + isPro: Boolean! url: String! adminUrl: String! permalink: String! @@ -1029,11 +1033,13 @@ type DeployApp implements Node & Owner { deleted: Boolean! favicon: URL screenshot(viewportSize: AppScreenshotViewportSize, appearance: AppScreenshotAppearance): URL - deployments(before: String, after: String, first: Int, last: Int): DeploymentConnection + deployments(before: String, after: String, first: Int, last: Int): DeploymentConnection @deprecated(reason: "Use rollouts instead") + rollouts(before: String, after: String, first: Int, last: Int): RolloutConnection buildConfiguration: BuildConfiguration sshServer: AppSshServer mails: [AppMail] kind: Kind + githubRepoConnection: GithubRepoConnection } """An enumeration.""" @@ -1351,7 +1357,7 @@ enum StatusEnum { SUCCESS WORKING RUNNING - FAILURE + FAILED QUEUED TIMEOUT INTERNAL_ERROR @@ -1360,31 +1366,108 @@ enum StatusEnum { type BuildConfiguration implements Node { setupDb: Boolean! - buildCmd: String! - installCmd: String! - canDeployWithoutRepo: Boolean! + startCmd: String + buildCmd: String + installCmd: String completionTimeInSeconds: Int! kind: BuildKind - repo: String! """The ID of the object""" id: ID! - name: String! - repoName: String! - repoNamespace: String! + name: String + repo: String @deprecated(reason: "This field is deprecated and return null always.") + repoName: String @deprecated(reason: "This field is deprecated and return null always.") + repoNamespace: String @deprecated(reason: "This field is deprecated and return null always.") } type BuildKind implements Node { setupDb: Boolean! - buildCmd: String! - installCmd: String! - canDeployWithoutRepo: Boolean! + startCmd: String + buildCmd: String + installCmd: String name: String! """The ID of the object""" id: ID! } +type RolloutConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [RolloutEdge]! +} + +"""A Relay edge containing a `Rollout` and its cursor.""" +type RolloutEdge { + """The item at the end of the edge""" + node: Rollout + + """A cursor for use in pagination""" + cursor: String! +} + +type Rollout implements Node { + """The ID of the object""" + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + deployappVersion: DeployAppVersion + buildCommand: String! + installCommand: String! + buildId: String + status: StatusEnum! + logUrl: String + buildConfiguration: BuildConfiguration + rolloutDetails: RolloutType +} + +union RolloutType = GitHubRollout | ZipRollout | PackageRollout + +type GitHubRollout implements Node { + """The ID of the object""" + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + deletedAt: DateTime + externalId: String + rollout: Rollout! + branch: String + commitHash: String + prevCommitHash: String + commitMessage: String + authorEmail: String + authorName: String + authorLogin: String + repoUrl: String! + commitUrl: String +} + +type ZipRollout implements Node { + """The ID of the object""" + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + deletedAt: DateTime + externalId: String + rollout: Rollout + zipFileUrl: String! + zipFileHash: String +} + +type PackageRollout implements Node { + """The ID of the object""" + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + deletedAt: DateTime + externalId: String + rollout: Rollout! + sourcePackageVersion: PackageVersion + sourcePackageRelease: PackageWebc +} + type AppSshServer implements Node { enabled: Boolean! users(offset: Int, before: String, after: String, first: Int, last: Int): SshUserConnection! @@ -1469,7 +1552,7 @@ type AppMail implements Node { id: ID! } -union Kind = WordpressAppKind +union Kind = WordpressAppKind | MCPServerAppKind type WordpressAppKind { adminUrl: String! @@ -1509,6 +1592,18 @@ type WordPressTheme { description: String } +type MCPServerAppKind { + url: String! + transport: MCPServerTransportEnum +} + +"""An enumeration.""" +enum MCPServerTransportEnum { + STDIO + STREAMABLE_HTTP + SSE +} + type LogConnection { """Pagination data for this connection.""" pageInfo: PageInfo! @@ -1548,6 +1643,26 @@ type AppVersionVolumeMountPath { subpath: String } +type PackageRolloutConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [PackageRolloutEdge]! + + """Total number of items in the connection.""" + totalCount: Int +} + +"""A Relay edge containing a `PackageRollout` and its cursor.""" +type PackageRolloutEdge { + """The item at the end of the edge""" + node: PackageRollout + + """A cursor for use in pagination""" + cursor: String! +} + type PackageDistribution { """ Download URL of the tar.gz file. @@ -1711,6 +1826,7 @@ type AppTemplate implements Node { description: String! demoUrl: String! repoUrl: String! + rootDir: String branch: String category: AppTemplateCategory! isPublic: Boolean! @@ -1724,6 +1840,7 @@ type AppTemplate implements Node { completionTimeInSeconds: Int! highlighted: Boolean! defaultImage: String + defaultRepositoryCloneName: String framework: String! templateFramework: TemplateFramework language: String! @@ -2506,20 +2623,6 @@ type SocialAuth implements Node { username: String! } -type GithubRepository { - url: String! - name: String! - namespace: String! -} - -type Webhook implements Node { - url: String! - active: Boolean! - - """The ID of the object""" - id: ID! -} - type Signature { id: ID! publicKey: PublicKey! @@ -2533,136 +2636,43 @@ type StripeCustomer { type Billing { stripeCustomer: StripeCustomer! - payments: [PaymentIntent]! + payments: [PaymentIntent]! @deprecated(reason: "Use `payment_connection` instead") subscriptions: [WasmerSubscription]! - paymentMethods: [PaymentMethod]! + paymentMethods: [PaymentMethod]! @deprecated(reason: "Use `payment_connection` instead") + paymentConnection(offset: Int, before: String, after: String, first: Int, last: Int): PaymentIntentConnection! + paymentMethodConnection(offset: Int, before: String, after: String, first: Int, last: Int): CardPaymentMethodConnection! } type PaymentIntent implements Node { """The datetime this object was created in stripe.""" created: DateTime - """Three-letter ISO currency code""" - currency: String! - - """ - Status of this PaymentIntent, one of requires_payment_method, requires_confirmation, requires_action, processing, requires_capture, canceled, or succeeded. You can read more about PaymentIntent statuses here. - """ - status: DjstripePaymentIntentStatusChoices! - """The ID of the object""" id: ID! amount: String! -} - -"""An enumeration.""" -enum DjstripePaymentIntentStatusChoices { - """ - Cancellation invalidates the intent for future confirmation and cannot be undone. - """ - CANCELED - - """Required actions have been handled.""" - PROCESSING - - """Payment Method require additional action, such as 3D secure.""" - REQUIRES_ACTION - - """Capture the funds on the cards which have been put on holds.""" - REQUIRES_CAPTURE - - """Intent is ready to be confirmed.""" - REQUIRES_CONFIRMATION - - """Intent created and requires a Payment Method to be attached.""" - REQUIRES_PAYMENT_METHOD - - """The funds are in your account.""" - SUCCEEDED + currency: String! + status: String! + invoicePdfUrl: String } type WasmerSubscription implements Node { """The datetime this object was created in stripe.""" created: DateTime - """A description of this object.""" - description: String - - """ - A date in the future at which the subscription will automatically get canceled. - """ + """The ID of the object""" + id: ID! cancelAt: DateTime - - """ - If the subscription has been canceled with the ``at_period_end`` flag set to true, ``cancel_at_period_end`` on the subscription will be true. You can use this attribute to determine whether a subscription that has a status of active is scheduled to be canceled at the end of the current period. - """ - cancelAtPeriodEnd: Boolean! - - """ - If the subscription has been canceled, the date of that cancellation. If the subscription was canceled with ``cancel_at_period_end``, canceled_at will still reflect the date of the initial cancellation request, not the end of the subscription period when the subscription is automatically moved to a canceled state. - """ canceledAt: DateTime - - """ - End of the current period for which the subscription has been invoiced. At the end of this period, a new invoice will be created. - """ - currentPeriodEnd: DateTime! - - """ - Start of the current period for which the subscription has been invoiced. - """ - currentPeriodStart: DateTime! - - """ - Number of days a customer has to pay invoices generated by this subscription. This value will be `null` for subscriptions where `billing=charge_automatically`. - """ + currentPeriodEnd: DateTime + currentPeriodStart: DateTime daysUntilDue: Int - - """ - If the subscription has ended (either because it was canceled or because the customer was switched to a subscription to a new plan), the date the subscription ended. - """ endedAt: DateTime - - """ - Date when the subscription was first created. The date might differ from the created date due to backdating. - """ startDate: DateTime - - """The status of this subscription.""" - status: DjstripeSubscriptionStatusChoices! - - """If the subscription has a trial, the end of that trial.""" + status: String trialEnd: DateTime - - """If the subscription has a trial, the beginning of that trial.""" trialStart: DateTime - - """The ID of the object""" - id: ID! -} - -"""An enumeration.""" -enum DjstripeSubscriptionStatusChoices { - """Active""" - ACTIVE - - """Canceled""" - CANCELED - - """Incomplete""" - INCOMPLETE - - """Incomplete Expired""" - INCOMPLETE_EXPIRED - - """Past due""" - PAST_DUE - - """Trialing""" - TRIALING - - """Unpaid""" - UNPAID + description: String + cancelAtPeriodEnd: Boolean } union PaymentMethod = CardPaymentMethod @@ -2707,6 +2717,46 @@ enum CardFunding { UNKNOWN } +type PaymentIntentConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [PaymentIntentEdge]! + + """Total number of items in the connection.""" + totalCount: Int +} + +"""A Relay edge containing a `PaymentIntent` and its cursor.""" +type PaymentIntentEdge { + """The item at the end of the edge""" + node: PaymentIntent + + """A cursor for use in pagination""" + cursor: String! +} + +type CardPaymentMethodConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [CardPaymentMethodEdge]! + + """Total number of items in the connection.""" + totalCount: Int +} + +"""A Relay edge containing a `CardPaymentMethod` and its cursor.""" +type CardPaymentMethodEdge { + """The item at the end of the edge""" + node: CardPaymentMethod + + """A cursor for use in pagination""" + cursor: String! +} + type Payment { id: ID amount: String @@ -2875,6 +2925,36 @@ input WorkloadRunnerWasmSourceV1 { webc: WebcSourceV1! } +type GithubAppInstallation implements Node { + """The ID of the object""" + id: ID! + slug: String! + githubConfigureUrl: String! + repositories(filterByName: String): [GithubInstallationRepository]! +} + +type GithubInstallationRepository implements Node { + """The ID of the object""" + id: ID! + repoUrl: String! + installation: GithubAppInstallation! + url: String! + name: String! + namespace: String! +} + +type GithubRepoConnection implements Node { + """The ID of the object""" + id: ID! + githubRepoInstallation: GithubInstallationRepository! + connectedBy: User! + deployBranch: String! + app: DeployApp! + pullRequestComments: Boolean! + connectedAt: DateTime! + deploymentStatusEvents: Boolean! +} + type Query { latestTOS: TermsOfService! getAppRegions(active: Boolean, supportsVolumes: Boolean, supportsDatabases: Boolean, offset: Int, before: String, after: String, first: Int, last: Int): AppRegionConnection! @@ -2889,6 +2969,7 @@ type Query { owner: String ): DeployApp getAppByGlobalAlias(alias: String!): DeployApp + autobuildDeploymentStatus(buildId: UUID!): AutobuildDeploymentStatus getDeployApps(sortBy: DeployAppsSortBy, updatedAfter: DateTime, offset: Int, before: String, after: String, first: Int, last: Int): DeployAppConnection! getAppVersions(sortBy: DeployAppVersionsSortBy, updatedAfter: DateTime, offset: Int, before: String, after: String, first: Int, last: Int): DeployAppVersionConnection! getTemplateFrameworks(offset: Int, before: String, after: String, first: Int, last: Int): TemplateFrameworkConnection @@ -2908,6 +2989,8 @@ type Query { name: String! ): Boolean! wordpressDeploymentDefaults: WordpressDeploymentDefaults! + rollout(id: ID!): Rollout + githubRollout(id: ID!): GitHubRollout viewer: User getUser(username: String!): User getPasswordResetToken(token: String!): GetPasswordResetToken @@ -3040,6 +3123,12 @@ enum DNSRecordsSortBy { OLDEST } +type AutobuildDeploymentStatus { + buildId: UUID! + status: StatusEnum! + appVersion: DeployAppVersion +} + type TemplateFrameworkConnection { """Pagination data for this connection.""" pageInfo: PageInfo! @@ -3683,6 +3772,7 @@ type Mutation { """Delete a database for an app.""" deleteAppDb(input: DeleteAppDBInput!): DeleteAppDBPayload + updateBuildConfig(input: UpdateBuildConfigInput!): UpdateBuildConfigPayload """Get the autobuild config for a given repo""" autobuildConfigForRepo(input: AutobuildConfigForRepoInput!): AutobuildConfigForRepoPayload @@ -3699,6 +3789,13 @@ type Mutation { """Update autobuild config for an app.""" updateAutobuildConfigForApp(input: UpdateAutobuildConfigForAppInput!): UpdateAutobuildConfigForAppPayload + """Connect a github repo to an app.""" + connectGithubRepoToApp(input: ConnectGithubRepoToAppInput!): ConnectGithubRepoToAppPayload + + """Disconnect a github repo from an app.""" + disconnectGithubRepoFromApp(input: DisconnectGithubRepoFromAppInput!): DisconnectGithubRepoFromAppPayload + updateGithubRepoConnection(input: UpdateGithubRepoAppConnectionInput!): UpdateGithubRepoAppConnectionPayload + """Deploy a wordpress site.""" deployWordpress(input: DeployWordpressInput!): DeployWordpressPayload @deprecated(reason: "Use `publishAppFromRepoAutobuild` subscription instead.") @@ -3765,12 +3862,9 @@ type Mutation { mfa2EmailAuth(input: MFAEmailAuthInput!): MFAAuthResponse mfa2EmailGetToken(input: MFAGenerateEmailOTPInput!): MFAEmailGenerationResponse generateCheckoutUrl(input: GenerateCheckoutUrlInput!): GenerateCheckoutUrlPayload - - """Add webhook to user""" - addWebhook(input: AddWebhookInput!): AddWebhookPayload - - """Add webhook to user""" - removeWebhook(input: RemoveWebhookInput!): RemoveWebhookPayload + createCheckoutSession(input: CreateCheckoutSessionInput!): CreateCheckoutSessionPayload + cancelSubscription(input: CancelSubscriptionInput!): CancelSubscriptionPayload + renewCanceledSubscription(input: RenewCanceledSubscriptionInput!): RenewCanceledSubscriptionPayload publishPublicKey(input: PublishPublicKeyInput!): PublishPublicKeyPayload publishPackage(input: PublishPackageInput!): PublishPackagePayload pushPackageRelease(input: PushPackageReleaseInput!): PushPackageReleasePayload @@ -4438,31 +4532,56 @@ input DeleteAppDBInput { clientMutationId: String } +type UpdateBuildConfigPayload { + buildConfig: BuildConfiguration! + success: Boolean! + clientMutationId: String +} + +input UpdateBuildConfigInput { + appId: ID! + presetName: String + startCmd: String + buildCmd: String + installCmd: String + clientMutationId: String +} + """Get the autobuild config for a given repo""" type AutobuildConfigForRepoPayload { """The build configuration""" buildConfig: BuildConfig """List of apps deployed with this repo.""" - deployedApps: [DeployApp] + deployedApps: [DeployApp] @deprecated(reason: "This field is not used anymore") clientMutationId: String } """The Build Configuration for a given repo""" type BuildConfig { - buildCmd: String! - installCmd: String! + startCmd: String + buildCmd: String + installCmd: String setupDb: Boolean! presetName: String! appName: String! - canDeployWithoutRepo: Boolean! completionTimeInSeconds: Int! branch: String + canDeployWithoutRepo: Boolean! @deprecated(reason: "This field is not used anymore") } input AutobuildConfigForRepoInput { """The repo URL""" repoUrl: String! + + """The path to build from""" + basePath: String @deprecated(reason: "Please use root_dir instead") + + """The root directory to build from""" + rootDir: String + + """The branch to use""" + branch: String clientMutationId: String } @@ -4472,7 +4591,7 @@ type AutobuildConfigForZipUploadPayload { buildConfig: BuildConfig """List of apps deployed with this repo.""" - deployedApps: [DeployApp] + deployedApps: [DeployApp] @deprecated(reason: "This field is not used anymore") clientMutationId: String } @@ -4486,12 +4605,19 @@ input AutobuildConfigForZipUploadInput { type InstallGithubAppPayload { success: Boolean! user: User! + installation: GithubAppInstallation clientMutationId: String } input InstallGithubAppInput { """Github app Installation ID""" installationId: ID! + + """Github App Account ID""" + githubAccountId: ID + + """Github App Account Login""" + githubAccountLogin: String clientMutationId: String } @@ -4525,6 +4651,53 @@ input UpdateAutobuildConfigForAppInput { clientMutationId: String } +"""Connect a github repo to an app.""" +type ConnectGithubRepoToAppPayload { + app: DeployApp! + githubRepoConnection: GithubRepoConnection! + success: Boolean! + clientMutationId: String +} + +input ConnectGithubRepoToAppInput { + """The ID of the App""" + appId: ID! + + """The ID of the Github app repository installation""" + installationRepoId: ID! + + """The branch to deploy from""" + deployBranch: String + clientMutationId: String +} + +"""Disconnect a github repo from an app.""" +type DisconnectGithubRepoFromAppPayload { + app: DeployApp! + success: Boolean! + clientMutationId: String +} + +input DisconnectGithubRepoFromAppInput { + """The ID of the App""" + appId: ID! + clientMutationId: String +} + +type UpdateGithubRepoAppConnectionPayload { + githubRepoConnection: GithubRepoConnection! + success: Boolean! + clientMutationId: String +} + +input UpdateGithubRepoAppConnectionInput { + """The ID of the GithubRepoConnection""" + connectionId: ID! + deploymentStatusEvents: Boolean + pullRequestComments: Boolean + clientMutationId: String +} + """Deploy a wordpress site.""" type DeployWordpressPayload { appVersion: DeployAppVersion! @@ -4644,6 +4817,7 @@ input DeployViaAutobuildInput { owner: String buildCmd: String installCmd: String + startCmd: String enableDatabase: Boolean secrets: [SecretInput] extraData: AutobuildDeploymentExtraData @@ -4659,6 +4833,12 @@ input DeployViaAutobuildInput { """Region to deploy the app""" region: String + """The path to build from (defaults to /)""" + basePath: String @deprecated(reason: "Please use root_dir instead") + + """The root directory to build from (defaults to /)""" + rootDir: String + """ Branch to deploy from. If no branch is specified, the default branch is used. """ @@ -4841,6 +5021,7 @@ input RegisterUserInput { acceptedTos: Boolean intent: String fingerprintVisitorId: String + enterProTrial: Boolean clientMutationId: String } @@ -4856,6 +5037,8 @@ input SocialAuthJWTInput { register: Boolean = false registerIntent: String fingerprintVisitorId: String + enterProTrial: Boolean + response: JSONString clientMutationId: String } @@ -5161,6 +5344,7 @@ type GenerateCheckoutUrlPayload { type StripeCheckout { url: String! expiresAt: DateTime! + clientSecret: String! } input GenerateCheckoutUrlInput { @@ -5181,25 +5365,54 @@ input GenerateCheckoutUrlInput { clientMutationId: String } -"""Add webhook to user""" -type AddWebhookPayload { - webhook: Webhook! +type CreateCheckoutSessionPayload { + clientSecret: String! clientMutationId: String } -input AddWebhookInput { - url: String! +input CreateCheckoutSessionInput { + """URL to redirect.""" + returnUrl: String! + + """ID of price (product) to charge the user.""" + priceId: ID! + + """Locale of the customer.""" + locale: String! + + """ID of owner to create subscription on. Defaults to current user.""" + forOwnerId: ID + + """Whether to apply a trial period if available.""" + isTrial: Boolean = false clientMutationId: String } -"""Add webhook to user""" -type RemoveWebhookPayload { - success: Boolean! +type CancelSubscriptionPayload { + ok: Boolean! clientMutationId: String } -input RemoveWebhookInput { - id: ID! +input CancelSubscriptionInput { + """ID of owner whose subscription to cancel.""" + forOwnerId: ID! + + """ID of the subscription to cancel""" + subscriptionId: ID! + clientMutationId: String +} + +type RenewCanceledSubscriptionPayload { + ok: Boolean! + clientMutationId: String +} + +input RenewCanceledSubscriptionInput { + """ID of owner whose subscription to renew.""" + forOwnerId: ID! + + """ID of the subscription to renew""" + subscriptionId: ID! clientMutationId: String } diff --git a/lib/backend-api/src/client.rs b/lib/backend-api/src/client.rs index f56e9553b8..8e28f7ef2d 100644 --- a/lib/backend-api/src/client.rs +++ b/lib/backend-api/src/client.rs @@ -2,8 +2,8 @@ use std::time::Duration; use crate::GraphQLApiFailure; -use anyhow::{bail, Context as _}; -use cynic::{http::CynicReqwestError, GraphQlResponse, Operation}; +use anyhow::{Context as _, bail}; +use cynic::{GraphQlResponse, Operation, http::CynicReqwestError}; #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] use reqwest::Proxy; use url::Url; @@ -13,7 +13,7 @@ pub struct Proxy; /// API client for the Wasmer API. /// -/// Use the queries in [`crate::queries`] to interact with the API. +/// Use the queries in [`crate::query`] to interact with the API. #[derive(Clone, Debug)] pub struct WasmerClient { auth_token: Option, @@ -63,9 +63,8 @@ impl WasmerClient { "" => false, other => { bail!( - "invalid value for {} - expected 0/false|1/true: '{}'", - Self::ENV_VAR_LOG_VARIABLES, - other + "invalid value for {} - expected 0/false|1/true: '{other}'", + Self::ENV_VAR_LOG_VARIABLES ); } } @@ -201,16 +200,16 @@ impl WasmerClient { } }; - if let Some(errors) = &res.errors { - if !errors.is_empty() { - tracing::warn!( - ?errors, - data=?res.data, - %query, - endpoint=%self.graphql_endpoint, - "GraphQL query succeeded, but returned errors", - ); - } + if let Some(errors) = &res.errors + && !errors.is_empty() + { + tracing::warn!( + ?errors, + data=?res.data, + %query, + endpoint=%self.graphql_endpoint, + "GraphQL query succeeded, but returned errors", + ); } Ok(res) @@ -248,11 +247,11 @@ impl WasmerClient { { let res = self.run_graphql_raw(operation).await?; - if let Some(errs) = res.errors { - if !errs.is_empty() { - let errs = GraphQLApiFailure { errors: errs }; - return Err(errs).context("GraphQL query failed"); - } + if let Some(errs) = res.errors + && !errs.is_empty() + { + let errs = GraphQLApiFailure { errors: errs }; + return Err(errs).context("GraphQL query failed"); } if let Some(data) = res.data { diff --git a/lib/backend-api/src/error.rs b/lib/backend-api/src/error.rs index 3b45e08c8c..97d3e53006 100644 --- a/lib/backend-api/src/error.rs +++ b/lib/backend-api/src/error.rs @@ -11,11 +11,11 @@ impl GraphQLApiFailure { errors: Option>, ) -> anyhow::Error { let msg = msg.into(); - if let Some(errs) = errors { - if !errs.is_empty() { - let err = GraphQLApiFailure { errors: errs }; - return anyhow::Error::new(err).context(msg); - } + if let Some(errs) = errors + && !errs.is_empty() + { + let err = GraphQLApiFailure { errors: errs }; + return anyhow::Error::new(err).context(msg); } anyhow::anyhow!("{msg} - query did not return any data") } diff --git a/lib/backend-api/src/global_id.rs b/lib/backend-api/src/global_id.rs index 0e4f3e82bf..e6aacba0b2 100644 --- a/lib/backend-api/src/global_id.rs +++ b/lib/backend-api/src/global_id.rs @@ -1,6 +1,6 @@ //! [`GlobalId`]s are used by the backend to identify a specific object. //! -//! This module provides a parser/encoder and related type defintions +//! This module provides a parser/encoder and related type definitions //! for global ids. use std::fmt::Display; diff --git a/lib/backend-api/src/query.rs b/lib/backend-api/src/query.rs index ba72361111..aed555a017 100644 --- a/lib/backend-api/src/query.rs +++ b/lib/backend-api/src/query.rs @@ -1,6 +1,6 @@ use std::{collections::HashSet, time::Duration}; -use anyhow::{bail, Context}; +use anyhow::{Context, bail}; use cynic::{MutationBuilder, QueryBuilder}; use futures::StreamExt; use merge_streams::MergeStreams; @@ -12,8 +12,8 @@ use wasmer_package::utils::from_bytes; use webc::Container; use crate::{ - types::{self, *}, GraphQLApiFailure, WasmerClient, + types::{self, *}, }; /// Rotate the s3 secrets tied to an app given its id. @@ -449,7 +449,7 @@ pub async fn fetch_webc_package( ))?, PackageIdent::Hash(h) => match get_package_release(client, &h.to_string()).await? { Some(webc) => Url::parse(&webc.webc_url)?, - None => anyhow::bail!("Could not find package with hash '{}'", h), + None => anyhow::bail!("Could not find package with hash '{h}'"), }, }; @@ -1841,7 +1841,7 @@ pub async fn generate_deploy_config_token_raw( .context("no token returned") } -/// Generate an SSH token for accesing Edge over SSH or SFTP. +/// Generate an SSH token for accessing Edge over SSH or SFTP. /// /// If an app id is provided, the token will be scoped to that app, /// and using the token will open an ssh context for that app. @@ -1960,7 +1960,7 @@ fn get_app_logs( /// Get pages of logs associated with an application that lie within the /// specified date range. /// -/// In contrast to [`get_app_logs`], this function collects the stream into a +/// In contrast to `get_app_logs`, this function collects the stream into a /// final vector. #[tracing::instrument(skip_all, level = "debug")] #[allow(clippy::let_with_type_underscore)] @@ -1997,7 +1997,7 @@ pub async fn get_app_logs_paginated( /// Get pages of logs associated with an application that lie within the /// specified date range with a specific instance identifier. /// -/// In contrast to [`get_app_logs`], this function collects the stream into a +/// In contrast to `get_app_logs`, this function collects the stream into a /// final vector. #[tracing::instrument(skip_all, level = "debug")] #[allow(clippy::let_with_type_underscore)] @@ -2044,7 +2044,7 @@ pub async fn get_app_logs_paginated_filter_instance( /// Get pages of logs associated with an specific request for application that lie within the /// specified date range. /// -/// In contrast to [`get_app_logs`], this function collects the stream into a +/// In contrast to `get_app_logs`, this function collects the stream into a /// final vector. #[tracing::instrument(skip_all, level = "debug")] #[allow(clippy::let_with_type_underscore)] @@ -2099,8 +2099,7 @@ pub async fn get_domain( let opt = client .run_graphql(types::GetDomain::build(vars)) - .await - .map_err(anyhow::Error::from)? + .await? .get_domain; Ok(opt) } @@ -2116,8 +2115,7 @@ pub async fn get_domain_zone_file( let opt = client .run_graphql(types::GetDomainWithZoneFile::build(vars)) - .await - .map_err(anyhow::Error::from)? + .await? .get_domain; Ok(opt) } @@ -2131,8 +2129,7 @@ pub async fn get_domain_with_records( let opt = client .run_graphql(types::GetDomainWithRecords::build(vars)) - .await - .map_err(anyhow::Error::from)? + .await? .get_domain; Ok(opt) } @@ -2151,8 +2148,7 @@ pub async fn register_domain( }; let opt = client .run_graphql_strict(types::RegisterDomain::build(vars)) - .await - .map_err(anyhow::Error::from)? + .await? .register_domain .context("Domain registration failed")? .domain @@ -2170,7 +2166,6 @@ pub async fn get_all_dns_records( client .run_graphql_strict(types::GetAllDnsRecords::build(vars)) .await - .map_err(anyhow::Error::from) .map(|x| x.get_all_dnsrecords) } @@ -2182,7 +2177,6 @@ pub async fn get_all_domains( let connection = client .run_graphql_strict(types::GetAllDomains::build(vars)) .await - .map_err(anyhow::Error::from) .map(|x| x.get_all_domains) .context("no domains returned")?; Ok(connection @@ -2235,7 +2229,6 @@ pub async fn purge_cache_for_app_version( client .run_graphql_strict(types::PurgeCacheForAppVersion::build(vars)) .await - .map_err(anyhow::Error::from) .map(|x| x.purge_cache_for_app_version) .context("backend did not return data")?; diff --git a/lib/backend-api/src/stream.rs b/lib/backend-api/src/stream.rs index c2a8f8eb1f..89a5d681e3 100644 --- a/lib/backend-api/src/stream.rs +++ b/lib/backend-api/src/stream.rs @@ -1,8 +1,8 @@ use std::{collections::VecDeque, task::Poll}; use futures::{ - future::{BoxFuture, OptionFuture}, Future, + future::{BoxFuture, OptionFuture}, }; use super::WasmerClient; @@ -106,10 +106,9 @@ impl futures::Stream for QueryStream { this.items.extend(items); this.fut.set(None.into()); - if let Some(item) = this.items.pop_front() { - Poll::Ready(Some(Ok(item))) - } else { - Poll::Ready(None) + match this.items.pop_front() { + Some(item) => Poll::Ready(Some(Ok(item))), + _ => Poll::Ready(None), } } Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err(err))), diff --git a/lib/backend-api/src/subscription.rs b/lib/backend-api/src/subscription.rs index 2935546e58..016ede5270 100644 --- a/lib/backend-api/src/subscription.rs +++ b/lib/backend-api/src/subscription.rs @@ -1,9 +1,9 @@ use crate::{ + WasmerClient, types::{ AutobuildDeploymentSubscription, AutobuildDeploymentSubscriptionVariables, PackageVersionReadySubscription, PackageVersionReadySubscriptionVariables, Uuid, }, - WasmerClient, }; use anyhow::Context; use async_tungstenite::tungstenite::client::IntoClientRequest; diff --git a/lib/backend-api/src/types.rs b/lib/backend-api/src/types.rs index e8741eb189..e84a715b87 100644 --- a/lib/backend-api/src/types.rs +++ b/lib/backend-api/src/types.rs @@ -303,7 +303,7 @@ mod queries { pub cursor: String, } - #[derive(serde::Serialize, cynic::QueryFragment, PartialEq, Eq, Debug)] + #[derive(serde::Serialize, cynic::QueryFragment, PartialEq, Eq, Debug, Clone)] pub struct AppTemplate { #[serde(rename = "demoUrl")] pub demo_url: String, @@ -326,6 +326,10 @@ mod queries { pub updated_at: DateTime, #[serde(rename = "useCases")] pub use_cases: Jsonstring, + #[serde(rename = "branch")] + pub branch: Option, + #[serde(rename = "rootDir")] + pub root_dir: Option, } #[derive(cynic::QueryVariables, Debug, Clone)] @@ -1324,7 +1328,7 @@ mod queries { pub enum StatusEnum { Success, Working, - Failure, + Failed, Queued, Timeout, InternalError, @@ -1337,7 +1341,7 @@ mod queries { match self { Self::Success => "success", Self::Working => "working", - Self::Failure => "failure", + Self::Failed => "failed", Self::Queued => "queued", Self::Timeout => "timeout", Self::InternalError => "internal_error", @@ -1365,17 +1369,16 @@ mod queries { #[derive(cynic::QueryFragment, Debug, Clone, Serialize)] pub struct AutobuildConfigForZipUploadPayload { pub build_config: Option, - pub deployed_apps: Option>>, } #[derive(cynic::QueryFragment, Debug, Clone, Serialize)] pub struct BuildConfig { - pub build_cmd: String, - pub install_cmd: String, + pub build_cmd: Option, + pub install_cmd: Option, + pub start_cmd: Option, pub setup_db: bool, pub preset_name: String, pub app_name: String, - pub can_deploy_without_repo: bool, pub completion_time_in_seconds: i32, pub branch: Option, } diff --git a/lib/c-api/Cargo.toml b/lib/c-api/Cargo.toml index c8628fdb76..86a5e22f40 100644 --- a/lib/c-api/Cargo.toml +++ b/lib/c-api/Cargo.toml @@ -44,8 +44,8 @@ enumset.workspace = true cfg-if.workspace = true libc.workspace = true thiserror.workspace = true -typetag = { version = "0.1", optional = true } -paste = "1.0" +typetag = { workspace = true, optional = true } +paste.workspace = true tokio = { workspace = true, features = [ "rt", "rt-multi-thread", @@ -57,13 +57,13 @@ tracing.workspace = true tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] } [dev-dependencies] -field-offset = "0.3.3" +field-offset.workspace = true [target.'cfg(target_os = "windows")'.dev-dependencies] -wasmer-inline-c = "0.1.1" +wasmer-inline-c.workspace = true [target.'cfg(not(target_os = "windows"))'.dev-dependencies] -inline-c = "0.1.7" +inline-c.workspace = true [features] default = ["wat", "sys-default", "cranelift", "compiler", "wasi", "middlewares"] @@ -146,4 +146,7 @@ webc_runner = ["virtual-fs", "webc"] jit = ["compiler"] [build-dependencies] -cbindgen = { version = "0.27", default-features = false } +cbindgen = { workspace = true, default-features = false } + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(coverage_nightly)'] } diff --git a/lib/c-api/build.rs b/lib/c-api/build.rs index ee0ca5b001..315a70cef2 100644 --- a/lib/c-api/build.rs +++ b/lib/c-api/build.rs @@ -53,7 +53,7 @@ const MIDDLEWARES_FEATURE_AS_C_DEFINE: &str = "WASMER_MIDDLEWARES_ENABLED"; const JSC_FEATURE_AS_C_DEFINE: &str = "WASMER_JSC_BACKEND"; macro_rules! map_feature_as_c_define { - ($feature:expr, $c_define:ident, $accumulator:ident) => { + ($feature:expr_2021, $c_define:ident, $accumulator:ident) => { #[cfg(feature = $feature)] { use std::fmt::Write; @@ -330,13 +330,15 @@ fn shared_object_dir() -> PathBuf { assert_eq!(shared_object_dir.file_name(), Some(OsStr::new("out"))); shared_object_dir.pop(); - assert!(shared_object_dir - .file_name() - .as_ref() - .unwrap() - .to_string_lossy() - .to_string() - .starts_with("wasmer-c-api")); + assert!( + shared_object_dir + .file_name() + .as_ref() + .unwrap() + .to_string_lossy() + .to_string() + .starts_with("wasmer-c-api") + ); shared_object_dir.pop(); assert_eq!(shared_object_dir.file_name(), Some(OsStr::new("build"))); diff --git a/lib/c-api/examples/wasmer-capi-examples-runner/Cargo.toml b/lib/c-api/examples/wasmer-capi-examples-runner/Cargo.toml index 48c7342727..36fae2abad 100644 --- a/lib/c-api/examples/wasmer-capi-examples-runner/Cargo.toml +++ b/lib/c-api/examples/wasmer-capi-examples-runner/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "wasmer-capi-examples-runner" -version = "6.1.0" -edition = "2021" -license = "MIT" description = "wasmer-capi-examples-runner" +version.workspace = true +edition.workspace = true +license.workspace = true [dependencies] -cc = "1.0" -target-lexicon = "0.11" -regex = "1.6" -walkdir = "2.3.2" \ No newline at end of file +cc.workspace = true +target-lexicon.workspace = true +regex.workspace = true +walkdir.workspace = true diff --git a/lib/c-api/src/error.rs b/lib/c-api/src/error.rs index 5925f78f53..769b670176 100644 --- a/lib/c-api/src/error.rs +++ b/lib/c-api/src/error.rs @@ -87,7 +87,7 @@ pub(crate) fn take_last_error() -> Option { /// /// See this module's documentation to get a complete example. // TODO(Amanieu): This should use size_t -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_last_error_length() -> c_int { LAST_ERROR.with(|prev| match *prev.borrow() { Some(ref err) => err.len() as c_int + 1, @@ -118,7 +118,7 @@ pub extern "C" fn wasmer_last_error_length() -> c_int { /// /// See this module's documentation to get a complete example. // TODO(Amanieu): This should use size_t -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_last_error_message( buffer: Option>, length: c_int, @@ -142,13 +142,15 @@ pub unsafe extern "C" fn wasmer_last_error_message( return -1; } - let buffer = slice::from_raw_parts_mut(buffer.cast::().as_ptr(), length); + let buffer = unsafe { slice::from_raw_parts_mut(buffer.cast::().as_ptr(), length) }; - ptr::copy_nonoverlapping( - error_message.as_ptr(), - buffer.as_mut_ptr(), - error_message.len(), - ); + unsafe { + ptr::copy_nonoverlapping( + error_message.as_ptr(), + buffer.as_mut_ptr(), + error_message.len(), + ); + } // Add a trailing null so people using the string as a `char *` don't // accidentally read into garbage. diff --git a/lib/c-api/src/lib.rs b/lib/c-api/src/lib.rs index 1b11792368..9beeebaa43 100644 --- a/lib/c-api/src/lib.rs +++ b/lib/c-api/src/lib.rs @@ -29,7 +29,7 @@ // For the same reason, we also turn off the warning for camel_case types. #![allow(clippy::missing_safety_doc)] #![allow(non_camel_case_types)] -#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] pub mod error; pub mod tracing; diff --git a/lib/c-api/src/tracing.rs b/lib/c-api/src/tracing.rs index e63e356835..9a8406a0ff 100644 --- a/lib/c-api/src/tracing.rs +++ b/lib/c-api/src/tracing.rs @@ -31,11 +31,11 @@ use std::ffi::c_int; use tracing::level_filters::LevelFilter; -use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; +use tracing_subscriber::{EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt}; const WHITELISTED_LOG_TARGETS: &[&str] = &["wasmer", "wasmer_wasix", "virtual_fs"]; -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_setup_tracing(verbosity_level: c_int, use_color: c_int) { let fmt_layer = fmt::layer() .with_target(true) diff --git a/lib/c-api/src/wasm_c_api/engine/config/mod.rs b/lib/c-api/src/wasm_c_api/engine/config/mod.rs index 33fc3dc49d..765b69a6c6 100644 --- a/lib/c-api/src/wasm_c_api/engine/config/mod.rs +++ b/lib/c-api/src/wasm_c_api/engine/config/mod.rs @@ -56,7 +56,7 @@ impl Default for wasmer_backend_config_kind_t { Self::Sys(sys::wasmer_sys_engine_config_t::default()) } #[cfg(feature = "v8")] - super::wasmer_backend_t::V8 => Self::V8(v8::wasmer_v8_engine_config_t::default()), + super::wasmer_backend_t::V8 => Self::V8(v8::wasmer_v8_engine_config_t), #[cfg(feature = "wasmi")] super::wasmer_backend_t::WASMI => { Self::Wasmi(wasmi::wasmer_wasmi_engine_config_t::default()) @@ -121,7 +121,7 @@ pub(crate) struct wasmer_backend_config_t { /// # .success(); /// # } /// ``` -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_config_set_target(config: &mut wasm_config_t, target: Box) { config.backend_config.target = Some(target); } @@ -134,8 +134,8 @@ pub extern "C" fn wasm_config_set_target(config: &mut wasm_config_t, target: Box /// /// # Example /// -/// See the documentation of the [`metering`] module. -#[no_mangle] +/// See the documentation of the [`wasmer_middlewares::metering`] module. +#[unsafe(no_mangle)] #[cfg(feature = "middlewares")] pub extern "C" fn wasm_config_push_middleware( config: &mut wasm_config_t, diff --git a/lib/c-api/src/wasm_c_api/engine/config/sys.rs b/lib/c-api/src/wasm_c_api/engine/config/sys.rs index 9faa61717f..29079eef0d 100644 --- a/lib/c-api/src/wasm_c_api/engine/config/sys.rs +++ b/lib/c-api/src/wasm_c_api/engine/config/sys.rs @@ -65,7 +65,7 @@ pub(crate) struct wasmer_sys_engine_config_t { /// # .success(); /// # } /// ``` -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_config_sys_canonicalize_nans(config: &mut wasm_config_t, enable: bool) { if let wasmer_backend_config_kind_t::Sys(ref mut c) = config.backend_config.inner { c.nan_canonicalization = enable; diff --git a/lib/c-api/src/wasm_c_api/engine/mod.rs b/lib/c-api/src/wasm_c_api/engine/mod.rs index d616381002..ed9c0eaf92 100644 --- a/lib/c-api/src/wasm_c_api/engine/mod.rs +++ b/lib/c-api/src/wasm_c_api/engine/mod.rs @@ -86,7 +86,7 @@ pub struct wasm_engine_t { pub(crate) inner: Engine, } -#[no_mangle] +#[unsafe(no_mangle)] #[allow(unreachable_code)] pub extern "C" fn wasm_engine_new() -> Box { Box::new(wasm_engine_t::default()) @@ -128,7 +128,7 @@ pub extern "C" fn wasm_engine_new() -> Box { /// ``` /// /// cbindgen:ignore -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_engine_delete(_engine: Option>) {} /// Creates an engine with a particular configuration. @@ -138,7 +138,7 @@ pub unsafe extern "C" fn wasm_engine_delete(_engine: Option>) /// See [`wasm_config_new`]. /// /// cbindgen:ignore -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_engine_new_with_config( config: Option>, ) -> Option> { @@ -208,7 +208,7 @@ pub struct wasm_config_t { /// ``` /// /// cbindgen:ignore -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_config_new() -> Box { Box::::default() } @@ -240,7 +240,7 @@ pub extern "C" fn wasm_config_new() -> Box { /// # } /// ``` /// cbindgen:ignore -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_config_delete(_config: Option>) {} /// Updates the configuration to specify a particular engine to use. @@ -274,7 +274,7 @@ pub extern "C" fn wasm_config_delete(_config: Option>) {} /// # .success(); /// # } /// ``` -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_config_set_backend(config: &mut wasm_config_t, engine: wasmer_backend_t) { config.backend = engine; } @@ -286,7 +286,11 @@ mod tests { #[cfg(target_os = "windows")] use wasmer_inline_c::assert_c; - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_engine_new() { (assert_c! { diff --git a/lib/c-api/src/wasm_c_api/externals/function.rs b/lib/c-api/src/wasm_c_api/externals/function.rs index e72c277edd..ed6c55d483 100644 --- a/lib/c-api/src/wasm_c_api/externals/function.rs +++ b/lib/c-api/src/wasm_c_api/externals/function.rs @@ -42,7 +42,7 @@ pub type wasm_func_callback_with_env_t = unsafe extern "C" fn( #[allow(non_camel_case_types)] pub type wasm_env_finalizer_t = unsafe extern "C" fn(*mut c_void); -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_func_new( store: Option<&mut wasm_store_t>, function_type: Option<&wasm_functype_t>, @@ -51,7 +51,7 @@ pub unsafe extern "C" fn wasm_func_new( let function_type = function_type?; let callback = callback?; let store = store?; - let mut store_mut = store.inner.store_mut(); + let mut store_mut = unsafe { store.inner.store_mut() }; let func_sig = &function_type.inner().function_type; let num_rets = func_sig.results().len(); @@ -74,7 +74,7 @@ pub unsafe extern "C" fn wasm_func_new( ] .into(); - let trap = callback(&processed_args, &mut results); + let trap = unsafe { callback(&processed_args, &mut results) }; if let Some(trap) = trap { return Err(trap.inner); @@ -96,7 +96,7 @@ pub unsafe extern "C" fn wasm_func_new( })) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_func_new_with_env( store: Option<&mut wasm_store_t>, function_type: Option<&wasm_functype_t>, @@ -107,7 +107,7 @@ pub unsafe extern "C" fn wasm_func_new_with_env( let function_type = function_type?; let callback = callback?; let store = store?; - let mut store_mut = store.inner.store_mut(); + let mut store_mut = unsafe { store.inner.store_mut() }; let func_sig = &function_type.inner().function_type; let num_rets = func_sig.results().len(); @@ -126,12 +126,11 @@ pub unsafe extern "C" fn wasm_func_new_with_env( impl Drop for WrapperEnv { fn drop(&mut self) { - if let Ok(mut guard) = self.env_finalizer.lock() { - if Arc::strong_count(&self.env_finalizer) == 1 { - if let Some(env_finalizer) = guard.take() { - unsafe { (env_finalizer)(self.env.as_ptr()) }; - } - } + if let Ok(mut guard) = self.env_finalizer.lock() + && Arc::strong_count(&self.env_finalizer) == 1 + && let Some(env_finalizer) = guard.take() + { + unsafe { (env_finalizer)(self.env.as_ptr()) }; } } } @@ -154,7 +153,7 @@ pub unsafe extern "C" fn wasm_func_new_with_env( ] .into(); - let trap = callback(env.data().env.as_ptr(), &processed_args, &mut results); + let trap = unsafe { callback(env.data().env.as_ptr(), &processed_args, &mut results) }; if let Some(trap) = trap { return Err(trap.inner); @@ -185,15 +184,15 @@ pub unsafe extern "C" fn wasm_func_new_with_env( })) } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_func_copy(func: &wasm_func_t) -> Box { Box::new(func.clone()) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_func_delete(_func: Option>) {} -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_func_call( func: Option<&mut wasm_func_t>, args: Option<&wasm_val_vec_t>, @@ -202,7 +201,7 @@ pub unsafe extern "C" fn wasm_func_call( let func = func?; let args = args?; let mut store = func.extern_.store.clone(); - let mut store_mut = store.store_mut(); + let mut store_mut = unsafe { store.store_mut() }; let params = args .as_slice() .iter() @@ -227,30 +226,25 @@ pub unsafe extern "C" fn wasm_func_call( } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_func_param_arity(func: &wasm_func_t) -> usize { - func.extern_ - .function() - .ty(&func.extern_.store.store()) - .params() - .len() + let store_ref = unsafe { func.extern_.store.store() }; + func.extern_.function().ty(&store_ref).params().len() } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_func_result_arity(func: &wasm_func_t) -> usize { - func.extern_ - .function() - .ty(&func.extern_.store.store()) - .results() - .len() + let store_ref = unsafe { func.extern_.store.store() }; + func.extern_.function().ty(&store_ref).results().len() } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_func_type( func: Option<&wasm_func_t>, ) -> Option> { let func = func?; + let store_ref = unsafe { func.extern_.store.store() }; Some(Box::new(wasm_functype_t::new( - func.extern_.function().ty(&func.extern_.store.store()), + func.extern_.function().ty(&store_ref), ))) } diff --git a/lib/c-api/src/wasm_c_api/externals/global.rs b/lib/c-api/src/wasm_c_api/externals/global.rs index 1c1519dcd6..6c4080258d 100644 --- a/lib/c-api/src/wasm_c_api/externals/global.rs +++ b/lib/c-api/src/wasm_c_api/externals/global.rs @@ -21,7 +21,7 @@ impl wasm_global_t { } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_global_new( store: Option<&mut wasm_store_t>, global_type: Option<&wasm_globaltype_t>, @@ -29,7 +29,7 @@ pub unsafe extern "C" fn wasm_global_new( ) -> Option> { let global_type = global_type?; let store = store?; - let mut store_mut = store.inner.store_mut(); + let mut store_mut = unsafe { store.inner.store_mut() }; let val = val?; let global_type = &global_type.inner().global_type; @@ -44,40 +44,38 @@ pub unsafe extern "C" fn wasm_global_new( })) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_global_delete(_global: Option>) {} -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_global_copy(global: &wasm_global_t) -> Box { // do shallow copy Box::new(global.clone()) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_global_get( global: &mut wasm_global_t, // own out: &mut wasm_val_t, ) { - let value = global - .extern_ - .global() - .get(&mut global.extern_.store.store_mut()); + let wasm_global = global.extern_.global(); + let mut store_mut = unsafe { global.extern_.store.store_mut() }; + let value = wasm_global.get(&mut store_mut); *out = value.try_into().unwrap(); } /// Note: This function returns nothing by design but it can raise an /// error if setting a new value fails. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_global_set(global: &mut wasm_global_t, val: &wasm_val_t) { let value: Value = val.try_into().unwrap(); - c_try!(global - .extern_ - .global() - .set(&mut global.extern_.store.store_mut(), value); otherwise ()); + let wasm_global = global.extern_.global(); + let mut store_mut = unsafe { global.extern_.store.store_mut() }; + c_try!(wasm_global.set(&mut store_mut, value); otherwise ()); } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_global_same( wasm_global1: &wasm_global_t, wasm_global2: &wasm_global_t, @@ -85,13 +83,14 @@ pub unsafe extern "C" fn wasm_global_same( wasm_global1.extern_.global() == wasm_global2.extern_.global() } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_global_type( global: Option<&wasm_global_t>, ) -> Option> { let global = global?; + let store_ref = unsafe { global.extern_.store.store() }; Some(Box::new(wasm_globaltype_t::new( - global.extern_.global().ty(&global.extern_.store.store()), + global.extern_.global().ty(&store_ref), ))) } @@ -102,7 +101,11 @@ mod tests { #[cfg(target_os = "windows")] use wasmer_inline_c::assert_c; - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_set_host_global_immutable() { (assert_c! { @@ -135,7 +138,11 @@ mod tests { .success(); } - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_set_guest_global_immutable() { (assert_c! { diff --git a/lib/c-api/src/wasm_c_api/externals/memory.rs b/lib/c-api/src/wasm_c_api/externals/memory.rs index a919ec98cb..d2e7d1a7a1 100644 --- a/lib/c-api/src/wasm_c_api/externals/memory.rs +++ b/lib/c-api/src/wasm_c_api/externals/memory.rs @@ -18,14 +18,14 @@ impl wasm_memory_t { } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_memory_new( store: Option<&mut wasm_store_t>, memory_type: Option<&wasm_memorytype_t>, ) -> Option> { let memory_type = memory_type?; let store = store?; - let mut store_mut = store.inner.store_mut(); + let mut store_mut = unsafe { store.inner.store_mut() }; let memory_type = memory_type.inner().memory_type; let memory = c_try!(Memory::new(&mut store_mut, memory_type)); Some(Box::new(wasm_memory_t { @@ -33,16 +33,16 @@ pub unsafe extern "C" fn wasm_memory_new( })) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_memory_delete(_memory: Option>) {} -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_memory_copy(memory: &wasm_memory_t) -> Box { // do shallow copy Box::new(memory.clone()) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_memory_same( wasm_memory1: &wasm_memory_t, wasm_memory2: &wasm_memory_t, @@ -50,55 +50,42 @@ pub unsafe extern "C" fn wasm_memory_same( wasm_memory1.extern_.memory() == wasm_memory2.extern_.memory() } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_memory_type( memory: Option<&wasm_memory_t>, ) -> Option> { let memory = memory?; + let store_ref = unsafe { memory.extern_.store.store() }; Some(Box::new(wasm_memorytype_t::new( - memory.extern_.memory().ty(&memory.extern_.store.store()), + memory.extern_.memory().ty(&store_ref), ))) } // get a raw pointer into bytes -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_memory_data(memory: &mut wasm_memory_t) -> *mut u8 { - memory - .extern_ - .memory() - .view(&memory.extern_.store.store()) - .data_ptr() + let store_ref = unsafe { memory.extern_.store.store() }; + memory.extern_.memory().view(&store_ref).data_ptr() } // size in bytes -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_memory_data_size(memory: &wasm_memory_t) -> usize { - memory - .extern_ - .memory() - .view(&memory.extern_.store.store()) - .size() - .bytes() - .0 + let store_ref = unsafe { memory.extern_.store.store() }; + memory.extern_.memory().view(&store_ref).size().bytes().0 } // size in pages -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_memory_size(memory: &wasm_memory_t) -> u32 { - memory - .extern_ - .memory() - .view(&memory.extern_.store.store()) - .size() - .0 as _ + let store_ref = unsafe { memory.extern_.store.store() }; + memory.extern_.memory().view(&store_ref).size().0 as _ } // delta is in pages -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_memory_grow(memory: &mut wasm_memory_t, delta: u32) -> bool { - memory - .extern_ - .memory() - .grow(&mut memory.extern_.store.store_mut(), Pages(delta)) - .is_ok() + let wasm_memory = memory.extern_.memory(); + let mut store_mut = unsafe { memory.extern_.store.store_mut() }; + wasm_memory.grow(&mut store_mut, Pages(delta)).is_ok() } diff --git a/lib/c-api/src/wasm_c_api/externals/mod.rs b/lib/c-api/src/wasm_c_api/externals/mod.rs index a6a2e4e851..b5c893a1b5 100644 --- a/lib/c-api/src/wasm_c_api/externals/mod.rs +++ b/lib/c-api/src/wasm_c_api/externals/mod.rs @@ -52,7 +52,7 @@ impl wasm_extern_t { } } -// #[no_mangle] +// #[unsafe(no_mangle)] // pub extern "C" fn wasm_extern_kind(e: &wasm_extern_t) -> wasm_externkind_t { // (match e.inner { // Extern::Function(_) => wasm_externkind_enum::WASM_EXTERN_FUNC, @@ -64,7 +64,8 @@ impl wasm_extern_t { impl wasm_extern_t { pub(crate) unsafe fn ty(&self) -> ExternType { - self.inner.ty(&self.store.store()) + let store_ref = unsafe { self.store.store() }; + self.inner.ty(&store_ref) } } @@ -77,55 +78,55 @@ impl From for Extern { wasm_declare_boxed_vec!(extern); /// Copy a `wasm_extern_t`. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_extern_copy(r#extern: &wasm_extern_t) -> Box { Box::new(r#extern.clone()) } /// Delete an extern. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_extern_delete(_extern: Option>) {} -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_func_as_extern(func: Option<&wasm_func_t>) -> Option<&wasm_extern_t> { Some(&func?.extern_) } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_global_as_extern(global: Option<&wasm_global_t>) -> Option<&wasm_extern_t> { Some(&global?.extern_) } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_memory_as_extern(memory: Option<&wasm_memory_t>) -> Option<&wasm_extern_t> { Some(&memory?.extern_) } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_table_as_extern(table: Option<&wasm_table_t>) -> Option<&wasm_extern_t> { Some(&table?.extern_) } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_extern_as_func(r#extern: Option<&wasm_extern_t>) -> Option<&wasm_func_t> { wasm_func_t::try_from(r#extern?) } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_extern_as_global( r#extern: Option<&wasm_extern_t>, ) -> Option<&wasm_global_t> { wasm_global_t::try_from(r#extern?) } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_extern_as_memory( r#extern: Option<&wasm_extern_t>, ) -> Option<&wasm_memory_t> { wasm_memory_t::try_from(r#extern?) } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_extern_as_table(r#extern: Option<&wasm_extern_t>) -> Option<&wasm_table_t> { wasm_table_t::try_from(r#extern?) } @@ -137,7 +138,11 @@ mod tests { #[cfg(target_os = "windows")] use wasmer_inline_c::assert_c; - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_extern_copy() { (assert_c! { diff --git a/lib/c-api/src/wasm_c_api/externals/table.rs b/lib/c-api/src/wasm_c_api/externals/table.rs index 839cb447f1..b0ecfeac8d 100644 --- a/lib/c-api/src/wasm_c_api/externals/table.rs +++ b/lib/c-api/src/wasm_c_api/externals/table.rs @@ -19,7 +19,7 @@ impl wasm_table_t { } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_table_new( _store: Option<&wasm_store_t>, _table_type: Option<&wasm_tabletype_t>, @@ -28,21 +28,22 @@ pub unsafe extern "C" fn wasm_table_new( todo!("get val from init somehow"); } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_table_delete(_table: Option>) {} -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_table_copy(table: &wasm_table_t) -> Box { // do shallow copy Box::new(table.clone()) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_table_size(table: &wasm_table_t) -> usize { - table.extern_.table().size(&table.extern_.store.store()) as _ + let store_ref = unsafe { table.extern_.store.store() }; + table.extern_.table().size(&store_ref) as _ } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_table_same( wasm_table1: &wasm_table_t, wasm_table2: &wasm_table_t, @@ -50,7 +51,7 @@ pub unsafe extern "C" fn wasm_table_same( wasm_table1.extern_.table() == wasm_table2.extern_.table() } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_table_grow( _table: &mut wasm_table_t, _delta: wasm_table_size_t, diff --git a/lib/c-api/src/wasm_c_api/function_env.rs b/lib/c-api/src/wasm_c_api/function_env.rs index a9e3910ab0..f3a1f82778 100644 --- a/lib/c-api/src/wasm_c_api/function_env.rs +++ b/lib/c-api/src/wasm_c_api/function_env.rs @@ -45,7 +45,7 @@ pub struct wasmer_funcenv_t { inner: FunctionCEnv, } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_funcenv_new( store: Option<&mut wasm_store_t>, mut data: *mut c_void, @@ -54,10 +54,11 @@ pub unsafe extern "C" fn wasmer_funcenv_new( if data.is_null() { data = &NULL_ENV_PLACEHOLDER as *const u32 as *mut u32 as *mut c_void; } - let inner = FunctionCEnv::new(std::ptr::NonNull::new_unchecked(data)); - let _ = FunctionEnv::new(&mut store.inner.store_mut(), inner); + let inner = FunctionCEnv::new(unsafe { std::ptr::NonNull::new_unchecked(data) }); + let mut store_mut = unsafe { store.inner.store_mut() }; + let _ = FunctionEnv::new(&mut store_mut, inner); Some(Box::new(wasmer_funcenv_t { inner })) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_funcenv_delete(_funcenv: Option>) {} diff --git a/lib/c-api/src/wasm_c_api/instance.rs b/lib/c-api/src/wasm_c_api/instance.rs index ab07dff657..0268a3d1a8 100644 --- a/lib/c-api/src/wasm_c_api/instance.rs +++ b/lib/c-api/src/wasm_c_api/instance.rs @@ -1,6 +1,6 @@ use super::externals::{wasm_extern_t, wasm_extern_vec_t}; use super::module::wasm_module_t; -use super::store::{wasm_store_t, StoreRef}; +use super::store::{StoreRef, wasm_store_t}; use super::trap::wasm_trap_t; use wasmer_api::{Extern, Instance, InstantiationError}; @@ -34,7 +34,7 @@ pub struct wasm_instance_t { /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_instance_new( store: Option<&mut wasm_store_t>, module: Option<&wasm_module_t>, @@ -42,7 +42,7 @@ pub unsafe extern "C" fn wasm_instance_new( trap: Option<&mut *mut wasm_trap_t>, ) -> Option> { let store = store?; - let mut store_mut = store.inner.store_mut(); + let mut store_mut = unsafe { store.inner.store_mut() }; let module = module?; let imports = imports?; @@ -104,7 +104,7 @@ pub unsafe extern "C" fn wasm_instance_new( /// # Example /// /// See [`wasm_instance_new`]. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_instance_delete(_instance: Option>) {} /// Gets the exports of the instance. @@ -190,7 +190,7 @@ pub unsafe extern "C" fn wasm_instance_delete(_instance: Option { paste::paste! { - #[no_mangle] + #[unsafe(no_mangle)] pub extern "C" fn [<$prefix _ $name _copy>](src: Option<&[<$prefix _ $name _t>]>) -> Option]>> { Some(Box::new(src?.clone())) } @@ -279,7 +279,7 @@ macro_rules! wasm_impl_delete { ($name:ident, $prefix:ident) => { paste::paste! { - #[no_mangle] + #[unsafe(no_mangle)] pub extern "C" fn [<$prefix _ $name _delete>](_: Option]>>) {} } }; diff --git a/lib/c-api/src/wasm_c_api/module.rs b/lib/c-api/src/wasm_c_api/module.rs index 971c2c765e..dd011abebf 100644 --- a/lib/c-api/src/wasm_c_api/module.rs +++ b/lib/c-api/src/wasm_c_api/module.rs @@ -24,15 +24,16 @@ pub struct wasm_module_t { /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_module_new( store: Option<&mut wasm_store_t>, bytes: Option<&wasm_byte_vec_t>, ) -> Option> { - let store = store?.inner.store_mut(); + let store = store?; + let store_mut = unsafe { store.inner.store_mut() }; let bytes = bytes?; - let module = c_try!(Module::from_binary(&store, bytes.as_slice())); + let module = c_try!(Module::from_binary(&store_mut, bytes.as_slice())); Some(Box::new(wasm_module_t { inner: module })) } @@ -42,7 +43,7 @@ pub unsafe extern "C" fn wasm_module_new( /// # Example /// /// See [`wasm_module_new`]. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_module_delete(_module: Option>) {} /// Validates a new WebAssembly module given the configuration @@ -86,13 +87,13 @@ pub unsafe extern "C" fn wasm_module_delete(_module: Option>) /// # .success(); /// # } /// ``` -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_module_validate( store: Option<&mut wasm_store_t>, bytes: Option<&wasm_byte_vec_t>, ) -> bool { let store = match store { - Some(store) => store.inner.store_mut(), + Some(store) => unsafe { store.inner.store_mut() }, None => return false, }; let bytes = match bytes { @@ -213,7 +214,7 @@ pub unsafe extern "C" fn wasm_module_validate( /// # .success(); /// # } /// ``` -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_module_exports( module: &wasm_module_t, // own @@ -353,7 +354,7 @@ pub unsafe extern "C" fn wasm_module_exports( /// # .success(); /// # } /// ``` -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_module_imports( module: &wasm_module_t, // own @@ -451,18 +452,19 @@ pub unsafe extern "C" fn wasm_module_imports( /// # .success(); /// # } /// ``` -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_module_deserialize( store: &wasm_store_t, bytes: Option<&wasm_byte_vec_t>, ) -> Option> { let bytes = bytes?; - let module = c_try!(Module::deserialize(&store.inner.store(), bytes.as_slice())); + let store_ref = unsafe { store.inner.store() }; + let module = c_try!(unsafe { Module::deserialize(&store_ref, bytes.as_slice()) }); - Some(NonNull::new_unchecked(Box::into_raw(Box::new( - wasm_module_t { inner: module }, - )))) + Some(unsafe { + NonNull::new_unchecked(Box::into_raw(Box::new(wasm_module_t { inner: module }))) + }) } /// Serializes a module into a binary representation that the @@ -472,7 +474,7 @@ pub unsafe extern "C" fn wasm_module_deserialize( /// # Example /// /// See [`wasm_module_deserialize`]. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_module_serialize(module: &wasm_module_t, out: &mut wasm_byte_vec_t) { let byte_vec = c_try!(module.inner.serialize(); otherwise ()); out.set_buffer(byte_vec.to_vec()); @@ -485,7 +487,11 @@ mod tests { #[cfg(target_os = "windows")] use wasmer_inline_c::assert_c; - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_module_validate() { (assert_c! { @@ -513,7 +519,11 @@ mod tests { .success(); } - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_module_new() { (assert_c! { @@ -543,7 +553,11 @@ mod tests { .success(); } - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_module_exports() { (assert_c! { @@ -652,7 +666,11 @@ mod tests { .success(); } - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_module_imports() { (assert_c! { @@ -771,7 +789,11 @@ mod tests { .success(); } - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_module_serialize() { (assert_c! { @@ -806,7 +828,11 @@ mod tests { .success(); } - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_module_serialize_and_deserialize() { (assert_c! { diff --git a/lib/c-api/src/wasm_c_api/store.rs b/lib/c-api/src/wasm_c_api/store.rs index da5b083bf5..ecb72ac16a 100644 --- a/lib/c-api/src/wasm_c_api/store.rs +++ b/lib/c-api/src/wasm_c_api/store.rs @@ -10,11 +10,11 @@ pub struct StoreRef { impl StoreRef { pub unsafe fn store(&self) -> BaseStoreRef<'_> { - (*self.inner.get()).as_store_ref() + unsafe { (*self.inner.get()).as_store_ref() } } pub unsafe fn store_mut(&mut self) -> StoreMut<'_> { - (*self.inner.get()).as_store_mut() + unsafe { (*self.inner.get()).as_store_mut() } } } @@ -29,7 +29,7 @@ pub struct wasm_store_t { /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_store_new( engine: Option<&wasm_engine_t>, ) -> Option> { @@ -48,5 +48,5 @@ pub unsafe extern "C" fn wasm_store_new( /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_store_delete(_store: Option>) {} diff --git a/lib/c-api/src/wasm_c_api/trap.rs b/lib/c-api/src/wasm_c_api/trap.rs index 390e8a96b5..953e10673f 100644 --- a/lib/c-api/src/wasm_c_api/trap.rs +++ b/lib/c-api/src/wasm_c_api/trap.rs @@ -24,7 +24,7 @@ impl From for wasm_trap_t { /// # Example /// /// See the module's documentation for a complete example. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_trap_new( _store: &mut wasm_store_t, message: &wasm_message_t, @@ -63,7 +63,7 @@ pub unsafe extern "C" fn wasm_trap_new( /// # Example /// /// See the module's documentation for a complete example. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_trap_delete(_trap: Option>) {} /// Gets the message attached to the trap. @@ -108,7 +108,7 @@ pub unsafe extern "C" fn wasm_trap_delete(_trap: Option>) {} /// # .success(); /// # } /// ``` -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_trap_message( trap: &wasm_trap_t, // own @@ -122,13 +122,13 @@ pub unsafe extern "C" fn wasm_trap_message( } /// Gets the origin frame attached to the trap. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_trap_origin(trap: &wasm_trap_t) -> Option> { trap.inner.trace().first().map(Into::into).map(Box::new) } /// Gets the trace (as a list of frames) attached to the trap. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_trap_trace( trap: &wasm_trap_t, // own @@ -150,7 +150,11 @@ mod tests { #[cfg(target_os = "windows")] use wasmer_inline_c::assert_c; - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_trap_message_null_terminated() { (assert_c! { @@ -183,7 +187,11 @@ mod tests { .success(); } - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_trap_message_not_null_terminated() { (assert_c! { diff --git a/lib/c-api/src/wasm_c_api/types/export.rs b/lib/c-api/src/wasm_c_api/types/export.rs index a60ccf48b4..cccd3807a9 100644 --- a/lib/c-api/src/wasm_c_api/types/export.rs +++ b/lib/c-api/src/wasm_c_api/types/export.rs @@ -11,7 +11,7 @@ pub struct wasm_exporttype_t { wasm_declare_boxed_vec!(exporttype); wasm_impl_copy_delete!(exporttype); -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_exporttype_new( name: &wasm_name_t, extern_type: Box, @@ -22,12 +22,12 @@ pub extern "C" fn wasm_exporttype_new( }) } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_exporttype_name(export_type: &wasm_exporttype_t) -> &wasm_name_t { &export_type.name } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_exporttype_type(export_type: &wasm_exporttype_t) -> &wasm_externtype_t { &export_type.extern_type } diff --git a/lib/c-api/src/wasm_c_api/types/extern_.rs b/lib/c-api/src/wasm_c_api/types/extern_.rs index 459d5fdcf9..522daa7a31 100644 --- a/lib/c-api/src/wasm_c_api/types/extern_.rs +++ b/lib/c-api/src/wasm_c_api/types/extern_.rs @@ -1,7 +1,7 @@ use super::super::externals::wasm_extern_t; use super::{ - wasm_functype_t, wasm_globaltype_t, wasm_memorytype_t, wasm_tabletype_t, WasmFunctionType, - WasmGlobalType, WasmMemoryType, WasmTableType, WasmTagType, + WasmFunctionType, WasmGlobalType, WasmMemoryType, WasmTableType, WasmTagType, wasm_functype_t, + wasm_globaltype_t, wasm_memorytype_t, wasm_tabletype_t, }; use std::convert::{TryFrom, TryInto}; use std::mem; @@ -89,25 +89,27 @@ impl From<&ExternType> for wasm_externtype_t { } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_extern_type(r#extern: &wasm_extern_t) -> Box { - Box::new(wasm_externtype_t::new(r#extern.ty())) + let ty = unsafe { r#extern.ty() }; + Box::new(wasm_externtype_t::new(ty)) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_extern_kind(r#extern: &wasm_extern_t) -> wasm_externkind_t { - wasm_externkind_enum::from(r#extern.ty()) as wasm_externkind_t + let ty = unsafe { r#extern.ty() }; + wasm_externkind_enum::from(ty) as wasm_externkind_t } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_externtype_delete(_extern_type: Option>) {} -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_externtype_copy(extern_type: &wasm_externtype_t) -> Box { Box::new(extern_type.clone()) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_externtype_kind( extern_type: &wasm_externtype_t, ) -> wasm_externkind_t { @@ -178,112 +180,112 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_memorytype_t { } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_externtype_as_functype_const( extern_type: &'static wasm_externtype_t, ) -> Option<&'static wasm_functype_t> { Some(c_try!(extern_type.try_into())) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_externtype_as_functype( extern_type: &'static wasm_externtype_t, ) -> Option<&'static wasm_functype_t> { Some(c_try!(extern_type.try_into())) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_functype_as_externtype_const( function_type: &'static wasm_functype_t, ) -> &'static wasm_externtype_t { &function_type.extern_type } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_functype_as_externtype( function_type: &'static wasm_functype_t, ) -> &'static wasm_externtype_t { &function_type.extern_type } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_externtype_as_globaltype_const( extern_type: &'static wasm_externtype_t, ) -> Option<&'static wasm_globaltype_t> { Some(c_try!(extern_type.try_into())) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_externtype_as_globaltype( extern_type: &'static wasm_externtype_t, ) -> Option<&'static wasm_globaltype_t> { Some(c_try!(extern_type.try_into())) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_globaltype_as_externtype_const( global_type: &'static wasm_globaltype_t, ) -> &'static wasm_externtype_t { &global_type.extern_type } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_globaltype_as_externtype( global_type: &'static wasm_globaltype_t, ) -> &'static wasm_externtype_t { &global_type.extern_type } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_externtype_as_tabletype_const( extern_type: &'static wasm_externtype_t, ) -> Option<&'static wasm_tabletype_t> { Some(c_try!(extern_type.try_into())) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_externtype_as_tabletype( extern_type: &'static wasm_externtype_t, ) -> Option<&'static wasm_tabletype_t> { Some(c_try!(extern_type.try_into())) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_tabletype_as_externtype_const( table_type: &'static wasm_tabletype_t, ) -> &'static wasm_externtype_t { &table_type.extern_type } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_tabletype_as_externtype( table_type: &'static wasm_tabletype_t, ) -> &'static wasm_externtype_t { &table_type.extern_type } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_externtype_as_memorytype_const( extern_type: &'static wasm_externtype_t, ) -> Option<&'static wasm_memorytype_t> { Some(c_try!(extern_type.try_into())) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_externtype_as_memorytype( extern_type: &'static wasm_externtype_t, ) -> Option<&'static wasm_memorytype_t> { Some(c_try!(extern_type.try_into())) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_memorytype_as_externtype_const( memory_type: &'static wasm_memorytype_t, ) -> &'static wasm_externtype_t { &memory_type.extern_type } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_memorytype_as_externtype( memory_type: &'static wasm_memorytype_t, ) -> &'static wasm_externtype_t { diff --git a/lib/c-api/src/wasm_c_api/types/frame.rs b/lib/c-api/src/wasm_c_api/types/frame.rs index 4619f1c632..c195cae9e6 100644 --- a/lib/c-api/src/wasm_c_api/types/frame.rs +++ b/lib/c-api/src/wasm_c_api/types/frame.rs @@ -21,30 +21,30 @@ impl From for wasm_frame_t { } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_frame_copy(frame: &wasm_frame_t) -> Box { Box::new(frame.clone()) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_frame_delete(_frame: Option>) {} -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_frame_instance(_frame: &wasm_frame_t) -> *const wasm_instance_t { std::ptr::null() } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_frame_func_index(frame: &wasm_frame_t) -> u32 { frame.info.func_index() } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_frame_func_offset(frame: &wasm_frame_t) -> usize { frame.info.func_offset() } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_frame_module_offset(frame: &wasm_frame_t) -> usize { frame.info.module_offset() } @@ -56,7 +56,7 @@ pub struct wasm_name_t { pub name: *mut c_char, } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_frame_module_name(frame: &wasm_frame_t) -> wasm_name_t { let module_name = Some(frame.info.module_name()).and_then(|f| Some(CString::new(f).ok()?.into_raw())); @@ -69,7 +69,7 @@ pub unsafe extern "C" fn wasm_frame_module_name(frame: &wasm_frame_t) -> wasm_na } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_frame_func_name(frame: &wasm_frame_t) -> wasm_name_t { let func_name = frame .info @@ -84,12 +84,12 @@ pub unsafe extern "C" fn wasm_frame_func_name(frame: &wasm_frame_t) -> wasm_name } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_name_delete(name: Option<&mut wasm_name_t>) { - if let Some(s) = name { - if !s.name.is_null() { - let _ = CString::from_raw(s.name); - } + if let Some(s) = name + && !s.name.is_null() + { + let _ = unsafe { CString::from_raw(s.name) }; } } diff --git a/lib/c-api/src/wasm_c_api/types/function.rs b/lib/c-api/src/wasm_c_api/types/function.rs index 52d10d54c5..747f6964b6 100644 --- a/lib/c-api/src/wasm_c_api/types/function.rs +++ b/lib/c-api/src/wasm_c_api/types/function.rs @@ -1,4 +1,4 @@ -use super::{wasm_externtype_t, wasm_valtype_vec_t, WasmExternType}; +use super::{WasmExternType, wasm_externtype_t, wasm_valtype_vec_t}; use std::fmt; use wasmer_api::{ExternType, FunctionType}; use wasmer_types::Type; @@ -69,7 +69,7 @@ impl wasm_functype_t { wasm_declare_boxed_vec!(functype); wasm_impl_copy_delete!(functype); -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_functype_new( params: Option<&mut wasm_valtype_vec_t>, results: Option<&mut wasm_valtype_vec_t>, @@ -94,7 +94,7 @@ pub unsafe extern "C" fn wasm_functype_new( )))) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_functype_params( function_type: Option<&wasm_functype_t>, ) -> Option<&wasm_valtype_vec_t> { @@ -103,7 +103,7 @@ pub unsafe extern "C" fn wasm_functype_params( Some(&function_type.inner().params) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_functype_results( function_type: Option<&wasm_functype_t>, ) -> Option<&wasm_valtype_vec_t> { diff --git a/lib/c-api/src/wasm_c_api/types/global.rs b/lib/c-api/src/wasm_c_api/types/global.rs index b15d3e820e..c35d832245 100644 --- a/lib/c-api/src/wasm_c_api/types/global.rs +++ b/lib/c-api/src/wasm_c_api/types/global.rs @@ -1,6 +1,6 @@ use super::{ - wasm_externtype_t, wasm_mutability_enum, wasm_mutability_t, wasm_valtype_delete, - wasm_valtype_t, WasmExternType, + WasmExternType, wasm_externtype_t, wasm_mutability_enum, wasm_mutability_t, + wasm_valtype_delete, wasm_valtype_t, }; use std::convert::TryInto; use wasmer_api::{ExternType, GlobalType}; @@ -48,7 +48,7 @@ impl wasm_globaltype_t { wasm_declare_boxed_vec!(globaltype); -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_globaltype_new( valtype: Option>, mutability: wasm_mutability_t, @@ -60,22 +60,24 @@ pub unsafe extern "C" fn wasm_globaltype_new( mutability.into(), ))); - wasm_valtype_delete(Some(valtype)); + unsafe { + wasm_valtype_delete(Some(valtype)); + } Some(global_type) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_globaltype_delete(_global_type: Option>) {} -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_globaltype_mutability( global_type: &wasm_globaltype_t, ) -> wasm_mutability_t { wasm_mutability_enum::from(global_type.inner().global_type.mutability).into() } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_globaltype_content( global_type: &wasm_globaltype_t, ) -> &wasm_valtype_t { diff --git a/lib/c-api/src/wasm_c_api/types/import.rs b/lib/c-api/src/wasm_c_api/types/import.rs index 8be6b99c11..9fcff330ba 100644 --- a/lib/c-api/src/wasm_c_api/types/import.rs +++ b/lib/c-api/src/wasm_c_api/types/import.rs @@ -13,7 +13,7 @@ pub struct wasm_importtype_t { wasm_declare_boxed_vec!(importtype); wasm_impl_copy!(importtype); -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_importtype_new( module: Option<&mut wasm_name_t>, name: Option<&mut wasm_name_t>, @@ -26,22 +26,22 @@ pub extern "C" fn wasm_importtype_new( })) } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_importtype_module(import_type: &wasm_importtype_t) -> &wasm_name_t { &import_type.module } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_importtype_name(import_type: &wasm_importtype_t) -> &wasm_name_t { &import_type.name } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_importtype_type(import_type: &wasm_importtype_t) -> &wasm_externtype_t { &import_type.extern_type } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_importtype_delete(_import_type: Option>) {} impl From for wasm_importtype_t { diff --git a/lib/c-api/src/wasm_c_api/types/memory.rs b/lib/c-api/src/wasm_c_api/types/memory.rs index a3506925d8..003a8ac2ef 100644 --- a/lib/c-api/src/wasm_c_api/types/memory.rs +++ b/lib/c-api/src/wasm_c_api/types/memory.rs @@ -1,4 +1,4 @@ -use super::{wasm_externtype_t, WasmExternType}; +use super::{WasmExternType, wasm_externtype_t}; use wasmer_api::{ExternType, MemoryType, Pages}; #[derive(Debug, Clone)] @@ -50,7 +50,7 @@ impl wasm_memorytype_t { wasm_declare_boxed_vec!(memorytype); -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box { let min_pages = Pages(limits.min as _); let max_pages = if limits.max == LIMITS_MAX_SENTINEL { @@ -64,7 +64,7 @@ pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box>) {} #[allow(non_camel_case_types)] @@ -77,7 +77,7 @@ pub struct wasm_limits_t { const LIMITS_MAX_SENTINEL: u32 = u32::MAX; -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_memorytype_limits(memory_type: &wasm_memorytype_t) -> &wasm_limits_t { &memory_type.inner().limits } diff --git a/lib/c-api/src/wasm_c_api/types/table.rs b/lib/c-api/src/wasm_c_api/types/table.rs index 108f11c0de..7fc650a007 100644 --- a/lib/c-api/src/wasm_c_api/types/table.rs +++ b/lib/c-api/src/wasm_c_api/types/table.rs @@ -1,5 +1,5 @@ use super::{ - wasm_externtype_t, wasm_limits_t, wasm_valtype_delete, wasm_valtype_t, WasmExternType, + WasmExternType, wasm_externtype_t, wasm_limits_t, wasm_valtype_delete, wasm_valtype_t, }; use wasmer_api::{ExternType, TableType}; @@ -55,7 +55,7 @@ impl wasm_tabletype_t { wasm_declare_boxed_vec!(tabletype); -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_tabletype_new( valtype: Option>, limits: &wasm_limits_t, @@ -72,20 +72,22 @@ pub unsafe extern "C" fn wasm_tabletype_new( max_elements, ))); - wasm_valtype_delete(Some(valtype)); + unsafe { + wasm_valtype_delete(Some(valtype)); + } Some(table_type) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_tabletype_limits(table_type: &wasm_tabletype_t) -> &wasm_limits_t { &table_type.inner().limits } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_tabletype_element(table_type: &wasm_tabletype_t) -> &wasm_valtype_t { &table_type.inner().content } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_tabletype_delete(_table_type: Option>) {} diff --git a/lib/c-api/src/wasm_c_api/types/value.rs b/lib/c-api/src/wasm_c_api/types/value.rs index fc00f9fec3..5776a8c2cd 100644 --- a/lib/c-api/src/wasm_c_api/types/value.rs +++ b/lib/c-api/src/wasm_c_api/types/value.rs @@ -81,7 +81,7 @@ impl From for wasm_valtype_t { } } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_valtype_new(kind: wasm_valkind_t) -> Option> { let kind_enum = kind.try_into().ok()?; let valtype = wasm_valtype_t { valkind: kind_enum }; @@ -89,10 +89,10 @@ pub extern "C" fn wasm_valtype_new(kind: wasm_valkind_t) -> Option>) {} -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_valtype_kind(valtype: Option<&wasm_valtype_t>) -> wasm_valkind_t { valtype .expect("`wasm_valtype_kind: argument is a null pointer") diff --git a/lib/c-api/src/wasm_c_api/unstable/engine.rs b/lib/c-api/src/wasm_c_api/unstable/engine.rs index 6366e39782..2acb212081 100644 --- a/lib/c-api/src/wasm_c_api/unstable/engine.rs +++ b/lib/c-api/src/wasm_c_api/unstable/engine.rs @@ -44,7 +44,7 @@ use super::{ /// # .success(); /// # } /// ``` -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasm_config_set_features( config: &mut wasm_config_t, features: Box, @@ -54,14 +54,14 @@ pub extern "C" fn wasm_config_set_features( /// Check whether there is no compiler available in this compiled /// library. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_is_headless() -> bool { !cfg!(feature = "compiler") } /// Check whether the given backend is available, i.e. part of this /// compiled library. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_is_backend_available(backend: wasmer_backend_t) -> bool { match backend { wasmer_backend_t::LLVM => cfg!(feature = "llvm"), @@ -85,10 +85,12 @@ mod tests { #[test] fn test_wasmer_is_headless() { - set_var( - "COMPILER", - if cfg!(feature = "compiler") { "0" } else { "1" }, - ); + unsafe { + set_var( + "COMPILER", + if cfg!(feature = "compiler") { "0" } else { "1" }, + ); + } (assert_c! { #include "tests/wasmer.h" @@ -102,28 +104,32 @@ mod tests { }) .success(); - remove_var("COMPILER"); + unsafe { + remove_var("COMPILER"); + } } #[test] fn test_wasmer_is_backend_available() { - set_var( - "CRANELIFT", - if cfg!(feature = "cranelift") { - "1" - } else { - "0" - }, - ); - set_var("LLVM", if cfg!(feature = "llvm") { "1" } else { "0" }); - set_var( - "SINGLEPASS", - if cfg!(feature = "singlepass") { - "1" - } else { - "0" - }, - ); + unsafe { + set_var( + "CRANELIFT", + if cfg!(feature = "cranelift") { + "1" + } else { + "0" + }, + ); + set_var("LLVM", if cfg!(feature = "llvm") { "1" } else { "0" }); + set_var( + "SINGLEPASS", + if cfg!(feature = "singlepass") { + "1" + } else { + "0" + }, + ); + } (assert_c! { #include "tests/wasmer.h" @@ -139,8 +145,10 @@ mod tests { }) .success(); - remove_var("CRANELIFT"); - remove_var("LLVM"); - remove_var("SINGLEPASS"); + unsafe { + remove_var("CRANELIFT"); + remove_var("LLVM"); + remove_var("SINGLEPASS"); + } } } diff --git a/lib/c-api/src/wasm_c_api/unstable/features.rs b/lib/c-api/src/wasm_c_api/unstable/features.rs index b00cffb5b0..57c1837e5d 100644 --- a/lib/c-api/src/wasm_c_api/unstable/features.rs +++ b/lib/c-api/src/wasm_c_api/unstable/features.rs @@ -53,7 +53,7 @@ pub struct wasmer_features_t { /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_features_new() -> Box { Box::new(wasmer_features_t { inner: Features::new(), @@ -65,7 +65,7 @@ pub extern "C" fn wasmer_features_new() -> Box { /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_features_delete(_features: Option>) {} /// Configures whether the WebAssembly threads proposal will be enabled. @@ -84,7 +84,7 @@ pub extern "C" fn wasmer_features_delete(_features: Option, enable: bool, @@ -118,7 +118,7 @@ pub extern "C" fn wasmer_features_threads( /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_features_reference_types( features: Option<&mut wasmer_features_t>, enable: bool, @@ -151,7 +151,7 @@ pub extern "C" fn wasmer_features_reference_types( /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_features_simd( features: Option<&mut wasmer_features_t>, enable: bool, @@ -184,7 +184,7 @@ pub extern "C" fn wasmer_features_simd( /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_features_bulk_memory( features: Option<&mut wasmer_features_t>, enable: bool, @@ -217,7 +217,7 @@ pub extern "C" fn wasmer_features_bulk_memory( /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_features_multi_value( features: Option<&mut wasmer_features_t>, enable: bool, @@ -249,7 +249,7 @@ pub extern "C" fn wasmer_features_multi_value( /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_features_tail_call( features: Option<&mut wasmer_features_t>, enable: bool, @@ -282,7 +282,7 @@ pub extern "C" fn wasmer_features_tail_call( /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_features_module_linking( features: Option<&mut wasmer_features_t>, enable: bool, @@ -315,7 +315,7 @@ pub extern "C" fn wasmer_features_module_linking( /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_features_multi_memory( features: Option<&mut wasmer_features_t>, enable: bool, @@ -348,7 +348,7 @@ pub extern "C" fn wasmer_features_multi_memory( /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_features_memory64( features: Option<&mut wasmer_features_t>, enable: bool, diff --git a/lib/c-api/src/wasm_c_api/unstable/middlewares/metering.rs b/lib/c-api/src/wasm_c_api/unstable/middlewares/metering.rs index ba61250e9f..5b122116f2 100644 --- a/lib/c-api/src/wasm_c_api/unstable/middlewares/metering.rs +++ b/lib/c-api/src/wasm_c_api/unstable/middlewares/metering.rs @@ -137,8 +137,8 @@ use super::wasmer_middleware_t; use std::sync::Arc; use wasmer_api::wasmparser::Operator; use wasmer_middlewares::{ - metering::{get_remaining_points, set_remaining_points, MeteringPoints}, Metering, + metering::{MeteringPoints, get_remaining_points, set_remaining_points}, }; /// Opaque type representing a metering middleware. @@ -172,7 +172,7 @@ pub type wasmer_metering_cost_function_t = /// # Example /// /// See module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_metering_new( initial_limit: u64, cost_function: wasmer_metering_cost_function_t, @@ -189,7 +189,7 @@ pub extern "C" fn wasmer_metering_new( /// # Example /// /// See module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_metering_delete(_metering: Option>) {} /// Returns the remaining metering points. `u64::MAX` means @@ -200,11 +200,12 @@ pub extern "C" fn wasmer_metering_delete(_metering: Option u64 { - match get_remaining_points(&mut instance.store.store_mut(), &instance.inner) { + let mut store_mut = unsafe { instance.store.store_mut() }; + match get_remaining_points(&mut store_mut, &instance.inner) { MeteringPoints::Remaining(value) => value, MeteringPoints::Exhausted => u64::MAX, } @@ -215,12 +216,13 @@ pub unsafe extern "C" fn wasmer_metering_get_remaining_points( /// # Example /// /// See module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_metering_points_are_exhausted( instance: &mut wasm_instance_t, ) -> bool { + let mut store_mut = unsafe { instance.store.store_mut() }; matches!( - get_remaining_points(&mut instance.store.store_mut(), &instance.inner), + get_remaining_points(&mut store_mut, &instance.inner), MeteringPoints::Exhausted, ) } @@ -297,24 +299,25 @@ pub unsafe extern "C" fn wasmer_metering_points_are_exhausted( /// # .success(); /// # } /// ``` -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_metering_set_remaining_points( instance: &mut wasm_instance_t, new_limit: u64, ) { - set_remaining_points(&mut instance.store.store_mut(), &instance.inner, new_limit); + let mut store_mut = unsafe { instance.store.store_mut() }; + set_remaining_points(&mut store_mut, &instance.inner, new_limit); } /// Transforms a [`wasmer_metering_t`] into a generic /// [`wasmer_middleware_t`], to then be pushed in the configuration with -/// [`wasm_config_push_middleware`][super::wasm_config_push_middleware]. +/// [`wasm_config_push_middleware`](crate::wasm_c_api::engine::wasm_config_push_middleware). /// /// This function takes ownership of `metering`. /// /// # Example /// /// See module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_metering_as_middleware( metering: Option>, ) -> Option> { diff --git a/lib/c-api/src/wasm_c_api/unstable/module.rs b/lib/c-api/src/wasm_c_api/unstable/module.rs index c5b3ddc6d0..149ee23e1c 100644 --- a/lib/c-api/src/wasm_c_api/unstable/module.rs +++ b/lib/c-api/src/wasm_c_api/unstable/module.rs @@ -55,7 +55,7 @@ use wasmer_api::Module; /// # .success(); /// # } /// ``` -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_module_name( module: &wasm_module_t, // own @@ -139,7 +139,7 @@ pub unsafe extern "C" fn wasmer_module_name( /// # .success(); /// # } /// ``` -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_module_set_name( module: &mut wasm_module_t, // own @@ -167,7 +167,7 @@ pub unsafe extern "C" fn wasmer_module_set_name( /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_module_new( engine: Option<&mut wasm_engine_t>, bytes: Option<&wasm_byte_vec_t>, diff --git a/lib/c-api/src/wasm_c_api/unstable/target_lexicon.rs b/lib/c-api/src/wasm_c_api/unstable/target_lexicon.rs index 183e27499e..66d8130d53 100644 --- a/lib/c-api/src/wasm_c_api/unstable/target_lexicon.rs +++ b/lib/c-api/src/wasm_c_api/unstable/target_lexicon.rs @@ -79,7 +79,7 @@ pub struct wasmer_target_t { /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_target_new( triple: Option>, cpu_features: Option>, @@ -97,7 +97,7 @@ pub extern "C" fn wasmer_target_new( /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_target_delete(_target: Option>) {} /// Unstable non-standard Wasmer-specific API to represent a target @@ -142,15 +142,14 @@ pub struct wasmer_triple_t { /// # Example /// /// See [`wasmer_triple_t`] or [`wasmer_triple_new_from_host`]. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_triple_new( triple: Option<&wasm_name_t>, ) -> Option> { let triple = triple?; - let triple = c_try!(str::from_utf8(slice::from_raw_parts( - triple.data, - triple.size - ))); + let triple = c_try!(str::from_utf8(unsafe { + slice::from_raw_parts(triple.data, triple.size) + })); Some(Box::new(wasmer_triple_t { inner: c_try!(Triple::from_str(triple)), @@ -181,7 +180,7 @@ pub unsafe extern "C" fn wasmer_triple_new( /// ``` /// /// See also [`wasmer_triple_new`]. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_triple_new_from_host() -> Box { Box::new(wasmer_triple_t { inner: Triple::host(), @@ -193,7 +192,7 @@ pub extern "C" fn wasmer_triple_new_from_host() -> Box { /// # Example /// /// See [`wasmer_triple_t`]. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_triple_delete(_triple: Option>) {} /// Unstable non-standard Wasmer-specific API to represent a set of @@ -263,7 +262,7 @@ pub struct wasmer_cpu_features_t { /// # Example /// /// See [`wasmer_cpu_features_t`]. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_cpu_features_new() -> Box { Box::new(wasmer_cpu_features_t { inner: CpuFeature::set(), @@ -275,7 +274,7 @@ pub extern "C" fn wasmer_cpu_features_new() -> Box { /// # Example /// /// See [`wasmer_cpu_features_t`]. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_cpu_features_delete(_cpu_features: Option>) {} /// Add a new CPU feature into the set represented by @@ -284,7 +283,7 @@ pub extern "C" fn wasmer_cpu_features_delete(_cpu_features: Option, feature: Option<&wasm_name_t>, @@ -298,10 +297,12 @@ pub unsafe extern "C" fn wasmer_cpu_features_add( _ => return false, }; let feature = c_try!( - str::from_utf8(slice::from_raw_parts( - feature.data, - feature.size, - )); + str::from_utf8(unsafe { + slice::from_raw_parts( + feature.data, + feature.size, + ) + }); otherwise false ); diff --git a/lib/c-api/src/wasm_c_api/unstable/wasi.rs b/lib/c-api/src/wasm_c_api/unstable/wasi.rs index f37a5e510f..0634bfd78c 100644 --- a/lib/c-api/src/wasm_c_api/unstable/wasi.rs +++ b/lib/c-api/src/wasm_c_api/unstable/wasi.rs @@ -66,7 +66,7 @@ mod __cbindgen_hack__ { pub data: *mut *mut wasmer_named_extern_t, } - #[no_mangle] + #[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_named_extern_vec_new( out: *mut wasmer_named_extern_vec_t, length: usize, @@ -75,7 +75,7 @@ mod __cbindgen_hack__ { unimplemented!() } - #[no_mangle] + #[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_named_extern_vec_new_uninitialized( out: *mut wasmer_named_extern_vec_t, length: usize, @@ -83,7 +83,7 @@ mod __cbindgen_hack__ { unimplemented!() } - #[no_mangle] + #[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_named_extern_vec_copy( out_ptr: &mut wasmer_named_extern_vec_t, in_ptr: &wasmer_named_extern_vec_t, @@ -91,14 +91,14 @@ mod __cbindgen_hack__ { unimplemented!() } - #[no_mangle] + #[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_named_extern_vec_delete( ptr: Option<&mut wasmer_named_extern_vec_t>, ) { unimplemented!() } - #[no_mangle] + #[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_named_extern_vec_new_empty( out: *mut wasmer_named_extern_vec_t, ) { @@ -110,7 +110,7 @@ mod __cbindgen_hack__ { /// `wasmer_named_extern_t`. /// /// The returned value isn't owned by the caller. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_named_extern_module( named_extern: Option<&wasmer_named_extern_t>, ) -> Option<&wasm_name_t> { @@ -120,7 +120,7 @@ pub extern "C" fn wasmer_named_extern_module( /// Non-standard function to get the name of a `wasmer_named_extern_t`. /// /// The returned value isn't owned by the caller. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_named_extern_name( named_extern: Option<&wasmer_named_extern_t>, ) -> Option<&wasm_name_t> { @@ -131,7 +131,7 @@ pub extern "C" fn wasmer_named_extern_name( /// `wasmer_named_extern_t`. /// /// The returned value isn't owned by the caller. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasmer_named_extern_unwrap( named_extern: Option<&wasmer_named_extern_t>, ) -> Option<&wasm_extern_t> { @@ -142,13 +142,13 @@ pub extern "C" fn wasmer_named_extern_unwrap( /// implementation with no particular order. Each import has its /// associated module name and name, so that it can be re-order later /// based on the `wasm_module_t` requirements. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_get_unordered_imports( wasi_env: Option<&mut wasi_env_t>, module: Option<&wasm_module_t>, imports: &mut wasmer_named_extern_vec_t, ) -> bool { - wasi_get_unordered_imports_inner(wasi_env, module, imports).is_some() + unsafe { wasi_get_unordered_imports_inner(wasi_env, module, imports) }.is_some() } unsafe fn wasi_get_unordered_imports_inner( @@ -158,10 +158,12 @@ unsafe fn wasi_get_unordered_imports_inner( ) -> Option<()> { let wasi_env = wasi_env?; let store = &mut wasi_env.store; - let mut store_mut = store.store_mut(); let module = module?; - let import_object = c_try!(wasi_env.inner.import_object(&mut store_mut, &module.inner)); + let import_object = { + let mut store_mut = unsafe { store.store_mut() }; + c_try!(wasi_env.inner.import_object(&mut store_mut, &module.inner)) + }; imports.set_buffer( import_object diff --git a/lib/c-api/src/wasm_c_api/value.rs b/lib/c-api/src/wasm_c_api/value.rs index a678751ba4..920b70a7c5 100644 --- a/lib/c-api/src/wasm_c_api/value.rs +++ b/lib/c-api/src/wasm_c_api/value.rs @@ -131,14 +131,14 @@ impl Default for wasm_val_t { } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_val_copy( // own out: &mut wasm_val_t, val: &wasm_val_t, ) { out.kind = val.kind; - out.of = c_try!(val.kind.try_into().map(|kind| { + out.of = c_try!(val.kind.try_into().map(|kind| unsafe { match kind { wasm_valkind_enum::WASM_I32 => wasm_val_inner { int32_t: val.of.int32_t, @@ -173,10 +173,12 @@ impl Drop for wasm_val_t { } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasm_val_delete(val: *mut wasm_val_t) { if !val.is_null() { - std::ptr::drop_in_place(val); + unsafe { + std::ptr::drop_in_place(val); + } } } @@ -215,7 +217,7 @@ impl TryFrom<&wasm_val_t> for Value { wasm_valkind_enum::WASM_F32 => Value::F32(unsafe { item.of.float32_t }), wasm_valkind_enum::WASM_F64 => Value::F64(unsafe { item.of.float64_t }), wasm_valkind_enum::WASM_EXTERNREF => { - return Err("EXTERNREF not supported at this time") + return Err("EXTERNREF not supported at this time"); } wasm_valkind_enum::WASM_FUNCREF => return Err("FUNCREF not supported at this time"), wasm_valkind_enum::WASM_EXNREF => return Err("EXNREF not supported at this time"), diff --git a/lib/c-api/src/wasm_c_api/version.rs b/lib/c-api/src/wasm_c_api/version.rs index 6f1dd0b85b..107aa6f9f4 100644 --- a/lib/c-api/src/wasm_c_api/version.rs +++ b/lib/c-api/src/wasm_c_api/version.rs @@ -32,7 +32,7 @@ static VERSION_PATCH: LazyLock = LazyLock::new(|| { /// # Example /// /// See the module's documentation. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_version() -> *const c_char { VERSION.as_ptr() as *const _ } @@ -71,7 +71,7 @@ pub unsafe extern "C" fn wasmer_version() -> *const c_char { /// # ); /// # } /// ``` -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_version_major() -> u8 { *VERSION_MAJOR } @@ -79,7 +79,7 @@ pub unsafe extern "C" fn wasmer_version_major() -> u8 { /// Get the minor version of the Wasmer C API. /// /// See [`wasmer_version_major`] to learn more and get an example. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_version_minor() -> u8 { *VERSION_MINOR } @@ -87,7 +87,7 @@ pub unsafe extern "C" fn wasmer_version_minor() -> u8 { /// Get the patch version of the Wasmer C API. /// /// See [`wasmer_version_major`] to learn more and get an example. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_version_patch() -> u8 { *VERSION_PATCH } @@ -122,7 +122,7 @@ pub unsafe extern "C" fn wasmer_version_patch() -> u8 { /// # .stdout(env!("CARGO_PKG_VERSION_PRE")); /// # } /// ``` -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasmer_version_pre() -> *const c_char { VERSION_PRE.as_ptr() as *const _ } diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 72243b7d2a..72ee5f47ce 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -7,7 +7,7 @@ use super::{ externals::{wasm_extern_t, wasm_extern_vec_t, wasm_func_t, wasm_memory_t}, instance::wasm_instance_t, module::wasm_module_t, - store::{wasm_store_t, StoreRef}, + store::{StoreRef, wasm_store_t}, types::wasm_byte_vec_t, }; use crate::error::update_last_error; @@ -19,11 +19,11 @@ use std::sync::Arc; #[cfg(feature = "webc_runner")] use wasmer_api::{AsStoreMut, Imports, Module}; use wasmer_wasix::{ + Pipe, PluggableRuntime, WasiEnv, WasiEnvBuilder, WasiFunctionEnv, WasiVersion, default_fs_backing, get_wasi_version, - runtime::task_manager::{tokio::TokioTaskManager, InlineWaker}, + runtime::task_manager::{block_on, tokio::TokioTaskManager}, virtual_fs::AsyncReadExt, virtual_fs::VirtualFile, - Pipe, PluggableRuntime, WasiEnv, WasiEnvBuilder, WasiFunctionEnv, WasiVersion, }; #[derive(Debug)] @@ -36,13 +36,13 @@ pub struct wasi_config_t { runtime: Option, } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_config_new( program_name: *const c_char, ) -> Option> { debug_assert!(!program_name.is_null()); - let name_c_str = CStr::from_ptr(program_name); + let name_c_str = unsafe { CStr::from_ptr(program_name) }; let prog_name = c_try!(name_c_str.to_str()); let runtime = tokio::runtime::Builder::new_multi_thread() @@ -60,7 +60,7 @@ pub unsafe extern "C" fn wasi_config_new( })) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_config_env( config: &mut wasi_config_t, key: *const c_char, @@ -69,30 +69,30 @@ pub unsafe extern "C" fn wasi_config_env( debug_assert!(!key.is_null()); debug_assert!(!value.is_null()); - let key_cstr = CStr::from_ptr(key); + let key_cstr = unsafe { CStr::from_ptr(key) }; let key_bytes = key_cstr.to_bytes(); - let value_cstr = CStr::from_ptr(value); + let value_cstr = unsafe { CStr::from_ptr(value) }; let value_bytes = value_cstr.to_bytes(); config.builder.add_env(key_bytes, value_bytes); } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_config_arg(config: &mut wasi_config_t, arg: *const c_char) { debug_assert!(!arg.is_null()); - let arg_cstr = CStr::from_ptr(arg); + let arg_cstr = unsafe { CStr::from_ptr(arg) }; let arg_bytes = arg_cstr.to_bytes(); config.builder.add_arg(arg_bytes); } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_config_preopen_dir( config: &mut wasi_config_t, dir: *const c_char, ) -> bool { - let dir_cstr = CStr::from_ptr(dir); + let dir_cstr = unsafe { CStr::from_ptr(dir) }; let dir_bytes = dir_cstr.to_bytes(); let dir_str = match std::str::from_utf8(dir_bytes) { Ok(dir_str) => dir_str, @@ -110,13 +110,13 @@ pub unsafe extern "C" fn wasi_config_preopen_dir( true } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_config_mapdir( config: &mut wasi_config_t, alias: *const c_char, dir: *const c_char, ) -> bool { - let alias_cstr = CStr::from_ptr(alias); + let alias_cstr = unsafe { CStr::from_ptr(alias) }; let alias_bytes = alias_cstr.to_bytes(); let alias_str = match std::str::from_utf8(alias_bytes) { Ok(alias_str) => alias_str, @@ -126,7 +126,7 @@ pub unsafe extern "C" fn wasi_config_mapdir( } }; - let dir_cstr = CStr::from_ptr(dir); + let dir_cstr = unsafe { CStr::from_ptr(dir) }; let dir_bytes = dir_cstr.to_bytes(); let dir_str = match std::str::from_utf8(dir_bytes) { Ok(dir_str) => dir_str, @@ -144,32 +144,32 @@ pub unsafe extern "C" fn wasi_config_mapdir( true } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasi_config_capture_stdout(config: &mut wasi_config_t) { config.inherit_stdout = false; } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasi_config_inherit_stdout(config: &mut wasi_config_t) { config.inherit_stdout = true; } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasi_config_capture_stderr(config: &mut wasi_config_t) { config.inherit_stderr = false; } -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasi_config_inherit_stderr(config: &mut wasi_config_t) { config.inherit_stderr = true; } -//#[no_mangle] +//#[unsafe(no_mangle)] //pub extern "C" fn wasi_config_capture_stdin(config: &mut wasi_config_t) { // config.inherit_stdin = false; //} -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { config.inherit_stdin = true; } @@ -180,14 +180,14 @@ pub struct wasi_filesystem_t { size: usize, } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_filesystem_init_static_memory( volume_bytes: Option<&wasm_byte_vec_t>, ) -> Option> { let volume_bytes = volume_bytes.as_ref()?; Some(Box::new(wasi_filesystem_t { ptr: { - let ptr = (volume_bytes.data.as_ref()?) as *const _ as *const c_char; + let ptr = unsafe { volume_bytes.data.as_ref()? } as *const _ as *const c_char; if ptr.is_null() { return None; } @@ -197,15 +197,15 @@ pub unsafe extern "C" fn wasi_filesystem_init_static_memory( })) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_filesystem_delete(ptr: *mut wasi_filesystem_t) { - let _ = Box::from_raw(ptr); + let _ = unsafe { Box::from_raw(ptr) }; } /// Initializes the `imports` with an import object that links to /// the custom file system #[cfg(feature = "webc_runner")] -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_env_with_filesystem( config: Box, store: Option<&mut wasm_store_t>, @@ -214,7 +214,7 @@ pub unsafe extern "C" fn wasi_env_with_filesystem( imports: Option<&mut wasm_extern_vec_t>, package: *const c_char, ) -> Option> { - wasi_env_with_filesystem_inner(config, store, module, fs, imports, package) + unsafe { wasi_env_with_filesystem_inner(config, store, module, fs, imports, package) } } #[cfg(feature = "webc_runner")] @@ -228,19 +228,23 @@ unsafe fn wasi_env_with_filesystem_inner( ) -> Option> { let store = &mut store?.inner; let fs = fs.as_ref()?; - let package_str = CStr::from_ptr(package); + let package_str = unsafe { CStr::from_ptr(package) }; let package = package_str.to_str().unwrap_or(""); let module = &module.as_ref()?.inner; let imports = imports?; - - let (wasi_env, import_object) = prepare_webc_env( - config, - &mut store.store_mut(), - module, - &*(fs.ptr as *const u8), // cast wasi_filesystem_t.ptr as &'static [u8] - fs.size, - package, - )?; + let fs_bytes = unsafe { &*(fs.ptr as *const u8) }; + + let (wasi_env, import_object) = { + let mut store_mut = unsafe { store.store_mut() }; + prepare_webc_env( + config, + &mut store_mut, + module, + fs_bytes, // cast wasi_filesystem_t.ptr as &'static [u8] + fs.size, + package, + )? + }; imports_set_buffer(store, module, import_object, imports)?; @@ -260,6 +264,7 @@ fn prepare_webc_env( package_name: &str, ) -> Option<(WasiFunctionEnv, Imports)> { use virtual_fs::static_fs::StaticFileSystem; + use wasmer_wasix::virtual_fs::FileSystem; use webc::v1::{FsEntryType, WebC}; let store_mut = store.as_store_mut(); @@ -286,15 +291,16 @@ fn prepare_webc_env( .header .top_level .iter() + .filter(|entry| entry.fs_type == FsEntryType::Dir) .cloned() - .filter(|e| e.fs_type == FsEntryType::Dir) .map(|e| e.text.to_string()) .collect::>() .into_iter() }) .collect::>(); - let filesystem = Box::new(StaticFileSystem::init(slice, package_name)?); + let filesystem = + Arc::new(StaticFileSystem::init(slice, package_name)?) as Arc; let mut builder = config.builder.runtime(Arc::new(rt)); if !config.inherit_stdout { @@ -328,13 +334,13 @@ pub struct wasi_env_t { /// Create a new WASI environment. /// /// It take ownership over the `wasi_config_t`. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_env_new( store: Option<&mut wasm_store_t>, mut config: Box, ) -> Option> { let store = &mut store?.inner; - let mut store_mut = store.store_mut(); + let mut store_mut = unsafe { store.store_mut() }; let runtime = config.runtime.take(); @@ -360,10 +366,12 @@ pub unsafe extern "C" fn wasi_env_new( // TODO: impl capturer for stdin - let env = c_try!(config - .builder - .runtime(Arc::new(rt)) - .finalize(&mut store_mut)); + let env = c_try!( + config + .builder + .runtime(Arc::new(rt)) + .finalize(&mut store_mut) + ); Some(Box::new(wasi_env_t { inner: env, @@ -372,11 +380,11 @@ pub unsafe extern "C" fn wasi_env_new( } /// Delete a [`wasi_env_t`]. -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn wasi_env_delete(state: Option>) { if let Some(mut env) = state { - env.inner - .on_exit(unsafe { &mut env.store.store_mut() }, None); + let mut store = unsafe { env.store.store_mut() }; + env.inner.on_exit(&mut store, None); } } @@ -384,20 +392,20 @@ pub extern "C" fn wasi_env_delete(state: Option>) { // NOTE: Only here to not break the C API. // This was previosly supported, but is no longer possible due to WASIX changes. // Customizing memories should be done through the builder or the runtime. -#[no_mangle] +#[unsafe(no_mangle)] #[deprecated(since = "4.0.0")] pub unsafe extern "C" fn wasi_env_set_memory(_env: &mut wasi_env_t, _memory: &wasm_memory_t) { panic!("wasmer_env_set_memory() is not supported"); } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_env_read_stdout( env: &mut wasi_env_t, buffer: *mut c_char, buffer_len: usize, ) -> isize { - let inner_buffer = slice::from_raw_parts_mut(buffer as *mut _, buffer_len); - let store = env.store.store(); + let inner_buffer = unsafe { slice::from_raw_parts_mut(buffer as *mut _, buffer_len) }; + let store = unsafe { env.store.store() }; let stdout = { let data = env.inner.data(&store); @@ -417,14 +425,14 @@ pub unsafe extern "C" fn wasi_env_read_stdout( } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_env_read_stderr( env: &mut wasi_env_t, buffer: *mut c_char, buffer_len: usize, ) -> isize { - let inner_buffer = slice::from_raw_parts_mut(buffer as *mut _, buffer_len); - let store = env.store.store(); + let inner_buffer = unsafe { slice::from_raw_parts_mut(buffer as *mut _, buffer_len) }; + let store = unsafe { env.store.store() }; let stderr = { let data = env.inner.data(&store); data.stderr() @@ -446,7 +454,7 @@ fn read_inner( wasi_file: &mut Box, inner_buffer: &mut [u8], ) -> isize { - InlineWaker::block_on(async { + block_on(async { match wasi_file.read(inner_buffer).await { Ok(a) => a as isize, Err(err) => { @@ -518,7 +526,7 @@ impl TryFrom for WasiVersion { } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_get_wasi_version(module: &wasm_module_t) -> wasi_version_t { get_wasi_version(&module.inner, false) .map(Into::into) @@ -527,14 +535,14 @@ pub unsafe extern "C" fn wasi_get_wasi_version(module: &wasm_module_t) -> wasi_v /// Non-standard function to get the imports needed for the WASI /// implementation ordered as expected by the `wasm_module_t`. -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_get_imports( _store: Option<&wasm_store_t>, wasi_env: Option<&mut wasi_env_t>, module: Option<&wasm_module_t>, imports: &mut wasm_extern_vec_t, ) -> bool { - wasi_get_imports_inner(wasi_env, module, imports).is_some() + unsafe { wasi_get_imports_inner(wasi_env, module, imports) }.is_some() } unsafe fn wasi_get_imports_inner( @@ -546,9 +554,10 @@ unsafe fn wasi_get_imports_inner( let store = &mut wasi_env.store; let module = module?; - let mut import_object = c_try!(wasi_env - .inner - .import_object(&mut store.store_mut(), &module.inner)); + let mut import_object = { + let mut store_mut = unsafe { store.store_mut() }; + c_try!(wasi_env.inner.import_object(&mut store_mut, &module.inner)) + }; let shared_memory = module.inner.imports().memories().next().map(|a| *a.ty()); @@ -557,15 +566,19 @@ unsafe fn wasi_get_imports_inner( None => wasmer_wasix::runtime::SpawnType::CreateMemory, }; - let tasks = wasi_env - .inner - .data(&store.store()) - .runtime - .task_manager() - .clone(); - let memory = tasks - .build_memory(&mut store.store_mut(), &spawn_type) - .unwrap(); + let tasks = { + let store_ref = unsafe { store.store() }; + wasi_env + .inner + .data(&store_ref) + .runtime + .task_manager() + .clone() + }; + let memory = { + let mut store_mut = unsafe { store.store_mut() }; + tasks.build_memory(&mut store_mut, &spawn_type).unwrap() + }; if let Some(memory) = memory { import_object.define("env", "memory", memory); @@ -582,40 +595,43 @@ pub(crate) fn imports_set_buffer( import_object: wasmer_api::Imports, imports: &mut wasm_extern_vec_t, ) -> Option<()> { - imports.set_buffer(c_try!(module - .imports() - .map(|import_type| { - let ext = import_object - .get_export(import_type.module(), import_type.name()) - .ok_or_else(|| { - format!( - "Failed to resolve import \"{}\" \"{}\"", - import_type.module(), - import_type.name() - ) - })?; - - Ok(Some(Box::new(wasm_extern_t::new(store.clone(), ext)))) - }) - .collect::, String>>())); + imports.set_buffer(c_try!( + module + .imports() + .map(|import_type| { + let ext = import_object + .get_export(import_type.module(), import_type.name()) + .ok_or_else(|| { + format!( + "Failed to resolve import \"{}\" \"{}\"", + import_type.module(), + import_type.name() + ) + })?; + + Ok(Some(Box::new(wasm_extern_t::new(store.clone(), ext)))) + }) + .collect::, String>>() + )); Some(()) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_env_initialize_instance( wasi_env: &mut wasi_env_t, store: &mut wasm_store_t, instance: &mut wasm_instance_t, ) -> bool { + let mut store_mut = unsafe { store.inner.store_mut() }; wasi_env .inner - .initialize(&mut store.inner.store_mut(), instance.inner.clone()) + .initialize(&mut store_mut, instance.inner.clone()) .unwrap(); true } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wasi_get_start_function( instance: &mut wasm_instance_t, ) -> Option> { @@ -633,7 +649,11 @@ mod tests { #[cfg(target_os = "windows")] use wasmer_inline_c::assert_c; - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_wasi_get_wasi_version_snapshot0() { (assert_c! { @@ -667,7 +687,11 @@ mod tests { .success(); } - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_wasi_get_wasi_version_snapshot1() { (assert_c! { @@ -701,7 +725,11 @@ mod tests { .success(); } - #[cfg_attr(coverage, ignore)] + #[allow( + unexpected_cfgs, + reason = "tools like cargo-llvm-coverage pass --cfg coverage" + )] + #[cfg_attr(coverage_nightly, coverage(off))] #[test] fn test_wasi_get_wasi_version_invalid() { (assert_c! { diff --git a/lib/c-api/src/wasm_c_api/wat.rs b/lib/c-api/src/wasm_c_api/wat.rs index 4d0c3928c6..ee44b0ae62 100644 --- a/lib/c-api/src/wasm_c_api/wat.rs +++ b/lib/c-api/src/wasm_c_api/wat.rs @@ -12,7 +12,7 @@ use super::types::wasm_byte_vec_t; /// # Safety /// This function is unsafe in order to be callable from C. #[cfg(feature = "wat")] -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn wat2wasm(wat: &wasm_byte_vec_t, out: &mut wasm_byte_vec_t) { match wasmer_api::wat2wasm(wat.as_slice()) { Ok(val) => out.set_buffer(val.into_owned()), diff --git a/lib/c-api/tests/wasmer-c-api-test-runner/Cargo.toml b/lib/c-api/tests/wasmer-c-api-test-runner/Cargo.toml index e4e7259427..585f66f705 100644 --- a/lib/c-api/tests/wasmer-c-api-test-runner/Cargo.toml +++ b/lib/c-api/tests/wasmer-c-api-test-runner/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "wasmer-c-api-test-runner" -version = "6.1.0" -edition = "2021" -license = "MIT" description = "wasmer-c-api-test-runner" +version.workspace = true +edition.workspace = true +license.workspace = true [dependencies] -cc = "1.0" -target-lexicon = "0.11" -regex = "1.6" -walkdir = "2.3.2" \ No newline at end of file +cc.workspace = true +target-lexicon.workspace = true +regex.workspace = true +walkdir.workspace = true diff --git a/lib/cache/Cargo.toml b/lib/cache/Cargo.toml index 2dc69b3b80..ba1aa5b3f6 100644 --- a/lib/cache/Cargo.toml +++ b/lib/cache/Cargo.toml @@ -19,13 +19,13 @@ thiserror.workspace = true blake3.workspace = true [dev-dependencies] -criterion = { version = "0.5", default-features = false } -clap = { version = "=4.4.11" } -clap_builder = { version = "=4.4.11" } -clap_derive = { version = "=4.4.7" } -clap_lex = { version = "=0.6.0" } +criterion = { workspace = true, default-features = false } +clap = { workspace = true, default-features = true } +clap_builder.workspace = true +clap_derive.workspace = true +clap_lex.workspace = true tempfile.workspace = true -rand = "0.8.3" +rand.workspace = true wasmer = { path = "../api", version = "=6.1.0", default-features = false, features = ["sys", "cranelift"] } wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "=6.1.0" } diff --git a/lib/cache/benches/bench_filesystem_cache.rs b/lib/cache/benches/bench_filesystem_cache.rs index 8153e7c7b3..00897ca603 100644 --- a/lib/cache/benches/bench_filesystem_cache.rs +++ b/lib/cache/benches/bench_filesystem_cache.rs @@ -1,7 +1,7 @@ #![allow(unused_imports)] -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use rand::distributions::Alphanumeric; -use rand::{thread_rng, Rng}; +use criterion::{Criterion, criterion_group, criterion_main}; +use rand::distr::Alphanumeric; +use rand::{Rng, rng}; use tempfile::TempDir; use wasmer::{Module, Store}; use wasmer_cache::Cache; @@ -9,7 +9,7 @@ use wasmer_cache::{FileSystemCache, Hash}; use wasmer_compiler_singlepass::Singlepass; fn random_key() -> Hash { - Hash::new(rand::thread_rng().gen::<[u8; 32]>()) + Hash::new(rand::rng().random::<[u8; 32]>()) } pub fn store_cache_universal(c: &mut Criterion) { diff --git a/lib/cache/src/filesystem.rs b/lib/cache/src/filesystem.rs index dabec09f28..0786bf480e 100644 --- a/lib/cache/src/filesystem.rs +++ b/lib/cache/src/filesystem.rs @@ -1,7 +1,7 @@ #![cfg_attr(not(feature = "filesystem"), allow(unused))] use crate::cache::Cache; use crate::hash::Hash; -use std::fs::{create_dir_all, File}; +use std::fs::{File, create_dir_all}; use std::io::{self, Write}; use std::path::PathBuf; use wasmer::{AsEngineRef, DeserializeError, Module, SerializeError}; @@ -68,10 +68,10 @@ impl FileSystemCache { // Create the directory and any parent directories if they don't yet exist. let res = create_dir_all(&path); if res.is_err() { - Err(io::Error::new( - io::ErrorKind::Other, - format!("failed to create cache directory: {}", path.display()), - )) + Err(io::Error::other(format!( + "failed to create cache directory: {}", + path.display() + ))) } else { Ok(Self { path, ext: None }) } @@ -103,7 +103,7 @@ impl Cache for FileSystemCache { key.to_string() }; let path = self.path.join(filename); - let ret = Module::deserialize_from_file(engine, path.clone()); + let ret = unsafe { Module::deserialize_from_file(engine, path.clone()) }; if ret.is_err() { // If an error occurs while deserializing then we can not trust it anymore // so delete the cache file diff --git a/lib/cache/src/lib.rs b/lib/cache/src/lib.rs index d988a65c4e..5e19b97522 100644 --- a/lib/cache/src/lib.rs +++ b/lib/cache/src/lib.rs @@ -13,7 +13,7 @@ clippy::unicode_not_nfc, clippy::use_self )] -#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] mod cache; mod filesystem; diff --git a/lib/cli-compiler/Cargo.toml b/lib/cli-compiler/Cargo.toml deleted file mode 100644 index dfc5c3de3d..0000000000 --- a/lib/cli-compiler/Cargo.toml +++ /dev/null @@ -1,83 +0,0 @@ -[package] -name = "wasmer-compiler-cli" -description = "Wasmer Compiler CLI" -categories = ["wasm", "command-line-interface"] -keywords = ["wasm", "webassembly", "cli"] -readme = "README.md" -default-run = "wasmer-compiler" -build = "build.rs" -authors.workspace = true -edition.workspace = true -homepage.workspace = true -license.workspace = true -repository.workspace = true -rust-version.workspace = true -version.workspace = true - -[[bin]] -name = "wasmer-compiler" -path = "src/bin/wasmer_compiler.rs" -doc = false - -[dependencies] -wasmer-compiler = { version = "=6.1.0", path = "../compiler", features = [ - "compiler", -] } -wasmer-types = { version = "=6.1.0", path = "../types", features = ["detect-wasm-features"] } -is-terminal = "0.4.7" -colored = "2.0" -anyhow.workspace = true -# For the function names autosuggestion -distance = "0.4" -# For the inspect subcommand -bytesize = "1.0" -cfg-if.workspace = true -# For debug feature -fern = { version = "0.6", features = ["colored"], optional = true } -log = { workspace = true, optional = true } -target-lexicon = { workspace = true, features = ["std"] } - -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -wasmer-compiler-singlepass = { version = "=6.1.0", path = "../compiler-singlepass", optional = true } -wasmer-compiler-cranelift = { version = "=6.1.0", path = "../compiler-cranelift", optional = true } -wasmer-compiler-llvm = { version = "=6.1.0", path = "../compiler-llvm", optional = true } -clap = { version = "4.4.0", features = ["derive", "env"] } - -[target.'cfg(target_arch = "wasm32")'.dependencies] -wasmer-compiler-singlepass = { version = "=6.1.0", path = "../compiler-singlepass", optional = true, default-features = false, features = [ - "wasm", -] } -wasmer-compiler-cranelift = { version = "=6.1.0", path = "../compiler-cranelift", optional = true, default-features = false, features = [ - "wasm", -] } -wasmer-compiler-llvm = { version = "=6.1.0", path = "../compiler-llvm", optional = true, default-features = false, features = [] } -# NOTE: Must use different features for clap because the "color" feature does not -# work on wasi, due to the anstream dependency not compiling. -clap = { version = "4.4.0", default-features = false, features = [ - "std", - "help", - "usage", - "error-context", - "suggestions", - "derive", - "env", -] } - -[target.'cfg(target_os = "linux")'.dependencies] -unix_mode = "0.1.3" - -[features] -# Don't add the compiler features in default, please add them on the Makefile -# since we might want to autoconfigure them depending on the availability on the host. -default = [] -engine = [] -compiler = ["wasmer-compiler/translator", "wasmer-compiler/compiler"] -singlepass = ["wasmer-compiler-singlepass", "compiler"] -cranelift = ["wasmer-compiler-cranelift", "compiler"] -debug = ["fern", "log"] -disable-all-logging = [] -jit = [] -llvm = ["wasmer-compiler-llvm"] - -[package.metadata.docs.rs] -rustc-args = ["--cfg", "docsrs"] diff --git a/lib/cli-compiler/README.md b/lib/cli-compiler/README.md deleted file mode 100644 index a4cba6cee9..0000000000 --- a/lib/cli-compiler/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# `wasmer-cli-compiler` -[![Build Status](https://github.com/wasmerio/wasmer/actions/workflows/build.yml/badge.svg?style=flat-square)](https://github.com/wasmerio/wasmer/actions?query=workflow%3Abuild) [![Join Wasmer Slack](https://img.shields.io/static/v1?label=Slack&message=join%20chat&color=brighgreen&style=flat-square)](https://slack.wasmer.io) [![MIT License](https://img.shields.io/github/license/wasmerio/wasmer.svg?style=flat-square)](https://github.com/wasmerio/wasmer/blob/main/LICENSE) - -This crate is the Wasmer Compiler only CLI. - - -## Features - -The Compiler only Wasmer supports the following features: -* `wasi` (default): support for [WASI]. -* `singlepass`: support for the [Singlepass compiler]. - -[WASI]: https://github.com/wasmerio/wasmer/tree/main/lib/wasi/ -[Singlepass compiler]: https://github.com/wasmerio/wasmer/tree/main/lib/compiler-singlepass/ - -## CLI commands - -Once you have Wasmer installed, you can start executing WebAssembly files easily: - -Get the current Wasmer version: - -```bash -wasmer-compiler -V -``` - -Compile a WebAssembly file: - -```bash -wasmer-compiler compile myfile.wasm -o myfile.wasmu --singlepass -``` diff --git a/lib/cli-compiler/build.rs b/lib/cli-compiler/build.rs deleted file mode 100644 index 36fe64763e..0000000000 --- a/lib/cli-compiler/build.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub fn main() { - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-env-changed=WASMER_INSTALL_PREFIX"); -} diff --git a/lib/cli-compiler/src/bin/wasmer_compiler.rs b/lib/cli-compiler/src/bin/wasmer_compiler.rs deleted file mode 100644 index c61d074130..0000000000 --- a/lib/cli-compiler/src/bin/wasmer_compiler.rs +++ /dev/null @@ -1,5 +0,0 @@ -use wasmer_compiler_cli::cli::wasmer_main; - -fn main() { - wasmer_main(); -} diff --git a/lib/cli-compiler/src/cli.rs b/lib/cli-compiler/src/cli.rs deleted file mode 100644 index c67e2df89f..0000000000 --- a/lib/cli-compiler/src/cli.rs +++ /dev/null @@ -1,75 +0,0 @@ -//! The logic for the Wasmer CLI tool. - -use crate::commands::Compile; -use crate::commands::{Config, Validate}; -use crate::error::PrettyError; -use anyhow::Result; - -use clap::{error::ErrorKind, Parser}; - -#[derive(Parser)] -#[clap( - name = "wasmer-compiler", - about = "WebAssembly standalone Compiler.", - author -)] -/// The options for the wasmer Command Line Interface -enum WasmerCLIOptions { - /// Validate a WebAssembly binary - #[clap(name = "validate")] - Validate(Validate), - - /// Compile a WebAssembly binary - #[clap(name = "compile")] - Compile(Compile), - - /// Get various configuration information needed - /// to compile programs which use Wasmer - #[clap(name = "config")] - Config(Config), -} - -impl WasmerCLIOptions { - fn execute(&self) -> Result<()> { - match self { - Self::Validate(validate) => validate.execute(), - Self::Compile(compile) => compile.execute(), - Self::Config(config) => config.execute(), - } - } -} - -/// The main function for the Wasmer CLI tool. -pub fn wasmer_main() { - // We allow windows to print properly colors - #[cfg(windows)] - colored::control::set_virtual_terminal(true).unwrap(); - - // We try to run wasmer with the normal arguments. - // Eg. `wasmer ` - // In case that fails, we fallback trying the Run subcommand directly. - // Eg. `wasmer myfile.wasm --dir=.` - // - // In case we've been run as wasmer-binfmt-interpreter myfile.wasm args, - // we assume that we're registered via binfmt_misc - let args = std::env::args().collect::>(); - let command = args.get(1); - let options = { - match command.unwrap_or(&"".to_string()).as_ref() { - "compile" | "config" | "help" | "inspect" | "validate" => WasmerCLIOptions::parse(), - _ => { - WasmerCLIOptions::try_parse_from(args.iter()).unwrap_or_else(|e| { - match e.kind() { - // This fixes a issue that: - // 1. Shows the version twice when doing `wasmer -V` - // 2. Shows the run help (instead of normal help) when doing `wasmer --help` - ErrorKind::DisplayVersion | ErrorKind::DisplayHelp => e.exit(), - _ => WasmerCLIOptions::Compile(Compile::parse()), - } - }) - } - } - }; - - PrettyError::report(options.execute()); -} diff --git a/lib/cli-compiler/src/commands.rs b/lib/cli-compiler/src/commands.rs deleted file mode 100644 index 74418834fa..0000000000 --- a/lib/cli-compiler/src/commands.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! The commands available in the Wasmer binary. -mod compile; -mod config; -mod validate; - -pub use compile::*; -pub use {config::*, validate::*}; diff --git a/lib/cli-compiler/src/commands/compile.rs b/lib/cli-compiler/src/commands/compile.rs deleted file mode 100644 index 50c69649c5..0000000000 --- a/lib/cli-compiler/src/commands/compile.rs +++ /dev/null @@ -1,119 +0,0 @@ -use crate::store::StoreOptions; -use crate::warning; -use anyhow::{Context, Result}; -use clap::Parser; -use std::fs; -use std::path::{Path, PathBuf}; -use wasmer_compiler::{ArtifactBuild, ArtifactCreate, ModuleEnvironment}; -use wasmer_types::entity::PrimaryMap; -use wasmer_types::target::{Architecture, CpuFeature, Target, Triple}; -use wasmer_types::{CompileError, MemoryIndex, MemoryStyle, TableIndex, TableStyle}; - -#[derive(Debug, Parser)] -/// The options for the `wasmer compile` subcommand -pub struct Compile { - /// Input file - #[clap(name = "FILE")] - path: PathBuf, - - /// Output file - #[clap(name = "OUTPUT PATH", short = 'o')] - output: PathBuf, - - /// Compilation Target triple - #[clap(long = "target")] - target_triple: Option, - - #[clap(flatten)] - store: StoreOptions, - - #[clap(short = 'm')] - cpu_features: Vec, -} - -impl Compile { - /// Runs logic for the `compile` subcommand - pub fn execute(&self) -> Result<()> { - self.inner_execute() - .context(format!("failed to compile `{}`", self.path.display())) - } - - fn inner_execute(&self) -> Result<()> { - let target = self - .target_triple - .as_ref() - .map(|target_triple| { - let mut features = self - .cpu_features - .clone() - .into_iter() - .fold(CpuFeature::set(), |a, b| a | b); - // Cranelift requires SSE2, so we have this "hack" for now to facilitate - // usage - if target_triple.architecture == Architecture::X86_64 { - features |= CpuFeature::SSE2; - } - Target::new(target_triple.clone(), features) - }) - .unwrap_or_default(); - let (engine_builder, compiler_type) = self.store.get_engine_for_target(target.clone())?; - let engine = engine_builder - .set_hash_algorithm(Some(wasmer_types::HashAlgorithm::Sha256)) - .engine(); - let output_filename = self - .output - .file_stem() - .map(|osstr| osstr.to_string_lossy().to_string()) - .unwrap_or_default(); - // `.wasmu` is the default extension for all the triples. It - // stands for “Wasm Universal”. - let recommended_extension = "wasmu"; - match self.output.extension() { - Some(ext) => { - if ext != recommended_extension { - warning!("the output file has a wrong extension. We recommend using `{}.{}` for the chosen target", &output_filename, &recommended_extension) - } - } - None => { - warning!("the output file has no extension. We recommend using `{}.{}` for the chosen target", &output_filename, &recommended_extension) - } - } - let tunables = self.store.get_tunables_for_target(&target)?; - - println!("Compiler: {compiler_type}"); - println!("Target: {}", target.triple()); - - // compile and save the artifact (without using module from api) - let path: &Path = self.path.as_ref(); - let wasm_bytes = std::fs::read(path)?; - let environ = ModuleEnvironment::new(); - let translation = environ.translate(&wasm_bytes).map_err(CompileError::Wasm)?; - let module = translation.module; - let memory_styles: PrimaryMap = module - .memories - .values() - .map(|memory_type| tunables.memory_style(memory_type)) - .collect(); - let table_styles: PrimaryMap = module - .tables - .values() - .map(|table_type| tunables.table_style(table_type)) - .collect(); - let artifact = ArtifactBuild::new( - &mut engine.inner_mut(), - &wasm_bytes, - &target, - memory_styles, - table_styles, - engine.hash_algorithm(), - )?; - let serialized = artifact.serialize()?; - fs::write(output_filename, serialized)?; - eprintln!( - "✔ File compiled successfully to `{}`.", - self.output.display(), - ); - - Ok(()) - } -} diff --git a/lib/cli-compiler/src/commands/config.rs b/lib/cli-compiler/src/commands/config.rs deleted file mode 100644 index 81d562f027..0000000000 --- a/lib/cli-compiler/src/commands/config.rs +++ /dev/null @@ -1,106 +0,0 @@ -use crate::VERSION; -use anyhow::{Context, Result}; -use clap::Parser; -use std::env; -use std::path::PathBuf; - -#[derive(Debug, Parser)] -/// The options for the `wasmer config` subcommand -pub struct Config { - /// Print the installation prefix. - #[clap(long, conflicts_with = "pkg_config")] - prefix: bool, - - /// Directory containing Wasmer executables. - #[clap(long, conflicts_with = "pkg_config")] - bindir: bool, - - /// Directory containing Wasmer headers. - #[clap(long, conflicts_with = "pkg_config")] - includedir: bool, - - /// Directory containing Wasmer libraries. - #[clap(long, conflicts_with = "pkg_config")] - libdir: bool, - - /// Libraries needed to link against Wasmer components. - #[clap(long, conflicts_with = "pkg_config")] - libs: bool, - - /// C compiler flags for files that include Wasmer headers. - #[clap(long, conflicts_with = "pkg_config")] - cflags: bool, - - /// It outputs the necessary details for compiling - /// and linking a program to Wasmer, using the `pkg-config` format. - #[clap(long)] - pkg_config: bool, -} - -impl Config { - /// Runs logic for the `config` subcommand - pub fn execute(&self) -> Result<()> { - self.inner_execute() - .context("failed to retrieve the wasmer config".to_string()) - } - fn inner_execute(&self) -> Result<()> { - let key = "WASMER_DIR"; - let wasmer_dir = env::var(key) - .ok() - .or_else(|| option_env!("WASMER_INSTALL_PREFIX").map(str::to_string)) - .or_else(|| { - // Allowing deprecated function home_dir since it works fine, - // and will never be removed from std. - #[allow(deprecated)] - let dir = std::env::home_dir()?.join(".wasmer").to_str()?.to_string(); - - Some(dir) - }) - .context(format!( - "failed to retrieve the {key} environment variables", - ))?; - - let prefix = PathBuf::from(wasmer_dir); - - let prefixdir = prefix.display().to_string(); - let bindir = prefix.join("bin").display().to_string(); - let includedir = prefix.join("include").display().to_string(); - let libdir = prefix.join("lib").display().to_string(); - let cflags = format!("-I{includedir}"); - let libs = format!("-L{libdir} -lwasmer"); - - if self.pkg_config { - println!("prefix={prefixdir}"); - println!("exec_prefix={bindir}"); - println!("includedir={includedir}"); - println!("libdir={libdir}"); - println!(); - println!("Name: wasmer"); - println!("Description: The Wasmer library for running WebAssembly"); - println!("Version: {VERSION}"); - println!("Cflags: {cflags}"); - println!("Libs: {libs}"); - return Ok(()); - } - - if self.prefix { - println!("{prefixdir}"); - } - if self.bindir { - println!("{bindir}"); - } - if self.includedir { - println!("{includedir}"); - } - if self.libdir { - println!("{libdir}"); - } - if self.libs { - println!("{libs}"); - } - if self.cflags { - println!("{cflags}"); - } - Ok(()) - } -} diff --git a/lib/cli-compiler/src/commands/validate.rs b/lib/cli-compiler/src/commands/validate.rs deleted file mode 100644 index 024d3791c2..0000000000 --- a/lib/cli-compiler/src/commands/validate.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::store::StoreOptions; -use anyhow::{bail, Context, Result}; -use clap::Parser; -use std::path::PathBuf; -use std::str::FromStr; -use wasmer_types::is_wasm; -use wasmer_types::target::{CpuFeature, Target, Triple}; - -#[derive(Debug, Parser)] -/// The options for the `wasmer validate` subcommand -pub struct Validate { - /// File to validate as WebAssembly - #[clap(name = "FILE")] - path: PathBuf, - - #[clap(flatten)] - store: StoreOptions, -} - -impl Validate { - /// Runs logic for the `validate` subcommand - pub fn execute(&self) -> Result<()> { - self.inner_execute() - .context(format!("failed to validate `{}`", self.path.display())) - } - fn inner_execute(&self) -> Result<()> { - let target = Target::new( - Triple::from_str("x86_64-linux-gnu").unwrap(), - CpuFeature::SSE2 | CpuFeature::AVX, - ); - let (engine_builder, _compiler_type) = self.store.get_engine_for_target(target)?; - let engine = engine_builder.engine(); - let module_contents = std::fs::read(&self.path)?; - if !is_wasm(&module_contents) { - bail!("`wasmer validate` only validates WebAssembly files"); - } - engine.validate(&module_contents)?; - eprintln!("Validation passed for `{}`.", self.path.display()); - Ok(()) - } -} diff --git a/lib/cli-compiler/src/common.rs b/lib/cli-compiler/src/common.rs deleted file mode 100644 index 81af03197c..0000000000 --- a/lib/cli-compiler/src/common.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! Common module with common used structures across different -//! commands. -use crate::VERSION; -use clap::Parser; -use std::env; -use std::path::PathBuf; - -#[derive(Debug, Parser, Clone, Default)] -/// The WebAssembly features that can be passed through the -/// Command Line args. -pub struct WasmFeatures { - /// Enable support for the SIMD proposal. - #[clap(long = "enable-simd")] - pub simd: bool, - - /// Enable support for the threads proposal. - #[clap(long = "enable-threads")] - pub threads: bool, - - /// Enable support for the reference types proposal. - #[clap(long = "enable-reference-types")] - pub reference_types: bool, - - /// Enable support for the multi value proposal. - #[clap(long = "enable-multi-value")] - pub multi_value: bool, - - /// Enable support for the bulk memory proposal. - #[clap(long = "enable-bulk-memory")] - pub bulk_memory: bool, - - /// Enable support for all pre-standard proposals. - #[clap(long = "enable-all")] - pub all: bool, -} - -/// Get the cache dir -pub fn get_cache_dir() -> PathBuf { - match env::var("WASMER_CACHE_DIR") { - Ok(dir) => { - let mut path = PathBuf::from(dir); - path.push(VERSION); - path - } - Err(_) => { - // We use a temporal directory for saving cache files - let mut temp_dir = env::temp_dir(); - temp_dir.push("wasmer"); - temp_dir.push(VERSION); - temp_dir - } - } -} diff --git a/lib/cli-compiler/src/error.rs b/lib/cli-compiler/src/error.rs deleted file mode 100644 index d1aa39a526..0000000000 --- a/lib/cli-compiler/src/error.rs +++ /dev/null @@ -1,114 +0,0 @@ -//! Implements `PretyError` to print pretty errors in the CLI (when they happen) - -use anyhow::{Chain, Error}; -use colored::*; -use std::fmt::{self, Debug, Write}; - -/// A `PrettyError` for printing `anyhow::Error` nicely. -pub struct PrettyError { - error: Error, -} - -/// A macro that prints a warning with nice colors -#[macro_export] -macro_rules! warning { - ($($arg:tt)*) => ({ - use colored::*; - eprintln!("{}: {}", "warning".yellow().bold(), format!($($arg)*)); - }) -} - -impl PrettyError { - /// Process a `Result` printing any errors and exiting - /// the process after - pub fn report(result: Result) -> ! { - std::process::exit(match result { - Ok(_t) => 0, - Err(error) => { - eprintln!("{:?}", PrettyError { error }); - 1 - } - }); - } -} - -impl Debug for PrettyError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let error = &self.error; - - if f.alternate() { - return Debug::fmt(&error, f); - } - - write!(f, "{}", format!("{}: {}", "error".red(), error).bold())?; - // write!(f, "{}", error)?; - - if let Some(cause) = error.source() { - // write!(f, "\n{}:", "caused by".bold().blue())?; - let chain = Chain::new(cause); - let (total_errors, _) = chain.size_hint(); - for (n, error) in chain.enumerate() { - writeln!(f)?; - let mut indented = Indented { - inner: f, - number: Some(n + 1), - is_last: n == total_errors - 1, - started: false, - }; - write!(indented, "{error}")?; - } - } - Ok(()) - } -} - -struct Indented<'a, D> { - inner: &'a mut D, - number: Option, - started: bool, - is_last: bool, -} - -impl Write for Indented<'_, T> -where - T: Write, -{ - fn write_str(&mut self, s: &str) -> fmt::Result { - for (i, line) in s.split('\n').enumerate() { - if !self.started { - self.started = true; - match self.number { - Some(number) => { - if !self.is_last { - write!( - self.inner, - "{} {: >4} ", - "│".bold().blue(), - format!("{number}:").dimmed() - )? - } else { - write!( - self.inner, - "{}{: >2}: ", - "╰─▶".bold().blue(), - format!("{number}").bold().blue() - )? - } - } - None => self.inner.write_str(" ")?, - } - } else if i > 0 { - self.inner.write_char('\n')?; - if self.number.is_some() { - self.inner.write_str(" ")?; - } else { - self.inner.write_str(" ")?; - } - } - - self.inner.write_str(line)?; - } - - Ok(()) - } -} diff --git a/lib/cli-compiler/src/lib.rs b/lib/cli-compiler/src/lib.rs deleted file mode 100644 index 7ee91dacca..0000000000 --- a/lib/cli-compiler/src/lib.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! The Wasmer binary lib - -#![deny( - missing_docs, - dead_code, - nonstandard_style, - unused_mut, - unused_variables, - unused_unsafe, - unreachable_patterns -)] -#![doc(html_favicon_url = "https://wasmer.io/images/icons/favicon-32x32.png")] -#![doc(html_logo_url = "https://github.com/wasmerio.png?size=200")] -#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] - -#[macro_use] -extern crate anyhow; - -pub mod commands; -pub mod common; -#[macro_use] -pub mod error; -pub mod cli; -#[cfg(feature = "debug")] -pub mod logging; -pub mod store; -pub mod utils; - -/// Version number of this crate. -pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/lib/cli-compiler/src/logging.rs b/lib/cli-compiler/src/logging.rs deleted file mode 100644 index 88ae282d80..0000000000 --- a/lib/cli-compiler/src/logging.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Logging functions for the debug feature. - -use anyhow::Result; -use fern::colors::{Color, ColoredLevelConfig}; -use std::time; - -/// The debug level -pub type DebugLevel = log::LevelFilter; - -/// Subroutine to instantiate the loggers -pub fn set_up_logging(verbose: u8) -> Result<(), String> { - let colors_line = ColoredLevelConfig::new() - .error(Color::Red) - .warn(Color::Yellow) - .trace(Color::BrightBlack); - let should_color = crate::utils::wasmer_should_print_color(); - - let colors_level = colors_line.info(Color::Green); - let level = match verbose { - 1 => DebugLevel::Debug, - _ => DebugLevel::Trace, - }; - let dispatch = fern::Dispatch::new() - .level(level) - .chain({ - let base = if should_color { - fern::Dispatch::new().format(move |out, message, record| { - let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH).expect("Can't get time"); - out.finish(format_args!( - "{color_line}[{seconds}.{millis} {level} {target}{color_line}]{ansi_close} {message}", - color_line = format_args!( - "\x1B[{}m", - colors_line.get_color(&record.level()).to_fg_str() - ), - seconds = time.as_secs(), - millis = time.subsec_millis(), - level = colors_level.color(record.level()), - target = record.target(), - ansi_close = "\x1B[0m", - message = message, - )); - }) - } else { - // default formatter without color - fern::Dispatch::new().format(move |out, message, record| { - let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH).expect("Can't get time"); - out.finish(format_args!( - "[{seconds}.{millis} {level} {target}] {message}", - seconds = time.as_secs(), - millis = time.subsec_millis(), - level = record.level(), - target = record.target(), - message = message, - )); - }) - }; - - base - .filter(|metadata| { - metadata.target().starts_with("wasmer") - }) - .chain(std::io::stdout()) - }); - - dispatch.apply().map_err(|e| format!("{}", e))?; - - Ok(()) -} diff --git a/lib/cli-compiler/src/store.rs b/lib/cli-compiler/src/store.rs deleted file mode 100644 index 9d2c0bb372..0000000000 --- a/lib/cli-compiler/src/store.rs +++ /dev/null @@ -1,407 +0,0 @@ -//! Common module with common used structures across different -//! commands. - -use crate::common::WasmFeatures; -use anyhow::Result; -use clap::Parser; -#[cfg(doc)] -use std::path::PathBuf; -use std::string::ToString; -#[allow(unused_imports)] -use std::sync::Arc; -use wasmer_compiler::{CompilerConfig, EngineBuilder, Features}; -use wasmer_types::target::{PointerWidth, Target}; -#[cfg(doc)] -use wasmer_types::Type; -use wasmer_types::{MemoryStyle, MemoryType, Pages, TableStyle, TableType}; - -/// Minimul Subset of Tunable parameters for WebAssembly compilation. -#[derive(Clone)] -pub struct SubsetTunables { - /// For static heaps, the size in wasm pages of the heap protected by bounds checking. - pub static_memory_bound: Pages, - - /// The size in bytes of the offset guard for static heaps. - pub static_memory_offset_guard_size: u64, - - /// The size in bytes of the offset guard for dynamic heaps. - pub dynamic_memory_offset_guard_size: u64, -} - -impl SubsetTunables { - /// Get the `BaseTunables` for a specific Target - pub fn for_target(target: &Target) -> Self { - let triple = target.triple(); - let pointer_width: PointerWidth = triple.pointer_width().unwrap(); - let (static_memory_bound, static_memory_offset_guard_size): (Pages, u64) = - match pointer_width { - PointerWidth::U16 => (0x400.into(), 0x1000), - PointerWidth::U32 => (0x4000.into(), 0x1_0000), - // Static Memory Bound: - // Allocating 4 GiB of address space let us avoid the - // need for explicit bounds checks. - // Static Memory Guard size: - // Allocating 2 GiB of address space lets us translate wasm - // offsets into x86 offsets as aggressively as we can. - PointerWidth::U64 => (0x1_0000.into(), 0x8000_0000), - }; - - // Allocate a small guard to optimize common cases but without - // wasting too much memory. - // The Windows memory manager seems more laxed than the other ones - // And a guard of just 1 page may not be enough is some borderline cases - // So using 2 pages for guard on this platform - #[cfg(target_os = "windows")] - let dynamic_memory_offset_guard_size: u64 = 0x2_0000; - #[cfg(not(target_os = "windows"))] - let dynamic_memory_offset_guard_size: u64 = 0x1_0000; - - Self { - static_memory_bound, - static_memory_offset_guard_size, - dynamic_memory_offset_guard_size, - } - } - /// Get a `MemoryStyle` for the provided `MemoryType` - pub fn memory_style(&self, memory: &MemoryType) -> MemoryStyle { - // A heap with a maximum that doesn't exceed the static memory bound specified by the - // tunables make it static. - // - // If the module doesn't declare an explicit maximum treat it as 4GiB. - let maximum = memory.maximum.unwrap_or_else(Pages::max_value); - if maximum <= self.static_memory_bound { - MemoryStyle::Static { - // Bound can be larger than the maximum for performance reasons - bound: self.static_memory_bound, - offset_guard_size: self.static_memory_offset_guard_size, - } - } else { - MemoryStyle::Dynamic { - offset_guard_size: self.dynamic_memory_offset_guard_size, - } - } - } - - /// Get a [`TableStyle`] for the provided [`TableType`]. - pub fn table_style(&self, _table: &TableType) -> TableStyle { - TableStyle::CallerChecksSignature - } -} - -#[derive(Debug, Clone, Parser, Default)] -/// The compiler and engine options -pub struct StoreOptions { - #[clap(flatten)] - compiler: CompilerOptions, -} - -#[derive(Debug, Clone, Parser, Default)] -/// The compiler options -pub struct CompilerOptions { - /// Use Singlepass compiler. - #[clap(long, conflicts_with_all = &["cranelift", "llvm"])] - singlepass: bool, - - /// Use Cranelift compiler. - #[clap(long, conflicts_with_all = &["singlepass", "llvm"])] - cranelift: bool, - - /// Use LLVM compiler. - #[clap(long, conflicts_with_all = &["singlepass", "cranelift"])] - llvm: bool, - - /// Enable compiler internal verification. - #[allow(unused)] - #[clap(long)] - #[allow(dead_code)] - enable_verifier: bool, - - /// LLVM debug directory, where IR and object files will be written to. - #[allow(unused)] - #[cfg(feature = "llvm")] - #[cfg_attr(feature = "llvm", clap(long, parse(from_os_str)))] - llvm_debug_dir: Option, - - #[clap(flatten)] - features: WasmFeatures, -} - -impl CompilerOptions { - fn get_compiler(&self) -> Result { - if self.cranelift { - Ok(CompilerType::Cranelift) - } else if self.llvm { - Ok(CompilerType::LLVM) - } else if self.singlepass { - Ok(CompilerType::Singlepass) - } else { - // Auto mode, we choose the best compiler for that platform - cfg_if::cfg_if! { - if #[cfg(all(feature = "cranelift", any(target_arch = "x86_64", target_arch = "aarch64")))] { - Ok(CompilerType::Cranelift) - } - else if #[cfg(all(feature = "singlepass", any(target_arch = "x86_64", target_arch = "aarch64")))] { - Ok(CompilerType::Singlepass) - } - else if #[cfg(feature = "llvm")] { - Ok(CompilerType::LLVM) - } else { - bail!("There are no available compilers for your architecture"); - } - } - } - } - - /// Get the enaled Wasm features. - pub fn get_features(&self, mut features: Features) -> Result { - if self.features.threads || self.features.all { - features.threads(true); - } - if self.features.multi_value || self.features.all { - features.multi_value(true); - } - if self.features.simd || self.features.all { - features.simd(true); - } - if self.features.bulk_memory || self.features.all { - features.bulk_memory(true); - } - if self.features.reference_types || self.features.all { - features.reference_types(true); - } - Ok(features) - } - - fn get_engine_by_type( - &self, - target: Target, - compiler_config: Box, - ) -> Result { - let features = self.get_features(compiler_config.default_features_for_target(&target))?; - let engine: EngineBuilder = EngineBuilder::new(compiler_config) - .set_target(Some(target)) - .set_features(Some(features)); - - Ok(engine) - } - - /// Get the Compiler Config for the current options - #[allow(unused_variables)] - pub(crate) fn get_compiler_config(&self) -> Result<(Box, CompilerType)> { - let compiler = self.get_compiler()?; - let compiler_config: Box = match compiler { - CompilerType::Headless => bail!("The headless engine can't be chosen"), - #[cfg(feature = "singlepass")] - CompilerType::Singlepass => { - let mut config = wasmer_compiler_singlepass::Singlepass::new(); - if self.enable_verifier { - config.enable_verifier(); - } - Box::new(config) - } - #[cfg(feature = "cranelift")] - CompilerType::Cranelift => { - let mut config = wasmer_compiler_cranelift::Cranelift::new(); - if self.enable_verifier { - config.enable_verifier(); - } - Box::new(config) - } - #[cfg(feature = "llvm")] - CompilerType::LLVM => { - use std::fmt; - use std::fs::File; - use std::io::Write; - use wasmer_compiler_llvm::{ - CompiledKind, InkwellMemoryBuffer, InkwellModule, LLVMCallbacks, - }; - use wasmer_types::entity::EntityRef; - let mut config = LLVM::new(); - struct Callbacks { - debug_dir: PathBuf, - } - impl Callbacks { - fn new(debug_dir: PathBuf) -> Result { - // Create the debug dir in case it doesn't exist - std::fs::create_dir_all(&debug_dir)?; - Ok(Self { debug_dir }) - } - } - // Converts a kind into a filename, that we will use to dump - // the contents of the IR object file to. - fn types_to_signature(types: &[Type]) -> String { - types - .iter() - .map(|ty| match ty { - Type::I32 => "i".to_string(), - Type::I64 => "I".to_string(), - Type::F32 => "f".to_string(), - Type::F64 => "F".to_string(), - Type::V128 => "v".to_string(), - Type::ExternRef => "e".to_string(), - Type::FuncRef => "r".to_string(), - }) - .collect::>() - .join("") - } - // Converts a kind into a filename, that we will use to dump - // the contents of the IR object file to. - fn function_kind_to_filename(kind: &CompiledKind) -> String { - match kind { - CompiledKind::Local(local_index) => { - format!("function_{}", local_index.index()) - } - CompiledKind::FunctionCallTrampoline(func_type) => format!( - "trampoline_call_{}_{}", - types_to_signature(&func_type.params()), - types_to_signature(&func_type.results()) - ), - CompiledKind::DynamicFunctionTrampoline(func_type) => format!( - "trampoline_dynamic_{}_{}", - types_to_signature(&func_type.params()), - types_to_signature(&func_type.results()) - ), - CompiledKind::Module => "module".into(), - } - } - impl LLVMCallbacks for Callbacks { - fn preopt_ir(&self, kind: &CompiledKind, module: &InkwellModule) { - let mut path = self.debug_dir.clone(); - path.push(format!("{}.preopt.ll", function_kind_to_filename(kind))); - module - .print_to_file(&path) - .expect("Error while dumping pre optimized LLVM IR"); - } - fn postopt_ir(&self, kind: &CompiledKind, module: &InkwellModule) { - let mut path = self.debug_dir.clone(); - path.push(format!("{}.postopt.ll", function_kind_to_filename(kind))); - module - .print_to_file(&path) - .expect("Error while dumping post optimized LLVM IR"); - } - fn obj_memory_buffer( - &self, - kind: &CompiledKind, - memory_buffer: &InkwellMemoryBuffer, - ) { - let mut path = self.debug_dir.clone(); - path.push(format!("{}.o", function_kind_to_filename(kind))); - let mem_buf_slice = memory_buffer.as_slice(); - let mut file = File::create(path) - .expect("Error while creating debug object file from LLVM IR"); - let mut pos = 0; - while pos < mem_buf_slice.len() { - pos += file.write(&mem_buf_slice[pos..]).unwrap(); - } - } - - fn asm_memory_buffer( - &self, - kind: &CompiledKind, - asm_memory_buffer: &InkwellMemoryBuffer, - ) { - let mut path = self.debug_dir.clone(); - path.push(format!("{}.s", function_kind_to_filename(kind))); - let mem_buf_slice = asm_memory_buffer.as_slice(); - let mut file = File::create(path) - .expect("Error while creating debug object file from LLVM IR"); - let mut pos = 0; - while pos < mem_buf_slice.len() { - pos += file.write(&mem_buf_slice[pos..]).unwrap(); - } - } - } - - impl fmt::Debug for Callbacks { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "LLVMCallbacks") - } - } - - if let Some(ref llvm_debug_dir) = self.llvm_debug_dir { - config.callbacks(Some(Arc::new(Callbacks::new(llvm_debug_dir.clone())?))); - } - if self.enable_verifier { - config.enable_verifier(); - } - Box::new(config) - } - #[cfg(not(all(feature = "singlepass", feature = "cranelift", feature = "llvm")))] - compiler => { - bail!( - "The `{}` compiler is not included in this binary.", - compiler.to_string() - ) - } - }; - - #[allow(unreachable_code)] - Ok((compiler_config, compiler)) - } -} - -/// The compiler used for the store -#[derive(Debug, PartialEq, Eq)] -pub enum CompilerType { - /// Singlepass compiler - Singlepass, - /// Cranelift compiler - Cranelift, - /// LLVM compiler - LLVM, - /// Headless compiler - #[allow(dead_code)] - Headless, -} - -impl CompilerType { - /// Return all enabled compilers - pub fn enabled() -> Vec { - vec![ - #[cfg(feature = "singlepass")] - Self::Singlepass, - #[cfg(feature = "cranelift")] - Self::Cranelift, - #[cfg(feature = "llvm")] - Self::LLVM, - ] - } -} - -impl std::fmt::Display for CompilerType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - match self { - Self::Singlepass => "singlepass", - Self::Cranelift => "cranelift", - Self::LLVM => "llvm", - Self::Headless => "headless", - } - ) - } -} - -impl StoreOptions { - /// Get a EngineBulder for the Target - pub fn get_engine_for_target(&self, target: Target) -> Result<(EngineBuilder, CompilerType)> { - let (compiler_config, compiler_type) = self.compiler.get_compiler_config()?; - let engine = self.get_engine_with_compiler(target, compiler_config)?; - Ok((engine, compiler_type)) - } - - fn get_engine_with_compiler( - &self, - target: Target, - compiler_config: Box, - ) -> Result { - self.compiler.get_engine_by_type(target, compiler_config) - } - - /// Get (Subset)Tunables for the Target - pub fn get_tunables_for_target(&self, target: &Target) -> Result { - let tunables = SubsetTunables::for_target(target); - Ok(tunables) - } -} diff --git a/lib/cli-compiler/src/utils.rs b/lib/cli-compiler/src/utils.rs deleted file mode 100644 index 7a4a925460..0000000000 --- a/lib/cli-compiler/src/utils.rs +++ /dev/null @@ -1,97 +0,0 @@ -//! Utility functions for the WebAssembly module -use anyhow::{bail, Context, Result}; -use is_terminal::IsTerminal; -use std::path::PathBuf; -use std::{env, path::Path}; - -/// Whether or not Wasmer should print with color -pub fn wasmer_should_print_color() -> bool { - env::var("WASMER_COLOR") - .ok() - .and_then(|inner| inner.parse::().ok()) - .unwrap_or_else(|| std::io::stdout().is_terminal()) -} - -fn retrieve_alias_pathbuf(alias: &str, real_dir: &str) -> Result<(String, PathBuf)> { - let pb = Path::new(real_dir) - .canonicalize() - .with_context(|| format!("Unable to get the absolute path for \"{real_dir}\""))?; - - if let Ok(pb_metadata) = pb.metadata() { - if !pb_metadata.is_dir() { - bail!("\"{real_dir}\" exists, but it is not a directory"); - } - } else { - bail!("Directory \"{real_dir}\" does not exist"); - } - - Ok((alias.to_string(), pb)) -} - -/// Parses a mapdir from a string -pub fn parse_mapdir(entry: &str) -> Result<(String, PathBuf)> { - // We try first splitting by `::` - if let [alias, real_dir] = entry.split("::").collect::>()[..] { - retrieve_alias_pathbuf(alias, real_dir) - } - // And then we try splitting by `:` (for compatibility with previous API) - else if let [alias, real_dir] = entry.split(':').collect::>()[..] { - retrieve_alias_pathbuf(alias, real_dir) - } else { - bail!( - "Directory mappings must consist of two paths separate by a `::` or `:`. Found {}", - &entry - ) - } -} - -/// Parses an environment variable. -pub fn parse_envvar(entry: &str) -> Result<(String, String)> { - let entry = entry.trim(); - - match entry.find('=') { - None => bail!( - "Environment variable must be of the form `=`; found `{}`", - &entry - ), - - Some(0) => bail!( - "Environment variable is not well formed, the `name` is missing in `=`; got `{}`", - &entry - ), - - Some(position) if position == entry.len() - 1 => bail!( - "Environment variable is not well formed, the `value` is missing in `=`; got `{}`", - &entry - ), - - Some(position) => Ok((entry[..position].into(), entry[position + 1..].into())), - } -} - -#[cfg(test)] -mod tests { - use super::parse_envvar; - - #[test] - fn test_parse_envvar() { - assert_eq!( - parse_envvar("A").unwrap_err().to_string(), - "Environment variable must be of the form `=`; found `A`" - ); - assert_eq!( - parse_envvar("=A").unwrap_err().to_string(), - "Environment variable is not well formed, the `name` is missing in `=`; got `=A`" - ); - assert_eq!( - parse_envvar("A=").unwrap_err().to_string(), - "Environment variable is not well formed, the `value` is missing in `=`; got `A=`" - ); - assert_eq!(parse_envvar("A=B").unwrap(), ("A".into(), "B".into())); - assert_eq!(parse_envvar(" A=B\t").unwrap(), ("A".into(), "B".into())); - assert_eq!( - parse_envvar("A=B=C=D").unwrap(), - ("A".into(), "B=C=D".into()) - ); - } -} diff --git a/lib/cli/Cargo.toml b/lib/cli/Cargo.toml index 6bcd2e89c9..7c80d773b5 100644 --- a/lib/cli/Cargo.toml +++ b/lib/cli/Cargo.toml @@ -108,6 +108,8 @@ enable-serde = [ "wasmer-wasix/enable-serde", ] +tokio-subscriber = ["dep:console-subscriber", "tokio/tracing"] + [dependencies] # Repo-local dependencies. @@ -152,6 +154,8 @@ wasmer-config = { version = "0.601.0", path = "../config" } shared-buffer = { workspace = true, optional = true } rkyv = { workspace = true, optional = true } + +# TODO: #5858 fuser = { version = "0.14.0", optional = true } time01 = { package = "time", version = "0.1.45", optional = true } @@ -159,62 +163,62 @@ time01 = { package = "time", version = "0.1.45", optional = true } # Third-party dependencies. http.workspace = true -is-terminal = "0.4.7" -colored = "2.0" +colored.workspace = true anyhow.workspace = true bytesize.workspace = true cfg-if.workspace = true tempfile.workspace = true serde.workspace = true serde_json.workspace = true -dirs = "4.0" +dirs.workspace = true +path-clean.workspace = true target-lexicon = { workspace = true, features = ["std"] } indexmap.workspace = true -walkdir = "2.3.2" -regex = "1.6.0" +walkdir.workspace = true +regex.workspace = true toml.workspace = true url.workspace = true libc.workspace = true -parking_lot = "0.12" -dialoguer = "0.11.0" +parking_lot.workspace = true +dialoguer.workspace = true hex.workspace = true flate2.workspace = true -cargo_metadata = "0.15.2" +cargo_metadata.workspace = true tar.workspace = true bytes.workspace = true thiserror.workspace = true log.workspace = true semver.workspace = true -pathdiff = "0.2.1" +pathdiff.workspace = true sha2.workspace = true object.workspace = true -wasm-coredump-builder = { version = "0.1.11", optional = true } +wasm-coredump-builder = { workspace = true, optional = true } tracing.workspace = true tracing-subscriber = { workspace = true, features = [ "env-filter", "fmt", "json", + "ansi" ] } async-trait = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } once_cell.workspace = true -indicatif = "0.17.5" -opener = "0.6.1" -normpath = "=1.1.1" +indicatif.workspace = true +opener.workspace = true +normpath.workspace = true hyper = { workspace = true, features = ["server"] } hyper-util = { workspace = true, features = ["tokio"] } http-body-util.workspace = true -futures = "0.3.29" -humantime = "2.1.0" -interfaces = { version = "0.0.9", optional = true } +futures.workspace = true +humantime.workspace = true +interfaces = { workspace = true, optional = true } -uuid = { version = "1.3.0", features = ["v4"] } +uuid = { workspace = true, features = ["v4"] } time = { workspace = true, features = ["macros"] } serde_yaml.workspace = true base64.workspace = true -# FIXME: 7.2 is not compatible with Rust 1.84 -comfy-table = "=7.1.4" - +comfy-table.workspace = true +git-version.workspace = true # Used by tuntap and connect futures-util.workspace = true @@ -223,22 +227,24 @@ tokio-tungstenite = { workspace = true, features = [ "rustls-tls-webpki-roots", "stream", ], optional = true } -mac_address = { version = "1.1.5", optional = true } -#tun-tap = { version = "0.1.4", features = ["tokio"], optional = true } +mac_address = { workspace = true, optional = true } +#tun-tap = { workspace = true, features = ["tokio"], optional = true } + +clap_complete.workspace = true +clap_mangen.workspace = true +zip = { workspace = true, features = ["deflate"] } +console.workspace = true +dotenvy.workspace = true +lzma-rs.workspace = true -clap_complete = "4.5.2" -clap_mangen = "0.2.20" -zip = { version = "2.4", default-features = false, features = ["deflate"] } -console = "0.15.8" -dotenvy = "0.15.7" -lzma-rs = "0.3.0" +console-subscriber = { workspace = true, optional = true } # NOTE: Must use different features for clap because the "color" feature does not # work on wasi due to the anstream dependency not compiling. [target.'cfg(not(target_family = "wasm"))'.dependencies] -clap = { version = "4.4.0", features = ["derive", "env"] } +clap = { workspace = true, default-features = true, features = ["derive", "env"] } [target.'cfg(target_family = "wasm")'.dependencies] -clap = { version = "4.4.0", default-features = false, features = [ +clap = { workspace = true, default-features = false, features = [ "std", "help", "usage", @@ -265,22 +271,22 @@ reqwest = { workspace = true, default-features = false, features = [ [build-dependencies] -chrono = { version = "0.4.38", default-features = false, features = [ +chrono = { workspace = true, default-features = false, features = [ "std", "clock", ] } [target.'cfg(target_os = "linux")'.dependencies] -unix_mode = "0.1.3" +unix_mode.workspace = true [dev-dependencies] -assert_cmd = "2.0.11" -predicates = "3.0.3" +assert_cmd.workspace = true +predicates.workspace = true pretty_assertions.workspace = true [target.'cfg(target_os = "windows")'.dependencies] -colored = "2.0.0" +colored.workspace = true [package.metadata.binstall] pkg-fmt = "tgz" diff --git a/lib/cli/build.rs b/lib/cli/build.rs index b8e6525d56..28df3c148f 100644 --- a/lib/cli/build.rs +++ b/lib/cli/build.rs @@ -1,26 +1,6 @@ -use std::process::Command; - use chrono::prelude::*; pub fn main() { - // Set WASMER_GIT_HASH - let git_hash = Command::new("git") - .args(["rev-parse", "HEAD"]) - .output() - .ok() - .and_then(|output| String::from_utf8(output.stdout).ok()) - .unwrap_or_default(); - println!("cargo:rustc-env=WASMER_BUILD_GIT_HASH={git_hash}"); - - if git_hash.len() > 5 { - println!( - "cargo:rustc-env=WASMER_BUILD_GIT_HASH_SHORT={}", - &git_hash[..7] - ); - } else { - println!("cargo:rustc-env=WASMER_BUILD_GIT_HASH_SHORT=???????"); - } - let utc: DateTime = Utc::now(); let date = utc.format("%Y-%m-%d").to_string(); println!("cargo:rustc-env=WASMER_BUILD_DATE={date}"); diff --git a/lib/cli/src/backend.rs b/lib/cli/src/backend.rs index ce3f449eca..214720427a 100644 --- a/lib/cli/src/backend.rs +++ b/lib/cli/src/backend.rs @@ -11,11 +11,11 @@ use std::string::ToString; use std::sync::Arc; use std::{path::PathBuf, str::FromStr}; -use anyhow::{bail, Result}; +use anyhow::{Context, Result, bail}; #[cfg(feature = "sys")] use wasmer::sys::*; use wasmer::*; -use wasmer_types::{target::Target, Features}; +use wasmer_types::{Features, target::Target}; #[cfg(feature = "compiler")] use wasmer_compiler::CompilerConfig; @@ -188,25 +188,27 @@ pub struct RuntimeOptions { #[clap(long)] enable_verifier: bool, + /// Debug directory, where IR and object files will be written to. + /// + /// Available for cranelift, LLVM and singlepass. + #[clap(long, alias = "llvm-debug-dir")] + compiler_debug_dir: Option, + /// Enable a profiler. /// /// Available for cranelift, LLVM and singlepass. #[clap(long, value_enum)] profiler: Option, - /// LLVM debug directory, where IR and object files will be written to. - /// - /// Only available for the LLVM compiler. - #[clap(long)] - llvm_debug_dir: Option, - /// Only available for the LLVM compiler. Enable the "pass-params" optimization, where the first (#0) /// global and the first (#0) memory passed between guest functions as explicit parameters. + #[cfg(feature = "llvm")] #[clap(long)] enable_pass_params_opt: bool, /// Only available for the LLVM compiler. Sets the number of threads used to compile the /// input module(s). + #[cfg(feature = "llvm")] #[clap(long)] llvm_num_threads: Option>, @@ -298,7 +300,7 @@ impl RuntimeOptions { pub fn get_engine(&self, target: &Target) -> Result { let backends = self.get_available_backends()?; - let backend = backends.first().unwrap(); + let backend = backends.first().context("no compiler backend enabled")?; let backend_kind = wasmer::BackendKind::from(backend); let required_features = wasmer::Engine::default_features_for_backend(&backend_kind, target); backend.get_engine(target, &required_features, self) @@ -338,7 +340,9 @@ impl RuntimeOptions { extra_text ); } else { - bail!("No backends support the required features for the Wasm module. Feel free to open an issue at https://github.com/wasmerio/wasmer/issues"); + bail!( + "No backends support the required features for the Wasm module. Feel free to open an issue at https://github.com/wasmerio/wasmer/issues" + ); } } filtered_backends @@ -456,6 +460,12 @@ impl RuntimeOptions { Profiler::Perfmap => config.enable_perfmap(), } } + if let Some(mut debug_dir) = self.compiler_debug_dir.clone() { + use wasmer_compiler_singlepass::SinglepassCallbacks; + + debug_dir.push("singlepass"); + config.callbacks(Some(SinglepassCallbacks::new(debug_dir)?)); + } Box::new(config) } @@ -470,15 +480,17 @@ impl RuntimeOptions { Profiler::Perfmap => config.enable_perfmap(), } } + if let Some(mut debug_dir) = self.compiler_debug_dir.clone() { + use wasmer_compiler_cranelift::CraneliftCallbacks; + + debug_dir.push("cranelift"); + config.callbacks(Some(CraneliftCallbacks::new(debug_dir)?)); + } Box::new(config) } #[cfg(feature = "llvm")] BackendType::LLVM => { - use std::{fmt, fs::File, io::Write}; - - use wasmer_compiler_llvm::{ - CompiledKind, InkwellMemoryBuffer, InkwellModule, LLVMCallbacks, LLVM, - }; + use wasmer_compiler_llvm::LLVMCallbacks; use wasmer_types::entity::EntityRef; let mut config = LLVM::new(); @@ -490,109 +502,9 @@ impl RuntimeOptions { config.num_threads(num_threads); } - struct Callbacks { - debug_dir: PathBuf, - } - impl Callbacks { - fn new(debug_dir: PathBuf) -> Result { - // Create the debug dir in case it doesn't exist - std::fs::create_dir_all(&debug_dir)?; - Ok(Self { debug_dir }) - } - } - // Converts a kind into a filename, that we will use to dump - // the contents of the IR object file to. - fn types_to_signature(types: &[Type]) -> String { - types - .iter() - .map(|ty| match ty { - Type::I32 => "i".to_string(), - Type::I64 => "I".to_string(), - Type::F32 => "f".to_string(), - Type::F64 => "F".to_string(), - Type::V128 => "v".to_string(), - Type::ExternRef => "e".to_string(), - Type::FuncRef => "r".to_string(), - Type::ExceptionRef => "x".to_string(), - }) - .collect::>() - .join("") - } - // Converts a kind into a filename, that we will use to dump - // the contents of the IR object file to. - fn function_kind_to_filename(kind: &CompiledKind) -> String { - match kind { - CompiledKind::Local(local_index) => { - format!("function_{}", local_index.index()) - } - CompiledKind::FunctionCallTrampoline(func_type) => format!( - "trampoline_call_{}_{}", - types_to_signature(func_type.params()), - types_to_signature(func_type.results()) - ), - CompiledKind::DynamicFunctionTrampoline(func_type) => format!( - "trampoline_dynamic_{}_{}", - types_to_signature(func_type.params()), - types_to_signature(func_type.results()) - ), - CompiledKind::Module => "module".into(), - } - } - impl LLVMCallbacks for Callbacks { - fn preopt_ir(&self, kind: &CompiledKind, module: &InkwellModule) { - let mut path = self.debug_dir.clone(); - path.push(format!("{}.preopt.ll", function_kind_to_filename(kind))); - module - .print_to_file(&path) - .expect("Error while dumping pre optimized LLVM IR"); - } - fn postopt_ir(&self, kind: &CompiledKind, module: &InkwellModule) { - let mut path = self.debug_dir.clone(); - path.push(format!("{}.postopt.ll", function_kind_to_filename(kind))); - module - .print_to_file(&path) - .expect("Error while dumping post optimized LLVM IR"); - } - fn obj_memory_buffer( - &self, - kind: &CompiledKind, - memory_buffer: &InkwellMemoryBuffer, - ) { - let mut path = self.debug_dir.clone(); - path.push(format!("{}.o", function_kind_to_filename(kind))); - let mem_buf_slice = memory_buffer.as_slice(); - let mut file = File::create(path) - .expect("Error while creating debug object file from LLVM IR"); - let mut pos = 0; - while pos < mem_buf_slice.len() { - pos += file.write(&mem_buf_slice[pos..]).unwrap(); - } - } - fn asm_memory_buffer( - &self, - kind: &CompiledKind, - asm_memory_buffer: &InkwellMemoryBuffer, - ) { - let mut path = self.debug_dir.clone(); - path.push(format!("{}.s", function_kind_to_filename(kind))); - let mem_buf_slice = asm_memory_buffer.as_slice(); - let mut file = File::create(path) - .expect("Error while creating debug object file from LLVM IR"); - let mut pos = 0; - while pos < mem_buf_slice.len() { - pos += file.write(&mem_buf_slice[pos..]).unwrap(); - } - } - } - - impl fmt::Debug for Callbacks { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "LLVMCallbacks") - } - } - - if let Some(ref llvm_debug_dir) = self.llvm_debug_dir { - config.callbacks(Some(Arc::new(Callbacks::new(llvm_debug_dir.clone())?))); + if let Some(mut debug_dir) = self.compiler_debug_dir.clone() { + debug_dir.push("llvm"); + config.callbacks(Some(LLVMCallbacks::new(debug_dir)?)); } if self.enable_verifier { config.enable_verifier(); @@ -608,10 +520,7 @@ impl RuntimeOptions { BackendType::V8 | BackendType::Wamr | BackendType::Wasmi => unreachable!(), #[cfg(not(all(feature = "singlepass", feature = "cranelift", feature = "llvm")))] compiler => { - bail!( - "The `{}` compiler is not included in this binary.", - compiler.to_string() - ) + bail!("The `{compiler}` compiler is not included in this binary.") } }; @@ -685,6 +594,12 @@ impl BackendType { Profiler::Perfmap => config.enable_perfmap(), } } + if let Some(mut debug_dir) = runtime_opts.compiler_debug_dir.clone() { + use wasmer_compiler_singlepass::SinglepassCallbacks; + + debug_dir.push("singlepass"); + config.callbacks(Some(SinglepassCallbacks::new(debug_dir)?)); + } let engine = wasmer_compiler::EngineBuilder::new(config) .set_features(Some(features.clone())) .set_target(Some(target.clone())) @@ -703,6 +618,12 @@ impl BackendType { Profiler::Perfmap => config.enable_perfmap(), } } + if let Some(mut debug_dir) = runtime_opts.compiler_debug_dir.clone() { + use wasmer_compiler_cranelift::CraneliftCallbacks; + + debug_dir.push("cranelift"); + config.callbacks(Some(CraneliftCallbacks::new(debug_dir)?)); + } let engine = wasmer_compiler::EngineBuilder::new(config) .set_features(Some(features.clone())) .set_target(Some(target.clone())) @@ -712,118 +633,14 @@ impl BackendType { } #[cfg(feature = "llvm")] Self::LLVM => { - use std::{fmt, fs::File, io::Write}; - - use wasmer_compiler_llvm::{ - CompiledKind, InkwellMemoryBuffer, InkwellModule, LLVMCallbacks, LLVM, - }; + use wasmer_compiler_llvm::LLVMCallbacks; use wasmer_types::entity::EntityRef; let mut config = wasmer_compiler_llvm::LLVM::new(); - struct Callbacks { - debug_dir: PathBuf, - } - impl Callbacks { - fn new(debug_dir: PathBuf) -> Result { - // Create the debug dir in case it doesn't exist - std::fs::create_dir_all(&debug_dir)?; - Ok(Self { debug_dir }) - } - } - // Converts a kind into a filename, that we will use to dump - // the contents of the IR object file to. - fn types_to_signature(types: &[Type]) -> String { - types - .iter() - .map(|ty| match ty { - Type::I32 => "i".to_string(), - Type::I64 => "I".to_string(), - Type::F32 => "f".to_string(), - Type::F64 => "F".to_string(), - Type::V128 => "v".to_string(), - Type::ExternRef => "e".to_string(), - Type::FuncRef => "r".to_string(), - Type::ExceptionRef => "x".to_string(), - }) - .collect::>() - .join("") - } - // Converts a kind into a filename, that we will use to dump - // the contents of the IR object file to. - fn function_kind_to_filename(kind: &CompiledKind) -> String { - match kind { - CompiledKind::Local(local_index) => { - format!("function_{}", local_index.index()) - } - CompiledKind::FunctionCallTrampoline(func_type) => format!( - "trampoline_call_{}_{}", - types_to_signature(func_type.params()), - types_to_signature(func_type.results()) - ), - CompiledKind::DynamicFunctionTrampoline(func_type) => format!( - "trampoline_dynamic_{}_{}", - types_to_signature(func_type.params()), - types_to_signature(func_type.results()) - ), - CompiledKind::Module => "module".into(), - } - } - impl LLVMCallbacks for Callbacks { - fn preopt_ir(&self, kind: &CompiledKind, module: &InkwellModule) { - let mut path = self.debug_dir.clone(); - path.push(format!("{}.preopt.ll", function_kind_to_filename(kind))); - module - .print_to_file(&path) - .expect("Error while dumping pre optimized LLVM IR"); - } - fn postopt_ir(&self, kind: &CompiledKind, module: &InkwellModule) { - let mut path = self.debug_dir.clone(); - path.push(format!("{}.postopt.ll", function_kind_to_filename(kind))); - module - .print_to_file(&path) - .expect("Error while dumping post optimized LLVM IR"); - } - fn obj_memory_buffer( - &self, - kind: &CompiledKind, - memory_buffer: &InkwellMemoryBuffer, - ) { - let mut path = self.debug_dir.clone(); - path.push(format!("{}.o", function_kind_to_filename(kind))); - let mem_buf_slice = memory_buffer.as_slice(); - let mut file = File::create(path) - .expect("Error while creating debug object file from LLVM IR"); - let mut pos = 0; - while pos < mem_buf_slice.len() { - pos += file.write(&mem_buf_slice[pos..]).unwrap(); - } - } - fn asm_memory_buffer( - &self, - kind: &CompiledKind, - asm_memory_buffer: &InkwellMemoryBuffer, - ) { - let mut path = self.debug_dir.clone(); - path.push(format!("{}.s", function_kind_to_filename(kind))); - let mem_buf_slice = asm_memory_buffer.as_slice(); - let mut file = File::create(path) - .expect("Error while creating debug object file from LLVM IR"); - let mut pos = 0; - while pos < mem_buf_slice.len() { - pos += file.write(&mem_buf_slice[pos..]).unwrap(); - } - } - } - - impl fmt::Debug for Callbacks { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "LLVMCallbacks") - } - } - - if let Some(ref llvm_debug_dir) = runtime_opts.llvm_debug_dir { - config.callbacks(Some(Arc::new(Callbacks::new(llvm_debug_dir.clone())?))); + if let Some(mut debug_dir) = runtime_opts.compiler_debug_dir.clone() { + debug_dir.push("llvm"); + config.callbacks(Some(LLVMCallbacks::new(debug_dir)?)); } if runtime_opts.enable_verifier { config.enable_verifier(); diff --git a/lib/cli/src/c_gen/staticlib_header.rs b/lib/cli/src/c_gen/staticlib_header.rs index 3767c6b6c1..3f690822c4 100644 --- a/lib/cli/src/c_gen/staticlib_header.rs +++ b/lib/cli/src/c_gen/staticlib_header.rs @@ -3,7 +3,7 @@ use wasmer_compiler::types::symbols::{Symbol, SymbolRegistry}; use wasmer_types::ModuleInfo; -use super::{generate_c, CStatement, CType}; +use super::{CStatement, CType, generate_c}; /// Helper functions to simplify the usage of the static artifact. fn gen_helper_functions(atom_name: &str, module_name: &str) -> String { diff --git a/lib/cli/src/commands/add.rs b/lib/cli/src/commands/add.rs index 83b232143b..d06d12c5ec 100644 --- a/lib/cli/src/commands/add.rs +++ b/lib/cli/src/commands/add.rs @@ -4,8 +4,8 @@ use anyhow::{Context, Error}; use clap::Parser; use std::process::{Command, Stdio}; use wasmer_backend_api::{ - types::{Bindings, ProgrammingLanguage}, WasmerClient, + types::{Bindings, ProgrammingLanguage}, }; use wasmer_config::package::NamedPackageIdent; @@ -58,7 +58,7 @@ impl AsyncCliCommand for CmdAdd { ) })?; - anyhow::ensure!(status.success(), "Command failed: {:?}", cmd); + anyhow::ensure!(status.success(), "Command failed: {cmd:?}"); Ok(()) } @@ -173,11 +173,7 @@ impl Target { if Command::new("yarn").arg("--version").output().is_err() { return Err(anyhow::anyhow!("yarn not installed")); } - if dev { - "yarn add --dev" - } else { - "yarn add" - } + if dev { "yarn add --dev" } else { "yarn add" } } Target::Npm { dev } => { if Command::new("npm").arg("--version").output().is_err() { @@ -193,11 +189,7 @@ impl Target { if Command::new("pnpm").arg("--version").output().is_err() { return Err(anyhow::anyhow!("pnpm not installed")); } - if dev { - "pnpm add --dev" - } else { - "pnpm add" - } + if dev { "pnpm add --dev" } else { "pnpm add" } } }; let mut command_line = command_line.to_string(); diff --git a/lib/cli/src/commands/app/create.rs b/lib/cli/src/commands/app/create.rs index 701fd3a516..e57b13b21a 100644 --- a/lib/cli/src/commands/app/create.rs +++ b/lib/cli/src/commands/app/create.rs @@ -10,13 +10,14 @@ use std::{ use anyhow::Context; use colored::Colorize; -use dialoguer::{theme::ColorfulTheme, Confirm, Select}; +use dialoguer::{Confirm, Select, theme::ColorfulTheme}; use futures::stream::TryStreamExt; use indexmap::IndexMap; -use is_terminal::IsTerminal; +use path_clean::PathClean; +use std::io::IsTerminal as _; use wasmer_backend_api::{ - types::{AppTemplate, TemplateLanguage}, WasmerClient, + types::{AppTemplate, TemplateLanguage}, }; use wasmer_config::{app::AppConfigV1, package::PackageSource}; @@ -234,7 +235,9 @@ impl CmdAppCreate { if self.non_interactive { if !self.quiet { eprintln!("The current directory is not empty."); - eprintln!("Use the `--dir` flag to specify another directory, or remove files from the currently selected one.") + eprintln!( + "Use the `--dir` flag to specify another directory, or remove files from the currently selected one." + ) } anyhow::bail!("Stopping as the directory is not empty") } else { @@ -271,7 +274,10 @@ impl CmdAppCreate { let (manifest_path, _) = if let Some(res) = load_package_manifest(&app_dir)? { res } else if self.use_local_manifest { - anyhow::bail!("The --use_local_manifest flag was passed, but path {} does not contain a valid package manifest.", app_dir.display()) + anyhow::bail!( + "The --use_local_manifest flag was passed, but path {} does not contain a valid package manifest.", + app_dir.display() + ) } else { return Ok(false); }; @@ -401,11 +407,11 @@ impl CmdAppCreate { None => return Ok(Vec::new()), }; - if let (Some(a), Some(b)) = (cached_items.first(), first_page.first()) { - if a == b { - // Cached items are up to date, no need to query more. - return Ok(cached_items); - } + if let (Some(a), Some(b)) = (cached_items.first(), first_page.first()) + && a == b + { + // Cached items are up to date, no need to query more. + return Ok(cached_items); } let mut items = first_page; @@ -483,11 +489,11 @@ impl CmdAppCreate { None => return Ok(Vec::new()), }; - if let (Some(a), Some(b)) = (cached_items.first(), first_page.first()) { - if a == b { - // Cached items are up to date, no need to query more. - return Ok(cached_items); - } + if let (Some(a), Some(b)) = (cached_items.first(), first_page.first()) + && a == b + { + // Cached items are up to date, no need to query more. + return Ok(cached_items); } let mut items = first_page; @@ -512,17 +518,22 @@ impl CmdAppCreate { } // A utility function used to fetch the URL of the template to use. - async fn get_template_url(&self, client: &WasmerClient) -> anyhow::Result { - let mut url = if let Some(template) = &self.template { + async fn get_template_url( + &self, + client: &WasmerClient, + ) -> anyhow::Result<(url::Url, Option)> { + let (mut url, selected_template): (url::Url, Option) = if let Some(template) = + &self.template + { if let Ok(url) = url::Url::parse(template) { - url + (url, None) } else if let Some(template) = wasmer_backend_api::query::fetch_app_template_from_slug(client, template.clone()) .await? { - url::Url::parse(&template.repo_url)? + (url::Url::parse(&template.repo_url)?, Some(template)) } else { - anyhow::bail!("Template '{}' not found in the registry", template) + anyhow::bail!("Template '{template}' not found in the registry") } } else { if self.non_interactive { @@ -599,18 +610,36 @@ impl CmdAppCreate { ) } - url::Url::parse(&selected_template.repo_url)? + ( + url::Url::parse(&selected_template.repo_url)?, + Some(selected_template.clone()), + ) }; let url = if url.path().contains("archive/refs/heads") || url.path().contains("/zipball/") { url } else { let old_path = url.path(); - url.set_path(&format!("{old_path}/zipball/main")); + let branch = if let Some(ref template) = selected_template { + template.branch.clone().unwrap_or("main".to_string()) + } else { + "main".to_string() + }; + url.set_path(&format!("{old_path}/zipball/{branch}")); url }; - Ok(url) + if let Some(ref template) = selected_template + && let Some(root_dir) = &template.root_dir + { + let mut path_root_dir = PathBuf::from(root_dir); + if path_root_dir.is_absolute() { + path_root_dir = path_root_dir.strip_prefix("/")?.to_path_buf(); + } + return Ok((url, Some(path_root_dir))); + } + + Ok((url, None)) } async fn create_from_template( @@ -621,12 +650,17 @@ impl CmdAppCreate { ) -> anyhow::Result { let client = match client { Some(client) => client, - None => anyhow::bail!("Cannot"), + None => anyhow::bail!("Cannot create app from template in offline mode"), }; - let url = self.get_template_url(client).await?; - - tracing::info!("Downloading template from url {url}"); + let (url, mut root_dir) = self.get_template_url(client).await?; + root_dir = root_dir.map(|v| v.clean()); + let root_dir_str = if let Some(ref root_dir) = root_dir { + root_dir.display().to_string() + } else { + "./".to_string() + }; + tracing::info!("Downloading template from url {url}, using root dir {root_dir_str}"); let output_path = self.get_output_dir(app_name).await?; let pb = indicatif::ProgressBar::new_spinner(); @@ -638,16 +672,17 @@ impl CmdAppCreate { .tick_strings(&["✶", "✸", "✹", "✺", "✹", "✷"]), ); - pb.set_message("Downloading package.."); + pb.set_message("Downloading template..."); let response = reqwest::get(url).await?; let bytes = response.bytes().await?; - pb.set_message("Unpacking the template.."); + pb.set_message("Unpacking the template..."); let cursor = Cursor::new(bytes); let mut archive = zip::ZipArchive::new(cursor)?; // Extract the files to the output path + // If root dir is specified, extract only the files inside of the root dir for entry in 0..archive.len() { let mut entry = archive .by_index(entry) @@ -655,22 +690,30 @@ impl CmdAppCreate { let path = entry.mangled_name(); - let path: PathBuf = { + // We skip the top-level directory, as Github archives always contain a top-level directory + // named after the repository name and latest commit hash. + let mut path: PathBuf = { let mut components = path.components(); components.next(); components.collect() }; - if path.to_str().unwrap_or_default().contains(".github") { - continue; + tracing::info!("Extracting file {path:?}"); + + if let Some(ref root_dir) = root_dir { + if !path.clean().starts_with(root_dir) { + continue; + } else { + path = path.strip_prefix(root_dir)?.to_path_buf(); + } } let path = output_path.join(path); - if let Some(parent) = path.parent() { - if !parent.exists() { - std::fs::create_dir_all(parent)?; - } + if let Some(parent) = path.parent() + && !parent.exists() + { + std::fs::create_dir_all(parent)?; } if !path.exists() { diff --git a/lib/cli/src/commands/app/delete.rs b/lib/cli/src/commands/app/delete.rs index 6ae4ca19db..4bcf49dd30 100644 --- a/lib/cli/src/commands/app/delete.rs +++ b/lib/cli/src/commands/app/delete.rs @@ -1,7 +1,7 @@ //! Delete an Edge app. use dialoguer::Confirm; -use is_terminal::IsTerminal; +use std::io::IsTerminal as _; use super::util::AppIdentOpts; use crate::{commands::AsyncCliCommand, config::WasmerEnv}; diff --git a/lib/cli/src/commands/app/deploy.rs b/lib/cli/src/commands/app/deploy.rs index 7e5095a46c..c43f510898 100644 --- a/lib/cli/src/commands/app/deploy.rs +++ b/lib/cli/src/commands/app/deploy.rs @@ -1,32 +1,32 @@ -use super::{util::login_user, AsyncCliCommand}; +use super::{AsyncCliCommand, util::login_user}; use crate::{ commands::{ - app::create::{minimal_app_config, write_app_config, CmdAppCreate}, - package::publish::PackagePublish, PublishWait, + app::create::{CmdAppCreate, minimal_app_config, write_app_config}, + package::publish::PackagePublish, }, config::WasmerEnv, opts::ItemFormatOpts, - utils::{load_package_manifest, DEFAULT_PACKAGE_MANIFEST_FILE}, + utils::{DEFAULT_PACKAGE_MANIFEST_FILE, load_package_manifest}, }; use anyhow::Context; use bytesize::ByteSize; use colored::Colorize; -use dialoguer::{theme::ColorfulTheme, Confirm}; +use dialoguer::{Confirm, theme::ColorfulTheme}; use indexmap::IndexMap; -use is_terminal::IsTerminal; +use std::io::IsTerminal as _; use std::io::Write; use std::{path::Path, path::PathBuf, str::FromStr, time::Duration}; use wasmer_backend_api::{ - types::{AutoBuildDeployAppLogKind, DeployApp, DeployAppVersion}, WasmerClient, + types::{AutoBuildDeployAppLogKind, DeployApp, DeployAppVersion}, }; use wasmer_config::{ app::AppConfigV1, package::{PackageIdent, PackageSource}, }; use wasmer_sdk::app::deploy_remote_build::{ - deploy_app_remote, DeployRemoteEvent, DeployRemoteOpts, + DeployRemoteEvent, DeployRemoteOpts, deploy_app_remote, }; static EDGE_HEADER_APP_VERSION_ID: http::HeaderName = @@ -603,7 +603,10 @@ impl AsyncCliCommand for CmdAppDeploy { // Create already points back to deploy. return self.create().await; } else { - anyhow::bail!("No app configuration was found in {}. Create an app before deploying or re-run in interactive mode!", app_config_path.display()); + anyhow::bail!( + "No app configuration was found in {}. Create an app before deploying or re-run in interactive mode!", + app_config_path.display() + ); } } @@ -629,7 +632,10 @@ impl AsyncCliCommand for CmdAppDeploy { if !wasmer_backend_api::query::viewer_can_deploy_to_namespace(&client, &owner).await? { eprintln!("It seems you don't have access to {}", owner.bold()); if self.non_interactive { - anyhow::bail!("Please, change the owner before deploying or check your current user with `{} whoami`.", std::env::args().next().unwrap_or("wasmer".into())); + anyhow::bail!( + "Please, change the owner before deploying or check your current user with `{} whoami`.", + std::env::args().next().unwrap_or("wasmer".into()) + ); } else { let user = wasmer_backend_api::query::current_user_with_namespaces(&client, None).await?; @@ -759,7 +765,7 @@ impl AsyncCliCommand for CmdAppDeploy { } let opts = match &app_cfg_new.package { - PackageSource::Path(ref path) => { + PackageSource::Path(path) => { let path = PathBuf::from(path); let path = if path.is_absolute() { @@ -903,7 +909,7 @@ impl AsyncCliCommand for CmdAppDeploy { } } } else { - log::info!("Using package {}", app_config.package.to_string()); + log::info!("Using package {}", app_config.package); DeployAppOpts { app: &app_config, original_config: Some(app_config.clone().to_yaml_value().unwrap()), @@ -915,7 +921,7 @@ impl AsyncCliCommand for CmdAppDeploy { } } _ => { - log::info!("Using package {}", app_config.package.to_string()); + log::info!("Using package {}", app_config.package); DeployAppOpts { app: &app_config, original_config: Some(app_config.clone().to_yaml_value().unwrap()), diff --git a/lib/cli/src/commands/app/logs.rs b/lib/cli/src/commands/app/logs.rs index 4ecd47275d..9a487d5497 100644 --- a/lib/cli/src/commands/app/logs.rs +++ b/lib/cli/src/commands/app/logs.rs @@ -4,7 +4,7 @@ use crate::utils::timestamp::parse_timestamp_or_relative_time_negative_offset; use colored::Colorize; use comfy_table::{Cell, Table}; use futures::StreamExt; -use time::{format_description::well_known::Rfc3339, OffsetDateTime}; +use time::{OffsetDateTime, format_description::well_known::Rfc3339}; use wasmer_backend_api::types::{Log, LogStream}; use crate::{config::WasmerEnv, opts::ListFormatOpts, utils::render::CliRender}; diff --git a/lib/cli/src/commands/app/regions/list.rs b/lib/cli/src/commands/app/regions/list.rs index 9828d24abb..f0782fe164 100644 --- a/lib/cli/src/commands/app/regions/list.rs +++ b/lib/cli/src/commands/app/regions/list.rs @@ -1,5 +1,5 @@ use crate::{commands::AsyncCliCommand, config::WasmerEnv, opts::ListFormatOpts}; -use is_terminal::IsTerminal; +use std::io::IsTerminal as _; /// List available Edge regions. #[derive(clap::Parser, Debug)] diff --git a/lib/cli/src/commands/app/secrets/create.rs b/lib/cli/src/commands/app/secrets/create.rs index f0570562aa..0719184f3c 100644 --- a/lib/cli/src/commands/app/secrets/create.rs +++ b/lib/cli/src/commands/app/secrets/create.rs @@ -1,12 +1,12 @@ use super::utils::Secret; use crate::{ - commands::{app::util::AppIdentFlag, AsyncCliCommand}, + commands::{AsyncCliCommand, app::util::AppIdentFlag}, config::WasmerEnv, }; use anyhow::Context; use colored::Colorize; use dialoguer::theme::ColorfulTheme; -use is_terminal::IsTerminal; +use std::io::IsTerminal as _; use std::{ collections::{HashMap, HashSet}, path::{Path, PathBuf}, @@ -102,7 +102,10 @@ impl CmdAppSecretsCreate { for secret in secrets { if sset.contains(&secret.name) { if self.non_interactive { - anyhow::bail!("Cannot create secret '{}' as it already exists. Use the `update` command instead.", secret.name.bold()); + anyhow::bail!( + "Cannot create secret '{}' as it already exists. Use the `update` command instead.", + secret.name.bold() + ); } else { if ret.contains_key(&secret.name) { eprintln!( @@ -121,7 +124,10 @@ impl CmdAppSecretsCreate { .interact()?; if !res { - eprintln!("Cannot create secret '{}' as it already exists. Use the `update` command instead.", secret.name.bold()); + eprintln!( + "Cannot create secret '{}' as it already exists. Use the `update` command instead.", + secret.name.bold() + ); } } } diff --git a/lib/cli/src/commands/app/secrets/delete.rs b/lib/cli/src/commands/app/secrets/delete.rs index 093b243905..62333115a5 100644 --- a/lib/cli/src/commands/app/secrets/delete.rs +++ b/lib/cli/src/commands/app/secrets/delete.rs @@ -1,10 +1,10 @@ use crate::{ - commands::{app::util::AppIdentFlag, AsyncCliCommand}, + commands::{AsyncCliCommand, app::util::AppIdentFlag}, config::WasmerEnv, }; use colored::Colorize; use dialoguer::theme::ColorfulTheme; -use is_terminal::IsTerminal; +use std::io::IsTerminal as _; use std::path::{Path, PathBuf}; use wasmer_backend_api::WasmerClient; @@ -150,7 +150,9 @@ impl AsyncCliCommand for CmdAppSecretsDelete { self.delete_from_file(&client, file, app_id).await } else if self.all { if self.non_interactive && !self.force { - anyhow::bail!("Refusing to delete all secrets in non-interactive mode without the `--force` flag.") + anyhow::bail!( + "Refusing to delete all secrets in non-interactive mode without the `--force` flag." + ) } let secrets = get_secrets(&client, &app_id).await?; for secret in secrets { diff --git a/lib/cli/src/commands/app/secrets/list.rs b/lib/cli/src/commands/app/secrets/list.rs index 6edb25c3cd..b1a92375e7 100644 --- a/lib/cli/src/commands/app/secrets/list.rs +++ b/lib/cli/src/commands/app/secrets/list.rs @@ -1,10 +1,10 @@ -use super::utils::{get_secrets, BackendSecretWrapper}; +use super::utils::{BackendSecretWrapper, get_secrets}; use crate::{ - commands::{app::util::AppIdentFlag, AsyncCliCommand}, + commands::{AsyncCliCommand, app::util::AppIdentFlag}, config::WasmerEnv, opts::ListFormatOpts, }; -use is_terminal::IsTerminal; +use std::io::IsTerminal as _; use std::path::PathBuf; /// Retrieve the value of an existing app secret. diff --git a/lib/cli/src/commands/app/secrets/reveal.rs b/lib/cli/src/commands/app/secrets/reveal.rs index ae16d67bfa..781216dd1c 100644 --- a/lib/cli/src/commands/app/secrets/reveal.rs +++ b/lib/cli/src/commands/app/secrets/reveal.rs @@ -1,12 +1,12 @@ use super::utils; use crate::{ - commands::{app::util::AppIdentFlag, AsyncCliCommand}, + commands::{AsyncCliCommand, app::util::AppIdentFlag}, config::WasmerEnv, opts::ListFormatOpts, utils::render::{ItemFormat, ListFormat}, }; use dialoguer::theme::ColorfulTheme; -use is_terminal::IsTerminal; +use std::io::IsTerminal as _; use std::path::PathBuf; /// Reveal the value of an existing app secret. diff --git a/lib/cli/src/commands/app/secrets/update.rs b/lib/cli/src/commands/app/secrets/update.rs index ba14eb6148..7ead78ae2b 100644 --- a/lib/cli/src/commands/app/secrets/update.rs +++ b/lib/cli/src/commands/app/secrets/update.rs @@ -1,12 +1,12 @@ use super::utils::Secret; use crate::{ - commands::{app::util::AppIdentFlag, AsyncCliCommand}, + commands::{AsyncCliCommand, app::util::AppIdentFlag}, config::WasmerEnv, }; use anyhow::Context; use colored::Colorize; use dialoguer::theme::ColorfulTheme; -use is_terminal::IsTerminal; +use std::io::IsTerminal as _; use std::{ collections::HashSet, path::{Path, PathBuf}, @@ -108,7 +108,10 @@ impl CmdAppSecretsUpdate { for secret in secrets { if !sset.contains(secret.name.as_str()) { if self.non_interactive { - anyhow::bail!("Cannot update secret '{}' in app {app_id} as it does not exist yet. Use the `create` command instead.", secret.name.bold()); + anyhow::bail!( + "Cannot update secret '{}' in app {app_id} as it does not exist yet. Use the `create` command instead.", + secret.name.bold() + ); } else { eprintln!( "Secret '{}' does not exist for the selected app.", @@ -120,7 +123,10 @@ impl CmdAppSecretsUpdate { .interact()?; if !res { - eprintln!("Cannot update secret '{}' as it does not exist yet. Use the `create` command instead.", secret.name.bold()); + eprintln!( + "Cannot update secret '{}' as it does not exist yet. Use the `create` command instead.", + secret.name.bold() + ); } } } diff --git a/lib/cli/src/commands/app/secrets/utils/mod.rs b/lib/cli/src/commands/app/secrets/utils/mod.rs index e6e329851a..b5c3d7c45c 100644 --- a/lib/cli/src/commands/app/secrets/utils/mod.rs +++ b/lib/cli/src/commands/app/secrets/utils/mod.rs @@ -6,9 +6,9 @@ use std::{ path::{Path, PathBuf}, str::FromStr, }; -use wasmer_backend_api::{types::Secret as BackendSecret, WasmerClient}; +use wasmer_backend_api::{WasmerClient, types::Secret as BackendSecret}; -use crate::commands::app::util::{get_app_config_from_dir, prompt_app_ident, AppIdent}; +use crate::commands::app::util::{AppIdent, get_app_config_from_dir, prompt_app_ident}; #[derive(serde::Serialize, serde::Deserialize)] pub(super) struct Secret { @@ -130,10 +130,12 @@ pub(super) async fn get_app_id( Some(app.id.into_inner()) } else { if !quiet { - eprintln!("{}: the app found in {} does not exist.\n{}: maybe it was not deployed yet?", - "Warning".bold().yellow(), - format!("'{}'", path.display()).dimmed(), - "Hint".bold()); + eprintln!( + "{}: the app found in {} does not exist.\n{}: maybe it was not deployed yet?", + "Warning".bold().yellow(), + format!("'{}'", path.display()).dimmed(), + "Hint".bold() + ); } None } diff --git a/lib/cli/src/commands/app/util.rs b/lib/cli/src/commands/app/util.rs index dfc22e6a0b..f34bd1afcd 100644 --- a/lib/cli/src/commands/app/util.rs +++ b/lib/cli/src/commands/app/util.rs @@ -1,12 +1,12 @@ use std::{path::Path, str::FromStr}; -use anyhow::{bail, Context}; +use anyhow::{Context, bail}; use colored::Colorize; -use dialoguer::{theme::ColorfulTheme, Confirm}; +use dialoguer::{Confirm, theme::ColorfulTheme}; use wasmer_backend_api::{ + WasmerClient, global_id::{GlobalId, NodeKind}, types::DeployApp, - WasmerClient, }; use wasmer_config::app::AppConfigV1; @@ -340,7 +340,9 @@ pub(super) async fn login_user( Some(n) => n, None => String::from("wasmer"), }; - eprintln!("You are not logged in. Use the `--token` flag or log in (use `{bin_name} login`) to {msg}."); + eprintln!( + "You are not logged in. Use the `--token` flag or log in (use `{bin_name} login`) to {msg}." + ); anyhow::bail!("Stopping execution as the user is not logged in.") } @@ -368,8 +370,8 @@ pub fn get_app_config_from_dir_opt( Ok(Some((config, app_config_path))) } -pub fn get_app_config_from_current_dir_opt( -) -> Result, anyhow::Error> { +pub fn get_app_config_from_current_dir_opt() +-> Result, anyhow::Error> { let current_dir = std::env::current_dir()?; get_app_config_from_dir_opt(¤t_dir) } diff --git a/lib/cli/src/commands/app/version/get.rs b/lib/cli/src/commands/app/version/get.rs index 66494724e9..3ca7172fc9 100644 --- a/lib/cli/src/commands/app/version/get.rs +++ b/lib/cli/src/commands/app/version/get.rs @@ -1,7 +1,7 @@ use anyhow::Context; use crate::{ - commands::{app::util::AppIdentOpts, AsyncCliCommand}, + commands::{AsyncCliCommand, app::util::AppIdentOpts}, config::WasmerEnv, opts::ItemFormatOpts, utils::render::ItemFormat, diff --git a/lib/cli/src/commands/app/version/list.rs b/lib/cli/src/commands/app/version/list.rs index 491a79540f..eb6a5399d5 100644 --- a/lib/cli/src/commands/app/version/list.rs +++ b/lib/cli/src/commands/app/version/list.rs @@ -1,7 +1,7 @@ use wasmer_backend_api::types::{DeployAppVersionsSortBy, GetDeployAppVersionsVars}; use crate::{ - commands::{app::util::AppIdentOpts, AsyncCliCommand}, + commands::{AsyncCliCommand, app::util::AppIdentOpts}, config::WasmerEnv, opts::ListFormatOpts, }; diff --git a/lib/cli/src/commands/app/volumes/credentials/mod.rs b/lib/cli/src/commands/app/volumes/credentials/mod.rs index 38d70515f5..e84cd6f63d 100644 --- a/lib/cli/src/commands/app/volumes/credentials/mod.rs +++ b/lib/cli/src/commands/app/volumes/credentials/mod.rs @@ -1,7 +1,7 @@ pub(super) mod rotate_secrets; use crate::{ - commands::{app::util::AppIdentOpts, AsyncCliCommand}, + commands::{AsyncCliCommand, app::util::AppIdentOpts}, config::WasmerEnv, }; diff --git a/lib/cli/src/commands/app/volumes/credentials/rotate_secrets.rs b/lib/cli/src/commands/app/volumes/credentials/rotate_secrets.rs index e2d041c64f..28507dcb70 100644 --- a/lib/cli/src/commands/app/volumes/credentials/rotate_secrets.rs +++ b/lib/cli/src/commands/app/volumes/credentials/rotate_secrets.rs @@ -1,8 +1,8 @@ use super::ItemFormatOpts; use crate::{ commands::{ - app::util::{AppIdent, AppIdentOpts}, AsyncCliCommand, + app::util::{AppIdent, AppIdentOpts}, }, config::WasmerEnv, }; diff --git a/lib/cli/src/commands/auth/login/auth_server.rs b/lib/cli/src/commands/auth/login/auth_server.rs index 4b2060ac68..45b7f8d44e 100644 --- a/lib/cli/src/commands/auth/login/auth_server.rs +++ b/lib/cli/src/commands/auth/login/auth_server.rs @@ -1,6 +1,6 @@ use super::AuthorizationState; use http_body_util::BodyExt; -use hyper::{body::Incoming, Request, Response, StatusCode}; +use hyper::{Request, Response, StatusCode, body::Incoming}; use reqwest::{Body, Method}; use tokio::net::TcpListener; diff --git a/lib/cli/src/commands/auth/login/mod.rs b/lib/cli/src/commands/auth/login/mod.rs index 5388964947..3a6ca6ea1c 100644 --- a/lib/cli/src/commands/auth/login/mod.rs +++ b/lib/cli/src/commands/auth/login/mod.rs @@ -8,9 +8,9 @@ use crate::{ commands::AsyncCliCommand, config::{UpdateRegistry, UserRegistry, WasmerConfig, WasmerEnv}, }; -use futures_util::{stream::FuturesUnordered, StreamExt}; +use futures_util::{StreamExt, stream::FuturesUnordered}; use std::{path::PathBuf, time::Duration}; -use wasmer_backend_api::{types::Nonce, WasmerClient}; +use wasmer_backend_api::{WasmerClient, types::Nonce}; #[derive(Debug, Clone)] enum AuthorizationState { @@ -256,7 +256,11 @@ impl AsyncCliCommand for Login { match self.login_and_save(&env, token).await { Ok(s) => { print!("Done!"); - println!("\n{} Login for Wasmer user {:?} saved","✔".green().bold(), s) + println!( + "\n{} Login for Wasmer user {:?} saved", + "✔".green().bold(), + s + ) } Err(_) => print!( "Warning: no user found on {:?} with the provided token.\nToken saved regardless.", @@ -352,7 +356,8 @@ mod tests { .get_opts() .filter(|arg| arg.get_id() != "token") .collect(); - let login_opts: Vec<_> = login.get_opts().collect(); + // the login opts, skipping the first positional argument (no-browser) + let login_opts: Vec<_> = login.get_opts().skip(1).collect(); assert_eq!(wasmer_env_opts, login_opts); @@ -379,12 +384,13 @@ mod tests { /// See https://github.com/wasmerio/wasmer/issues/4147. #[test] fn login_with_invalid_token_does_not_panic() { + let temp = TempDir::new().unwrap(); let cmd = Login { no_browser: true, - wasmer_dir: crate::config::DEFAULT_WASMER_DIR.clone(), + wasmer_dir: temp.path().to_path_buf(), registry: Some("http://localhost:11".to_string().into()), token: Some("invalid".to_string()), - cache_dir: crate::config::DEFAULT_WASMER_CACHE_DIR.clone(), + cache_dir: temp.path().join("cache").to_path_buf(), }; let res = cmd.run(); diff --git a/lib/cli/src/commands/auth/logout.rs b/lib/cli/src/commands/auth/logout.rs index ffbb79789a..b8934a6483 100644 --- a/lib/cli/src/commands/auth/logout.rs +++ b/lib/cli/src/commands/auth/logout.rs @@ -1,9 +1,9 @@ use crate::{ commands::AsyncCliCommand, - config::{WasmerConfig, WasmerEnv, DEFAULT_PROD_REGISTRY}, + config::{DEFAULT_PROD_REGISTRY, WasmerConfig, WasmerEnv}, }; use colored::Colorize; -use is_terminal::IsTerminal; +use std::io::IsTerminal as _; /// Log out from Wasmer #[derive(Debug, Clone, clap::Parser)] diff --git a/lib/cli/src/commands/binfmt.rs b/lib/cli/src/commands/binfmt.rs index 7af57e0675..a351368c00 100644 --- a/lib/cli/src/commands/binfmt.rs +++ b/lib/cli/src/commands/binfmt.rs @@ -5,9 +5,9 @@ use std::{ path::{Path, PathBuf}, }; -use anyhow::{bail, Context, Result}; -use clap::Parser; use Action::*; +use anyhow::{Context, Result, bail}; +use clap::Parser; #[derive(Debug, Parser, Clone, Copy)] enum Action { @@ -91,15 +91,22 @@ impl Binfmt { b":PFC", ] .concat(), + [ + b":wasm32-webc:M::\\x00webc::".as_ref(), + bin_path.as_os_str().as_bytes(), + b":PFC", + ] + .concat(), ]) } _ => None, }; let wasm_registration = self.binfmt_misc.join("wasm32"); let wat_registration = self.binfmt_misc.join("wasm32-wat"); + let webc_registration = self.binfmt_misc.join("wasm32-webc"); match self.action { - Reregister | Unregister => { - let unregister = [wasm_registration, wat_registration] + Register | Reregister | Unregister => { + let unregister = [wasm_registration, wat_registration, webc_registration] .iter() .map(|registration| { if registration.exists() { @@ -112,10 +119,6 @@ impl Binfmt { .context("Couldn't write binfmt unregister request")?; Ok(true) } else { - eprintln!( - "Warning: {} does not exist, not unregistered.", - registration.to_string_lossy() - ); Ok(false) } }) @@ -126,13 +129,8 @@ impl Binfmt { bail!("Nothing unregistered"); } } - _ => (), }; if let Some(specs) = specs { - if cfg!(target_env = "gnu") { - // Approximate. ELF parsing for a proper check feels like overkill here. - eprintln!("Warning: wasmer has been compiled for glibc, and is thus likely dynamically linked. Invoking wasm binaries in chroots or mount namespaces (lxc, docker, ...) may not work."); - } specs .iter() .map(|spec| { diff --git a/lib/cli/src/commands/compile.rs b/lib/cli/src/commands/compile.rs index 4c2cc45389..c1d347d529 100644 --- a/lib/cli/src/commands/compile.rs +++ b/lib/cli/src/commands/compile.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result, bail}; use clap::Parser; use wasmer::{ sys::{engine::NativeEngineExt, *}, @@ -81,11 +81,19 @@ impl Compile { match self.output.extension() { Some(ext) => { if ext != recommended_extension { - warning!("the output file has a wrong extension. We recommend using `{}.{}` for the chosen target", &output_filename, &recommended_extension) + warning!( + "the output file has a wrong extension. We recommend using `{}.{}` for the chosen target", + &output_filename, + &recommended_extension + ) } } None => { - warning!("the output file has no extension. We recommend using `{}.{}` for the chosen target", &output_filename, &recommended_extension) + warning!( + "the output file has no extension. We recommend using `{}.{}` for the chosen target", + &output_filename, + &recommended_extension + ) } } println!("Compiler: {}", engine.deterministic_id()); diff --git a/lib/cli/src/commands/config.rs b/lib/cli/src/commands/config.rs index 035d6bf887..643f8fd2ca 100644 --- a/lib/cli/src/commands/config.rs +++ b/lib/cli/src/commands/config.rs @@ -1,6 +1,6 @@ use crate::{ - config::{UpdateRegistry, WasmerConfig, WasmerEnv}, VERSION, + config::{UpdateRegistry, WasmerConfig, WasmerEnv}, }; use anyhow::{Context, Result}; use clap::Parser; @@ -272,14 +272,13 @@ impl GetOrSet { StorableConfigField::RegistryUrl(s) => { config.registry.set_current_registry(&s.url).await; let current_registry = config.registry.get_current_registry(); - if let Ok(client) = env.client() { - if let Some(u) = + if let Ok(client) = env.client() + && let Some(u) = wasmer_backend_api::query::current_user(&client).await? - { - println!( + { + println!( "Successfully logged into registry {current_registry:?} as user {u:?}" ); - } } } StorableConfigField::RegistryToken(t) => { diff --git a/lib/cli/src/commands/create_exe.rs b/lib/cli/src/commands/create_exe.rs index d4fba44fe1..52599337b0 100644 --- a/lib/cli/src/commands/create_exe.rs +++ b/lib/cli/src/commands/create_exe.rs @@ -4,10 +4,10 @@ use self::utils::normalize_atom_name; use super::CliCommand; use crate::{ backend::RuntimeOptions, - common::{normalize_path, HashAlgorithm}, + common::{HashAlgorithm, normalize_path}, config::WasmerEnv, }; -use anyhow::{anyhow, bail, Context, Result}; +use anyhow::{Context, Result, anyhow, bail}; use clap::Parser; use object::ObjectSection; use serde::{Deserialize, Serialize}; @@ -49,8 +49,8 @@ pub struct CreateExe { #[clap(name = "OUTPUT PATH", short = 'o')] output: PathBuf, - /// Optional directorey used for debugging: if present, will output the zig command - /// for reproducing issues in a debug directory + /// Optional directory used for debugging: if present, will output the zig command + /// for reproducing issues in a debug directory. #[clap(long, name = "DEBUG PATH")] debug_dir: Option, @@ -635,7 +635,8 @@ impl PrefixMapCompilation { if prefixes.len() != atoms.len() { println!( "WARNING: invalid mapping of prefix and atoms: expected prefixes for {} atoms, got {} prefixes", - atoms.len(), prefixes.len() + atoms.len(), + prefixes.len() ); } @@ -692,7 +693,9 @@ impl PrefixMapCompilation { manual_prefixes.insert(normalize_atom_name(&atoms[0].0), prefix.to_string()); } _ => { - return Err(anyhow::anyhow!("invalid --precompiled-atom {p:?} - correct format is ATOM:PREFIX:PATH or ATOM:PATH")); + return Err(anyhow::anyhow!( + "invalid --precompiled-atom {p:?} - correct format is ATOM:PREFIX:PATH or ATOM:PATH" + )); } } } @@ -1304,7 +1307,11 @@ fn link_exe_from_dir( include_path.push("include"); if !include_path.exists() { // Can happen when we got the wrong library_path - return Err(anyhow::anyhow!("Wasmer include path {} does not exist, maybe library path {} is wrong (expected /lib/libwasmer.a)?", include_path.display(), library_path.display())); + return Err(anyhow::anyhow!( + "Wasmer include path {} does not exist, maybe library path {} is wrong (expected /lib/libwasmer.a)?", + include_path.display(), + library_path.display() + )); } cmd.arg("-I"); cmd.arg(normalize_path(&format!("{}", include_path.display()))); @@ -1388,10 +1395,9 @@ fn link_exe_from_dir( .context(anyhow!("Could not execute `zig`: {cmd:?}"))?; if !compilation.status.success() { - return Err(anyhow::anyhow!(String::from_utf8_lossy( - &compilation.stderr - ) - .to_string())); + return Err(anyhow::anyhow!( + String::from_utf8_lossy(&compilation.stderr).to_string() + )); } // remove file if it exists - if not done, can lead to errors on copy @@ -1450,7 +1456,11 @@ fn link_objects_system_linker( include_path.push("include"); if !include_path.exists() { // Can happen when we got the wrong library_path - return Err(anyhow::anyhow!("Wasmer include path {} does not exist, maybe library path {} is wrong (expected /lib/libwasmer.a)?", include_path.display(), libwasmer_path.display())); + return Err(anyhow::anyhow!( + "Wasmer include path {} does not exist, maybe library path {} is wrong (expected /lib/libwasmer.a)?", + include_path.display(), + libwasmer_path.display() + )); } command = command.arg("-I"); command = command.arg(normalize_path(&format!("{}", include_path.display()))); @@ -1508,9 +1518,9 @@ fn generate_wasmer_main_c( let prefix = prefixes .get_prefix_for_atom(&utils::normalize_atom_name(a)) .ok_or_else(|| { + let formatted_prefixes = format!("{prefixes:#?}"); anyhow::anyhow!( - "cannot find prefix for atom {a} when generating wasmer_main.c ({:#?})", - prefixes + "cannot find prefix for atom {a} when generating wasmer_main.c ({formatted_prefixes})" ) })?; let atom_name = prefix.clone(); @@ -1564,10 +1574,10 @@ fn generate_wasmer_main_c( let prefix = prefixes .get_prefix_for_atom(&utils::normalize_atom_name(atom_names[0])) .ok_or_else(|| { + let formatted_prefixes = format!("{prefixes:#?}"); anyhow::anyhow!( - "cannot find prefix for atom {} when generating wasmer_main.c ({:#?})", - &atom_names[0], - prefixes + "cannot find prefix for atom {} when generating wasmer_main.c ({formatted_prefixes})", + &atom_names[0] ) })?; write!(c_code_to_instantiate, "module = atom_{prefix};")?; @@ -1576,9 +1586,9 @@ fn generate_wasmer_main_c( let prefix = prefixes .get_prefix_for_atom(&utils::normalize_atom_name(a)) .ok_or_else(|| { + let formatted_prefixes = format!("{prefixes:#?}"); anyhow::anyhow!( - "cannot find prefix for atom {a} when generating wasmer_main.c ({:#?})", - prefixes + "cannot find prefix for atom {a} when generating wasmer_main.c ({formatted_prefixes})" ) })?; writeln!( @@ -1617,7 +1627,7 @@ pub(super) mod utils { path::{Path, PathBuf}, }; - use anyhow::{anyhow, Context}; + use anyhow::{Context, anyhow}; use target_lexicon::{Architecture, Environment, OperatingSystem, Triple}; use wasmer_types::target::{CpuFeature, Target}; @@ -1647,20 +1657,20 @@ pub(super) mod utils { ) -> Result { let target = target_triple; - if let Some(tarball_path) = cross_subc.tarball.as_mut() { - if tarball_path.is_relative() { - *tarball_path = starting_cd.join(&tarball_path); - if !tarball_path.exists() { - return Err(anyhow!( - "Tarball path `{}` does not exist.", - tarball_path.display() - )); - } else if tarball_path.is_dir() { - return Err(anyhow!( - "Tarball path `{}` is a directory.", - tarball_path.display() - )); - } + if let Some(tarball_path) = cross_subc.tarball.as_mut() + && tarball_path.is_relative() + { + *tarball_path = starting_cd.join(&tarball_path); + if !tarball_path.exists() { + return Err(anyhow!( + "Tarball path `{}` does not exist.", + tarball_path.display() + )); + } else if tarball_path.is_dir() { + return Err(anyhow!( + "Tarball path `{}` is a directory.", + tarball_path.display() + )); } } @@ -1767,10 +1777,10 @@ pub(super) mod utils { return None; } - if let Architecture::Aarch64(_) = target.architecture { - if !(filename.contains("aarch64") || filename.contains("arm64")) { - return None; - } + if let Architecture::Aarch64(_) = target.architecture + && !(filename.contains("aarch64") || filename.contains("arm64")) + { + return None; } if let Architecture::X86_64 = target.architecture { @@ -1783,22 +1793,22 @@ pub(super) mod utils { } } - if let OperatingSystem::Windows = target.operating_system { - if !filename.contains("windows") { - return None; - } + if let OperatingSystem::Windows = target.operating_system + && !filename.contains("windows") + { + return None; } - if let OperatingSystem::Darwin = target.operating_system { - if !(filename.contains("apple") || filename.contains("darwin")) { - return None; - } + if let OperatingSystem::Darwin(_) = target.operating_system + && !(filename.contains("apple") || filename.contains("darwin")) + { + return None; } - if let OperatingSystem::Linux = target.operating_system { - if !filename.contains("linux") { - return None; - } + if let OperatingSystem::Linux = target.operating_system + && !filename.contains("linux") + { + return None; } Some(true) @@ -1851,7 +1861,9 @@ pub(super) mod utils { }) .cloned() .ok_or_else(|| { - anyhow!("Could not find libwasmer.a for {} target in the provided tarball path (files = {files:#?})", target) + anyhow!( + "Could not find libwasmer.a for {target} target in the provided tarball path (files = {files:#?})" + ) }) } @@ -1879,7 +1891,7 @@ pub(super) mod utils { }; let os = match target_triple.operating_system { OperatingSystem::Linux => "linux".into(), - OperatingSystem::Darwin => "macos".into(), + OperatingSystem::Darwin(_) => "macos".into(), OperatingSystem::Windows => "windows".into(), v => v.to_string(), }; @@ -1948,14 +1960,18 @@ pub(super) mod utils { pub(super) fn find_zig_binary(path: Option) -> Result { use std::env::split_paths; + #[cfg(not(unix))] + use std::ffi::OsStr; #[cfg(unix)] - use std::os::unix::ffi::OsStrExt; + use std::ffi::OsString; + #[cfg(unix)] + use std::os::unix::ffi::OsStringExt; let path_var = std::env::var("PATH").unwrap_or_default(); #[cfg(unix)] let system_path_var = std::process::Command::new("getconf") .args(["PATH"]) .output() - .map(|output| output.stdout) + .map(|output| OsString::from_vec(output.stdout)) .unwrap_or_default(); let retval = if let Some(p) = path { if p.exists() { @@ -1965,16 +1981,12 @@ pub(super) mod utils { } } else { let mut retval = None; - for mut p in split_paths(&path_var).chain(split_paths( - #[cfg(unix)] - { - &OsStr::from_bytes(&system_path_var[..]) - }, - #[cfg(not(unix))] - { - OsStr::new("") - }, - )) { + #[cfg(unix)] + let combined_paths = + split_paths(&path_var).chain(split_paths(system_path_var.as_os_str())); + #[cfg(not(unix))] + let combined_paths = split_paths(&path_var).chain(split_paths(OsStr::new(""))); + for mut p in combined_paths { p.push(get_zig_exe_str()); if p.exists() { retval = Some(p); @@ -2008,7 +2020,10 @@ pub(super) mod utils { .map_err(|e| anyhow!("could not parse zig version: {version_slice}: {e}"))?; if version_semver < semver::Version::parse("0.10.0").unwrap() { - Err(anyhow!("`zig` binary in PATH (`{}`) is not a new enough version (`{version_slice}`): please use version `0.10.0` or newer.", retval.display())) + Err(anyhow!( + "`zig` binary in PATH (`{}`) is not a new enough version (`{version_slice}`): please use version `0.10.0` or newer.", + retval.display() + )) } else { Ok(retval) } @@ -2143,7 +2158,7 @@ pub(super) mod utils { mod http_fetch { use std::path::Path; - use anyhow::{anyhow, Context, Result}; + use anyhow::{Context, Result, anyhow}; pub(super) fn get_release( release_version: Option, @@ -2290,7 +2305,7 @@ mod http_fetch { ) -> Result { let filename = browser_download_url .split('/') - .last() + .next_back() .unwrap_or("output") .to_string(); diff --git a/lib/cli/src/commands/create_obj.rs b/lib/cli/src/commands/create_obj.rs index a50d823d9e..a7586a4fde 100644 --- a/lib/cli/src/commands/create_obj.rs +++ b/lib/cli/src/commands/create_obj.rs @@ -21,8 +21,8 @@ pub struct CreateObj { #[clap(name = "OUTPUT_PATH", short = 'o')] output: PathBuf, - /// Optional directorey used for debugging: if present, will - /// output the files to a debug instead of a temp directory + /// Optional directory used for debugging: if present, will + /// output the files to a debug instead of a temporary directory. #[clap(long, name = "DEBUG PATH")] debug_dir: Option, diff --git a/lib/cli/src/commands/gen_c_header.rs b/lib/cli/src/commands/gen_c_header.rs index 2a6bcec2ce..38763da7fe 100644 --- a/lib/cli/src/commands/gen_c_header.rs +++ b/lib/cli/src/commands/gen_c_header.rs @@ -4,11 +4,11 @@ use anyhow::{Context, Error}; use bytes::Bytes; use clap::Parser; use wasmer_compiler::{ - object::ObjectMetadataBuilder, types::symbols::ModuleMetadataSymbolRegistry, Artifact, + Artifact, object::ObjectMetadataBuilder, types::symbols::ModuleMetadataSymbolRegistry, }; use wasmer_package::{package::WasmerPackageError, utils::from_bytes}; use wasmer_types::target::{CpuFeature, Triple}; -use webc::{compat::SharedBytes, Container, ContainerError, DetectError}; +use webc::{Container, ContainerError, DetectError, compat::SharedBytes}; use crate::backend::RuntimeOptions; @@ -82,7 +82,9 @@ impl GenCHeader { let engine = RuntimeOptions::default().get_sys_compiler_engine_for_target(target.clone())?; if !engine.is_sys() { - anyhow::bail!("Cannot use this engine to generate c-headers! Please, use one of `cranelift`, `llvm` or `singlepass`."); + anyhow::bail!( + "Cannot use this engine to generate c-headers! Please, use one of `cranelift`, `llvm` or `singlepass`." + ); } let engine = engine.into_sys(); diff --git a/lib/cli/src/commands/gen_completions.rs b/lib/cli/src/commands/gen_completions.rs index e3b64794d7..0b12a7cc52 100644 --- a/lib/cli/src/commands/gen_completions.rs +++ b/lib/cli/src/commands/gen_completions.rs @@ -1,6 +1,6 @@ use super::WasmerCmd; use clap::CommandFactory; -use clap_complete::{generate, Shell}; +use clap_complete::{Shell, generate}; use std::fs::OpenOptions; #[derive(Debug, Clone, clap::Parser)] diff --git a/lib/cli/src/commands/init.rs b/lib/cli/src/commands/init.rs index 26b416bb3a..33fc7d771a 100644 --- a/lib/cli/src/commands/init.rs +++ b/lib/cli/src/commands/init.rs @@ -556,7 +556,7 @@ fn parse_cargo_toml(manifest_path: &PathBuf) -> Result, ) -> Option>> { - if is_terminal::IsTerminal::is_terminal(&std::io::stdin()) { + if std::io::stdin().is_terminal() { return Some(tokio::task::spawn(async move { tokio::select! { _ = done => {} @@ -233,14 +235,61 @@ impl WasmerCmd { } fn run_inner() -> Result<(), anyhow::Error> { + let mut args_os = std::env::args_os(); + + let args = args_os.next().into_iter(); + + let mut binfmt_args: Vec = Vec::new(); if is_binfmt_interpreter() { - Run::from_binfmt_args().execute(crate::logging::Output::default()); - } + // In case of binfmt misc the first argument is wasmer-binfmt-interpreter, the second is the full path to the executable + // and the third is the original string for the executable as originally called by the user. + + // For now we are only using the real path and ignoring the original executable name. + // Ideally we would use the real path to load the file and the original name to pass it as argv[0] to the wasm module. + + let current_dir = std::env::current_dir() + .unwrap() + .into_os_string() + .into_string() + .unwrap(); + let mut mount_paths = vec!["/home", "/etc", "/tmp", "/var", "/nix", "/opt", "/root"] + .into_iter() + .filter(|path| { + let path = std::path::Path::new(path); + if !path.is_dir() { + // Not a directory + return false; + } + if std::fs::read_dir(path).is_err() { + // No permissions + return false; + } + true + }) + .collect::>(); + if !current_dir.starts_with("/home") { + mount_paths.push(current_dir.as_str()); + } - match WasmerCmd::try_parse() { + binfmt_args.push("run".into()); + binfmt_args.push("--net".into()); + // TODO: This does not seem to work, needs further investigation. + binfmt_args.push("--forward-host-env".into()); + for mount_path in mount_paths { + binfmt_args.push(format!("--mapdir={mount_path}:{mount_path}").into()); + } + binfmt_args.push(format!("--cwd={current_dir}").into()); + binfmt_args.push("--quiet".into()); + binfmt_args.push("--".into()); + binfmt_args.push(args_os.next().unwrap()); + args_os.next().unwrap(); + }; + let args_vec = args.chain(binfmt_args).chain(args_os).collect::>(); + + match WasmerCmd::try_parse_from(args_vec.iter()) { Ok(args) => args.execute(), Err(e) => { - let first_arg_is_subcommand = if let Some(first_arg) = args().nth(1) { + let first_arg_is_subcommand = if let Some(first_arg) = args_vec.get(1) { let mut ret = false; let cmd = WasmerCmd::command(); @@ -262,16 +311,14 @@ impl WasmerCmd { | clap::error::ErrorKind::UnknownArgument ) && !first_arg_is_subcommand; - if might_be_wasmer_run { - if let Ok(run) = Run::try_parse() { - // Try to parse the command using the `wasmer some/package` - // shorthand. Note that this has discoverability issues - // because it's not shown as part of the main argument - // parser's help, but that's fine. - let output = crate::logging::Output::default(); - output.initialize_logging(); - run.execute(output); - } + if might_be_wasmer_run && let Ok(run) = Run::try_parse_from(args_vec.iter()) { + // Try to parse the command using the `wasmer some/package` + // shorthand. Note that this has discoverability issues + // because it's not shown as part of the main argument + // parser's help, but that's fine. + let output = crate::logging::Output::default(); + output.initialize_logging(); + run.execute(output); } e.exit(); @@ -471,14 +518,41 @@ fn print_version(verbose: bool) -> Result<(), anyhow::Error> { println!( "wasmer {} ({} {})", env!("CARGO_PKG_VERSION"), - env!("WASMER_BUILD_GIT_HASH_SHORT"), + git_version!( + args = ["--abbrev=8", "--always", "--dirty=-modified", "--exclude=*"], + fallback = "" + ), env!("WASMER_BUILD_DATE") ); println!("binary: {}", env!("CARGO_PKG_NAME")); - println!("commit-hash: {}", env!("WASMER_BUILD_GIT_HASH")); + println!( + "commit-hash: {}", + git_version!( + args = [ + "--abbrev=40", + "--always", + "--dirty=-modified", + "--exclude=*" + ], + fallback = "", + ), + ); println!("commit-date: {}", env!("WASMER_BUILD_DATE")); println!("host: {}", target_lexicon::HOST); + let cpu_features = { + let feats = wasmer_types::target::CpuFeature::for_host(); + let all = wasmer_types::target::CpuFeature::all(); + all.iter() + .map(|f| { + let available = feats.contains(f); + format!("{}={}", f, if available { "true" } else { "false" }) + }) + .collect::>() + .join(",") + }; + println!("cpu: {cpu_features}"); + let mut runtimes = Vec::<&'static str>::new(); if cfg!(feature = "singlepass") { runtimes.push("singlepass"); diff --git a/lib/cli/src/commands/package/build.rs b/lib/cli/src/commands/package/build.rs index 16590d208d..c0f14e6fe2 100644 --- a/lib/cli/src/commands/package/build.rs +++ b/lib/cli/src/commands/package/build.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use anyhow::Context; -use dialoguer::console::{style, Emoji}; +use dialoguer::console::{Emoji, style}; use indicatif::ProgressBar; use sha2::Digest; use wasmer_config::package::PackageHash; diff --git a/lib/cli/src/commands/package/common/mod.rs b/lib/cli/src/commands/package/common/mod.rs index ef5a32e302..3221529f0f 100644 --- a/lib/cli/src/commands/package/common/mod.rs +++ b/lib/cli/src/commands/package/common/mod.rs @@ -219,7 +219,9 @@ pub(super) async fn login_user( } } else { let bin_name = self::macros::bin_name!(); - eprintln!("You are not logged in. Use the `--token` flag or log in (use `{bin_name} login`) to {msg}."); + eprintln!( + "You are not logged in. Use the `--token` flag or log in (use `{bin_name} login`) to {msg}." + ); anyhow::bail!("Stopping execution as the user is not logged in.") } } diff --git a/lib/cli/src/commands/package/common/wait.rs b/lib/cli/src/commands/package/common/wait.rs index 0aef557cfa..8704ae41cb 100644 --- a/lib/cli/src/commands/package/common/wait.rs +++ b/lib/cli/src/commands/package/common/wait.rs @@ -1,5 +1,5 @@ use futures::StreamExt; -use wasmer_backend_api::{types::PackageVersionState, WasmerClient}; +use wasmer_backend_api::{WasmerClient, types::PackageVersionState}; /// Different conditions that can be "awaited" when publishing a package. #[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)] diff --git a/lib/cli/src/commands/package/download.rs b/lib/cli/src/commands/package/download.rs index 54888fa407..2feca66827 100644 --- a/lib/cli/src/commands/package/download.rs +++ b/lib/cli/src/commands/package/download.rs @@ -1,7 +1,7 @@ use std::{env::current_dir, path::PathBuf}; -use anyhow::{bail, Context}; -use dialoguer::console::{style, Emoji}; +use anyhow::{Context, bail}; +use dialoguer::console::{Emoji, style}; use indicatif::{ProgressBar, ProgressStyle}; use tempfile::NamedTempFile; use wasmer_config::package::{PackageIdent, PackageSource}; @@ -16,8 +16,8 @@ use crate::config::WasmerEnv; /// Download the `wasmer/hello` package, writing to `./hello@.webc`. /// /// * `wasmer package download --unpack wasmer/hello@0.1.0 -o hello.webc` -/// Download the `wasmer/hello` package version `0.1.0`, writing to `./hello.webc`, -/// and unpacking it to `./hello.webc.unpacked/`. +/// Download the `wasmer/hello` package version `0.1.0`, writing to `./hello.webc`, +/// and unpacking it to `./hello.webc.unpacked/`. #[derive(clap::Parser, Debug)] pub struct PackageDownload { #[clap(flatten)] @@ -190,7 +190,7 @@ impl PackageDownload { (pkg.webc_url, ident, filename) } PackageSource::Path(p) => bail!("cannot download a package from a local path: '{p}'"), - PackageSource::Url(url) => bail!("cannot download a package from a URL: '{}'", url), + PackageSource::Url(url) => bail!("cannot download a package from a URL: '{url}'"), }; let builder = { diff --git a/lib/cli/src/commands/package/publish.rs b/lib/cli/src/commands/package/publish.rs index df34b4751d..bafeee76e2 100644 --- a/lib/cli/src/commands/package/publish.rs +++ b/lib/cli/src/commands/package/publish.rs @@ -1,16 +1,16 @@ use crate::{ commands::{ + AsyncCliCommand, package::{ common::{wait::*, *}, push::PackagePush, tag::PackageTag, }, - AsyncCliCommand, }, config::WasmerEnv, }; use colored::Colorize; -use is_terminal::IsTerminal; +use std::io::IsTerminal as _; use std::path::{Path, PathBuf}; use wasmer_backend_api::WasmerClient; use wasmer_config::package::{Manifest, PackageIdent}; diff --git a/lib/cli/src/commands/package/push.rs b/lib/cli/src/commands/package/push.rs index af4318af59..831e60cb56 100644 --- a/lib/cli/src/commands/package/push.rs +++ b/lib/cli/src/commands/package/push.rs @@ -5,7 +5,7 @@ use crate::{ }; use anyhow::Context; use colored::Colorize; -use is_terminal::IsTerminal; +use std::io::IsTerminal as _; use std::path::{Path, PathBuf}; use wasmer_backend_api::WasmerClient; use wasmer_config::package::{Manifest, PackageHash}; @@ -65,12 +65,11 @@ impl PackagePush { return Ok(owner.clone()); } - if let Some(pkg) = &manifest.package { - if let Some(ns) = &pkg.name { - if let Some(first) = ns.split('/').next() { - return Ok(first.to_string()); - } - } + if let Some(pkg) = &manifest.package + && let Some(ns) = &pkg.name + && let Some(first) = ns.split('/').next() + { + return Ok(first.to_string()); } if self.non_interactive { @@ -93,12 +92,11 @@ impl PackagePush { return Ok(Some(name.clone())); } - if let Some(pkg) = &manifest.package { - if let Some(ns) = &pkg.name { - if let Some(name) = ns.split('/').nth(1) { - return Ok(Some(name.to_string())); - } - } + if let Some(pkg) = &manifest.package + && let Some(ns) = &pkg.name + && let Some(name) = ns.split('/').nth(1) + { + return Ok(Some(name.to_string())); } Ok(None) @@ -153,7 +151,9 @@ impl PackagePush { if r.success { r.package_webc.unwrap().id } else { - anyhow::bail!("An unidentified error occurred while publishing the package. (response had success: false)") + anyhow::bail!( + "An unidentified error occurred while publishing the package. (response had success: false)" + ) } } None => anyhow::bail!("An unidentified error occurred while publishing the package."), // <- This is extremely bad.. @@ -184,7 +184,9 @@ impl PackagePush { let name = self.get_name(manifest).await?; let private = self.get_privacy(manifest); - tracing::info!("If published, package privacy is {private}, namespace is {namespace} and name is {name:?}"); + tracing::info!( + "If published, package privacy is {private}, namespace is {namespace} and name is {name:?}" + ); let pb = make_spinner!( self.quiet, diff --git a/lib/cli/src/commands/package/tag.rs b/lib/cli/src/commands/package/tag.rs index ce4ad0d81f..fb2c44d436 100644 --- a/lib/cli/src/commands/package/tag.rs +++ b/lib/cli/src/commands/package/tag.rs @@ -1,14 +1,14 @@ use crate::{ commands::{ - package::common::{macros::*, wait::wait_package, *}, AsyncCliCommand, + package::common::{macros::*, wait::wait_package, *}, }, config::WasmerEnv, }; use anyhow::Context; use colored::Colorize; -use dialoguer::{theme::ColorfulTheme, Confirm}; -use is_terminal::IsTerminal; +use dialoguer::{Confirm, theme::ColorfulTheme}; +use std::io::IsTerminal as _; use std::{ path::{Path, PathBuf}, str::FromStr, @@ -268,7 +268,9 @@ impl PackageTag { None => { spinner_err!(pb, "The package is not in the registry!"); if !self.quiet { - eprintln!("\n\nThe package with the required hash does not exist in the selected registry."); + eprintln!( + "\n\nThe package with the required hash does not exist in the selected registry." + ); let bin_name = bin_name!(); let cli = std::env::args() .filter(|s| !s.starts_with('-')) @@ -326,12 +328,11 @@ impl PackageTag { return Ok(Some(name.clone())); } - if let Some(pkg) = &manifest.and_then(|m| m.package.as_ref()) { - if let Some(ns) = &pkg.name { - if let Some(name) = ns.split('/').nth(1) { - return Ok(Some(name.to_string())); - } - } + if let Some(pkg) = &manifest.and_then(|m| m.package.as_ref()) + && let Some(ns) = &pkg.name + && let Some(name) = ns.split('/').nth(1) + { + return Ok(Some(name.to_string())); } if allow_unnamed { @@ -367,12 +368,11 @@ impl PackageTag { return Ok(namespace.clone()); } - if let Some(pkg) = manifest.and_then(|m| m.package.clone()) { - if let Some(name) = &pkg.name { - if let Some(ns) = name.split('/').next() { - return Ok(ns.to_string()); - } - } + if let Some(pkg) = manifest.and_then(|m| m.package.clone()) + && let Some(name) = &pkg.name + && let Some(ns) = name.split('/').next() + { + return Ok(ns.to_string()); } if self.non_interactive { @@ -466,7 +466,10 @@ impl PackageTag { let mut new_version = registry_version.clone(); new_version.patch += 1; if must_bump { - eprintln!("{}: Registry already has version {user_version} of {full_pkg_name}, but with different contents.", "Warn".bold().yellow()); + eprintln!( + "{}: Registry already has version {user_version} of {full_pkg_name}, but with different contents.", + "Warn".bold().yellow() + ); eprintln!( "{}: Not bumping the version will make this action fail.", "Warn".bold().yellow() diff --git a/lib/cli/src/commands/package/unpack.rs b/lib/cli/src/commands/package/unpack.rs index 08e579d4bb..25d58b429a 100644 --- a/lib/cli/src/commands/package/unpack.rs +++ b/lib/cli/src/commands/package/unpack.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use anyhow::Context; -use dialoguer::console::{style, Emoji}; +use dialoguer::console::{Emoji, style}; use indicatif::ProgressBar; use wasmer_package::utils::from_disk; diff --git a/lib/cli/src/commands/run/capabilities/mod.rs b/lib/cli/src/commands/run/capabilities/mod.rs index ada750bd57..43e3c36bc9 100644 --- a/lib/cli/src/commands/run/capabilities/mod.rs +++ b/lib/cli/src/commands/run/capabilities/mod.rs @@ -1,6 +1,6 @@ use crate::config::WasmerEnv; -use super::PackageSource; +use super::CliPackageSource; use anyhow::anyhow; use sha2::{Digest, Sha256}; use std::{ @@ -25,7 +25,7 @@ pub(crate) struct PkgCapabilityCache { pub(crate) fn get_capability_cache_path( env: &WasmerEnv, - input: &PackageSource, + input: &CliPackageSource, ) -> anyhow::Result { let registry_name = env .registry_public_url()? @@ -36,7 +36,7 @@ pub(crate) fn get_capability_cache_path( // We don't have the bytes of the module yet, but we still want to have the // package-capabilities cache be as close to an actual identifier as possible. let package_cache_path = match &input { - PackageSource::File(f) => { + CliPackageSource::File(f) => { let full_path = f.canonicalize()?.to_path_buf(); let metadata = full_path .parent() @@ -61,7 +61,7 @@ pub(crate) fn get_capability_cache_path( format!("path_{}.json", hex::encode(hash.finalize())) } - PackageSource::Dir(f) => { + CliPackageSource::Dir(f) => { let full_path = f.canonicalize()?.to_path_buf(); let metadata = full_path.metadata()?.modified()?; @@ -82,7 +82,7 @@ pub(crate) fn get_capability_cache_path( format!("path_{}.json", hex::encode(hash.finalize())) } - PackageSource::Package(p) => match p { + CliPackageSource::Package(p) => match p { PackageSpecifier::Ident(id) => match id { wasmer_config::package::PackageIdent::Named(n) => format!( "ident_{}_{}", diff --git a/lib/cli/src/commands/run/capabilities/net.rs b/lib/cli/src/commands/run/capabilities/net.rs index 7f12fd7368..d6610260ad 100644 --- a/lib/cli/src/commands/run/capabilities/net.rs +++ b/lib/cli/src/commands/run/capabilities/net.rs @@ -7,7 +7,7 @@ use std::{ time::Duration, }; -use super::{super::PackageSource, PkgCapabilityCache}; +use super::{super::CliPackageSource, PkgCapabilityCache}; use anyhow::Context; use colored::Colorize; use dialoguer::theme::ColorfulTheme; diff --git a/lib/cli/src/commands/run/mod.rs b/lib/cli/src/commands/run/mod.rs index e92a857731..881681a896 100644 --- a/lib/cli/src/commands/run/mod.rs +++ b/lib/cli/src/commands/run/mod.rs @@ -1,10 +1,13 @@ #![allow(missing_docs, unused)] mod capabilities; +mod package_source; +mod runtime; +mod target; mod wasi; use std::{ - collections::{hash_map::DefaultHasher, BTreeMap}, + collections::{BTreeMap, hash_map::DefaultHasher}, fmt::{Binary, Display}, fs::File, hash::{BuildHasherDefault, Hash, Hasher}, @@ -16,40 +19,40 @@ use std::{ time::{Duration, SystemTime, UNIX_EPOCH}, }; -use anyhow::{anyhow, bail, Context, Error}; +use anyhow::{Context, Error, anyhow, bail}; use clap::{Parser, ValueEnum}; use futures::future::BoxFuture; use indicatif::{MultiProgress, ProgressBar}; -use is_terminal::IsTerminal as _; use once_cell::sync::Lazy; use tempfile::NamedTempFile; use url::Url; #[cfg(feature = "sys")] use wasmer::sys::NativeEngineExt; use wasmer::{ - AsStoreMut, DeserializeError, Engine, Function, Imports, Instance, Module, Store, Type, - TypedFunction, Value, + AsStoreMut, DeserializeError, Engine, Function, Imports, Instance, Module, RuntimeError, Store, + Type, TypedFunction, Value, }; -use wasmer_types::{target::Target, Features}; +use wasmer_types::{Features, target::Target}; #[cfg(feature = "compiler")] use wasmer_compiler::ArtifactBuild; -use wasmer_config::package::PackageSource as PackageSpecifier; +use wasmer_config::package::PackageSource; use wasmer_package::utils::from_disk; use wasmer_types::ModuleHash; #[cfg(feature = "journal")] use wasmer_wasix::journal::{LogFileJournal, SnapshotTrigger}; use wasmer_wasix::{ + Runtime, SpawnError, WasiError, bin_factory::{BinaryPackage, BinaryPackageCommand}, journal::CompactingLogFileJournal, runners::{ + MappedCommand, MappedDirectory, Runner, dcgi::{DcgiInstanceFactory, DcgiRunner}, dproxy::DProxyRunner, wasi::{RuntimeOrEngine, WasiRunner}, wcgi::{self, AbortHandle, NoOpWcgiCallbacks, WcgiRunner}, - MappedCommand, MappedDirectory, Runner, }, runtime::{ module_cache::{CacheError, HashedModuleData}, @@ -57,16 +60,19 @@ use wasmer_wasix::{ resolver::QueryError, task_manager::VirtualTaskManagerExt, }, - Runtime, SpawnError, WasiError, }; -use webc::metadata::Manifest; use webc::Container; +use webc::metadata::Manifest; use crate::{ backend::RuntimeOptions, commands::run::wasi::Wasi, common::HashAlgorithm, config::WasmerEnv, error::PrettyError, logging::Output, }; +use self::{ + package_source::CliPackageSource, runtime::MonitoringRuntime, target::ExecutableTarget, +}; + const TICK: Duration = Duration::from_millis(250); /// The unstable `wasmer run` subcommand. @@ -93,8 +99,8 @@ pub struct Run { #[clap(name = "COREDUMP_PATH", long)] coredump_on_trap: Option, /// The file, URL, or package to run. - #[clap(value_parser = PackageSource::infer)] - input: PackageSource, + #[clap(value_parser = CliPackageSource::infer)] + input: CliPackageSource, /// Command-line arguments passed to the package args: Vec, /// Hashing algorithm to be used for module hash @@ -139,7 +145,7 @@ impl Run { // Try to detect WebAssembly features before selecting a backend tracing::info!("Input source: {:?}", self.input); - if let PackageSource::File(path) = &self.input { + if let CliPackageSource::File(path) = &self.input { tracing::info!("Input file path: {}", path.display()); // Try to read and detect any file that exists, regardless of extension @@ -158,7 +164,9 @@ impl Run { ); wasm_bytes = Some(bytes); } else { - tracing::info!("File does not have valid WebAssembly magic number, will try to run it anyway"); + tracing::info!( + "File does not have valid WebAssembly magic number, will try to run it anyway" + ); // Still provide the bytes so the engine can attempt to run it wasm_bytes = Some(bytes); } @@ -184,7 +192,7 @@ impl Run { } None => { // No WebAssembly file available for analysis, check if we have a webc package - if let PackageSource::Package(ref pkg_source) = &self.input { + if let CliPackageSource::Package(pkg_source) = &self.input { tracing::info!("Checking package for WebAssembly features: {}", pkg_source); self.rt.get_engine(&Target::default())? } else { @@ -218,7 +226,11 @@ impl Run { // This is a slow operation, so let's temporarily wrap the runtime with // something that displays progress - let monitoring_runtime = Arc::new(MonitoringRuntime::new(runtime, pb.clone())); + let monitoring_runtime = Arc::new(MonitoringRuntime::new( + runtime, + pb.clone(), + output.is_quiet_or_no_tty(), + )); let runtime: Arc = monitoring_runtime.runtime.clone(); let monitoring_runtime: Arc = monitoring_runtime; @@ -244,56 +256,61 @@ impl Run { } => self.execute_wasm(&path, module, module_hash, runtime.clone()), ExecutableTarget::Package(pkg) => { // Check if we should update the engine based on the WebC package features - if let Some(cmd) = pkg.get_entrypoint_command() { - if let Some(features) = cmd.wasm_features() { - // Get the right engine for these features - let backends = self.rt.get_available_backends()?; - let available_engines = backends - .iter() - .map(|b| b.to_string()) - .collect::>() - .join(", "); - - let filtered_backends = RuntimeOptions::filter_backends_by_features( - backends.clone(), - &features, + if let Some(cmd) = pkg.get_entrypoint_command() + && let Some(features) = cmd.wasm_features() + { + // Get the right engine for these features + let backends = self.rt.get_available_backends()?; + let available_engines = backends + .iter() + .map(|b| b.to_string()) + .collect::>() + .join(", "); + + let filtered_backends = RuntimeOptions::filter_backends_by_features( + backends.clone(), + &features, + &Target::default(), + ); + + if !filtered_backends.is_empty() { + let engine_id = filtered_backends[0].to_string(); + + // Get a new engine that's compatible with the required features + if let Ok(new_engine) = filtered_backends[0].get_engine( &Target::default(), - ); - - if !filtered_backends.is_empty() { - let engine_id = filtered_backends[0].to_string(); - - // Get a new engine that's compatible with the required features - if let Ok(new_engine) = filtered_backends[0].get_engine( - &Target::default(), - &features, - &self.rt, - ) { - tracing::info!( - "The command '{}' requires to run the Wasm module with the features {:?}. The backends available are {}. Choosing {}.", - cmd.name(), - features, - available_engines, - engine_id - ); - // Create a new runtime with the updated engine - let new_runtime = self.wasi.prepare_runtime( - new_engine, + &features, + &self.rt, + ) { + tracing::info!( + "The command '{}' requires to run the Wasm module with the features {:?}. The backends available are {}. Choosing {}.", + cmd.name(), + features, + available_engines, + engine_id + ); + // Create a new runtime with the updated engine + let capability_cache_path = + capabilities::get_capability_cache_path( &self.env, - &capabilities::get_capability_cache_path( - &self.env, - &self.input, - )?, - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build()?, - preferred_webc_version, + &self.input, )?; - - let new_runtime = - Arc::new(MonitoringRuntime::new(new_runtime, pb.clone())); - return self.execute_webc(&pkg, new_runtime); - } + let new_runtime = self.wasi.prepare_runtime( + new_engine, + &self.env, + &capability_cache_path, + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build()?, + preferred_webc_version, + )?; + + let new_runtime = Arc::new(MonitoringRuntime::new( + new_runtime, + pb.clone(), + output.is_quiet_or_no_tty(), + )); + return self.execute_webc(&pkg, new_runtime); } } } @@ -303,10 +320,10 @@ impl Run { }; // restore the TTY state as the execution may have changed it - if let Some(state) = tty { - if let Some(tty) = runtime.tty() { - tty.tty_set(state); - } + if let Some(state) = tty + && let Some(tty) = runtime.tty() + { + tty.tty_set(state); } if let Err(e) = &result { @@ -371,7 +388,8 @@ impl Run { let mut dependencies = Vec::new(); for name in &self.wasi.uses { - let specifier = PackageSpecifier::from_str(name) + let specifier = name + .parse::() .with_context(|| format!("Unable to parse \"{name}\" as a package specifier"))?; let pkg = { let specifier = specifier.clone(); @@ -505,18 +523,24 @@ impl Run { } }; - let return_values = invoke_function(&instance, &mut store, entry_function, &self.args)?; - - println!( - "{}", - return_values - .iter() - .map(|val| val.to_string()) - .collect::>() - .join(" ") - ); - - Ok(()) + let result = invoke_function(&instance, &mut store, entry_function, &self.args)?; + + match result { + Ok(return_values) => { + println!( + "{}", + return_values + .iter() + .map(|val| val.to_string()) + .collect::>() + .join(" ") + ); + Ok(()) + } + Err(err) => { + bail!("{}", err.display(&mut store)); + } + } } fn build_wasi_runner( @@ -527,8 +551,7 @@ impl Run { let mut runner = WasiRunner::new(); - let (is_home_mapped, is_tmp_mapped, mapped_diretories) = - self.wasi.build_mapped_directories()?; + let (is_home_mapped, mapped_diretories) = self.wasi.build_mapped_directories()?; runner .with_args(&self.args) @@ -537,10 +560,16 @@ impl Run { .with_mapped_host_commands(self.wasi.build_mapped_commands()?) .with_mapped_directories(mapped_diretories) .with_home_mapped(is_home_mapped) - .with_tmp_mapped(is_tmp_mapped) .with_forward_host_env(self.wasi.forward_host_env) .with_capabilities(self.wasi.capabilities()); + if let Some(cwd) = self.wasi.cwd.as_ref() { + if !cwd.starts_with("/") { + bail!("The argument to --cwd must be an absolute path"); + } + runner.with_current_dir(cwd.clone()); + } + if let Some(ref entry_function) = self.invoke { runner.with_entry_function(entry_function); } @@ -609,44 +638,6 @@ impl Run { } } } - - /// Create Run instance for arguments/env, assuming we're being run from a - /// CFP binfmt interpreter. - pub fn from_binfmt_args() -> Self { - Run::from_binfmt_args_fallible().unwrap_or_else(|e| { - crate::error::PrettyError::report::<()>( - Err(e).context("Failed to set up wasmer binfmt invocation"), - ) - }) - } - - fn from_binfmt_args_fallible() -> Result { - if cfg!(not(target_os = "linux")) { - bail!("binfmt_misc is only available on linux."); - } - - let argv = std::env::args().collect::>(); - let (_interpreter, executable, original_executable, args) = match &argv[..] { - [a, b, c, rest @ ..] => (a, b, c, rest), - _ => { - bail!("Wasmer binfmt interpreter needs at least three arguments (including $0) - must be registered as binfmt interpreter with the CFP flags. (Got arguments: {:?})", argv); - } - }; - let rt = RuntimeOptions::default(); - Ok(Run { - env: WasmerEnv::default(), - rt, - wasi: Wasi::for_binfmt_interpreter()?, - wcgi: WcgiOptions::default(), - stack_size: None, - entrypoint: Some(original_executable.to_string()), - invoke: None, - coredump_on_trap: None, - input: PackageSource::infer(executable)?, - args: args.to_vec(), - hash_algorithm: None, - }) - } } fn invoke_function( @@ -654,16 +645,14 @@ fn invoke_function( store: &mut Store, func: &Function, args: &[String], -) -> Result, Error> { +) -> anyhow::Result, RuntimeError>> { let func_ty = func.ty(store); let required_arguments = func_ty.params().len(); let provided_arguments = args.len(); anyhow::ensure!( required_arguments == provided_arguments, - "Function expected {} arguments, but received {}", - required_arguments, - provided_arguments, + "Function expected {required_arguments} arguments, but received {provided_arguments}" ); let invoke_args = args @@ -675,9 +664,7 @@ fn invoke_function( }) .collect::, _>>()?; - let return_values = func.call(store, &invoke_args)?; - - Ok(return_values) + Ok(func.call(store, &invoke_args)) } fn parse_value(s: &str, ty: wasmer_types::Type) -> Result { @@ -692,204 +679,6 @@ fn parse_value(s: &str, ty: wasmer_types::Type) -> Result { Ok(value) } -/// The input that was passed in via the command-line. -#[derive(Debug, Clone, PartialEq)] -enum PackageSource { - /// A file on disk (`*.wasm`, `*.webc`, etc.). - File(PathBuf), - /// A directory containing a `wasmer.toml` file - Dir(PathBuf), - /// A package to be downloaded (a URL, package name, etc.) - Package(PackageSpecifier), -} - -impl PackageSource { - fn infer(s: &str) -> Result { - let path = Path::new(s); - if path.is_file() { - return Ok(PackageSource::File(path.to_path_buf())); - } else if path.is_dir() { - return Ok(PackageSource::Dir(path.to_path_buf())); - } - - if let Ok(pkg) = PackageSpecifier::from_str(s) { - return Ok(PackageSource::Package(pkg)); - } - - Err(anyhow::anyhow!( - "Unable to resolve \"{s}\" as a URL, package name, or file on disk" - )) - } - - /// Try to resolve the [`PackageSource`] to an executable artifact. - /// - /// This will try to automatically download and cache any resources from the - /// internet. - #[tracing::instrument(level = "debug", skip_all)] - fn resolve_target( - &self, - rt: &Arc, - pb: &ProgressBar, - ) -> Result { - match self { - PackageSource::File(path) => ExecutableTarget::from_file(path, rt, pb), - PackageSource::Dir(d) => ExecutableTarget::from_dir(d, rt, pb), - PackageSource::Package(pkg) => { - pb.set_message("Loading from the registry"); - let inner_pck = pkg.clone(); - let inner_rt = rt.clone(); - let pkg = rt.task_manager().spawn_and_block_on(async move { - BinaryPackage::from_registry(&inner_pck, inner_rt.as_ref()).await - })??; - Ok(ExecutableTarget::Package(pkg)) - } - } - } -} - -impl Display for PackageSource { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - PackageSource::File(path) | PackageSource::Dir(path) => write!(f, "{}", path.display()), - PackageSource::Package(p) => write!(f, "{p}"), - } - } -} - -/// We've been given the path for a file... What does it contain and how should -/// that be run? -#[derive(Debug, Clone)] -enum TargetOnDisk { - WebAssemblyBinary, - Wat, - LocalWebc, - Artifact, -} - -impl TargetOnDisk { - fn from_file(path: &Path) -> Result { - // Normally the first couple hundred bytes is enough to figure - // out what type of file this is. - let mut buffer = [0_u8; 512]; - - let mut f = File::open(path) - .with_context(|| format!("Unable to open \"{}\" for reading", path.display()))?; - let bytes_read = f.read(&mut buffer)?; - - let leading_bytes = &buffer[..bytes_read]; - - if wasmer::is_wasm(leading_bytes) { - return Ok(TargetOnDisk::WebAssemblyBinary); - } - - if webc::detect(leading_bytes).is_ok() { - return Ok(TargetOnDisk::LocalWebc); - } - - #[cfg(feature = "compiler")] - if ArtifactBuild::is_deserializable(leading_bytes) { - return Ok(TargetOnDisk::Artifact); - } - - // If we can't figure out the file type based on its content, fall back - // to checking the extension. - - match path.extension().and_then(|s| s.to_str()) { - Some("wat") => Ok(TargetOnDisk::Wat), - Some("wasm") => Ok(TargetOnDisk::WebAssemblyBinary), - Some("webc") => Ok(TargetOnDisk::LocalWebc), - Some("wasmu") => Ok(TargetOnDisk::WebAssemblyBinary), - _ => bail!("Unable to determine how to execute \"{}\"", path.display()), - } - } -} - -#[derive(Debug, Clone)] -enum ExecutableTarget { - WebAssembly { - module: Module, - module_hash: ModuleHash, - path: PathBuf, - }, - Package(BinaryPackage), -} - -impl ExecutableTarget { - /// Try to load a Wasmer package from a directory containing a `wasmer.toml` - /// file. - #[tracing::instrument(level = "debug", skip_all)] - fn from_dir( - dir: &Path, - runtime: &Arc, - pb: &ProgressBar, - ) -> Result { - pb.set_message(format!("Loading \"{}\" into memory", dir.display())); - pb.set_message("Resolving dependencies"); - let inner_runtime = runtime.clone(); - let pkg = runtime.task_manager().spawn_and_block_on({ - let path = dir.to_path_buf(); - - async move { BinaryPackage::from_dir(&path, inner_runtime.as_ref()).await } - })??; - - Ok(ExecutableTarget::Package(pkg)) - } - - /// Try to load a file into something that can be used to run it. - #[tracing::instrument(level = "debug", skip_all)] - fn from_file( - path: &Path, - runtime: &Arc, - pb: &ProgressBar, - ) -> Result { - pb.set_message(format!("Loading from \"{}\"", path.display())); - - match TargetOnDisk::from_file(path)? { - TargetOnDisk::WebAssemblyBinary | TargetOnDisk::Wat => { - let wasm = std::fs::read(path)?; - let module_data = HashedModuleData::new(wasm); - let module_hash = *module_data.hash(); - - pb.set_message("Compiling to WebAssembly"); - let module = runtime - .load_hashed_module_sync(module_data, None) - .with_context(|| format!("Unable to compile \"{}\"", path.display()))?; - - Ok(ExecutableTarget::WebAssembly { - module, - module_hash, - path: path.to_path_buf(), - }) - } - TargetOnDisk::Artifact => { - let engine = runtime.engine(); - pb.set_message("Deserializing pre-compiled WebAssembly module"); - let module = unsafe { Module::deserialize_from_file(&engine, path)? }; - - let module_hash = module.info().hash.ok_or_else(|| { - anyhow::Error::msg("module hash is not present in the artifact") - })?; - - Ok(ExecutableTarget::WebAssembly { - module, - module_hash, - path: path.to_path_buf(), - }) - } - TargetOnDisk::LocalWebc => { - let container = from_disk(path)?; - pb.set_message("Resolving dependencies"); - - let inner_runtime = runtime.clone(); - let pkg = runtime.task_manager().spawn_and_block_on(async move { - BinaryPackage::from_webc(&container, inner_runtime.as_ref()).await - })??; - Ok(ExecutableTarget::Package(pkg)) - } - } - } -} - #[cfg(feature = "coredump")] fn generate_coredump(err: &Error, source_name: String, coredump_path: &Path) -> Result<(), Error> { let err: &wasmer::RuntimeError = match err.downcast_ref() { @@ -1011,218 +800,3 @@ fn get_exit_code( None } - -#[derive(Debug)] -struct MonitoringRuntime { - runtime: Arc, - progress: ProgressBar, -} - -impl MonitoringRuntime { - fn new(runtime: R, progress: ProgressBar) -> Self { - MonitoringRuntime { - runtime: Arc::new(runtime), - progress, - } - } -} - -impl wasmer_wasix::Runtime for MonitoringRuntime { - fn networking(&self) -> &virtual_net::DynVirtualNetworking { - self.runtime.networking() - } - - fn task_manager(&self) -> &Arc { - self.runtime.task_manager() - } - - fn package_loader( - &self, - ) -> Arc { - let inner = self.runtime.package_loader(); - Arc::new(MonitoringPackageLoader { - inner, - progress: self.progress.clone(), - }) - } - - fn module_cache( - &self, - ) -> Arc { - self.runtime.module_cache() - } - - fn source(&self) -> Arc { - let inner = self.runtime.source(); - Arc::new(MonitoringSource { - inner, - progress: self.progress.clone(), - }) - } - - fn engine(&self) -> wasmer::Engine { - self.runtime.engine() - } - - fn new_store(&self) -> wasmer::Store { - self.runtime.new_store() - } - - fn http_client(&self) -> Option<&wasmer_wasix::http::DynHttpClient> { - self.runtime.http_client() - } - - fn tty(&self) -> Option<&(dyn wasmer_wasix::os::TtyBridge + Send + Sync)> { - self.runtime.tty() - } - - #[cfg(feature = "journal")] - fn read_only_journals<'a>( - &'a self, - ) -> Box> + 'a> { - self.runtime.read_only_journals() - } - - #[cfg(feature = "journal")] - fn writable_journals<'a>( - &'a self, - ) -> Box> + 'a> { - self.runtime.writable_journals() - } - - #[cfg(feature = "journal")] - fn active_journal(&self) -> Option<&'_ wasmer_wasix::journal::DynJournal> { - self.runtime.active_journal() - } - - fn load_hashed_module( - &self, - module: HashedModuleData, - engine: Option<&Engine>, - ) -> BoxFuture<'_, Result> { - let hash = *module.hash(); - let fut = self.runtime.load_hashed_module(module, engine); - Box::pin(compile_with_progress(fut, hash, None)) - } - - fn load_hashed_module_sync( - &self, - wasm: HashedModuleData, - engine: Option<&Engine>, - ) -> Result { - let hash = *wasm.hash(); - compile_with_progress_sync( - || self.runtime.load_hashed_module_sync(wasm, engine), - &hash, - None, - ) - } - - fn load_command_module( - &self, - cmd: &BinaryPackageCommand, - ) -> BoxFuture<'_, Result> { - let fut = self.runtime.load_command_module(cmd); - - Box::pin(compile_with_progress( - fut, - *cmd.hash(), - Some(cmd.name().to_owned()), - )) - } - - fn load_command_module_sync( - &self, - cmd: &wasmer_wasix::bin_factory::BinaryPackageCommand, - ) -> Result { - compile_with_progress_sync( - || self.runtime.load_command_module_sync(cmd), - cmd.hash(), - Some(cmd.name()), - ) - } -} - -async fn compile_with_progress<'a, F, T>(fut: F, hash: ModuleHash, name: Option) -> T -where - F: std::future::Future + Send + 'a, - T: Send + 'static, -{ - let mut pb = new_progressbar_compile(&hash, name.as_deref()); - let res = fut.await; - pb.finish_and_clear(); - res -} - -fn compile_with_progress_sync(f: F, hash: &ModuleHash, name: Option<&str>) -> T -where - F: FnOnce() -> T, -{ - let mut pb = new_progressbar_compile(hash, name); - let res = f(); - pb.finish_and_clear(); - res -} - -fn new_progressbar_compile(hash: &ModuleHash, name: Option<&str>) -> ProgressBar { - // Only show a spinner if we're running in a TTY - if std::io::stderr().is_terminal() { - let msg = if let Some(name) = name { - format!("Compiling WebAssembly module for command '{name}' ({hash})...") - } else { - format!("Compiling WebAssembly module {hash}...") - }; - let pb = ProgressBar::new_spinner().with_message(msg); - pb.enable_steady_tick(Duration::from_millis(100)); - pb - } else { - ProgressBar::hidden() - } -} - -#[derive(Debug)] -struct MonitoringSource { - inner: Arc, - progress: ProgressBar, -} - -#[async_trait::async_trait] -impl wasmer_wasix::runtime::resolver::Source for MonitoringSource { - async fn query( - &self, - package: &PackageSpecifier, - ) -> Result, QueryError> { - self.progress.set_message(format!("Looking up {package}")); - self.inner.query(package).await - } -} - -#[derive(Debug)] -struct MonitoringPackageLoader { - inner: Arc, - progress: ProgressBar, -} - -#[async_trait::async_trait] -impl wasmer_wasix::runtime::package_loader::PackageLoader for MonitoringPackageLoader { - async fn load( - &self, - summary: &wasmer_wasix::runtime::resolver::PackageSummary, - ) -> Result { - let pkg_id = summary.package_id(); - self.progress.set_message(format!("Downloading {pkg_id}")); - - self.inner.load(summary).await - } - - async fn load_package_tree( - &self, - root: &Container, - resolution: &wasmer_wasix::runtime::resolver::Resolution, - root_is_local_dir: bool, - ) -> Result { - self.inner - .load_package_tree(root, resolution, root_is_local_dir) - .await - } -} diff --git a/lib/cli/src/commands/run/package_source.rs b/lib/cli/src/commands/run/package_source.rs new file mode 100644 index 0000000000..92c5d76faa --- /dev/null +++ b/lib/cli/src/commands/run/package_source.rs @@ -0,0 +1,79 @@ +use std::{ + path::{Path, PathBuf}, + sync::Arc, +}; + +use anyhow::Error; +use indicatif::ProgressBar; +use wasmer_config::package::PackageSource; +use wasmer_wasix::{ + Runtime, bin_factory::BinaryPackage, runtime::task_manager::VirtualTaskManagerExt as _, +}; + +use super::ExecutableTarget; + +/// CLI representation of a target to execute. +#[derive(Debug, Clone, PartialEq)] +pub enum CliPackageSource { + /// A file on disk (`*.wasm`, `*.webc`, etc.). + File(PathBuf), + /// A directory containing a `wasmer.toml` file + Dir(PathBuf), + /// A package to be downloaded (a URL, package name, etc.) + Package(PackageSource), +} + +impl CliPackageSource { + pub fn infer(s: &str) -> Result { + let path = Path::new(s); + if path.is_file() { + return Ok(Self::File(path.to_path_buf())); + } else if path.is_dir() { + return Ok(Self::Dir(path.to_path_buf())); + } + + if let Ok(pkg) = s.parse::() { + return Ok(Self::Package(pkg)); + } + + Err(anyhow::anyhow!( + "Unable to resolve \"{s}\" as a URL, package name, or file on disk" + )) + } + + /// Try to resolve the [`PackageSource`] to an executable artifact. + /// + /// This will try to automatically download and cache any resources from the + /// internet. + #[tracing::instrument(level = "debug", skip_all)] + pub fn resolve_target( + &self, + rt: &Arc, + pb: &ProgressBar, + ) -> Result { + match self { + Self::File(path) => ExecutableTarget::from_file(path, rt, pb), + Self::Dir(d) => ExecutableTarget::from_dir(d, rt, pb), + Self::Package(pkg) => { + pb.set_message("Loading from the registry"); + let inner_pck = pkg.clone(); + let inner_rt = rt.clone(); + let pkg = rt.task_manager().spawn_and_block_on(async move { + BinaryPackage::from_registry(&inner_pck, inner_rt.as_ref()).await + })??; + Ok(ExecutableTarget::Package(Box::new(pkg))) + } + } + } +} + +impl std::fmt::Display for CliPackageSource { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::File(path) | Self::Dir(path) => { + write!(f, "{}", path.display()) + } + Self::Package(p) => write!(f, "{p}"), + } + } +} diff --git a/lib/cli/src/commands/run/runtime.rs b/lib/cli/src/commands/run/runtime.rs new file mode 100644 index 0000000000..d0e712b6e0 --- /dev/null +++ b/lib/cli/src/commands/run/runtime.rs @@ -0,0 +1,285 @@ +//! Provides CLI-specific Wasix components. + +use std::{sync::Arc, time::Duration}; + +use anyhow::Error; +use futures::future::BoxFuture; +use indicatif::ProgressBar; +use std::io::IsTerminal as _; +use wasmer::{Engine, Module}; +use wasmer_config::package::PackageSource; +use wasmer_types::ModuleHash; +use wasmer_wasix::{ + SpawnError, + bin_factory::{BinaryPackage, BinaryPackageCommand}, + runtime::{ + module_cache::HashedModuleData, + resolver::{PackageSummary, QueryError}, + }, +}; +use webc::Container; + +/// Special wasix runtime implementation for the CLI. +/// +/// Wraps an undelrying runtime and adds progress monitoring for package +/// compilation. +#[derive(Debug)] +pub struct MonitoringRuntime { + pub runtime: Arc, + progress: ProgressBar, + quiet_mode: bool, +} + +impl MonitoringRuntime { + pub fn new(runtime: R, progress: ProgressBar, quiet_mode: bool) -> Self { + MonitoringRuntime { + runtime: Arc::new(runtime), + progress, + quiet_mode, + } + } +} + +impl wasmer_wasix::Runtime for MonitoringRuntime { + fn networking(&self) -> &virtual_net::DynVirtualNetworking { + self.runtime.networking() + } + + fn task_manager(&self) -> &Arc { + self.runtime.task_manager() + } + + fn package_loader( + &self, + ) -> Arc { + let inner = self.runtime.package_loader(); + Arc::new(MonitoringPackageLoader { + inner, + progress: self.progress.clone(), + }) + } + + fn module_cache( + &self, + ) -> Arc { + self.runtime.module_cache() + } + + fn source(&self) -> Arc { + let inner = self.runtime.source(); + Arc::new(MonitoringSource { + inner, + progress: self.progress.clone(), + }) + } + + fn engine(&self) -> Engine { + self.runtime.engine() + } + + fn new_store(&self) -> wasmer::Store { + self.runtime.new_store() + } + + fn http_client(&self) -> Option<&wasmer_wasix::http::DynHttpClient> { + self.runtime.http_client() + } + + fn tty(&self) -> Option<&(dyn wasmer_wasix::os::TtyBridge + Send + Sync)> { + self.runtime.tty() + } + + #[cfg(feature = "journal")] + fn read_only_journals<'a>( + &'a self, + ) -> Box> + 'a> { + self.runtime.read_only_journals() + } + + #[cfg(feature = "journal")] + fn writable_journals<'a>( + &'a self, + ) -> Box> + 'a> { + self.runtime.writable_journals() + } + + #[cfg(feature = "journal")] + fn active_journal(&self) -> Option<&'_ wasmer_wasix::journal::DynJournal> { + self.runtime.active_journal() + } + + fn load_hashed_module( + &self, + module: HashedModuleData, + engine: Option<&Engine>, + ) -> BoxFuture<'_, Result> { + if self.quiet_mode { + Box::pin(self.runtime.load_hashed_module(module, engine)) + } else { + let hash = *module.hash(); + let fut = self.runtime.load_hashed_module(module, engine); + Box::pin(compile_with_progress( + &self.progress, + fut, + hash, + None, + self.quiet_mode, + )) + } + } + + fn load_hashed_module_sync( + &self, + wasm: HashedModuleData, + engine: Option<&Engine>, + ) -> Result { + if self.quiet_mode { + self.runtime.load_hashed_module_sync(wasm, engine) + } else { + let hash = *wasm.hash(); + compile_with_progress_sync( + &self.progress, + move || self.runtime.load_hashed_module_sync(wasm, engine), + &hash, + None, + ) + } + } + + fn load_command_module( + &self, + cmd: &BinaryPackageCommand, + ) -> BoxFuture<'_, Result> { + if self.quiet_mode { + self.runtime.load_command_module(cmd) + } else { + let fut = self.runtime.load_command_module(cmd); + + Box::pin(compile_with_progress( + &self.progress, + fut, + *cmd.hash(), + Some(cmd.name().to_owned()), + self.quiet_mode, + )) + } + } + + fn load_command_module_sync( + &self, + cmd: &wasmer_wasix::bin_factory::BinaryPackageCommand, + ) -> Result { + if self.quiet_mode { + self.runtime.load_command_module_sync(cmd) + } else { + compile_with_progress_sync( + &self.progress, + || self.runtime.load_command_module_sync(cmd), + cmd.hash(), + Some(cmd.name()), + ) + } + } +} + +async fn compile_with_progress<'a, F, T>( + bar: &ProgressBar, + fut: F, + hash: ModuleHash, + name: Option, + quiet_mode: bool, +) -> T +where + F: std::future::Future + Send + 'a, + T: Send + 'static, +{ + if quiet_mode { + fut.await + } else { + let should_clear = bar.is_finished() || bar.is_hidden(); + show_compile_progress(bar, &hash, name.as_deref()); + let res = fut.await; + if should_clear { + bar.finish_and_clear(); + } + + res + } +} + +fn compile_with_progress_sync( + bar: &ProgressBar, + f: F, + hash: &ModuleHash, + name: Option<&str>, +) -> T +where + F: FnOnce() -> T, +{ + let should_clear = bar.is_finished() || bar.is_hidden(); + show_compile_progress(bar, hash, name); + let res = f(); + if should_clear { + bar.finish_and_clear(); + } + res +} + +fn show_compile_progress(bar: &ProgressBar, hash: &ModuleHash, name: Option<&str>) { + // Only show a spinner if we're running in a TTY + let hash = hash.to_string(); + let hash = &hash[0..8]; + let msg = if let Some(name) = name { + format!("Compiling WebAssembly module for command '{name}' ({hash})...") + } else { + format!("Compiling WebAssembly module {hash}...") + }; + + bar.set_message(msg); + bar.enable_steady_tick(Duration::from_millis(100)); + + if bar.is_finished() || bar.is_hidden() { + bar.reset(); + } +} + +#[derive(Debug)] +struct MonitoringSource { + inner: Arc, + progress: ProgressBar, +} + +#[async_trait::async_trait] +impl wasmer_wasix::runtime::resolver::Source for MonitoringSource { + async fn query(&self, package: &PackageSource) -> Result, QueryError> { + self.progress.set_message(format!("Looking up {package}")); + self.inner.query(package).await + } +} + +#[derive(Debug)] +struct MonitoringPackageLoader { + inner: Arc, + progress: ProgressBar, +} + +#[async_trait::async_trait] +impl wasmer_wasix::runtime::package_loader::PackageLoader for MonitoringPackageLoader { + async fn load(&self, summary: &PackageSummary) -> Result { + let pkg_id = summary.package_id(); + self.progress.set_message(format!("Downloading {pkg_id}")); + + self.inner.load(summary).await + } + + async fn load_package_tree( + &self, + root: &Container, + resolution: &wasmer_wasix::runtime::resolver::Resolution, + root_is_local_dir: bool, + ) -> Result { + self.inner + .load_package_tree(root, resolution, root_is_local_dir) + .await + } +} diff --git a/lib/cli/src/commands/run/target.rs b/lib/cli/src/commands/run/target.rs new file mode 100644 index 0000000000..4bc06e7335 --- /dev/null +++ b/lib/cli/src/commands/run/target.rs @@ -0,0 +1,153 @@ +use std::{ + fs::File, + io::Read as _, + path::{Path, PathBuf}, + sync::Arc, +}; + +use anyhow::{Context as _, Error, bail}; +use indicatif::ProgressBar; +use wasmer::Module; +#[cfg(feature = "compiler")] +use wasmer_compiler::ArtifactBuild; +use wasmer_types::ModuleHash; +use wasmer_wasix::{ + Runtime, + bin_factory::BinaryPackage, + runtime::{module_cache::HashedModuleData, task_manager::VirtualTaskManagerExt as _}, +}; + +/// We've been given the path for a file... What does it contain and how should +/// that be run? +#[derive(Debug, Clone)] +pub enum TargetOnDisk { + WebAssemblyBinary, + Wat, + LocalWebc, + Artifact, +} + +impl TargetOnDisk { + pub fn from_file(path: &Path) -> Result { + // Normally the first couple hundred bytes is enough to figure + // out what type of file this is. + let mut buffer = [0_u8; 512]; + + let mut f = File::open(path) + .with_context(|| format!("Unable to open \"{}\" for reading", path.display()))?; + let bytes_read = f.read(&mut buffer)?; + + let leading_bytes = &buffer[..bytes_read]; + + if wasmer::is_wasm(leading_bytes) { + return Ok(TargetOnDisk::WebAssemblyBinary); + } + + if webc::detect(leading_bytes).is_ok() { + return Ok(TargetOnDisk::LocalWebc); + } + + #[cfg(feature = "compiler")] + if ArtifactBuild::is_deserializable(leading_bytes) { + return Ok(TargetOnDisk::Artifact); + } + + // If we can't figure out the file type based on its content, fall back + // to checking the extension. + + match path.extension().and_then(|s| s.to_str()) { + Some("wat") => Ok(TargetOnDisk::Wat), + Some("wasm") => Ok(TargetOnDisk::WebAssemblyBinary), + Some("webc") => Ok(TargetOnDisk::LocalWebc), + Some("wasmu") => Ok(TargetOnDisk::WebAssemblyBinary), + _ => bail!("Unable to determine how to execute \"{}\"", path.display()), + } + } +} + +#[allow(clippy::large_enum_variant)] +#[derive(Debug, Clone)] +pub enum ExecutableTarget { + WebAssembly { + module: Module, + module_hash: ModuleHash, + path: PathBuf, + }, + Package(Box), +} + +impl ExecutableTarget { + /// Try to load a Wasmer package from a directory containing a `wasmer.toml` + /// file. + #[tracing::instrument(level = "debug", skip_all)] + pub fn from_dir( + dir: &Path, + runtime: &Arc, + pb: &ProgressBar, + ) -> Result { + pb.set_message(format!("Loading \"{}\" into memory", dir.display())); + pb.set_message("Resolving dependencies"); + let inner_runtime = runtime.clone(); + let pkg = runtime.task_manager().spawn_and_block_on({ + let path = dir.to_path_buf(); + + async move { BinaryPackage::from_dir(&path, inner_runtime.as_ref()).await } + })??; + + Ok(ExecutableTarget::Package(Box::new(pkg))) + } + + /// Try to load a file into something that can be used to run it. + #[tracing::instrument(level = "debug", skip_all)] + pub fn from_file( + path: &Path, + runtime: &Arc, + pb: &ProgressBar, + ) -> Result { + pb.set_message(format!("Loading from \"{}\"", path.display())); + + match TargetOnDisk::from_file(path)? { + TargetOnDisk::WebAssemblyBinary | TargetOnDisk::Wat => { + let wasm = std::fs::read(path)?; + let module_data = HashedModuleData::new(wasm); + let module_hash = *module_data.hash(); + + pb.set_message("Compiling to WebAssembly"); + let module = runtime + .load_hashed_module_sync(module_data, None) + .with_context(|| format!("Unable to compile \"{}\"", path.display()))?; + + Ok(ExecutableTarget::WebAssembly { + module, + module_hash, + path: path.to_path_buf(), + }) + } + TargetOnDisk::Artifact => { + let engine = runtime.engine(); + pb.set_message("Deserializing pre-compiled WebAssembly module"); + let module = unsafe { Module::deserialize_from_file(&engine, path)? }; + + let module_hash = module.info().hash.ok_or_else(|| { + anyhow::Error::msg("module hash is not present in the artifact") + })?; + + Ok(ExecutableTarget::WebAssembly { + module, + module_hash, + path: path.to_path_buf(), + }) + } + TargetOnDisk::LocalWebc => { + let container = wasmer_package::utils::from_disk(path)?; + pb.set_message("Resolving dependencies"); + + let inner_runtime = runtime.clone(); + let pkg = runtime.task_manager().spawn_and_block_on(async move { + BinaryPackage::from_webc(&container, inner_runtime.as_ref()).await + })??; + Ok(ExecutableTarget::Package(Box::new(pkg))) + } + } + } +} diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index f5a8b7604a..e324e668e2 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -2,11 +2,11 @@ use std::{ collections::{BTreeSet, HashMap}, path::{Path, PathBuf}, str::FromStr, - sync::{mpsc::Sender, Arc}, + sync::{Arc, mpsc::Sender}, time::Duration, }; -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result, bail}; use bytes::Bytes; use clap::Parser; use tokio::runtime::Handle; @@ -19,12 +19,14 @@ use wasmer_types::ModuleHash; #[cfg(feature = "journal")] use wasmer_wasix::journal::{LogFileJournal, SnapshotTrigger}; use wasmer_wasix::{ + PluggableRuntime, RewindState, Runtime, WasiEnv, WasiEnvBuilder, WasiError, WasiFunctionEnv, + WasiVersion, bin_factory::BinaryPackage, capabilities::Capabilities, default_fs_backing, get_wasi_versions, http::HttpClient, journal::{CompactingLogFileJournal, DynJournal, DynReadableJournal}, - os::{tty_sys::SysTty, TtyBridge}, + os::{TtyBridge, tty_sys::SysTty}, rewind_ext, runners::MAPPED_CURRENT_DIR_DEFAULT_PATH, runners::{MappedCommand, MappedDirectory}, @@ -35,14 +37,12 @@ use wasmer_wasix::{ BackendSource, FileSystemSource, InMemorySource, MultiSource, Source, WebSource, }, task_manager::{ - tokio::{RuntimeOrHandle, TokioTaskManager}, VirtualTaskManagerExt, + tokio::{RuntimeOrHandle, TokioTaskManager}, }, }, types::__WASI_STDIN_FILENO, wasmer_wasix_types::wasi::Errno, - PluggableRuntime, RewindState, Runtime, WasiEnv, WasiEnvBuilder, WasiError, WasiFunctionEnv, - WasiVersion, }; use crate::{ @@ -51,8 +51,8 @@ use crate::{ }; use super::{ + CliPackageSource, ExecutableTarget, capabilities::{self, PkgCapabilityCache}, - ExecutableTarget, PackageSource, }; const WAPM_SOURCE_CACHE_TIMEOUT: Duration = Duration::from_secs(10 * 60); @@ -60,7 +60,7 @@ const WAPM_SOURCE_CACHE_TIMEOUT: Duration = Duration::from_secs(10 * 60); #[derive(Debug, Parser, Clone, Default)] /// WASI Options pub struct Wasi { - /// WASI pre-opened directory + /// WASI pre-opened directories #[clap(long = "dir", name = "DIR", group = "wasi")] pub(crate) pre_opened_directories: Vec, @@ -72,6 +72,11 @@ pub struct Wasi { )] pub(crate) mapped_dirs: Vec, + /// Set the module's initial CWD to this path; does not work with + /// WASI preview 1 modules. + #[clap(long = "cwd")] + pub(crate) cwd: Option, + /// Pass custom environment variables #[clap( long = "env", @@ -294,7 +299,7 @@ impl Wasi { uses.push(pkg); } - let builder = WasiEnv::builder(program_name) + let mut builder = WasiEnv::builder(program_name) .runtime(Arc::clone(&rt)) .args(args) .envs(self.env_vars.clone()) @@ -314,7 +319,9 @@ impl Wasi { for dir in &self.pre_opened_directories { let mapping = if dir == Path::new(".") { if have_current_dir { - bail!("Cannot pre-open the current directory twice: --dir=. must only be specified once"); + bail!( + "Cannot pre-open the current directory twice: --dir=. must only be specified once" + ); } have_current_dir = true; @@ -370,7 +377,9 @@ impl Wasi { let mapping = if guest == "." { if have_current_dir { - bail!("Cannot pre-open the current directory twice: '--mapdir=?:.' / '--dir=.' must only be specified once"); + bail!( + "Cannot pre-open the current directory twice: '--mapdir=?:.' / '--dir=.' must only be specified once" + ); } have_current_dir = true; @@ -390,7 +399,7 @@ impl Wasi { if !mapped_dirs.is_empty() { // TODO: should we expose the common ancestor instead of root? let fs_backing: Arc = - Arc::new(PassthruFileSystem::new(default_fs_backing())); + Arc::new(PassthruFileSystem::new_arc(default_fs_backing())); for MappedDirectory { host, guest } in self.mapped_dirs.clone() { let host = if !host.is_absolute() { Path::new("/").join(host) @@ -401,16 +410,23 @@ impl Wasi { } } + if let Some(cwd) = self.cwd.as_ref() { + if !cwd.starts_with("/") { + bail!("The argument to --cwd must be an absolute path"); + } + builder = builder.current_dir(cwd.clone()); + } + // Open the root of the new filesystem - let b = builder + builder = builder .sandbox_fs(root_fs) .preopen_dir(Path::new("/")) .unwrap(); if have_current_dir { - b.map_dir(".", MAPPED_CURRENT_DIR_DEFAULT_PATH)? + builder.map_dir(".", MAPPED_CURRENT_DIR_DEFAULT_PATH)? } else { - b.map_dir(".", "/")? + builder.map_dir(".", "/")? } }; @@ -479,9 +495,7 @@ impl Wasi { Ok(Vec::new()) } - pub fn build_mapped_directories( - &self, - ) -> Result<(bool, bool, Vec), anyhow::Error> { + pub fn build_mapped_directories(&self) -> Result<(bool, Vec), anyhow::Error> { let mut mapped_dirs = Vec::new(); // Process the --dirs flag and merge it with --mapdir. @@ -489,7 +503,9 @@ impl Wasi { for dir in &self.pre_opened_directories { let mapping = if dir == Path::new(".") { if have_current_dir { - bail!("Cannot pre-open the current directory twice: --dir=. must only be specified once"); + bail!( + "Cannot pre-open the current directory twice: --dir=. must only be specified once" + ); } have_current_dir = true; @@ -545,7 +561,9 @@ impl Wasi { let mapping = if guest == "." { if have_current_dir { - bail!("Cannot pre-open the current directory twice: '--mapdir=?:.' / '--dir=.' must only be specified once"); + bail!( + "Cannot pre-open the current directory twice: '--mapdir=?:.' / '--dir=.' must only be specified once" + ); } have_current_dir = true; @@ -562,9 +580,7 @@ impl Wasi { mapped_dirs.push(mapping); } - let is_tmp_mapped = mapped_dirs.iter().any(|d| d.guest == "/tmp"); - - Ok((have_current_dir, is_tmp_mapped, mapped_dirs)) + Ok((have_current_dir, mapped_dirs)) } pub fn build_mapped_commands(&self) -> Result, anyhow::Error> { @@ -617,7 +633,7 @@ impl Wasi { pkg_cache_path: &Path, rt_or_handle: I, preferred_webc_version: webc::Version, - ) -> Result + ) -> Result> where I: Into, { @@ -726,7 +742,7 @@ impl Wasi { &self, env: &WasmerEnv, client: Arc, - ) -> Result { + ) -> Result { let checkout_dir = env.cache_dir().join("checkouts"); let tokens = tokens_by_authority(env)?; @@ -743,7 +759,7 @@ impl Wasi { env: &WasmerEnv, client: Arc, preferred_webc_version: webc::Version, - ) -> Result { + ) -> Result { let mut source = MultiSource::default(); // Note: This should be first so our "preloaded" sources get a chance to @@ -802,17 +818,17 @@ fn tokens_by_authority(env: &WasmerEnv) -> Result> { let config = env.config()?; for credentials in config.registry.tokens { - if let Ok(url) = Url::parse(&credentials.registry) { - if url.has_authority() { - tokens.insert(url.authority().to_string(), credentials.token); - } + if let Ok(url) = Url::parse(&credentials.registry) + && url.has_authority() + { + tokens.insert(url.authority().to_string(), credentials.token); } } - if let (Ok(current_registry), Some(token)) = (env.registry_endpoint(), env.token()) { - if current_registry.has_authority() { - tokens.insert(current_registry.authority().to_string(), token); - } + if let (Ok(current_registry), Some(token)) = (env.registry_endpoint(), env.token()) + && current_registry.has_authority() + { + tokens.insert(current_registry.authority().to_string(), token); } // Note: The global wasmer.toml config file stores URLs for the GraphQL @@ -829,10 +845,10 @@ fn tokens_by_authority(env: &WasmerEnv) -> Result> { let mut frontend_tokens = HashMap::new(); for (hostname, token) in &tokens { - if let Some(frontend_url) = hostname.strip_prefix("registry.") { - if !tokens.contains_key(frontend_url) { - frontend_tokens.insert(frontend_url.to_string(), token.clone()); - } + if let Some(frontend_url) = hostname.strip_prefix("registry.") + && !tokens.contains_key(frontend_url) + { + frontend_tokens.insert(frontend_url.to_string(), token.clone()); } } tokens.extend(frontend_tokens); diff --git a/lib/cli/src/commands/self_update.rs b/lib/cli/src/commands/self_update.rs index dd74fa274a..0469c8f98c 100644 --- a/lib/cli/src/commands/self_update.rs +++ b/lib/cli/src/commands/self_update.rs @@ -32,6 +32,8 @@ impl SelfUpdate { #[cfg(target_os = "windows")] fn inner_execute(&self) -> Result<(), anyhow::Error> { - anyhow::bail!("Self update is not supported on Windows. Use install instructions on the Wasmer homepage: https://wasmer.io"); + anyhow::bail!( + "Self update is not supported on Windows. Use install instructions on the Wasmer homepage: https://wasmer.io" + ); } } diff --git a/lib/cli/src/commands/ssh.rs b/lib/cli/src/commands/ssh.rs index d128b950ba..ff5f95889d 100644 --- a/lib/cli/src/commands/ssh.rs +++ b/lib/cli/src/commands/ssh.rs @@ -1,9 +1,9 @@ //! Edge SSH command. use anyhow::Context; -use wasmer_backend_api::{types::DeployApp, WasmerClient}; +use wasmer_backend_api::{WasmerClient, types::DeployApp}; -use super::{app::AppIdentArgOpts, AsyncCliCommand}; +use super::{AsyncCliCommand, app::AppIdentArgOpts}; use crate::{config::WasmerEnv, edge_config::LoadedEdgeConfig}; /// Start a remote SSH session. @@ -126,7 +126,7 @@ impl AsyncCliCommand for CmdSsh { if exit.success() { Ok(()) } else { - Err(anyhow::anyhow!("ssh failed with status {}", exit)) + Err(anyhow::anyhow!("ssh failed with status {exit}")) } } } diff --git a/lib/cli/src/commands/validate.rs b/lib/cli/src/commands/validate.rs index 450ae50bd4..4485a14074 100644 --- a/lib/cli/src/commands/validate.rs +++ b/lib/cli/src/commands/validate.rs @@ -1,8 +1,8 @@ use std::path::PathBuf; -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result, bail}; use clap::Parser; -use wasmer::{is_wasm, Module}; +use wasmer::{Module, is_wasm}; use wasmer_types::target::Target; use crate::backend::RuntimeOptions; diff --git a/lib/cli/src/commands/wasmer_create_exe_main.c b/lib/cli/src/commands/wasmer_create_exe_main.c index c4c60fcea6..ec728bcd4e 100644 --- a/lib/cli/src/commands/wasmer_create_exe_main.c +++ b/lib/cli/src/commands/wasmer_create_exe_main.c @@ -124,7 +124,7 @@ int main(int argc, char *argv[]) { } } - // select the --command only if if was given before a "--", such + // select the --command only if it was given before a "--", such for (int i = 1; i < argc; i++) { if ((strcmp(argv[i], "--command") == 0 || strcmp(argv[i], "-c") == 0) && dash_dash_position > i) { // next arg is a command diff --git a/lib/cli/src/commands/wast.rs b/lib/cli/src/commands/wast.rs index 52c97cab3c..0b8c33dbfa 100644 --- a/lib/cli/src/commands/wast.rs +++ b/lib/cli/src/commands/wast.rs @@ -4,8 +4,8 @@ use std::path::PathBuf; use anyhow::{Context, Result}; use clap::Parser; use wasmer::{ - sys::{engine::NativeEngineExt, Target}, Store, + sys::{Target, engine::NativeEngineExt}, }; use wasmer_wast::Wast as WastSpectest; diff --git a/lib/cli/src/common.rs b/lib/cli/src/common.rs index f65d4eaeca..247b38019f 100644 --- a/lib/cli/src/common.rs +++ b/lib/cli/src/common.rs @@ -41,20 +41,15 @@ pub(crate) fn normalize_path(s: &str) -> String { } /// Hashing algorithm to be used for the module info -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum, Default)] pub enum HashAlgorithm { /// Sha256 + #[default] Sha256, /// XXHash XXHash, } -impl Default for HashAlgorithm { - fn default() -> Self { - Self::Sha256 - } -} - impl From for wasmer_types::HashAlgorithm { fn from(value: HashAlgorithm) -> Self { match value { diff --git a/lib/cli/src/config/env.rs b/lib/cli/src/config/env.rs index 6a4fe4c6be..99728b8ef2 100644 --- a/lib/cli/src/config/env.rs +++ b/lib/cli/src/config/env.rs @@ -22,8 +22,7 @@ pub struct WasmerEnv { #[clap(long, env = "WASMER_CACHE_DIR", default_value = super::DEFAULT_WASMER_CACHE_DIR.as_os_str())] pub(crate) cache_dir: PathBuf, - /// The registry to fetch packages from (inferred from the environment by - /// default) + /// Change the current registry #[clap(long, env = "WASMER_REGISTRY")] pub(crate) registry: Option, @@ -150,8 +149,7 @@ impl WasmerEnv { Ok(Self::APP_DOMAIN_DEV.to_string()) } else { anyhow::bail!( - "could not determine app domain for backend url '{}': unknown backend", - domain + "could not determine app domain for backend url '{domain}': unknown backend" ); } } @@ -179,7 +177,9 @@ impl WasmerEnv { pub fn client(&self) -> Result { let client = self.client_unauthennticated()?; if client.auth_token().is_none() { - anyhow::bail!("no token provided - run 'wasmer login', specify --token=XXX, or set the WASMER_TOKEN env var"); + anyhow::bail!( + "no token provided - run 'wasmer login', specify --token=XXX, or set the WASMER_TOKEN env var" + ); } Ok(client) diff --git a/lib/cli/src/config/mod.rs b/lib/cli/src/config/mod.rs index 0a9822e183..55824d1def 100644 --- a/lib/cli/src/config/mod.rs +++ b/lib/cli/src/config/mod.rs @@ -81,6 +81,7 @@ impl Default for MultiRegistry { } } +#[allow(unused)] #[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)] pub struct Registry { pub url: String, @@ -181,8 +182,8 @@ impl MultiRegistry { let registry_formatted = format_graphql(registry); self.tokens .iter() - .filter(|login| login.registry == registry || login.registry == registry_formatted) - .last() + .rev() + .find(|login| login.registry == registry || login.registry == registry_formatted) .map(|login| login.token.clone()) } diff --git a/lib/cli/src/edge_config.rs b/lib/cli/src/edge_config.rs index 7d5aa5f903..fc12c7e914 100644 --- a/lib/cli/src/edge_config.rs +++ b/lib/cli/src/edge_config.rs @@ -4,7 +4,7 @@ use std::{ time::Duration, }; -use anyhow::{bail, Context}; +use anyhow::{Context, bail}; use serde::{Deserialize, Serialize}; use time::OffsetDateTime; @@ -35,10 +35,7 @@ impl EdgeConfig { .context("invalid client config: no 'version' key found")?; if version != Self::VERSION as i64 { - bail!( - "Invalid client config: unknown config version '{}'", - version - ); + bail!("Invalid client config: unknown config version '{version}'"); } let config = toml::from_str(data_str)?; @@ -137,19 +134,19 @@ pub fn load_config(custom_path: Option) -> Result { - return Ok(LoadedEdgeConfig { config, path }); - } - Err(err) => { - eprintln!( - "WARNING: failed to load config file at '{}': {}", - path.display(), - err - ); - } + if let Some(path) = path + && path.is_file() + { + match try_load_config(&path) { + Ok(config) => { + return Ok(LoadedEdgeConfig { config, path }); + } + Err(err) => { + eprintln!( + "WARNING: failed to load config file at '{}': {}", + path.display(), + err + ); } } } diff --git a/lib/cli/src/lib.rs b/lib/cli/src/lib.rs index 1b2961e6c0..cdf22c4975 100644 --- a/lib/cli/src/lib.rs +++ b/lib/cli/src/lib.rs @@ -13,7 +13,7 @@ )] // Allowed because it makes code more readable. #![allow(clippy::bool_comparison, clippy::match_like_matches_macro)] -#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] //#[cfg(all(target_os = "linux", feature = "tun-tap"))] //mod net; diff --git a/lib/cli/src/logging.rs b/lib/cli/src/logging.rs index 1f4c7a0097..c67343d7c5 100644 --- a/lib/cli/src/logging.rs +++ b/lib/cli/src/logging.rs @@ -1,8 +1,8 @@ //! Logging functions for the debug feature. -use is_terminal::IsTerminal; +use std::io::IsTerminal as _; use tracing::level_filters::LevelFilter; -use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; +use tracing_subscriber::{EnvFilter, Layer, fmt, layer::SubscriberExt, util::SubscriberInitExt}; const WHITELISTED_LOG_TARGETS: &[&str] = &["wasmer", "wasmer_wasix", "virtual_fs"]; @@ -32,9 +32,16 @@ impl Output { self.verbose > 0 } + /// Returns true if either the `--quiet` flag is set or stderr is not a TTY. + pub fn is_quiet_or_no_tty(&self) -> bool { + self.quiet || !std::io::stderr().is_terminal() + } + /// Initialize logging based on the `$RUST_LOG` environment variable and /// command-line flags. pub fn initialize_logging(&self) { + let filter_layer = self.log_filter(); + let fmt_layer = fmt::layer() .with_target(true) .with_ansi(self.should_emit_colors()) @@ -49,18 +56,24 @@ impl Output { } }; - let filter_layer = self.log_filter(); + let registry = tracing_subscriber::registry(); + + #[cfg(feature = "tokio-subscriber")] + let registry = registry.with(console_subscriber::spawn()); match self.log_format { - LogFormat::Text => tracing_subscriber::registry() - .with(filter_layer) - .with(fmt_layer.compact().with_target(true)) + LogFormat::Text => registry + .with( + fmt_layer + .compact() + .with_target(true) + .with_filter(filter_layer), + ) .init(), - LogFormat::Json => tracing_subscriber::registry() - .with(filter_layer) - .with(fmt_layer.json().with_target(true)) + LogFormat::Json => registry + .with(fmt_layer.json().with_target(true).with_filter(filter_layer)) .init(), - } + }; } fn log_filter(&self) -> EnvFilter { diff --git a/lib/cli/src/utils/mod.rs b/lib/cli/src/utils/mod.rs index c418b8e179..f918cea6b3 100644 --- a/lib/cli/src/utils/mod.rs +++ b/lib/cli/src/utils/mod.rs @@ -6,14 +6,9 @@ pub(crate) mod render; pub(crate) mod timestamp; pub(crate) mod unpack; -use std::{ - path::{Path, PathBuf}, - str::FromStr, -}; +use std::path::{Path, PathBuf}; -use anyhow::{bail, Context as _, Result}; -use once_cell::sync::Lazy; -use regex::Regex; +use anyhow::{Context as _, Result, bail}; use wasmer_wasix::runners::MappedDirectory; fn retrieve_alias_pathbuf(alias: &str, real_dir: &str) -> Result { @@ -95,7 +90,7 @@ pub fn load_package_manifest( "Could not read package manifest at '{}'", file_path.display() ) - }) + }); } }; @@ -110,78 +105,6 @@ pub fn load_package_manifest( Ok(Some((file_path, manifest))) } -/// The identifier for an app or package in the form, `owner/package@version`, -/// where the `owner` and `version` are optional. -#[derive(Debug, Clone, PartialEq)] -pub(crate) struct Identifier { - /// The package's name. - pub name: String, - /// The package's owner, typically a username or namespace. - pub owner: Option, - /// The package's version number. - pub version: Option, -} - -impl Identifier { - pub fn new(name: impl Into) -> Self { - Identifier { - name: name.into(), - owner: None, - version: None, - } - } - - pub fn with_owner(self, owner: impl Into) -> Self { - Identifier { - owner: Some(owner.into()), - ..self - } - } - - pub fn with_version(self, version: impl Into) -> Self { - Identifier { - version: Some(version.into()), - ..self - } - } -} - -impl FromStr for Identifier { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - const PATTERN: &str = r"^(?x) - (?: - (?P[a-zA-Z][\w\d_.-]*) - / - )? - (?P[a-zA-Z][\w\d_.-]*) - (?: - @ - (?P[\w\d.]+) - )? - $ - "; - static RE: Lazy = Lazy::new(|| Regex::new(PATTERN).unwrap()); - - let caps = RE.captures(s).context( - "Invalid package identifier, expected something like namespace/package@version", - )?; - - let mut identifier = Identifier::new(&caps["name"]); - - if let Some(owner) = caps.name("owner") { - identifier = identifier.with_owner(owner.as_str()); - } - - if let Some(version) = caps.name("version") { - identifier = identifier.with_version(version.as_str()); - } - - Ok(identifier) - } -} - /// Merge two yaml values by recursively merging maps from b into a. /// /// Preserves old values that were not in b. @@ -249,46 +172,6 @@ c: c assert_eq!(merged, c); } - #[test] - fn parse_valid_identifiers() { - let inputs = [ - ("python", Identifier::new("python")), - ( - "syrusakbary/python", - Identifier::new("python").with_owner("syrusakbary"), - ), - ( - "wasmer/wasmer.io", - Identifier::new("wasmer.io").with_owner("wasmer"), - ), - ( - "syrusakbary/python@1.2.3", - Identifier::new("python") - .with_owner("syrusakbary") - .with_version("1.2.3"), - ), - ( - "python@1.2.3", - Identifier::new("python").with_version("1.2.3"), - ), - ]; - - for (src, expected) in inputs { - let identifier = Identifier::from_str(src).expect(src); - assert_eq!(identifier, expected); - } - } - - #[test] - fn invalid_package_identifiers() { - let inputs = ["", "$", "python/", "/python", "python@", "."]; - - for input in inputs { - let result = Identifier::from_str(input); - assert!(result.is_err(), "Got {result:?} from {input:?}"); - } - } - #[test] fn test_parse_envvar() { assert_eq!( diff --git a/lib/cli/src/utils/prompts.rs b/lib/cli/src/utils/prompts.rs index 2e2209f2ad..f5754ce6df 100644 --- a/lib/cli/src/utils/prompts.rs +++ b/lib/cli/src/utils/prompts.rs @@ -1,6 +1,6 @@ use anyhow::Context; use colored::Colorize; -use dialoguer::{theme::ColorfulTheme, Select}; +use dialoguer::{Select, theme::ColorfulTheme}; use wasmer_backend_api::WasmerClient; use wasmer_config::package::NamedPackageIdent; diff --git a/lib/cli/src/utils/timestamp.rs b/lib/cli/src/utils/timestamp.rs index 61b61f187f..d9e4b109ed 100644 --- a/lib/cli/src/utils/timestamp.rs +++ b/lib/cli/src/utils/timestamp.rs @@ -1,6 +1,6 @@ use time::{ - format_description::well_known::{Rfc2822, Rfc3339}, Date, OffsetDateTime, PrimitiveDateTime, Time, + format_description::well_known::{Rfc2822, Rfc3339}, }; /// Try to parse the string as a timestamp in a number of well-known formats. diff --git a/lib/cli/tests/version.rs b/lib/cli/tests/version.rs index 1dcb7e8307..62558358fb 100644 --- a/lib/cli/tests/version.rs +++ b/lib/cli/tests/version.rs @@ -1,4 +1,5 @@ -use assert_cmd::Command; +use assert_cmd::cargo::cargo_bin_cmd; +use git_version::git_version; const WASMER_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -6,15 +7,13 @@ const WASMER_VERSION: &str = env!("CARGO_PKG_VERSION"); fn short_version_string() { let version_number = format!("wasmer {WASMER_VERSION}"); - Command::cargo_bin("wasmer") - .unwrap() + cargo_bin_cmd!("wasmer") .arg("--version") .assert() .success() .stdout(predicates::str::contains(&version_number)); - Command::cargo_bin("wasmer") - .unwrap() + cargo_bin_cmd!("wasmer") .arg("-V") .assert() .success() @@ -26,12 +25,14 @@ fn long_version_string() { let long_version_number = format!( "wasmer {} ({} {})", env!("CARGO_PKG_VERSION"), - env!("WASMER_BUILD_GIT_HASH_SHORT"), + git_version!( + args = ["--abbrev=8", "--always", "--dirty=-modified", "--exclude=*"], + fallback = "" + ), env!("WASMER_BUILD_DATE") ); - Command::cargo_bin("wasmer") - .unwrap() + cargo_bin_cmd!("wasmer") .arg("--version") .arg("--verbose") .assert() @@ -39,8 +40,7 @@ fn long_version_string() { .stdout(predicates::str::contains(&long_version_number)) .stdout(predicates::str::contains("binary:")); - Command::cargo_bin("wasmer") - .unwrap() + cargo_bin_cmd!("wasmer") .arg("-Vv") .assert() .success() @@ -52,15 +52,13 @@ fn long_version_string() { fn help_text_contains_version() { let version_number = format!("wasmer {WASMER_VERSION}"); - Command::cargo_bin("wasmer") - .unwrap() + cargo_bin_cmd!("wasmer") .arg("-h") .assert() .success() .stdout(predicates::str::contains(&version_number)); - Command::cargo_bin("wasmer") - .unwrap() + cargo_bin_cmd!("wasmer") .arg("--help") .assert() .success() diff --git a/lib/compiler-cranelift/Cargo.toml b/lib/compiler-cranelift/Cargo.toml index 44ab1886ed..3132b1a2b0 100644 --- a/lib/compiler-cranelift/Cargo.toml +++ b/lib/compiler-cranelift/Cargo.toml @@ -14,20 +14,22 @@ rust-version.workspace = true version.workspace = true [dependencies] -wasmer-compiler = { path = "../compiler", version = "=6.1.0", features = [ +wasmer-compiler = { path = "../compiler", version = "=6.1.0", default-features = false, features = [ "translator", "compiler", -], default-features = false } +] } wasmer-types = { path = "../types", version = "=6.1.0", default-features = false, features = [ "std", ] } -cranelift-entity = { version = "=0.110.2", default-features = false } -cranelift-codegen = { version = "=0.110.2", default-features = false, features = [ + +cranelift-entity = { workspace = true } +cranelift-codegen = { workspace = true, features = [ "x86", "arm64", "riscv64", ] } -cranelift-frontend = { version = "=0.110.2", default-features = false } +cranelift-frontend = { workspace = true } + itertools.workspace = true tracing.workspace = true hashbrown = { workspace = true, optional = true } @@ -35,10 +37,10 @@ rayon = { workspace = true, optional = true } more-asserts.workspace = true gimli = { workspace = true, optional = true } smallvec.workspace = true -target-lexicon = { workspace = true, default-features = false } +target-lexicon = { workspace = true } [dev-dependencies] -cranelift-codegen = { version = "=0.110.2", features = ["all-arch"] } +cranelift-codegen = { workspace = true, features = ["all-arch"] } [badges] maintenance = { status = "actively-developed" } diff --git a/lib/compiler-cranelift/build.rs b/lib/compiler-cranelift/build.rs deleted file mode 100644 index 69eb555dbe..0000000000 --- a/lib/compiler-cranelift/build.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Wasmer Cranelift compiler build script. -//! -//! Sets the git revsion? for $PURPOSE -//! TODO(syrus): explain what's happening here - -use std::process::Command; -use std::str; - -fn main() { - let git_rev = match Command::new("git").args(["rev-parse", "HEAD"]).output() { - Ok(output) => str::from_utf8(&output.stdout).unwrap().trim().to_string(), - Err(_) => env!("CARGO_PKG_VERSION").to_string(), - }; - println!("cargo:rustc-env=GIT_REV={git_rev}"); -} diff --git a/lib/compiler-cranelift/src/compiler.rs b/lib/compiler-cranelift/src/compiler.rs index 6acb6efec4..21e6892af6 100644 --- a/lib/compiler-cranelift/src/compiler.rs +++ b/lib/compiler-cranelift/src/compiler.rs @@ -3,21 +3,23 @@ #[cfg(feature = "unwind")] use crate::dwarf::WriterRelocate; +#[cfg(feature = "unwind")] +use crate::translator::CraneliftUnwindInfo; use crate::{ address_map::get_function_address_map, config::Cranelift, - func_environ::{get_function_name, FuncEnvironment}, + func_environ::{FuncEnvironment, get_function_name}, trampoline::{ - make_trampoline_dynamic_function, make_trampoline_function_call, FunctionBuilderContext, + FunctionBuilderContext, make_trampoline_dynamic_function, make_trampoline_function_call, }, translator::{ - compiled_function_unwind_info, irlibcall_to_libcall, irreloc_to_relocationkind, - signature_to_cranelift_ir, CraneliftUnwindInfo, FuncTranslator, + FuncTranslator, compiled_function_unwind_info, irlibcall_to_libcall, + irreloc_to_relocationkind, signature_to_cranelift_ir, }, }; use cranelift_codegen::{ - ir::{self, ExternalName, UserFuncName}, Context, FinalizedMachReloc, FinalizedRelocTarget, MachTrap, + ir::{self, ExternalName, UserFuncName}, }; #[cfg(feature = "unwind")] @@ -27,21 +29,25 @@ use gimli::write::{Address, EhFrame, FrameTable, Writer}; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use std::sync::Arc; +#[cfg(feature = "unwind")] +use wasmer_compiler::types::{section::SectionIndex, unwind::CompiledFunctionUnwindInfo}; use wasmer_compiler::{ + Compiler, FunctionBinaryReader, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, + ModuleMiddlewareChain, ModuleTranslationState, types::{ function::{ Compilation, CompiledFunction, CompiledFunctionFrameInfo, FunctionBody, UnwindInfo, }, module::CompileModuleInfo, relocation::{Relocation, RelocationTarget}, - section::SectionIndex, - unwind::CompiledFunctionUnwindInfo, }, - Compiler, FunctionBinaryReader, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, - ModuleMiddlewareChain, ModuleTranslationState, }; -use wasmer_types::entity::{EntityRef, PrimaryMap}; -use wasmer_types::target::{CallingConvention, Target}; +#[cfg(feature = "unwind")] +use wasmer_types::entity::EntityRef; +use wasmer_types::entity::PrimaryMap; +#[cfg(feature = "unwind")] +use wasmer_types::target::CallingConvention; +use wasmer_types::target::Target; use wasmer_types::{ CompileError, FunctionIndex, LocalFunctionIndex, ModuleInfo, SignatureIndex, TrapCode, TrapInformation, @@ -112,128 +118,9 @@ impl CraneliftCompiler { } }; - let mut custom_sections = PrimaryMap::new(); - - #[cfg(not(feature = "rayon"))] - let mut func_translator = FuncTranslator::new(); - #[cfg(not(feature = "rayon"))] - let (functions, fdes): (Vec, Vec<_>) = function_body_inputs - .iter() - .collect::)>>() - .into_iter() - .map(|(i, input)| { - let func_index = module.func_index(i); - let mut context = Context::new(); - let mut func_env = FuncEnvironment::new( - isa.frontend_config(), - module, - &signatures, - &memory_styles, - table_styles, - ); - context.func.name = match get_function_name(func_index) { - ExternalName::User(nameref) => { - if context.func.params.user_named_funcs().is_valid(nameref) { - let name = &context.func.params.user_named_funcs()[nameref]; - UserFuncName::User(name.clone()) - } else { - UserFuncName::default() - } - } - ExternalName::TestCase(testcase) => UserFuncName::Testcase(testcase), - _ => UserFuncName::default(), - }; - context.func.signature = signatures[module.functions[func_index]].clone(); - // if generate_debug_info { - // context.func.collect_debug_info(); - // } - let mut reader = - MiddlewareBinaryReader::new_with_offset(input.data, input.module_offset); - reader.set_middleware_chain( - self.config - .middlewares - .generate_function_middleware_chain(i), - ); - - func_translator.translate( - module_translation_state, - &mut reader, - &mut context.func, - &mut func_env, - i, - )?; - - let mut code_buf: Vec = Vec::new(); - context - .compile_and_emit(&*isa, &mut code_buf, &mut Default::default()) - .map_err(|error| CompileError::Codegen(error.inner.to_string()))?; - - let result = context.compiled_code().unwrap(); - let func_relocs = result - .buffer - .relocs() - .into_iter() - .map(|r| mach_reloc_to_reloc(module, r)) - .collect::>(); - - let traps = result - .buffer - .traps() - .into_iter() - .map(mach_trap_to_trap) - .collect::>(); - - let (unwind_info, fde) = match compiled_function_unwind_info(&*isa, &context)? { - #[cfg(feature = "unwind")] - CraneliftUnwindInfo::Fde(fde) => { - if dwarf_frametable.is_some() { - let fde = fde.to_fde(Address::Symbol { - // The symbol is the kind of relocation. - // "0" is used for functions - symbol: WriterRelocate::FUNCTION_SYMBOL, - // We use the addend as a way to specify the - // function index - addend: i.index() as _, - }); - // The unwind information is inserted into the dwarf section - (Some(CompiledFunctionUnwindInfo::Dwarf), Some(fde)) - } else { - (None, None) - } - } - #[cfg(feature = "unwind")] - other => (other.maybe_into_to_windows_unwind(), None), - - // This is a bit hacky, but necessary since gimli is not - // available when the "unwind" feature is disabled. - #[cfg(not(feature = "unwind"))] - other => (other.maybe_into_to_windows_unwind(), None::<()>), - }; - - let range = reader.range(); - let address_map = get_function_address_map(&context, range, code_buf.len()); - - Ok(( - CompiledFunction { - body: FunctionBody { - body: code_buf, - unwind_info, - }, - relocations: func_relocs, - frame_info: CompiledFunctionFrameInfo { address_map, traps }, - }, - fde, - )) - }) - .collect::, CompileError>>()? - .into_iter() - .unzip(); - #[cfg(feature = "rayon")] - let (functions, fdes): (Vec, Vec<_>) = function_body_inputs - .iter() - .collect::)>>() - .par_iter() - .map_init(FuncTranslator::new, |func_translator, (i, input)| { + let compile_function = + |func_translator: &mut FuncTranslator, + (i, input): (&LocalFunctionIndex, &FunctionBodyData)| { let func_index = module.func_index(*i); let mut context = Context::new(); let mut func_env = FuncEnvironment::new( @@ -243,7 +130,7 @@ impl CraneliftCompiler { memory_styles, table_styles, ); - context.func.name = match get_function_name(func_index) { + context.func.name = match get_function_name(&mut context.func, func_index) { ExternalName::User(nameref) => { if context.func.params.user_named_funcs().is_valid(nameref) { let name = &context.func.params.user_named_funcs()[nameref]; @@ -276,17 +163,42 @@ impl CraneliftCompiler { *i, )?; + if let Some(callbacks) = self.config.callbacks.as_ref() { + use wasmer_compiler::misc::CompiledKind; + + callbacks.preopt_ir( + &CompiledKind::Local(*i, compile_info.module.get_function_name(func_index)), + context.func.display().to_string().as_bytes(), + ); + } + let mut code_buf: Vec = Vec::new(); - context - .compile_and_emit(&*isa, &mut code_buf, &mut Default::default()) + let mut ctrl_plane = Default::default(); + let func_name_map = context.func.params.user_named_funcs().clone(); + let result = context + .compile(&*isa, &mut ctrl_plane) .map_err(|error| CompileError::Codegen(format!("{error:#?}")))?; + code_buf.extend_from_slice(result.code_buffer()); + + if let Some(callbacks) = self.config.callbacks.as_ref() { + use wasmer_compiler::misc::CompiledKind; + + callbacks.obj_memory_buffer( + &CompiledKind::Local(*i, compile_info.module.get_function_name(func_index)), + &code_buf, + ); + callbacks.asm_memory_buffer( + &CompiledKind::Local(*i, compile_info.module.get_function_name(func_index)), + target.triple().architecture, + &code_buf, + )?; + } - let result = context.compiled_code().unwrap(); let func_relocs = result .buffer .relocs() .iter() - .map(|r| mach_reloc_to_reloc(module, r)) + .map(|r| mach_reloc_to_reloc(module, &func_name_map, r)) .collect::>(); let traps = result @@ -337,11 +249,37 @@ impl CraneliftCompiler { }, fde, )) + }; + + #[cfg_attr(not(feature = "unwind"), allow(unused_mut))] + let mut custom_sections = PrimaryMap::new(); + + #[cfg(not(feature = "rayon"))] + let mut func_translator = FuncTranslator::new(); + #[cfg(not(feature = "rayon"))] + #[cfg_attr(not(feature = "unwind"), allow(unused_variables))] + let (functions, fdes): (Vec, Vec<_>) = function_body_inputs + .iter() + .collect::)>>() + .into_iter() + .map(|(i, input)| compile_function(&mut func_translator, (&i, input))) + .collect::, CompileError>>()? + .into_iter() + .unzip(); + #[cfg(feature = "rayon")] + #[cfg_attr(not(feature = "unwind"), allow(unused_variables))] + let (functions, fdes): (Vec, Vec<_>) = function_body_inputs + .iter() + .collect::)>>() + .par_iter() + .map_init(FuncTranslator::new, |func_translator, &(i, input)| { + compile_function(func_translator, (&i, input)) }) .collect::, CompileError>>()? .into_iter() .unzip(); + #[cfg_attr(not(feature = "unwind"), allow(unused_mut))] let mut unwind_info = UnwindInfo::default(); #[cfg(feature = "unwind")] @@ -367,10 +305,18 @@ impl CraneliftCompiler { .values() .collect::>() .into_iter() - .map(|sig| make_trampoline_function_call(&*isa, &mut cx, sig)) + .map(|sig| { + make_trampoline_function_call( + &self.config().callbacks, + &*isa, + target.triple().architecture, + &mut cx, + sig, + ) + }) .collect::, CompileError>>()? .into_iter() - .collect::>(); + .collect(); #[cfg(feature = "rayon")] let function_call_trampolines = module .signatures @@ -378,11 +324,17 @@ impl CraneliftCompiler { .collect::>() .par_iter() .map_init(FunctionBuilderContext::new, |cx, sig| { - make_trampoline_function_call(&*isa, cx, sig) + make_trampoline_function_call( + &self.config().callbacks, + &*isa, + target.triple().architecture, + cx, + sig, + ) }) .collect::, CompileError>>()? .into_iter() - .collect::>(); + .collect(); use wasmer_types::VMOffsets; let offsets = VMOffsets::new_for_trampolines(frontend_config.pointer_bytes()); @@ -394,21 +346,37 @@ impl CraneliftCompiler { .imported_function_types() .collect::>() .into_iter() - .map(|func_type| make_trampoline_dynamic_function(&*isa, &offsets, &mut cx, &func_type)) + .map(|func_type| { + make_trampoline_dynamic_function( + &self.config().callbacks, + &*isa, + target.triple().architecture, + &offsets, + &mut cx, + &func_type, + ) + }) .collect::, CompileError>>()? .into_iter() - .collect::>(); + .collect(); #[cfg(feature = "rayon")] let dynamic_function_trampolines = module .imported_function_types() .collect::>() .par_iter() .map_init(FunctionBuilderContext::new, |cx, func_type| { - make_trampoline_dynamic_function(&*isa, &offsets, cx, func_type) + make_trampoline_dynamic_function( + &self.config().callbacks, + &*isa, + target.triple().architecture, + &offsets, + cx, + func_type, + ) }) .collect::, CompileError>>()? .into_iter() - .collect::>(); + .collect(); let got = wasmer_compiler::types::function::GOT::empty(); @@ -480,7 +448,11 @@ impl Compiler for CraneliftCompiler { } } -fn mach_reloc_to_reloc(module: &ModuleInfo, reloc: &FinalizedMachReloc) -> Relocation { +fn mach_reloc_to_reloc( + module: &ModuleInfo, + func_index_map: &cranelift_entity::PrimaryMap, + reloc: &FinalizedMachReloc, +) -> Relocation { let FinalizedMachReloc { offset, kind, @@ -494,10 +466,11 @@ fn mach_reloc_to_reloc(module: &ModuleInfo, reloc: &FinalizedMachReloc) -> Reloc } }; let reloc_target: RelocationTarget = if let ExternalName::User(extname_ref) = name { + let func_index = func_index_map[*extname_ref].index; //debug_assert_eq!(namespace, 0); RelocationTarget::LocalFunc( module - .local_func_index(FunctionIndex::from_u32(extname_ref.as_u32())) + .local_func_index(FunctionIndex::from_u32(func_index)) .expect("The provided function should be local"), ) } else if let ExternalName::LibCall(libcall) = name { @@ -523,23 +496,31 @@ fn mach_trap_to_trap(trap: &MachTrap) -> TrapInformation { /// Translates the Cranelift IR TrapCode into generic Trap Code fn translate_ir_trapcode(trap: ir::TrapCode) -> TrapCode { - match trap { - ir::TrapCode::StackOverflow => TrapCode::StackOverflow, - ir::TrapCode::HeapOutOfBounds => TrapCode::HeapAccessOutOfBounds, - ir::TrapCode::HeapMisaligned => TrapCode::UnalignedAtomic, - ir::TrapCode::TableOutOfBounds => TrapCode::TableAccessOutOfBounds, - ir::TrapCode::IndirectCallToNull => TrapCode::IndirectCallToNull, - ir::TrapCode::BadSignature => TrapCode::BadSignature, - ir::TrapCode::IntegerOverflow => TrapCode::IntegerOverflow, - ir::TrapCode::IntegerDivisionByZero => TrapCode::IntegerDivisionByZero, - ir::TrapCode::BadConversionToInteger => TrapCode::BadConversionToInteger, - ir::TrapCode::UnreachableCodeReached => TrapCode::UnreachableCodeReached, - ir::TrapCode::Interrupt => unimplemented!("Interrupts not supported"), - ir::TrapCode::NullReference | ir::TrapCode::NullI31Ref => { - unimplemented!("Null reference not supported") - } - ir::TrapCode::User(_user_code) => unimplemented!("User trap code not supported"), - // ir::TrapCode::Interrupt => TrapCode::Interrupt, - // ir::TrapCode::User(user_code) => TrapCode::User(user_code), + if trap == ir::TrapCode::STACK_OVERFLOW { + TrapCode::StackOverflow + } else if trap == ir::TrapCode::HEAP_OUT_OF_BOUNDS { + TrapCode::HeapAccessOutOfBounds + } else if trap == crate::TRAP_HEAP_MISALIGNED { + TrapCode::UnalignedAtomic + } else if trap == crate::TRAP_TABLE_OUT_OF_BOUNDS { + TrapCode::TableAccessOutOfBounds + } else if trap == crate::TRAP_INDIRECT_CALL_TO_NULL { + TrapCode::IndirectCallToNull + } else if trap == crate::TRAP_BAD_SIGNATURE { + TrapCode::BadSignature + } else if trap == ir::TrapCode::INTEGER_OVERFLOW { + TrapCode::IntegerOverflow + } else if trap == ir::TrapCode::INTEGER_DIVISION_BY_ZERO { + TrapCode::IntegerDivisionByZero + } else if trap == ir::TrapCode::BAD_CONVERSION_TO_INTEGER { + TrapCode::BadConversionToInteger + } else if trap == crate::TRAP_UNREACHABLE { + TrapCode::UnreachableCodeReached + } else if trap == crate::TRAP_INTERRUPT { + unimplemented!("Interrupts not supported") + } else if trap == crate::TRAP_NULL_REFERENCE || trap == crate::TRAP_NULL_I31_REF { + unimplemented!("Null reference not supported") + } else { + unimplemented!("Trap code {trap:?} not supported") } } diff --git a/lib/compiler-cranelift/src/config.rs b/lib/compiler-cranelift/src/config.rs index d983cdda6f..11b8c4d8a6 100644 --- a/lib/compiler-cranelift/src/config.rs +++ b/lib/compiler-cranelift/src/config.rs @@ -1,14 +1,67 @@ use crate::compiler::CraneliftCompiler; use cranelift_codegen::{ - isa::{lookup, TargetIsa}, - settings::{self, Configurable}, CodegenResult, + isa::{TargetIsa, lookup}, + settings::{self, Configurable}, +}; +use std::{ + collections::HashMap, + fs::File, + io::{self, Write}, + sync::Arc, +}; +use std::{num::NonZero, path::PathBuf}; +use wasmer_compiler::{ + Compiler, CompilerConfig, Engine, EngineBuilder, ModuleMiddleware, + misc::{CompiledKind, function_kind_to_filename, save_assembly_to_file}, }; -use std::num::NonZero; -use std::sync::Arc; -use wasmer_compiler::{Compiler, CompilerConfig, Engine, EngineBuilder, ModuleMiddleware}; use wasmer_types::target::{Architecture, CpuFeature, Target}; +/// Callbacks to the different Cranelift compilation phases. +#[derive(Debug, Clone)] +pub struct CraneliftCallbacks { + debug_dir: PathBuf, +} + +impl CraneliftCallbacks { + /// Creates a new instance of `CraneliftCallbacks` with the specified debug directory. + pub fn new(debug_dir: PathBuf) -> Result { + // Create the debug dir in case it doesn't exist + std::fs::create_dir_all(&debug_dir)?; + Ok(Self { debug_dir }) + } + + /// Writes the pre-optimization intermediate representation to a debug file. + pub fn preopt_ir(&self, kind: &CompiledKind, mem_buffer: &[u8]) { + let mut path = self.debug_dir.clone(); + path.push(function_kind_to_filename(kind, ".preopt.clif")); + let mut file = + File::create(path).expect("Error while creating debug file from Cranelift IR"); + file.write_all(mem_buffer).unwrap(); + } + + /// Writes the object file memory buffer to a debug file. + pub fn obj_memory_buffer(&self, kind: &CompiledKind, mem_buffer: &[u8]) { + let mut path = self.debug_dir.clone(); + path.push(function_kind_to_filename(kind, ".o")); + let mut file = + File::create(path).expect("Error while creating debug file from Cranelift object"); + file.write_all(mem_buffer).unwrap(); + } + + /// Writes the assembly memory buffer to a debug file. + pub fn asm_memory_buffer( + &self, + kind: &CompiledKind, + arch: Architecture, + mem_buffer: &[u8], + ) -> Result<(), wasmer_types::CompileError> { + let mut path = self.debug_dir.clone(); + path.push(function_kind_to_filename(kind, ".s")); + save_assembly_to_file(arch, path, mem_buffer, HashMap::::new()) + } +} + // Runtime Environment /// Possible optimization levels for the Cranelift codegen backend. @@ -41,6 +94,7 @@ pub struct Cranelift { pub num_threads: NonZero, /// The middleware chain. pub(crate) middlewares: Vec>, + pub(crate) callbacks: Option, } impl Cranelift { @@ -55,6 +109,7 @@ impl Cranelift { num_threads: std::thread::available_parallelism().unwrap_or(NonZero::new(1).unwrap()), middlewares: vec![], enable_perfmap: false, + callbacks: None, } } @@ -131,11 +186,11 @@ impl Cranelift { builder.enable("has_lzcnt").expect("should be valid flag"); } - builder.finish(self.flags(target)) + builder.finish(self.flags()) } /// Generates the flags for the compiler - pub fn flags(&self, target: &Target) -> settings::Flags { + pub fn flags(&self) -> settings::Flags { let mut flags = settings::builder(); // Enable probestack @@ -143,12 +198,10 @@ impl Cranelift { .enable("enable_probestack") .expect("should be valid flag"); - // Only inline probestack is supported on AArch64 - if matches!(target.triple().architecture, Architecture::Aarch64(_)) { - flags - .set("probestack_strategy", "inline") - .expect("should be valid flag"); - } + // Always use inline stack probes (otherwise the call to Probestack needs to be relocated). + flags + .set("probestack_strategy", "inline") + .expect("should be valid flag"); if self.enable_pic { flags.enable("is_pic").expect("should be a valid flag"); @@ -160,6 +213,12 @@ impl Cranelift { .enable("use_colocated_libcalls") .expect("should be a valid flag"); + // Allow Cranelift to implicitly spill multi-value returns via a hidden + // StructReturn argument when register results are exhausted. + flags + .enable("enable_multi_ret_implicit_sret") + .expect("should be a valid flag"); + // Invert cranelift's default-on verification to instead default off. let enable_verifier = if self.enable_verifier { "true" @@ -169,9 +228,6 @@ impl Cranelift { flags .set("enable_verifier", enable_verifier) .expect("should be valid flag"); - flags - .set("enable_safepoints", "true") - .expect("should be valid flag"); flags .set( @@ -195,6 +251,13 @@ impl Cranelift { settings::Flags::new(flags) } + + /// Callbacks that will triggered in the different compilation + /// phases in Cranelift. + pub fn callbacks(&mut self, callbacks: Option) -> &mut Self { + self.callbacks = callbacks; + self + } } impl CompilerConfig for Cranelift { diff --git a/lib/compiler-cranelift/src/debug/address_map.rs b/lib/compiler-cranelift/src/debug/address_map.rs index c8900a0bc4..0adfaba2b5 100644 --- a/lib/compiler-cranelift/src/debug/address_map.rs +++ b/lib/compiler-cranelift/src/debug/address_map.rs @@ -2,8 +2,8 @@ // addresses of a WebAssembly module into the native code. use cranelift_codegen::ir; -use wasmer_types::entity::PrimaryMap; use wasmer_types::LocalFunctionIndex; +use wasmer_types::entity::PrimaryMap; /// Value ranges for functions. pub type ValueLabelsRanges = PrimaryMap; diff --git a/lib/compiler-cranelift/src/dwarf.rs b/lib/compiler-cranelift/src/dwarf.rs index 68e7582318..deacc4ae26 100644 --- a/lib/compiler-cranelift/src/dwarf.rs +++ b/lib/compiler-cranelift/src/dwarf.rs @@ -4,7 +4,7 @@ use wasmer_compiler::types::{ relocation::{Relocation, RelocationKind, RelocationTarget}, section::{CustomSection, CustomSectionProtection, SectionBody}, }; -use wasmer_types::{entity::EntityRef, target::Endianness, LocalFunctionIndex}; +use wasmer_types::{LocalFunctionIndex, entity::EntityRef, target::Endianness}; #[derive(Clone, Debug)] pub struct WriterRelocate { diff --git a/lib/compiler-cranelift/src/func_environ.rs b/lib/compiler-cranelift/src/func_environ.rs index 3f01707f40..1868a7cf0b 100644 --- a/lib/compiler-cranelift/src/func_environ.rs +++ b/lib/compiler-cranelift/src/func_environ.rs @@ -9,11 +9,11 @@ use crate::{ use cranelift_codegen::{ cursor::FuncCursor, ir::{ - self, + self, AbiParam, ArgumentPurpose, Function, InstBuilder, MemFlags, Signature, + UserExternalName, condcodes::IntCC, immediates::{Offset32, Uimm64}, types::*, - AbiParam, ArgumentPurpose, Function, InstBuilder, MemFlags, Signature, }, isa::TargetFrontendConfig, }; @@ -21,15 +21,18 @@ use cranelift_frontend::FunctionBuilder; use std::convert::TryFrom; use wasmer_compiler::wasmparser::HeapType; use wasmer_types::{ - entity::{EntityRef, PrimaryMap, SecondaryMap}, FunctionIndex, FunctionType, GlobalIndex, LocalFunctionIndex, MemoryIndex, MemoryStyle, ModuleInfo, SignatureIndex, TableIndex, TableStyle, Type as WasmerType, VMBuiltinFunctionIndex, VMOffsets, WasmError, WasmResult, + entity::{EntityRef, PrimaryMap, SecondaryMap}, }; /// Compute an `ir::ExternalName` for a given wasm function index. -pub fn get_function_name(func_index: FunctionIndex) -> ir::ExternalName { - ir::ExternalName::user(ir::UserExternalNameRef::from_u32(func_index.as_u32())) +pub fn get_function_name(func: &mut Function, func_index: FunctionIndex) -> ir::ExternalName { + ir::ExternalName::user( + func.params + .ensure_user_func_name(UserExternalName::new(0, func_index.as_u32())), + ) } /// The type of the `current_elements` field. @@ -267,7 +270,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { // dst AbiParam::new(I32), // value - AbiParam::new(R64), + AbiParam::new(self.reference_type()), // len AbiParam::new(I32), ], @@ -298,7 +301,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext), AbiParam::new(I32), ], - returns: vec![AbiParam::new(R64)], + returns: vec![AbiParam::new(self.reference_type())], call_conv: self.target_config.default_call_conv, }) }); @@ -326,7 +329,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { AbiParam::new(I32), AbiParam::new(I32), ], - returns: vec![AbiParam::new(R64)], + returns: vec![AbiParam::new(self.reference_type())], call_conv: self.target_config.default_call_conv, }) }); @@ -361,7 +364,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext), AbiParam::new(I32), AbiParam::new(I32), - AbiParam::new(R64), + AbiParam::new(self.reference_type()), ], returns: vec![], call_conv: self.target_config.default_call_conv, @@ -397,7 +400,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { params: vec![ AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext), // TODO: figure out what the representation of a Wasm value is - AbiParam::new(R64), + AbiParam::new(self.reference_type()), AbiParam::new(I32), AbiParam::new(I32), ], @@ -1052,22 +1055,20 @@ impl BaseFuncEnvironment for FuncEnvironment<'_> { ) -> WasmResult { Ok(match ty { HeapType::Abstract { ty, .. } => match ty { - wasmer_compiler::wasmparser::AbstractHeapType::Func => { - pos.ins().null(self.reference_type()) - } - wasmer_compiler::wasmparser::AbstractHeapType::Extern => { - pos.ins().null(self.reference_type()) + wasmer_compiler::wasmparser::AbstractHeapType::Func + | wasmer_compiler::wasmparser::AbstractHeapType::Extern => { + pos.ins().iconst(self.reference_type(), 0) } _ => { return Err(WasmError::Unsupported( "`ref.null T` that is not a `funcref` or an `externref`".into(), - )) + )); } }, HeapType::Concrete(_) => { return Err(WasmError::Unsupported( "`ref.null T` that is not a `funcref` or an `externref`".into(), - )) + )); } }) } @@ -1077,17 +1078,9 @@ impl BaseFuncEnvironment for FuncEnvironment<'_> { mut pos: cranelift_codegen::cursor::FuncCursor, value: ir::Value, ) -> WasmResult { - let bool_is_null = match pos.func.dfg.value_type(value) { - // `externref` - ty if ty.is_ref() => pos.ins().is_null(value), - // `funcref` - ty if ty == self.pointer_type() => { - pos.ins() - .icmp_imm(cranelift_codegen::ir::condcodes::IntCC::Equal, value, 0) - } - _ => unreachable!(), - }; - + let bool_is_null = + pos.ins() + .icmp_imm(cranelift_codegen::ir::condcodes::IntCC::Equal, value, 0); Ok(pos.ins().uextend(ir::types::I32, bool_is_null)) } @@ -1262,7 +1255,8 @@ impl BaseFuncEnvironment for FuncEnvironment<'_> { ) -> WasmResult { let sigidx = self.module.functions[index]; let signature = func.import_signature(self.signatures[sigidx].clone()); - let name = get_function_name(index); + let name = get_function_name(func, index); + Ok(func.import_function(ir::ExtFuncData { name, signature, @@ -1290,7 +1284,7 @@ impl BaseFuncEnvironment for FuncEnvironment<'_> { // check if the funcref is null builder .ins() - .trapz(anyfunc_ptr, ir::TrapCode::IndirectCallToNull); + .trapz(anyfunc_ptr, crate::TRAP_INDIRECT_CALL_TO_NULL); let func_addr = builder.ins().load( pointer_type, @@ -1327,7 +1321,7 @@ impl BaseFuncEnvironment for FuncEnvironment<'_> { let cmp = builder .ins() .icmp(IntCC::Equal, callee_sig_id, caller_sig_id); - builder.ins().trapz(cmp, ir::TrapCode::BadSignature); + builder.ins().trapz(cmp, crate::TRAP_BAD_SIGNATURE); } } diff --git a/lib/compiler-cranelift/src/lib.rs b/lib/compiler-cranelift/src/lib.rs index 5d8857f3ed..47301f01a5 100644 --- a/lib/compiler-cranelift/src/lib.rs +++ b/lib/compiler-cranelift/src/lib.rs @@ -6,7 +6,7 @@ //! Compared to LLVM, Cranelift is a bit faster and made entirely in Rust. #![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] #![warn(unused_import_braces)] -#![allow(clippy::new_without_default, clippy::new_without_default)] +#![allow(clippy::new_without_default)] #![warn( clippy::float_arithmetic, clippy::mut_mut, @@ -16,7 +16,7 @@ clippy::unicode_not_nfc, clippy::use_self )] -#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] #[cfg(not(feature = "std"))] #[macro_use] @@ -27,15 +27,13 @@ extern crate std; #[cfg(not(feature = "std"))] use hashbrown::{ - hash_map, + HashMap, hash_map, hash_map::Entry::{Occupied, Vacant}, - HashMap, }; #[cfg(feature = "std")] use std::collections::{ - hash_map, + HashMap, hash_map, hash_map::Entry::{Occupied, Vacant}, - HashMap, }; mod address_map; @@ -50,10 +48,34 @@ mod table; mod trampoline; mod translator; +use cranelift_codegen::ir::TrapCode; + pub use crate::compiler::CraneliftCompiler; -pub use crate::config::{Cranelift, CraneliftOptLevel}; +pub use crate::config::{Cranelift, CraneliftCallbacks, CraneliftOptLevel}; pub use crate::debug::{ModuleInfoMemoryOffset, ModuleInfoVmctxInfo, ValueLabelsRanges}; pub use crate::trampoline::make_trampoline_function_call; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + +/// Offset applied to user-defined trap codes to avoid colliding with +/// Cranelift-reserved values. +const TRAP_USER_OFFSET: u8 = 32; + +/// Trap reported when an indirect call targets a null function reference. +#[allow(clippy::identity_op, reason = "for clarity")] +pub const TRAP_INDIRECT_CALL_TO_NULL: TrapCode = TrapCode::unwrap_user(TRAP_USER_OFFSET + 0); +/// Trap reported when an indirect call signature does not match. +pub const TRAP_BAD_SIGNATURE: TrapCode = TrapCode::unwrap_user(TRAP_USER_OFFSET + 1); +/// Trap reported when a table access goes out of bounds. +pub const TRAP_TABLE_OUT_OF_BOUNDS: TrapCode = TrapCode::unwrap_user(TRAP_USER_OFFSET + 2); +/// Trap reported when a heap access violates alignment guarantees. +pub const TRAP_HEAP_MISALIGNED: TrapCode = TrapCode::unwrap_user(TRAP_USER_OFFSET + 3); +/// Trap reported when unreachable code is executed. +pub const TRAP_UNREACHABLE: TrapCode = TrapCode::unwrap_user(TRAP_USER_OFFSET + 4); +/// Trap reported when a null reference is observed. +pub const TRAP_NULL_REFERENCE: TrapCode = TrapCode::unwrap_user(TRAP_USER_OFFSET + 5); +/// Trap reported when a null i31 reference is observed. +pub const TRAP_NULL_I31_REF: TrapCode = TrapCode::unwrap_user(TRAP_USER_OFFSET + 6); +/// Trap reported for interrupts (not currently supported). +pub const TRAP_INTERRUPT: TrapCode = TrapCode::unwrap_user(TRAP_USER_OFFSET + 7); diff --git a/lib/compiler-cranelift/src/table.rs b/lib/compiler-cranelift/src/table.rs index b1dc08787e..6136e132ce 100644 --- a/lib/compiler-cranelift/src/table.rs +++ b/lib/compiler-cranelift/src/table.rs @@ -1,5 +1,5 @@ use cranelift_codegen::cursor::FuncCursor; -use cranelift_codegen::ir::{self, condcodes::IntCC, immediates::Imm64, InstBuilder}; +use cranelift_codegen::ir::{self, InstBuilder, condcodes::IntCC, immediates::Imm64}; use cranelift_frontend::FunctionBuilder; /// Size of a WebAssembly table, in elements. @@ -62,7 +62,7 @@ impl TableData { .icmp(IntCC::UnsignedGreaterThanOrEqual, index, bound); if !enable_table_access_spectre_mitigation { - pos.ins().trapnz(oob, ir::TrapCode::TableOutOfBounds); + pos.ins().trapnz(oob, crate::TRAP_TABLE_OUT_OF_BOUNDS); } // Convert `index` to `addr_ty`. @@ -95,7 +95,7 @@ impl TableData { let zero = pos.ins().iconst(addr_ty, 0); ( pos.ins().select_spectre_guard(oob, zero, element_addr), - base_flags.with_trap_code(Some(ir::TrapCode::TableOutOfBounds)), + base_flags.with_trap_code(Some(crate::TRAP_TABLE_OUT_OF_BOUNDS)), ) } else { (element_addr, base_flags.with_trap_code(None)) diff --git a/lib/compiler-cranelift/src/trampoline/dynamic_function.rs b/lib/compiler-cranelift/src/trampoline/dynamic_function.rs index ead1caa3f9..804d312564 100644 --- a/lib/compiler-cranelift/src/trampoline/dynamic_function.rs +++ b/lib/compiler-cranelift/src/trampoline/dynamic_function.rs @@ -3,20 +3,26 @@ //! A trampoline generator for calling dynamic host functions from Wasm. -use crate::translator::{compiled_function_unwind_info, signature_to_cranelift_ir}; +use crate::{ + CraneliftCallbacks, + translator::{compiled_function_unwind_info, signature_to_cranelift_ir}, +}; use cranelift_codegen::{ + Context, ir::{self, Function, InstBuilder, MemFlags, StackSlotData, StackSlotKind, UserFuncName}, isa::TargetIsa, - Context, }; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use std::{cmp, mem}; -use wasmer_compiler::types::function::FunctionBody; +use target_lexicon::Architecture; +use wasmer_compiler::{misc::CompiledKind, types::function::FunctionBody}; use wasmer_types::{CompileError, FunctionType, VMOffsets}; /// Create a trampoline for invoking a WebAssembly function. pub fn make_trampoline_dynamic_function( + callbacks: &Option, isa: &dyn TargetIsa, + arch: Architecture, offsets: &VMOffsets, fn_builder_ctx: &mut FunctionBuilderContext, func_type: &FunctionType, @@ -102,10 +108,31 @@ pub fn make_trampoline_dynamic_function( builder.finalize() } + if let Some(callbacks) = callbacks.as_ref() { + callbacks.preopt_ir( + &CompiledKind::DynamicFunctionTrampoline(func_type.clone()), + context.func.display().to_string().as_bytes(), + ); + } + let mut code_buf = Vec::new(); - context - .compile_and_emit(isa, &mut code_buf, &mut Default::default()) + let mut ctrl_plane = Default::default(); + let compiled = context + .compile(isa, &mut ctrl_plane) .map_err(|error| CompileError::Codegen(error.inner.to_string()))?; + code_buf.extend_from_slice(compiled.code_buffer()); + + if let Some(callbacks) = callbacks.as_ref() { + callbacks.obj_memory_buffer( + &CompiledKind::DynamicFunctionTrampoline(func_type.clone()), + &code_buf, + ); + callbacks.asm_memory_buffer( + &CompiledKind::DynamicFunctionTrampoline(func_type.clone()), + arch, + &code_buf, + )?; + } let unwind_info = compiled_function_unwind_info(isa, &context)?.maybe_into_to_windows_unwind(); diff --git a/lib/compiler-cranelift/src/trampoline/function_call.rs b/lib/compiler-cranelift/src/trampoline/function_call.rs index ebe874f0b3..ca5c963618 100644 --- a/lib/compiler-cranelift/src/trampoline/function_call.rs +++ b/lib/compiler-cranelift/src/trampoline/function_call.rs @@ -8,20 +8,26 @@ //! let my_func = instance.exports.get("func"); //! my_func.call([1, 2]) //! ``` -use crate::translator::{compiled_function_unwind_info, signature_to_cranelift_ir}; +use crate::{ + CraneliftCallbacks, + translator::{compiled_function_unwind_info, signature_to_cranelift_ir}, +}; use cranelift_codegen::{ + Context, ir::{self, InstBuilder}, isa::TargetIsa, - Context, }; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use std::mem; -use wasmer_compiler::types::function::FunctionBody; +use target_lexicon::Architecture; +use wasmer_compiler::{misc::CompiledKind, types::function::FunctionBody}; use wasmer_types::{CompileError, FunctionType}; /// Create a trampoline for invoking a WebAssembly function. pub fn make_trampoline_function_call( + callbacks: &Option, isa: &dyn TargetIsa, + arch: Architecture, fn_builder_ctx: &mut FunctionBuilderContext, func_type: &FunctionType, ) -> Result { @@ -102,11 +108,31 @@ pub fn make_trampoline_function_call( builder.finalize() } - let mut code_buf = Vec::new(); + if let Some(callbacks) = callbacks.as_ref() { + callbacks.preopt_ir( + &CompiledKind::FunctionCallTrampoline(func_type.clone()), + context.func.display().to_string().as_bytes(), + ); + } - context - .compile_and_emit(isa, &mut code_buf, &mut Default::default()) + let mut code_buf = Vec::new(); + let mut ctrl_plane = Default::default(); + let compiled = context + .compile(isa, &mut ctrl_plane) .map_err(|error| CompileError::Codegen(error.inner.to_string()))?; + code_buf.extend_from_slice(compiled.code_buffer()); + + if let Some(callbacks) = callbacks.as_ref() { + callbacks.obj_memory_buffer( + &CompiledKind::FunctionCallTrampoline(func_type.clone()), + &code_buf, + ); + callbacks.asm_memory_buffer( + &CompiledKind::FunctionCallTrampoline(func_type.clone()), + arch, + &code_buf, + )?; + } let unwind_info = compiled_function_unwind_info(isa, &context)?.maybe_into_to_windows_unwind(); diff --git a/lib/compiler-cranelift/src/translator/code_translator.rs b/lib/compiler-cranelift/src/translator/code_translator.rs index b02d1b613a..842e350236 100644 --- a/lib/compiler-cranelift/src/translator/code_translator.rs +++ b/lib/compiler-cranelift/src/translator/code_translator.rs @@ -21,7 +21,7 @@ //! - the `get_global` and `set_global` instructions depend on how the globals are implemented; //! - `memory.size` and `memory.grow` are runtime functions; //! - `call_indirect` has to translate the function index into the address of where this -//! is; +//! is; //! //! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as //! argument. @@ -79,13 +79,14 @@ mod bounds_checks; use super::func_environ::{FuncEnvironment, GlobalVariable}; use super::func_state::{ControlStackFrame, ElseData, FuncTranslationState}; use super::translation_utils::{block_with_params, f32_translation, f64_translation}; -use crate::{hash_map, HashMap}; +use crate::{HashMap, hash_map}; use core::convert::TryFrom; use cranelift_codegen::ir::condcodes::{FloatCC, IntCC}; use cranelift_codegen::ir::immediates::Offset32; use cranelift_codegen::ir::types::*; use cranelift_codegen::ir::{ - self, AtomicRmwOp, ConstantData, InstBuilder, JumpTableData, MemFlags, Value, ValueLabel, + self, AtomicRmwOp, BlockArg, ConstantData, InstBuilder, JumpTableData, MemFlags, Value, + ValueLabel, }; use cranelift_codegen::packed_option::ReservedValue; use cranelift_frontend::{FunctionBuilder, Variable}; @@ -94,7 +95,7 @@ use smallvec::SmallVec; use std::vec::Vec; use wasmer_compiler::wasmparser::{MemArg, Operator}; -use wasmer_compiler::{from_binaryreadererror_wasmerror, wasm_unsupported, ModuleTranslationState}; +use wasmer_compiler::{ModuleTranslationState, from_binaryreadererror_wasmerror, wasm_unsupported}; use wasmer_types::{ FunctionIndex, GlobalIndex, MemoryIndex, SignatureIndex, TableIndex, WasmResult, }; @@ -106,7 +107,7 @@ use wasmer_types::{ /// when we can statically determine that a Wasm access will unconditionally /// trap. macro_rules! unwrap_or_return_unreachable_state { - ($state:ident, $value:expr) => { + ($state:ident, $value:expr_2021) => { match $value { Reachability::Reachable(x) => x, Reachability::Unreachable => { @@ -252,7 +253,7 @@ pub fn translate_operator( // We do nothing } Operator::Unreachable => { - builder.ins().trap(ir::TrapCode::UnreachableCodeReached); + builder.ins().trap(crate::TRAP_UNREACHABLE); state.reachable = false; } /***************************** Control flow blocks ********************************** @@ -1196,7 +1197,7 @@ pub fn translate_operator( } Err(wasmer_types::WasmError::Unsupported(_err)) => { // If multiple threads hit a mutex then the function will fail - builder.ins().trap(ir::TrapCode::UnreachableCodeReached); + builder.ins().trap(crate::TRAP_UNREACHABLE); state.reachable = false; } Err(err) => { @@ -2243,13 +2244,13 @@ pub fn translate_operator( | Operator::GlobalAtomicRmwXor { .. } | Operator::GlobalAtomicRmwXchg { .. } | Operator::GlobalAtomicRmwCmpxchg { .. } => { - return Err(wasm_unsupported!("Global atomics not supported yet!")) + return Err(wasm_unsupported!("Global atomics not supported yet!")); } Operator::TableAtomicGet { .. } | Operator::TableAtomicSet { .. } | Operator::TableAtomicRmwXchg { .. } | Operator::TableAtomicRmwCmpxchg { .. } => { - return Err(wasm_unsupported!("Table atomics not supported yet!")) + return Err(wasm_unsupported!("Table atomics not supported yet!")); } Operator::StructAtomicGet { .. } | Operator::StructAtomicGetS { .. } @@ -2262,7 +2263,7 @@ pub fn translate_operator( | Operator::StructAtomicRmwXor { .. } | Operator::StructAtomicRmwXchg { .. } | Operator::StructAtomicRmwCmpxchg { .. } => { - return Err(wasm_unsupported!("Table atomics not supported yet!")) + return Err(wasm_unsupported!("Table atomics not supported yet!")); } Operator::ArrayAtomicGet { .. } | Operator::ArrayAtomicGetS { .. } @@ -2275,7 +2276,7 @@ pub fn translate_operator( | Operator::ArrayAtomicRmwXor { .. } | Operator::ArrayAtomicRmwXchg { .. } | Operator::ArrayAtomicRmwCmpxchg { .. } => { - return Err(wasm_unsupported!("Array atomics not supported yet!")) + return Err(wasm_unsupported!("Array atomics not supported yet!")); } Operator::ContNew { .. } => todo!(), Operator::ContBind { .. } => todo!(), @@ -2573,7 +2574,7 @@ where let adjusted_index = builder .ins() - .uadd_overflow_trap(index, offset, ir::TrapCode::HeapOutOfBounds); + .uadd_overflow_trap(index, offset, ir::TrapCode::HEAP_OUT_OF_BOUNDS); bounds_checks::bounds_check_and_compute_addr( builder, environ, @@ -2641,7 +2642,7 @@ fn align_atomic_addr( .ins() .band_imm(effective_addr, i64::from(loaded_bytes - 1)); let f = builder.ins().icmp_imm(IntCC::NotEqual, misalignment, 0); - builder.ins().trapnz(f, ir::TrapCode::HeapMisaligned); + builder.ins().trapnz(f, crate::TRAP_HEAP_MISALIGNED); } } @@ -2759,7 +2760,7 @@ fn fold_atomic_mem_addr( let r = builder .ins() .icmp_imm(IntCC::UnsignedGreaterThanOrEqual, a, 0x1_0000_0000i64); - builder.ins().trapnz(r, ir::TrapCode::HeapOutOfBounds); + builder.ins().trapnz(r, ir::TrapCode::HEAP_OUT_OF_BOUNDS); builder.ins().ireduce(I32, a) } else { linear_mem_addr @@ -2771,7 +2772,7 @@ fn fold_atomic_mem_addr( let f = builder .ins() .icmp_imm(IntCC::Equal, final_lma_misalignment, i64::from(0)); - builder.ins().trapz(f, ir::TrapCode::HeapMisaligned); + builder.ins().trapz(f, crate::TRAP_HEAP_MISALIGNED); final_lma } @@ -2795,7 +2796,7 @@ fn translate_atomic_rmw( return Err(wasm_unsupported!( "atomic_rmw: unsupported access type {:?}", access_ty - )) + )); } }; let w_ty_ok = matches!(widened_ty, I32 | I64); @@ -2844,7 +2845,7 @@ fn translate_atomic_cas( return Err(wasm_unsupported!( "atomic_cas: unsupported access type {:?}", access_ty - )) + )); } }; let w_ty_ok = matches!(widened_ty, I32 | I64); @@ -2893,7 +2894,7 @@ fn translate_atomic_load( return Err(wasm_unsupported!( "atomic_load: unsupported access type {:?}", access_ty - )) + )); } }; let w_ty_ok = matches!(widened_ty, I32 | I64); @@ -2935,7 +2936,7 @@ fn translate_atomic_store( return Err(wasm_unsupported!( "atomic_store: unsupported access type {:?}", access_ty - )) + )); } }; let d_ty_ok = matches!(data_ty, I32 | I64); @@ -3259,22 +3260,13 @@ fn is_non_canonical_v128(ty: ir::Type) -> bool { /// actually necessary, and if not, the original slice is returned. Otherwise the cast values /// are returned in a slice that belongs to the caller-supplied `SmallVec`. fn canonicalise_v128_values<'a>( - tmp_canonicalised: &'a mut SmallVec<[ir::Value; 16]>, + tmp_canonicalised: &'a mut SmallVec<[ir::BlockArg; 16]>, builder: &mut FunctionBuilder, values: &'a [ir::Value], -) -> &'a [ir::Value] { +) -> &'a [ir::BlockArg] { debug_assert!(tmp_canonicalised.is_empty()); - // First figure out if any of the parameters need to be cast. Mostly they don't need to be. - let any_non_canonical = values - .iter() - .any(|v| is_non_canonical_v128(builder.func.dfg.value_type(*v))); - // Hopefully we take this exit most of the time, hence doing no heap allocation. - if !any_non_canonical { - return values; - } - // Otherwise we'll have to cast, and push the resulting `Value`s into `canonicalised`. for v in values { - tmp_canonicalised.push(if is_non_canonical_v128(builder.func.dfg.value_type(*v)) { + let value = if is_non_canonical_v128(builder.func.dfg.value_type(*v)) { builder.ins().bitcast( I8X16, MemFlags::new().with_endianness(ir::Endianness::Little), @@ -3282,7 +3274,8 @@ fn canonicalise_v128_values<'a>( ) } else { *v - }); + }; + tmp_canonicalised.push(BlockArg::from(value)); } tmp_canonicalised.as_slice() } @@ -3295,7 +3288,7 @@ fn canonicalise_then_jump( destination: ir::Block, params: &[ir::Value], ) -> ir::Inst { - let mut tmp_canonicalised = SmallVec::<[ir::Value; 16]>::new(); + let mut tmp_canonicalised = SmallVec::<[_; 16]>::new(); let canonicalised = canonicalise_v128_values(&mut tmp_canonicalised, builder, params); builder.ins().jump(destination, canonicalised) } @@ -3309,10 +3302,10 @@ fn canonicalise_brif( block_else: ir::Block, params_else: &[ir::Value], ) -> ir::Inst { - let mut tmp_canonicalised_then = SmallVec::<[ir::Value; 16]>::new(); + let mut tmp_canonicalised_then = SmallVec::<[_; 16]>::new(); let canonicalised_then = canonicalise_v128_values(&mut tmp_canonicalised_then, builder, params_then); - let mut tmp_canonicalised_else = SmallVec::<[ir::Value; 16]>::new(); + let mut tmp_canonicalised_else = SmallVec::<[_; 16]>::new(); let canonicalised_else = canonicalise_v128_values(&mut tmp_canonicalised_else, builder, params_else); builder.ins().brif( diff --git a/lib/compiler-cranelift/src/translator/code_translator/bounds_checks.rs b/lib/compiler-cranelift/src/translator/code_translator/bounds_checks.rs index 58b8c13c31..bae55f7957 100644 --- a/lib/compiler-cranelift/src/translator/code_translator/bounds_checks.rs +++ b/lib/compiler-cranelift/src/translator/code_translator/bounds_checks.rs @@ -24,14 +24,14 @@ use crate::{ heap::{HeapData, HeapStyle}, translator::func_environ::FuncEnvironment, }; +use Reachability::*; use cranelift_codegen::{ cursor::{Cursor, FuncCursor}, - ir::{self, condcodes::IntCC, InstBuilder, RelSourceLoc}, + ir::{self, InstBuilder, RelSourceLoc, condcodes::IntCC}, ir::{Expr, Fact}, }; use cranelift_frontend::FunctionBuilder; use wasmer_types::WasmResult; -use Reachability::*; /// Helper used to emit bounds checks (as necessary) and compute the native /// address of a heap access. @@ -281,7 +281,7 @@ where let adjusted_index = builder.ins().uadd_overflow_trap( index, access_size_val, - ir::TrapCode::HeapOutOfBounds, + ir::TrapCode::HEAP_OUT_OF_BOUNDS, ); if pcc { builder.func.dfg.facts[adjusted_index] = Some(Fact::value_offset( @@ -326,7 +326,7 @@ where "static memories require the ability to use virtual memory" ); env.before_unconditionally_trapping_memory_access(builder)?; - builder.ins().trap(ir::TrapCode::HeapOutOfBounds); + builder.ins().trap(ir::TrapCode::HEAP_OUT_OF_BOUNDS); Unreachable } @@ -568,7 +568,7 @@ fn explicit_check_oob_condition_and_compute_addr( ) -> ir::Value { if !spectre_mitigations_enabled { pos.ins() - .trapnz(oob_condition, ir::TrapCode::HeapOutOfBounds); + .trapnz(oob_condition, ir::TrapCode::HEAP_OUT_OF_BOUNDS); } let mut addr = compute_addr(pos, heap, addr_ty, index, offset, pcc); diff --git a/lib/compiler-cranelift/src/translator/func_environ.rs b/lib/compiler-cranelift/src/translator/func_environ.rs index a732a39ae0..e53a0cb810 100644 --- a/lib/compiler-cranelift/src/translator/func_environ.rs +++ b/lib/compiler-cranelift/src/translator/func_environ.rs @@ -70,7 +70,7 @@ pub trait TargetEnvironment { /// Get the Cranelift reference type to use for native references. /// - /// This returns `R64` for 64-bit architectures and `R32` for 32-bit architectures. + /// This returns the target pointer type for both `funcref` and `externref`. fn reference_type(&self) -> ir::Type { reference_type(self.target_config()).expect("expected reference type") } @@ -296,7 +296,7 @@ pub trait FuncEnvironment: TargetEnvironment { /// Translate a `table.size` WebAssembly instruction. fn translate_table_size(&mut self, pos: FuncCursor, index: TableIndex) - -> WasmResult; + -> WasmResult; /// Translate a `table.grow` WebAssembly instruction. fn translate_table_grow( @@ -370,11 +370,10 @@ pub trait FuncEnvironment: TargetEnvironment { /// null sentinel is not a null reference type pointer for your type. If you /// override this method, then you should also override /// `translate_ref_is_null` as well. - fn translate_ref_null(&mut self, pos: FuncCursor, ty: HeapType) -> WasmResult; - // { - // let _ = ty; - // Ok(pos.ins().null(self.reference_type(ty))) - // } + fn translate_ref_null(&mut self, mut pos: FuncCursor, ty: HeapType) -> WasmResult { + let _ = ty; + Ok(pos.ins().iconst(self.reference_type(), 0)) + } /// Translate a `ref.is_null` WebAssembly instruction. /// @@ -389,8 +388,10 @@ pub trait FuncEnvironment: TargetEnvironment { mut pos: FuncCursor, value: ir::Value, ) -> WasmResult { - let is_null = pos.ins().is_null(value); - Ok(pos.ins().uextend(ir::types::I64, is_null)) + let is_null = pos + .ins() + .icmp_imm(cranelift_codegen::ir::condcodes::IntCC::Equal, value, 0); + Ok(pos.ins().uextend(ir::types::I32, is_null)) } /// Translate a `ref.func` WebAssembly instruction. diff --git a/lib/compiler-cranelift/src/translator/func_translator.rs b/lib/compiler-cranelift/src/translator/func_translator.rs index 6ae1b40903..363344bb4b 100644 --- a/lib/compiler-cranelift/src/translator/func_translator.rs +++ b/lib/compiler-cranelift/src/translator/func_translator.rs @@ -12,12 +12,13 @@ use super::func_environ::{FuncEnvironment, ReturnMode}; use super::func_state::FuncTranslationState; use super::translation_utils::get_vmctx_value_label; use crate::translator::code_translator::bitcast_wasm_returns; +use core::convert::TryFrom; use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::{self, Block, InstBuilder, ValueLabel}; use cranelift_codegen::timing; -use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; +use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; +use wasmer_compiler::{FunctionBinaryReader, ModuleTranslationState, wptype_to_type}; use wasmer_compiler::{wasm_unsupported, wasmparser}; -use wasmer_compiler::{wptype_to_type, FunctionBinaryReader, ModuleTranslationState}; use wasmer_types::{LocalFunctionIndex, WasmResult}; /// WebAssembly to Cranelift IR function translator. @@ -137,8 +138,10 @@ fn declare_wasm_parameters( // signature parameters. For example, a `vmctx` pointer. if environ.is_wasm_parameter(&builder.func.signature, i) { // This is a normal WebAssembly signature parameter, so create a local for it. - let local = Variable::new(next_local); - builder.declare_var(local, param_type.value_type); + let local = builder.declare_var(param_type.value_type); + let local_index = local.index(); + debug_assert_eq!(local_index, next_local); + debug_assert!(u32::try_from(local_index).is_ok()); next_local += 1; let param_value = builder.block_params(entry_block)[i]; @@ -197,7 +200,7 @@ fn declare_locals( } Ref(ty) => { if ty.is_func_ref() || ty.is_extern_ref() { - builder.ins().null(environ.reference_type()) + builder.ins().iconst(environ.reference_type(), 0) } else { return Err(wasm_unsupported!("unsupported reference type: {:?}", ty)); } @@ -207,8 +210,10 @@ fn declare_locals( let wasmer_ty = wptype_to_type(wasm_type).unwrap(); let ty = builder.func.dfg.value_type(zeroval); for _ in 0..count { - let local = Variable::new(*next_local); - builder.declare_var(local, ty); + let local = builder.declare_var(ty); + let local_index = local.index(); + debug_assert_eq!(local_index, *next_local); + debug_assert!(u32::try_from(local_index).is_ok()); builder.def_var(local, zeroval); builder.set_val_label(zeroval, ValueLabel::new(*next_local)); environ.push_local_decl_on_stack(wasmer_ty); diff --git a/lib/compiler-cranelift/src/translator/mod.rs b/lib/compiler-cranelift/src/translator/mod.rs index accc867c46..e39037bc6c 100644 --- a/lib/compiler-cranelift/src/translator/mod.rs +++ b/lib/compiler-cranelift/src/translator/mod.rs @@ -12,4 +12,6 @@ pub use self::func_translator::FuncTranslator; pub use self::translation_utils::{ irlibcall_to_libcall, irreloc_to_relocationkind, signature_to_cranelift_ir, }; -pub(crate) use self::unwind::{compiled_function_unwind_info, CraneliftUnwindInfo}; +#[cfg(feature = "unwind")] +pub(crate) use self::unwind::CraneliftUnwindInfo; +pub(crate) use self::unwind::compiled_function_unwind_info; diff --git a/lib/compiler-cranelift/src/translator/translation_utils.rs b/lib/compiler-cranelift/src/translator/translation_utils.rs index 81a4d835d8..88419ac2ed 100644 --- a/lib/compiler-cranelift/src/translator/translation_utils.rs +++ b/lib/compiler-cranelift/src/translator/translation_utils.rs @@ -1,7 +1,6 @@ //! Helper functions and structures for the translation. use super::func_environ::TargetEnvironment; -use crate::std::string::ToString; use cranelift_codegen::{ binemit::Reloc, ir::{self, AbiParam}, @@ -37,13 +36,7 @@ pub fn signature_to_cranelift_ir( /// Helper function translating wasmparser types to Cranelift types when possible. pub fn reference_type(target_config: TargetFrontendConfig) -> WasmResult { - match target_config.pointer_type() { - ir::types::I32 => Ok(ir::types::R32), - ir::types::I64 => Ok(ir::types::R64), - _ => Err(WasmError::Unsupported( - "unsupported pointer type".to_string(), - )), - } + Ok(target_config.pointer_type()) } /// Helper function translating wasmparser types to Cranelift types when possible. diff --git a/lib/compiler-cranelift/src/translator/unwind.rs b/lib/compiler-cranelift/src/translator/unwind.rs index ceddcbd505..ed0510ef09 100644 --- a/lib/compiler-cranelift/src/translator/unwind.rs +++ b/lib/compiler-cranelift/src/translator/unwind.rs @@ -2,8 +2,10 @@ //! module. #[cfg(feature = "unwind")] -use cranelift_codegen::isa::unwind::{systemv::UnwindInfo as DwarfFDE, UnwindInfo}; -use cranelift_codegen::{isa, print_errors::pretty_error, Context}; +use cranelift_codegen::isa::unwind::{UnwindInfo, systemv::UnwindInfo as DwarfFDE}; +#[cfg(feature = "unwind")] +use cranelift_codegen::print_errors::pretty_error; +use cranelift_codegen::{Context, isa}; use wasmer_compiler::types::unwind::CompiledFunctionUnwindInfo; use wasmer_types::CompileError; @@ -62,8 +64,8 @@ pub(crate) fn compiled_function_unwind_info( #[cfg(not(feature = "unwind"))] /// Constructs unwind info object from Cranelift IR pub(crate) fn compiled_function_unwind_info( - isa: &dyn isa::TargetIsa, - context: &Context, + _isa: &dyn isa::TargetIsa, + _context: &Context, ) -> Result { Ok(CraneliftUnwindInfo::None) } diff --git a/lib/compiler-llvm/Cargo.toml b/lib/compiler-llvm/Cargo.toml index 853cdb66e9..eb074ffca7 100644 --- a/lib/compiler-llvm/Cargo.toml +++ b/lib/compiler-llvm/Cargo.toml @@ -20,33 +20,28 @@ wasmer-compiler = { path = "../compiler", version = "=6.1.0", features = [ ] } wasmer-vm = { path = "../vm", version = "=6.1.0" } wasmer-types = { path = "../types", version = "=6.1.0" } -target-lexicon = { workspace = true, default-features = false } +target-lexicon = { workspace = true } smallvec.workspace = true object = { workspace = true, features = ["read"] } libc.workspace = true byteorder.workspace = true itertools.workspace = true rayon.workspace = true -phf = { version = "0.11.2", features = ["macros"] } +phf = { workspace = true, features = ["macros"] } tracing = { workspace = true, features = ["log"] } - -[dependencies.inkwell] -package = "inkwell" -version = "0.5.0" -default-features = false -features = [ - "llvm18-0-prefer-static", +inkwell = { workspace = true, features = [ + "llvm21-1-prefer-static", "target-x86", "target-aarch64", "target-riscv", "target-loongarch", -] +] } [build-dependencies] -cc = "1.0" -regex = "1.5" +cc.workspace = true +regex.workspace = true semver.workspace = true -rustc_version = "0.4" +rustc_version.workspace = true [features] test = [] diff --git a/lib/compiler-llvm/LICENSE b/lib/compiler-llvm/LICENSE index 622ebe383d..c225bd62f9 100644 --- a/lib/compiler-llvm/LICENSE +++ b/lib/compiler-llvm/LICENSE @@ -4,7 +4,7 @@ License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. Parameters Licensor: Wasmer, Inc. -Licensed Work: Wasmer LLVM Version 6.0.0 or later. The Licensed Work is +Licensed Work: Wasmer LLVM Version 6.1.0 or later. The Licensed Work is (c) 2025 Wasmer, Inc. Additional Use Grant: You may make production use of the Licensed Work provided you are either a Sponsor under the Wasmer Sponsorhip Program or an entity @@ -34,6 +34,12 @@ Additional Use Grant: You may make production use of the Licensed Work provided that of your associated Sponsor is terminated for any reason, the additional rights granted under this Sponsor Exception shall immediately revert to the standard limitations of BUSL 1.1. + + For purposes of this License, any code, binaries, or other output + generated by the Licensed Work ("Generated Code") shall be deemed part + of the Licensed Work and subject to the same terms, conditions, and + restrictions as the Licensed Work itself, including the limitations on + production use and the Change Date. Change Date: Four years from the date the Licensed Work is published Change License: MPL 2.0 @@ -83,4 +89,4 @@ TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND -TITLE. \ No newline at end of file +TITLE. diff --git a/lib/compiler-llvm/README.md b/lib/compiler-llvm/README.md index e2d789068c..eec852844c 100644 --- a/lib/compiler-llvm/README.md +++ b/lib/compiler-llvm/README.md @@ -23,20 +23,20 @@ to native speeds. ## Requirements The LLVM compiler requires a valid installation of LLVM in your system. -It currently requires **LLVM 18**. +It currently requires **LLVM 21**. You can install LLVM easily on your Debian-like system via this command: ```bash wget https://apt.llvm.org/llvm.sh -O /tmp/llvm.sh -sudo bash /tmp/llvm.sh 18 +sudo bash /tmp/llvm.sh 21 ``` Or in macOS: ```bash -brew install llvm@18 +brew install llvm@21 ``` Or via any of the [pre-built binaries that LLVM offers][llvm-pre-built]. diff --git a/lib/compiler-llvm/src/abi/aarch64_systemv.rs b/lib/compiler-llvm/src/abi/aarch64_systemv.rs index 2076f62962..b4a9aa37eb 100644 --- a/lib/compiler-llvm/src/abi/aarch64_systemv.rs +++ b/lib/compiler-llvm/src/abi/aarch64_systemv.rs @@ -1,13 +1,13 @@ use crate::abi::Abi; use crate::error::{err, err_nt}; -use crate::translator::intrinsics::{type_to_llvm, Intrinsics}; +use crate::translator::intrinsics::{Intrinsics, type_to_llvm}; use inkwell::{ + AddressSpace, attributes::{Attribute, AttributeLoc}, builder::Builder, context::Context, types::{AnyType, BasicMetadataTypeEnum, BasicType, FunctionType, StructType}, values::{BasicValue, BasicValueEnum, CallSiteValue, FunctionValue, IntValue, PointerValue}, - AddressSpace, }; use wasmer_types::CompileError; use wasmer_types::{FunctionType as FuncSig, Type}; @@ -412,7 +412,7 @@ impl Abi for Aarch64SystemV { } }; - if let Some(basic_value) = call_site.try_as_basic_value().left() { + if let Some(basic_value) = call_site.try_as_basic_value().basic() { if func_sig.results().len() > 1 { if basic_value.get_type() == intrinsics.i64_ty.as_basic_type_enum() { assert!(func_sig.results().len() == 2); @@ -514,12 +514,10 @@ impl Abi for Aarch64SystemV { { let sret_ty = call_site .try_as_basic_value() - .right() - .unwrap() + .unwrap_instruction() .get_operand(0) .unwrap() - .left() - .unwrap(); + .unwrap_value(); let sret = sret_ty.into_pointer_value(); // re-build the llvm-type struct holding the return values let llvm_results: Vec<_> = func_sig @@ -600,9 +598,11 @@ impl Abi for Aarch64SystemV { let high = err!(builder.build_int_z_extend(high, intrinsics.i64_ty, "")); let high = err!(builder.build_left_shift(high, intrinsics.i64_ty.const_int(32, false), "")); - err_nt!(builder - .build_or(low, high, "") - .map(|v| v.as_basic_value_enum())) + err_nt!( + builder + .build_or(low, high, "") + .map(|v| v.as_basic_value_enum()) + ) }; let to_i64 = |v: BasicValueEnum<'ctx>| -> Result, CompileError> { diff --git a/lib/compiler-llvm/src/abi/x86_64_systemv.rs b/lib/compiler-llvm/src/abi/x86_64_systemv.rs index f0bad7fb01..000d2c8f60 100644 --- a/lib/compiler-llvm/src/abi/x86_64_systemv.rs +++ b/lib/compiler-llvm/src/abi/x86_64_systemv.rs @@ -1,7 +1,8 @@ use crate::abi::Abi; use crate::error::{err, err_nt}; -use crate::translator::intrinsics::{type_to_llvm, Intrinsics}; +use crate::translator::intrinsics::{Intrinsics, type_to_llvm}; use inkwell::{ + AddressSpace, attributes::{Attribute, AttributeLoc}, builder::Builder, context::Context, @@ -10,7 +11,6 @@ use inkwell::{ BasicValue, BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue, PointerValue, VectorValue, }, - AddressSpace, }; use wasmer_types::{CompileError, FunctionType as FuncSig, Type}; use wasmer_vm::VMOffsets; @@ -438,7 +438,7 @@ impl Abi for X86_64SystemV { } }; - if let Some(basic_value) = call_site.try_as_basic_value().left() { + if let Some(basic_value) = call_site.try_as_basic_value().basic() { if func_sig.results().len() > 1 { if basic_value.get_type() == intrinsics.i64_ty.as_basic_type_enum() { assert!(func_sig.results().len() == 2); @@ -548,12 +548,10 @@ impl Abi for X86_64SystemV { { let sret_ty = call_site .try_as_basic_value() - .right() - .unwrap() + .unwrap_instruction() .get_operand(0) .unwrap() - .left() - .unwrap(); + .unwrap_value(); let sret = sret_ty.into_pointer_value(); // re-build the llvm-type struct holding the return values let llvm_results: Vec<_> = func_sig @@ -637,9 +635,11 @@ impl Abi for X86_64SystemV { let high = err!(builder.build_int_z_extend(high, intrinsics.i64_ty, "")); let high = err!(builder.build_left_shift(high, intrinsics.i64_ty.const_int(32, false), "")); - err_nt!(builder - .build_or(low, high, "") - .map(|v| v.as_basic_value_enum())) + err_nt!( + builder + .build_or(low, high, "") + .map(|v| v.as_basic_value_enum()) + ) }; let pack_f32s = |first: BasicValueEnum<'ctx>, @@ -655,9 +655,11 @@ impl Abi for X86_64SystemV { intrinsics.i32_zero, "" )); - err_nt!(builder - .build_insert_element(vec, second, intrinsics.i32_ty.const_int(1, false), "") - .map(|v| v.as_basic_value_enum())) + err_nt!( + builder + .build_insert_element(vec, second, intrinsics.i32_ty.const_int(1, false), "") + .map(|v| v.as_basic_value_enum()) + ) }; let build_struct = |ty: StructType<'ctx>, values: &[BasicValueEnum<'ctx>]| { diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index 376dd03207..bd228ea7fe 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -1,28 +1,28 @@ use crate::config::LLVM; use crate::trampoline::FuncTrampoline; use crate::translator::FuncTranslator; -use crate::CompiledKind; +use inkwell::DLLStorageClass; use inkwell::context::Context; use inkwell::memory_buffer::MemoryBuffer; use inkwell::module::{Linkage, Module}; use inkwell::targets::FileType; -use inkwell::DLLStorageClass; +use rayon::ThreadPoolBuilder; use rayon::iter::ParallelBridge; use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; -use rayon::ThreadPoolBuilder; use std::borrow::Cow; use std::collections::{HashMap, HashSet}; use std::sync::Arc; +use wasmer_compiler::misc::CompiledKind; use wasmer_compiler::types::function::{Compilation, UnwindInfo}; use wasmer_compiler::types::module::CompileModuleInfo; use wasmer_compiler::types::relocation::RelocationKind; use wasmer_compiler::{ + Compiler, FunctionBodyData, ModuleMiddleware, ModuleTranslationState, types::{ relocation::RelocationTarget, section::{CustomSection, CustomSectionProtection, SectionBody, SectionIndex}, symbols::{Symbol, SymbolRegistry}, }, - Compiler, FunctionBodyData, ModuleMiddleware, ModuleTranslationState, }; use wasmer_types::entity::{EntityRef, PrimaryMap}; use wasmer_types::target::Target; @@ -114,7 +114,7 @@ impl ModuleBasedSymbolRegistry { } // If the name starts with a problematic prefix, we prefix it with an underscore. - fn fixup_problematic_name(name: &str) -> Cow { + fn fixup_problematic_name(name: &str) -> Cow<'_, str> { for prefix in Self::PROBLEMATIC_PREFIXES { if name.starts_with(prefix) { return format!("_{name}").into(); @@ -194,6 +194,7 @@ impl LLVMCompiler { &compile_info.memory_styles, &compile_info.table_styles, symbol_registry, + target.triple(), )?; Ok(module.write_bitcode_to_memory().as_slice().to_vec()) @@ -410,6 +411,7 @@ impl Compiler for LLVMCompiler { memory_styles, table_styles, &symbol_registry, + target.triple(), ) }, ) @@ -436,6 +438,7 @@ impl Compiler for LLVMCompiler { memory_styles, table_styles, &symbol_registry, + target.triple(), ) }) .collect::, CompileError>>()? @@ -469,6 +472,8 @@ impl Compiler for LLVMCompiler { reloc.offset += offset; } eh_frame_section_bytes.extend_from_slice(custom_section.bytes.as_slice()); + // Terminate the eh_frame info with a zero-length CIE. + eh_frame_section_bytes.extend_from_slice(&[0, 0, 0, 0]); eh_frame_section_relocations.extend(custom_section.relocations); // TODO: we do this to keep the count right, remove it. module_custom_sections.push(CustomSection { @@ -514,35 +519,6 @@ impl Compiler for LLVMCompiler { }) .collect::>(); - let mut unwind_info = UnwindInfo::default(); - - if !eh_frame_section_bytes.is_empty() { - let eh_frame_idx = SectionIndex::from_u32(module_custom_sections.len() as u32); - // Terminate the eh_frame info with a zero-length CIE. - // - // There may be more info added later in lib/object/src/module.rs emit_compilation - // but that's okay, because an eh_frame can have multiple CIEs. - eh_frame_section_bytes.extend_from_slice(&[0, 0, 0, 0]); - module_custom_sections.push(CustomSection { - protection: CustomSectionProtection::Read, - alignment: None, - bytes: SectionBody::new_with_vec(eh_frame_section_bytes), - relocations: eh_frame_section_relocations, - }); - unwind_info.eh_frame = Some(eh_frame_idx); - } - - if !compact_unwind_section_bytes.is_empty() { - let cu_index = SectionIndex::from_u32(module_custom_sections.len() as u32); - module_custom_sections.push(CustomSection { - protection: CustomSectionProtection::Read, - alignment: None, - bytes: SectionBody::new_with_vec(compact_unwind_section_bytes), - relocations: compact_unwind_section_relocations, - }); - unwind_info.compact_unwind = Some(cu_index); - } - let function_call_trampolines = if self.config.num_threads.get() > 1 { let pool = ThreadPoolBuilder::new() .num_threads(self.config.num_threads.get()) @@ -581,42 +557,60 @@ impl Compiler for LLVMCompiler { .collect::, CompileError>>()? }; - let dynamic_function_trampolines = if self.config.num_threads.get() > 1 { - let pool = ThreadPoolBuilder::new() - .num_threads(self.config.num_threads.get()) - .build() - .map_err(|e| CompileError::Resource(e.to_string()))?; - pool.install(|| { - module - .imported_function_types() - .collect::>() - .par_iter() - .map_init( - || { - let target_machine = self.config().target_machine(target); - FuncTrampoline::new(target_machine, binary_format).unwrap() - }, - |func_trampoline, func_type| { - func_trampoline.dynamic_trampoline(func_type, self.config(), "") - }, - ) - .collect::>() - .into_iter() - .collect::, CompileError>>() - })? - } else { + // TODO: I removed the parallel processing of dynamic trampolines because we're passing + // the sections bytes and relocations directly into the trampoline generation function. + // We can move that logic out and re-enable parallel processing. Hopefully, there aren't + // enough dynamic trampolines to actually cause a noticeable performance degradation. + let dynamic_function_trampolines = { let target_machine = self.config().target_machine(target); let func_trampoline = FuncTrampoline::new(target_machine, binary_format).unwrap(); module .imported_function_types() .collect::>() .into_iter() - .map(|func_type| func_trampoline.dynamic_trampoline(&func_type, self.config(), "")) + .enumerate() + .map(|(index, func_type)| { + func_trampoline.dynamic_trampoline( + &func_type, + self.config(), + "", + index as u32, + &mut module_custom_sections, + &mut eh_frame_section_bytes, + &mut eh_frame_section_relocations, + &mut compact_unwind_section_bytes, + &mut compact_unwind_section_relocations, + ) + }) .collect::>() .into_iter() .collect::, CompileError>>()? }; + let mut unwind_info = UnwindInfo::default(); + + if !eh_frame_section_bytes.is_empty() { + let eh_frame_idx = SectionIndex::from_u32(module_custom_sections.len() as u32); + module_custom_sections.push(CustomSection { + protection: CustomSectionProtection::Read, + alignment: None, + bytes: SectionBody::new_with_vec(eh_frame_section_bytes), + relocations: eh_frame_section_relocations, + }); + unwind_info.eh_frame = Some(eh_frame_idx); + } + + if !compact_unwind_section_bytes.is_empty() { + let cu_index = SectionIndex::from_u32(module_custom_sections.len() as u32); + module_custom_sections.push(CustomSection { + protection: CustomSectionProtection::Read, + alignment: None, + bytes: SectionBody::new_with_vec(compact_unwind_section_bytes), + relocations: compact_unwind_section_relocations, + }); + unwind_info.compact_unwind = Some(cu_index); + } + let mut got = wasmer_compiler::types::function::GOT::empty(); if !got_targets.is_empty() { diff --git a/lib/compiler-llvm/src/config.rs b/lib/compiler-llvm/src/config.rs index 1a0261b0b4..3fcf077448 100644 --- a/lib/compiler-llvm/src/config.rs +++ b/lib/compiler-llvm/src/config.rs @@ -1,17 +1,21 @@ use crate::compiler::LLVMCompiler; +pub use inkwell::OptimizationLevel as LLVMOptLevel; use inkwell::targets::{ CodeModel, InitializationConfig, RelocMode, Target as InkwellTarget, TargetMachine, - TargetTriple, + TargetMachineOptions, TargetTriple, }; -pub use inkwell::OptimizationLevel as LLVMOptLevel; use itertools::Itertools; +use std::fs::File; +use std::io::{self, Write}; +use std::path::PathBuf; use std::sync::Arc; use std::{fmt::Debug, num::NonZero}; use target_lexicon::BinaryFormat; +use wasmer_compiler::misc::{CompiledKind, function_kind_to_filename}; use wasmer_compiler::{Compiler, CompilerConfig, Engine, EngineBuilder, ModuleMiddleware}; use wasmer_types::{ + Features, target::{Architecture, OperatingSystem, Target, Triple}, - Features, FunctionType, LocalFunctionIndex, }; /// The InkWell ModuleInfo type @@ -20,25 +24,50 @@ pub type InkwellModule<'ctx> = inkwell::module::Module<'ctx>; /// The InkWell MemoryBuffer type pub type InkwellMemoryBuffer = inkwell::memory_buffer::MemoryBuffer; -/// The compiled function kind, used for debugging in the `LLVMCallbacks`. +/// Callbacks to the different LLVM compilation phases. #[derive(Debug, Clone)] -pub enum CompiledKind { - // A locally-defined function in the Wasm file. - Local(LocalFunctionIndex), - // A function call trampoline for a given signature. - FunctionCallTrampoline(FunctionType), - // A dynamic function trampoline for a given signature. - DynamicFunctionTrampoline(FunctionType), - // An entire Wasm module. - Module, +pub struct LLVMCallbacks { + debug_dir: PathBuf, } -/// Callbacks to the different LLVM compilation phases. -pub trait LLVMCallbacks: Debug + Send + Sync { - fn preopt_ir(&self, function: &CompiledKind, module: &InkwellModule); - fn postopt_ir(&self, function: &CompiledKind, module: &InkwellModule); - fn obj_memory_buffer(&self, function: &CompiledKind, memory_buffer: &InkwellMemoryBuffer); - fn asm_memory_buffer(&self, function: &CompiledKind, memory_buffer: &InkwellMemoryBuffer); +impl LLVMCallbacks { + pub fn new(debug_dir: PathBuf) -> Result { + // Create the debug dir in case it doesn't exist + std::fs::create_dir_all(&debug_dir)?; + Ok(Self { debug_dir }) + } + + pub fn preopt_ir(&self, kind: &CompiledKind, module: &InkwellModule) { + let mut path = self.debug_dir.clone(); + path.push(function_kind_to_filename(kind, ".preopt.ll")); + module + .print_to_file(&path) + .expect("Error while dumping pre optimized LLVM IR"); + } + pub fn postopt_ir(&self, kind: &CompiledKind, module: &InkwellModule) { + let mut path = self.debug_dir.clone(); + path.push(function_kind_to_filename(kind, ".postopt.ll")); + module + .print_to_file(&path) + .expect("Error while dumping post optimized LLVM IR"); + } + pub fn obj_memory_buffer(&self, kind: &CompiledKind, memory_buffer: &InkwellMemoryBuffer) { + let mut path = self.debug_dir.clone(); + path.push(function_kind_to_filename(kind, ".o")); + let mem_buf_slice = memory_buffer.as_slice(); + let mut file = + File::create(path).expect("Error while creating debug object file from LLVM IR"); + file.write_all(mem_buf_slice).unwrap(); + } + + pub fn asm_memory_buffer(&self, kind: &CompiledKind, asm_memory_buffer: &InkwellMemoryBuffer) { + let mut path = self.debug_dir.clone(); + path.push(function_kind_to_filename(kind, ".s")); + let mem_buf_slice = asm_memory_buffer.as_slice(); + let mut file = + File::create(path).expect("Error while creating debug assembly file from LLVM IR"); + file.write_all(mem_buf_slice).unwrap(); + } } #[derive(Debug, Clone)] @@ -49,7 +78,7 @@ pub struct LLVM { pub(crate) enable_perfmap: bool, pub(crate) opt_level: LLVMOptLevel, is_pic: bool, - pub(crate) callbacks: Option>, + pub(crate) callbacks: Option, /// The middleware chain. pub(crate) middlewares: Vec>, /// Number of threads to use when compiling a module. @@ -94,7 +123,7 @@ impl LLVM { /// Callbacks that will triggered in the different compilation /// phases in LLVM. - pub fn callbacks(&mut self, callbacks: Option>) -> &mut Self { + pub fn callbacks(&mut self, callbacks: Option) -> &mut Self { self.callbacks = callbacks; self } @@ -129,21 +158,22 @@ impl LLVM { } pub(crate) fn target_operating_system(&self, target: &Target) -> OperatingSystem { - if target.triple().operating_system == OperatingSystem::Darwin && !self.is_pic { - // LLVM detects static relocation + darwin + 64-bit and - // force-enables PIC because MachO doesn't support that - // combination. They don't check whether they're targeting - // MachO, they check whether the OS is set to Darwin. - // - // Since both linux and darwin use SysV ABI, this should work. - // but not in the case of Aarch64, there the ABI is slightly different - #[allow(clippy::match_single_binding)] - match target.triple().architecture { - Architecture::Aarch64(_) => OperatingSystem::Darwin, - _ => OperatingSystem::Linux, + match target.triple().operating_system { + OperatingSystem::Darwin(deployment) if !self.is_pic => { + // LLVM detects static relocation + darwin + 64-bit and + // force-enables PIC because MachO doesn't support that + // combination. They don't check whether they're targeting + // MachO, they check whether the OS is set to Darwin. + // + // Since both linux and darwin use SysV ABI, this should work. + // but not in the case of Aarch64, there the ABI is slightly different + #[allow(clippy::match_single_binding)] + match target.triple().architecture { + Architecture::Aarch64(_) => OperatingSystem::Darwin(deployment), + _ => OperatingSystem::Linux, + } } - } else { - target.triple().operating_system + other => other, } } @@ -152,7 +182,7 @@ impl LLVM { target.triple().binary_format } else { match self.target_operating_system(target) { - OperatingSystem::Darwin => target_lexicon::BinaryFormat::Macho, + OperatingSystem::Darwin(_) => target_lexicon::BinaryFormat::Macho, _ => target_lexicon::BinaryFormat::Elf, } } @@ -245,61 +275,29 @@ impl LLVM { let target_triple = self.target_triple(target); let llvm_target = InkwellTarget::from_triple(&target_triple).unwrap(); - let llvm_target_machine = llvm_target - .create_target_machine( - &target_triple, - match triple.architecture { - Architecture::Riscv64(_) => "generic-rv64", - Architecture::LoongArch64 => "generic-la64", - _ => "generic", - }, - match triple.architecture { - Architecture::Riscv64(_) => "+m,+a,+c,+d,+f", - Architecture::LoongArch64 => "+f,+d", - _ => &llvm_cpu_features, - }, - self.opt_level, - self.reloc_mode(self.target_binary_format(target)), - match triple.architecture { - Architecture::LoongArch64 | Architecture::Riscv64(_) => CodeModel::Medium, - _ => self.code_model(self.target_binary_format(target)), - }, - ) - .unwrap(); - + let mut llvm_target_machine_options = TargetMachineOptions::new() + .set_cpu(match triple.architecture { + Architecture::Riscv64(_) => "generic-rv64", + Architecture::LoongArch64 => "generic-la64", + _ => "generic", + }) + .set_features(match triple.architecture { + Architecture::Riscv64(_) => "+m,+a,+c,+d,+f", + Architecture::LoongArch64 => "+f,+d", + _ => &llvm_cpu_features, + }) + .set_level(self.opt_level) + .set_reloc_mode(self.reloc_mode(self.target_binary_format(target))) + .set_code_model(match triple.architecture { + Architecture::LoongArch64 | Architecture::Riscv64(_) => CodeModel::Medium, + _ => self.code_model(self.target_binary_format(target)), + }); if let Architecture::Riscv64(_) = triple.architecture { - // TODO: totally non-portable way to change ABI - unsafe { - // This structure mimic the internal structure from inkwell - // that is defined as - // #[derive(Debug)] - // pub struct TargetMachine { - // pub(crate) target_machine: LLVMTargetMachineRef, - // } - pub struct MyTargetMachine { - pub target_machine: *const u8, - } - // It is use to live patch the create LLVMTargetMachine - // to hard change the ABI and force "-mabi=lp64d" ABI - // instead of the default that don't use float registers - // because there is no current way to do this change - - let my_target_machine: MyTargetMachine = std::mem::transmute(llvm_target_machine); - - *((my_target_machine.target_machine as *mut u8).offset(0x410) as *mut u64) = 5; - std::ptr::copy_nonoverlapping( - c"lp64d".as_ptr(), - (my_target_machine.target_machine as *mut i8).offset(0x418), - 6, - ); - - std::mem::transmute::( - my_target_machine, - ) - } - } else { - llvm_target_machine + llvm_target_machine_options = llvm_target_machine_options.set_abi("lp64d"); } + llvm_target + .create_target_machine_from_options(&target_triple, llvm_target_machine_options) + .unwrap() } } diff --git a/lib/compiler-llvm/src/error.rs b/lib/compiler-llvm/src/error.rs index 0ebe4ade2c..91159de8cd 100644 --- a/lib/compiler-llvm/src/error.rs +++ b/lib/compiler-llvm/src/error.rs @@ -1,11 +1,11 @@ macro_rules! err_nt { - ($e: expr) => { + ($e: expr_2021) => { $e.map_err(|v| CompileError::Codegen(v.to_string())) }; } macro_rules! err { - ($e: expr) => { + ($e: expr_2021) => { $e.map_err(|v| CompileError::Codegen(v.to_string()))? }; } diff --git a/lib/compiler-llvm/src/lib.rs b/lib/compiler-llvm/src/lib.rs index fc07773983..6ef214c60c 100644 --- a/lib/compiler-llvm/src/lib.rs +++ b/lib/compiler-llvm/src/lib.rs @@ -12,7 +12,7 @@ )] #![doc(html_favicon_url = "https://wasmer.io/images/icons/favicon-32x32.png")] #![doc(html_logo_url = "https://github.com/wasmerio.png?size=200")] -#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] mod abi; mod compiler; @@ -23,6 +23,4 @@ mod trampoline; mod translator; pub use crate::compiler::LLVMCompiler; -pub use crate::config::{ - CompiledKind, InkwellMemoryBuffer, InkwellModule, LLVMCallbacks, LLVMOptLevel, LLVM, -}; +pub use crate::config::{InkwellMemoryBuffer, InkwellModule, LLVM, LLVMCallbacks, LLVMOptLevel}; diff --git a/lib/compiler-llvm/src/object_file.rs b/lib/compiler-llvm/src/object_file.rs index e6392e5d8a..a148507247 100644 --- a/lib/compiler-llvm/src/object_file.rs +++ b/lib/compiler-llvm/src/object_file.rs @@ -5,7 +5,7 @@ use std::collections::{HashMap, HashSet}; use std::convert::TryInto; use std::num::TryFromIntError; -use wasmer_types::{entity::PrimaryMap, CompileError, SourceLoc}; +use wasmer_types::{CompileError, SourceLoc, entity::PrimaryMap}; use wasmer_compiler::types::{ address_map::{FunctionAddressMap, InstructionAddressMap}, @@ -30,6 +30,7 @@ pub struct CompiledFunction { pub custom_sections: CustomSections, pub eh_frame_section_indices: Vec, pub compact_unwind_section_indices: Vec, + pub gcc_except_table_section_indices: Vec, } static LIBCALLS_ELF: phf::Map<&'static str, LibCall> = phf::phf_map! { @@ -78,13 +79,12 @@ static LIBCALLS_ELF: phf::Map<&'static str, LibCall> = phf::phf_map! { "wasmer_vm_memory32_atomic_notify" => LibCall::Memory32AtomicNotify, "wasmer_vm_imported_memory32_atomic_notify" => LibCall::ImportedMemory32AtomicNotify, "wasmer_vm_throw" => LibCall::Throw, - "wasmer_vm_rethrow" => LibCall::Rethrow, "wasmer_vm_alloc_exception" => LibCall::AllocException, - "wasmer_vm_delete_exception" => LibCall::DeleteException, - "wasmer_vm_read_exception" => LibCall::ReadException, - "wasmer_vm_dbg_usize" => LibCall::DebugUsize, + "wasmer_vm_read_exnref" => LibCall::ReadExnRef, + "wasmer_vm_exception_into_exnref" => LibCall::LibunwindExceptionIntoExnRef, "wasmer_eh_personality" => LibCall::EHPersonality, "wasmer_eh_personality2" => LibCall::EHPersonality2, + "wasmer_vm_dbg_usize" => LibCall::DebugUsize, "wasmer_vm_dbg_str" => LibCall::DebugStr, }; @@ -133,18 +133,18 @@ static LIBCALLS_MACHO: phf::Map<&'static str, LibCall> = phf::phf_map! { "_wasmer_vm_imported_memory32_atomic_wait64" => LibCall::ImportedMemory32AtomicWait64, "_wasmer_vm_memory32_atomic_notify" => LibCall::Memory32AtomicNotify, "_wasmer_vm_imported_memory32_atomic_notify" => LibCall::ImportedMemory32AtomicNotify, + "_wasmer_vm_throw" => LibCall::Throw, - "_wasmer_vm_rethrow" => LibCall::Rethrow, "_wasmer_vm_alloc_exception" => LibCall::AllocException, - "_wasmer_vm_delete_exception" => LibCall::DeleteException, - "_wasmer_vm_read_exception" => LibCall::ReadException, - "_wasmer_vm_dbg_usize" => LibCall::DebugUsize, + "_wasmer_vm_read_exnref" => LibCall::ReadExnRef, + "_wasmer_vm_exception_into_exnref" => LibCall::LibunwindExceptionIntoExnRef, // Note: on macOS+Mach-O the personality function *must* be called like this, otherwise LLVM // will generate things differently than "normal", wreaking havoc. // // todo: find out if it is a bug in LLVM or it is expected. "___gxx_personality_v0" => LibCall::EHPersonality, "_wasmer_eh_personality2" => LibCall::EHPersonality2, + "_wasmer_vm_dbg_usize" => LibCall::DebugUsize, "_wasmer_vm_dbg_str" => LibCall::DebugStr, }; @@ -166,7 +166,7 @@ where _ => { return Err(CompileError::UnsupportedTarget(format!( "Unsupported binary format {binary_fmt:?}" - ))) + ))); } }; @@ -221,6 +221,12 @@ where // Add macos-specific unwind sections. let mut compact_unwind_section_indices = vec![]; + // .gcc_except_table sections, which contain the actual LSDA data. + // We don't need the actual sections for anything (yet), but trampoline + // codegen checks custom section counts to verify there aren't any + // unexpected custom sections, so we do a bit of book-keeping here. + let mut gcc_except_table_section_indices = vec![]; + for section in obj.sections() { let index = section.index(); if section.kind() == object::SectionKind::Elf(object::elf::SHT_X86_64_UNWIND) @@ -235,6 +241,11 @@ where worklist.push(index); compact_unwind_section_indices.push(index); + elf_section_to_target(index); + } else if section.name().unwrap_or_default() == ".gcc_except_table" { + worklist.push(index); + gcc_except_table_section_indices.push(index); + elf_section_to_target(index); } } @@ -277,22 +288,27 @@ where reloc_target } else if let object::SymbolSection::Section(section_index) = symbol.section() { if matches!( - reloc.kind(), - object::RelocationKind::MachO { - value: object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12, - relative: false - } | object::RelocationKind::MachO { - value: object::macho::ARM64_RELOC_POINTER_TO_GOT, - relative: true - } | object::RelocationKind::MachO { - value: object::macho::ARM64_RELOC_GOT_LOAD_PAGE21, - relative: true - } | object::RelocationKind::MachO { - value: object::macho::ARM64_RELOC_PAGE21, - relative: true - } | object::RelocationKind::MachO { - value: object::macho::ARM64_RELOC_PAGEOFF12, - relative: false + reloc.flags(), + object::RelocationFlags::MachO { + r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12, + r_pcrel: false, + .. + } | object::RelocationFlags::MachO { + r_type: object::macho::ARM64_RELOC_POINTER_TO_GOT, + r_pcrel: true, + .. + } | object::RelocationFlags::MachO { + r_type: object::macho::ARM64_RELOC_GOT_LOAD_PAGE21, + r_pcrel: true, + .. + } | object::RelocationFlags::MachO { + r_type: object::macho::ARM64_RELOC_PAGE21, + r_pcrel: true, + .. + } | object::RelocationFlags::MachO { + r_type: object::macho::ARM64_RELOC_PAGEOFF12, + r_pcrel: false, + .. } ) { // (caveat: this comment comes from a point in time after the `addend` @@ -373,198 +389,243 @@ where ))); } }; - let kind = match (obj.architecture(), reloc.kind(), reloc.size()) { - (_, object::RelocationKind::Absolute, 64) => RelocationKind::Abs8, - (_, object::RelocationKind::Absolute, 32) => RelocationKind::Abs4, + let kind = match (obj.architecture(), reloc.flags(), reloc.size()) { + ( + _, + object::RelocationFlags::Elf { + r_type: object::elf::R_X86_64_64, + }, + 64, + ) => RelocationKind::Abs8, + ( + _, + object::RelocationFlags::Elf { + r_type: object::elf::R_386_32, + }, + 32, + ) => RelocationKind::Abs4, ( object::Architecture::X86_64, - object::RelocationKind::Elf(object::elf::R_X86_64_PC64), + object::RelocationFlags::Elf { + r_type: object::elf::R_X86_64_PC64, + }, 0, ) => RelocationKind::X86PCRel8, - (object::Architecture::Aarch64, object::RelocationKind::PltRelative, 26) => { - RelocationKind::Arm64Call - } ( object::Architecture::Aarch64, - object::RelocationKind::Elf(object::elf::R_AARCH64_MOVW_UABS_G0_NC), + object::RelocationFlags::Elf { + r_type: object::elf::R_AARCH64_CALL26, + }, + 26, + ) => RelocationKind::Arm64Call, + ( + object::Architecture::Aarch64, + object::RelocationFlags::Elf { + r_type: object::elf::R_AARCH64_MOVW_UABS_G0_NC, + }, 0, ) => RelocationKind::Arm64Movw0, ( object::Architecture::Aarch64, - object::RelocationKind::Elf(object::elf::R_AARCH64_MOVW_UABS_G1_NC), + object::RelocationFlags::Elf { + r_type: object::elf::R_AARCH64_MOVW_UABS_G1_NC, + }, 0, ) => RelocationKind::Arm64Movw1, ( object::Architecture::Aarch64, - object::RelocationKind::Elf(object::elf::R_AARCH64_MOVW_UABS_G2_NC), + object::RelocationFlags::Elf { + r_type: object::elf::R_AARCH64_MOVW_UABS_G2_NC, + }, 0, ) => RelocationKind::Arm64Movw2, ( object::Architecture::Aarch64, - object::RelocationKind::Elf(object::elf::R_AARCH64_MOVW_UABS_G3), + object::RelocationFlags::Elf { + r_type: object::elf::R_AARCH64_MOVW_UABS_G3, + }, 0, ) => RelocationKind::Arm64Movw3, ( object::Architecture::Riscv64, - object::RelocationKind::Elf(object::elf::R_RISCV_CALL_PLT), + object::RelocationFlags::Elf { + r_type: object::elf::R_RISCV_CALL_PLT, + }, 0, ) => RelocationKind::RiscvCall, ( object::Architecture::Riscv64, - object::RelocationKind::Elf(object::elf::R_RISCV_PCREL_HI20), + object::RelocationFlags::Elf { + r_type: object::elf::R_RISCV_PCREL_HI20, + }, 0, ) => RelocationKind::RiscvPCRelHi20, ( object::Architecture::Riscv64, - object::RelocationKind::Elf(object::elf::R_RISCV_PCREL_LO12_I), + object::RelocationFlags::Elf { + r_type: object::elf::R_RISCV_PCREL_LO12_I, + }, 0, ) => RelocationKind::RiscvPCRelLo12I, ( object::Architecture::LoongArch64, - object::RelocationKind::Elf(object::elf::R_LARCH_ABS_HI20), + object::RelocationFlags::Elf { + r_type: object::elf::R_LARCH_ABS_HI20, + }, 0, ) => RelocationKind::LArchAbsHi20, ( object::Architecture::LoongArch64, - object::RelocationKind::Elf(object::elf::R_LARCH_ABS_LO12), + object::RelocationFlags::Elf { + r_type: object::elf::R_LARCH_ABS_LO12, + }, 0, ) => RelocationKind::LArchAbsLo12, ( object::Architecture::LoongArch64, - object::RelocationKind::Elf(object::elf::R_LARCH_ABS64_HI12), + object::RelocationFlags::Elf { + r_type: object::elf::R_LARCH_ABS64_HI12, + }, 0, ) => RelocationKind::LArchAbs64Hi12, ( object::Architecture::LoongArch64, - object::RelocationKind::Elf(object::elf::R_LARCH_ABS64_LO20), + object::RelocationFlags::Elf { + r_type: object::elf::R_LARCH_ABS64_LO20, + }, 0, ) => RelocationKind::LArchAbs64Lo20, ( object::Architecture::LoongArch64, - // FIXME: Replace with R_LARCH_CALL36 while object is updated - // to 0.32.2. - // https://github.com/gimli-rs/object/commit/16b6d902f6c9b39ec7aaea141460f8981e57dd79 - object::RelocationKind::Elf(110), + object::RelocationFlags::Elf { + r_type: object::elf::R_LARCH_CALL36, + }, 0, ) => RelocationKind::LArchCall36, ( object::Architecture::LoongArch64, - object::RelocationKind::Elf(object::elf::R_LARCH_PCALA_HI20), + object::RelocationFlags::Elf { + r_type: object::elf::R_LARCH_PCALA_HI20, + }, 0, ) => RelocationKind::LArchPCAlaHi20, ( object::Architecture::LoongArch64, - object::RelocationKind::Elf(object::elf::R_LARCH_PCALA_LO12), + object::RelocationFlags::Elf { + r_type: object::elf::R_LARCH_PCALA_LO12, + }, 0, ) => RelocationKind::LArchPCAlaLo12, ( object::Architecture::LoongArch64, - object::RelocationKind::Elf(object::elf::R_LARCH_PCALA64_HI12), + object::RelocationFlags::Elf { + r_type: object::elf::R_LARCH_PCALA64_HI12, + }, 0, ) => RelocationKind::LArchPCAla64Hi12, ( object::Architecture::LoongArch64, - object::RelocationKind::Elf(object::elf::R_LARCH_PCALA64_LO20), + object::RelocationFlags::Elf { + r_type: object::elf::R_LARCH_PCALA64_LO20, + }, 0, ) => RelocationKind::LArchPCAla64Lo20, ( object::Architecture::Aarch64, - object::RelocationKind::Elf(object::elf::R_AARCH64_ADR_PREL_LO21), + object::RelocationFlags::Elf { + r_type: object::elf::R_AARCH64_ADR_PREL_LO21, + }, 0, ) => RelocationKind::Aarch64AdrPrelLo21, ( object::Architecture::Aarch64, - object::RelocationKind::Elf(object::elf::R_AARCH64_ADR_PREL_PG_HI21), + object::RelocationFlags::Elf { + r_type: object::elf::R_AARCH64_ADR_PREL_PG_HI21, + }, 0, ) => RelocationKind::Aarch64AdrPrelPgHi21, ( object::Architecture::Aarch64, - object::RelocationKind::Elf(object::elf::R_AARCH64_LDST128_ABS_LO12_NC), + object::RelocationFlags::Elf { + r_type: object::elf::R_AARCH64_LDST128_ABS_LO12_NC, + }, 0, ) => RelocationKind::Aarch64Ldst128AbsLo12Nc, ( object::Architecture::Aarch64, - object::RelocationKind::Elf(object::elf::R_AARCH64_ADD_ABS_LO12_NC), + object::RelocationFlags::Elf { + r_type: object::elf::R_AARCH64_ADD_ABS_LO12_NC, + }, 0, ) => RelocationKind::Aarch64AddAbsLo12Nc, ( object::Architecture::Aarch64, - object::RelocationKind::Elf(object::elf::R_AARCH64_LDST64_ABS_LO12_NC), + object::RelocationFlags::Elf { + r_type: object::elf::R_AARCH64_LDST64_ABS_LO12_NC, + }, 0, ) => RelocationKind::Aarch64Ldst64AbsLo12Nc, - (object::Architecture::Aarch64, object::RelocationKind::MachO { value, .. }, _) => { - match value { - object::macho::ARM64_RELOC_UNSIGNED => { - RelocationKind::MachoArm64RelocUnsigned - } - object::macho::ARM64_RELOC_SUBTRACTOR => { - RelocationKind::MachoArm64RelocSubtractor - } - object::macho::ARM64_RELOC_BRANCH26 => { - RelocationKind::MachoArm64RelocBranch26 - } - object::macho::ARM64_RELOC_PAGE21 => RelocationKind::MachoArm64RelocPage21, - object::macho::ARM64_RELOC_PAGEOFF12 => { - RelocationKind::MachoArm64RelocPageoff12 - } - object::macho::ARM64_RELOC_GOT_LOAD_PAGE21 => { - RelocationKind::MachoArm64RelocGotLoadPage21 - } - object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12 => { - RelocationKind::MachoArm64RelocGotLoadPageoff12 - } - object::macho::ARM64_RELOC_POINTER_TO_GOT => { - RelocationKind::MachoArm64RelocPointerToGot - } - object::macho::ARM64_RELOC_TLVP_LOAD_PAGE21 => { - RelocationKind::MachoArm64RelocTlvpLoadPage21 - } - object::macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => { - RelocationKind::MachoArm64RelocTlvpLoadPageoff12 - } - object::macho::ARM64_RELOC_ADDEND => RelocationKind::MachoArm64RelocAddend, - _ => { - return Err(CompileError::Codegen(format!( - "unknown relocation {reloc:?}", - ))) - } + ( + object::Architecture::Aarch64, + object::RelocationFlags::MachO { r_type: value, .. }, + _, + ) => match value { + object::macho::ARM64_RELOC_UNSIGNED => RelocationKind::MachoArm64RelocUnsigned, + object::macho::ARM64_RELOC_SUBTRACTOR => { + RelocationKind::MachoArm64RelocSubtractor } - } - (object::Architecture::X86_64, object::RelocationKind::MachO { value, .. }, _) => { - match value { - object::macho::X86_64_RELOC_UNSIGNED => { - RelocationKind::MachoX86_64RelocUnsigned - } - object::macho::X86_64_RELOC_SIGNED => { - RelocationKind::MachoX86_64RelocSigned - } - object::macho::X86_64_RELOC_BRANCH => { - RelocationKind::MachoX86_64RelocBranch - } - object::macho::X86_64_RELOC_GOT_LOAD => { - RelocationKind::MachoX86_64RelocGotLoad - } - object::macho::X86_64_RELOC_GOT => RelocationKind::MachoX86_64RelocGot, - object::macho::X86_64_RELOC_SUBTRACTOR => { - RelocationKind::MachoX86_64RelocSubtractor - } - object::macho::X86_64_RELOC_SIGNED_1 => { - RelocationKind::MachoX86_64RelocSigned1 - } - object::macho::X86_64_RELOC_SIGNED_2 => { - RelocationKind::MachoX86_64RelocSigned2 - } - object::macho::X86_64_RELOC_SIGNED_4 => { - RelocationKind::MachoX86_64RelocSigned4 - } - object::macho::X86_64_RELOC_TLV => RelocationKind::MachoX86_64RelocTlv, - _ => { - return Err(CompileError::Codegen(format!( - "unknown relocation {reloc:?}" - ))) - } + object::macho::ARM64_RELOC_BRANCH26 => RelocationKind::MachoArm64RelocBranch26, + object::macho::ARM64_RELOC_PAGE21 => RelocationKind::MachoArm64RelocPage21, + object::macho::ARM64_RELOC_PAGEOFF12 => { + RelocationKind::MachoArm64RelocPageoff12 } - } + object::macho::ARM64_RELOC_GOT_LOAD_PAGE21 => { + RelocationKind::MachoArm64RelocGotLoadPage21 + } + object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12 => { + RelocationKind::MachoArm64RelocGotLoadPageoff12 + } + object::macho::ARM64_RELOC_POINTER_TO_GOT => { + RelocationKind::MachoArm64RelocPointerToGot + } + object::macho::ARM64_RELOC_TLVP_LOAD_PAGE21 => { + RelocationKind::MachoArm64RelocTlvpLoadPage21 + } + object::macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => { + RelocationKind::MachoArm64RelocTlvpLoadPageoff12 + } + object::macho::ARM64_RELOC_ADDEND => RelocationKind::MachoArm64RelocAddend, + _ => { + return Err(CompileError::Codegen(format!( + "unknown relocation {reloc:?}", + ))); + } + }, + ( + object::Architecture::X86_64, + object::RelocationFlags::MachO { r_type: value, .. }, + _, + ) => match value { + object::macho::X86_64_RELOC_UNSIGNED => { + RelocationKind::MachoX86_64RelocUnsigned + } + object::macho::X86_64_RELOC_SIGNED => RelocationKind::MachoX86_64RelocSigned, + object::macho::X86_64_RELOC_BRANCH => RelocationKind::MachoX86_64RelocBranch, + object::macho::X86_64_RELOC_GOT_LOAD => RelocationKind::MachoX86_64RelocGotLoad, + object::macho::X86_64_RELOC_GOT => RelocationKind::MachoX86_64RelocGot, + object::macho::X86_64_RELOC_SUBTRACTOR => { + RelocationKind::MachoX86_64RelocSubtractor + } + object::macho::X86_64_RELOC_SIGNED_1 => RelocationKind::MachoX86_64RelocSigned1, + object::macho::X86_64_RELOC_SIGNED_2 => RelocationKind::MachoX86_64RelocSigned2, + object::macho::X86_64_RELOC_SIGNED_4 => RelocationKind::MachoX86_64RelocSigned4, + object::macho::X86_64_RELOC_TLV => RelocationKind::MachoX86_64RelocTlv, + _ => { + return Err(CompileError::Codegen(format!( + "unknown relocation {reloc:?}" + ))); + } + }, _ => { return Err(CompileError::Codegen(format!( "unknown relocation {reloc:?}", @@ -612,6 +673,20 @@ where }) .collect::, _>>()?; + let gcc_except_table_section_indices = gcc_except_table_section_indices + .iter() + .map(|index| { + section_to_custom_section.get(index).map_or_else( + || { + Err(CompileError::Codegen(format!( + ".gcc_except_table section with index={index:?} was never loaded", + ))) + }, + |idx| Ok(*idx), + ) + }) + .collect::, _>>()?; + let mut custom_sections = section_to_custom_section .iter() .map(|(elf_section_index, custom_section_index)| { @@ -671,5 +746,6 @@ where custom_sections, eh_frame_section_indices, compact_unwind_section_indices, + gcc_except_table_section_indices, }) } diff --git a/lib/compiler-llvm/src/trampoline/wasm.rs b/lib/compiler-llvm/src/trampoline/wasm.rs index e9a95f3a3d..3d976494c2 100644 --- a/lib/compiler-llvm/src/trampoline/wasm.rs +++ b/lib/compiler-llvm/src/trampoline/wasm.rs @@ -1,11 +1,15 @@ +// TODO: Remove +#![allow(unused)] + use crate::{ - abi::{get_abi, Abi, G0M0FunctionKind}, - config::{CompiledKind, LLVM}, + abi::{Abi, G0M0FunctionKind, get_abi}, + config::LLVM, error::{err, err_nt}, - object_file::{load_object_file, CompiledFunction}, - translator::intrinsics::{type_to_llvm, type_to_llvm_ptr, Intrinsics}, + object_file::{CompiledFunction, load_object_file}, + translator::intrinsics::{Intrinsics, type_to_llvm, type_to_llvm_ptr}, }; use inkwell::{ + AddressSpace, DLLStorageClass, attributes::{Attribute, AttributeLoc}, context::Context, module::{Linkage, Module}, @@ -13,14 +17,21 @@ use inkwell::{ targets::{FileType, TargetMachine}, types::FunctionType, values::{BasicMetadataValueEnum, FunctionValue}, - AddressSpace, DLLStorageClass, }; use std::{cmp, convert::TryInto}; use target_lexicon::BinaryFormat; -use wasmer_compiler::types::{ - function::FunctionBody, module::CompileModuleInfo, relocation::RelocationTarget, +use wasmer_compiler::{ + misc::CompiledKind, + types::{ + function::FunctionBody, + module::CompileModuleInfo, + relocation::{Relocation, RelocationTarget}, + section::{CustomSection, CustomSectionProtection, SectionBody, SectionIndex}, + }, +}; +use wasmer_types::{ + CompileError, FunctionIndex, FunctionType as FuncType, LocalFunctionIndex, entity::PrimaryMap, }; -use wasmer_types::{CompileError, FunctionType as FuncType, LocalFunctionIndex}; use wasmer_vm::MemoryStyle; pub struct FuncTrampoline { @@ -50,7 +61,7 @@ impl FuncTrampoline { _ => { return Err(CompileError::UnsupportedTarget(format!( "Unsupported binary format: {binary_fmt:?}", - ))) + ))); } }, binary_fmt, @@ -63,7 +74,7 @@ impl FuncTrampoline { config: &LLVM, name: &str, compile_info: &CompileModuleInfo, - ) -> Result { + ) -> Result, CompileError> { // The function type, used for the callbacks. let function = CompiledKind::FunctionCallTrampoline(ty.clone()); let module = self.ctx.create_module(""); @@ -172,6 +183,19 @@ impl FuncTrampoline { } let mem_buf_slice = memory_buffer.as_slice(); + + // Use a dummy function index to detect relocations against the trampoline + // function's address, which shouldn't exist and are not supported. + // Note, we just drop all custom sections, and verify that the function + // body itself has no relocations at all. This value should never be + // touched at all. However, it is set up so that if we do touch it (maybe + // due to someone changing the code later on), it'll explode, which is desirable! + let dummy_reloc_target = + RelocationTarget::DynamicTrampoline(FunctionIndex::from_u32(u32::MAX - 1)); + + // Note: we don't count .gcc_except_table here because native-to-wasm + // trampolines are not supposed to generate any LSDA sections. We *want* them + // to terminate libunwind's stack searches. let CompiledFunction { compiled_function, custom_sections, @@ -181,7 +205,7 @@ impl FuncTrampoline { } = load_object_file( mem_buf_slice, &self.func_section, - RelocationTarget::LocalFunc(LocalFunctionIndex::from_u32(0)), + dummy_reloc_target, |name: &str| { Err(CompileError::Codegen(format!( "trampoline generation produced reference to unknown function {name}", @@ -226,7 +250,7 @@ impl FuncTrampoline { ty: &FuncType, config: &LLVM, name: &str, - ) -> Result { + ) -> Result, CompileError> { // The function type, used for the callbacks let function = CompiledKind::DynamicFunctionTrampoline(ty.clone()); let module = self.ctx.create_module(""); @@ -241,6 +265,8 @@ impl FuncTrampoline { self.abi .func_type_to_llvm(&self.ctx, &intrinsics, None, ty, None)?; let trampoline_func = module.add_function(name, trampoline_ty, Some(Linkage::External)); + trampoline_func.set_personality_function(intrinsics.personality); + trampoline_func.add_attribute(AttributeLoc::Function, intrinsics.frame_pointer); for (attr, attr_loc) in trampoline_attrs { trampoline_func.add_attribute(attr_loc, attr); } @@ -280,11 +306,19 @@ impl FuncTrampoline { Ok(module) } + + #[allow(clippy::too_many_arguments)] pub fn dynamic_trampoline( &self, ty: &FuncType, config: &LLVM, name: &str, + dynamic_trampoline_index: u32, + final_module_custom_sections: &mut PrimaryMap, + eh_frame_section_bytes: &mut Vec, + eh_frame_section_relocations: &mut Vec, + compact_unwind_section_bytes: &mut Vec, + compact_unwind_section_relocations: &mut Vec, ) -> Result { let function = CompiledKind::DynamicFunctionTrampoline(ty.clone()); let target_machine = &self.target_machine; @@ -308,12 +342,12 @@ impl FuncTrampoline { compiled_function, custom_sections, eh_frame_section_indices, - mut compact_unwind_section_indices, - .. + compact_unwind_section_indices, + gcc_except_table_section_indices, } = load_object_file( mem_buf_slice, &self.func_section, - RelocationTarget::LocalFunc(LocalFunctionIndex::from_u32(0)), + RelocationTarget::DynamicTrampoline(FunctionIndex::from_u32(dynamic_trampoline_index)), |name: &str| { Err(CompileError::Codegen(format!( "trampoline generation produced reference to unknown function {name}", @@ -321,26 +355,7 @@ impl FuncTrampoline { }, self.binary_fmt, )?; - let mut all_sections_are_eh_sections = true; - let mut unwind_section_indices = eh_frame_section_indices; - unwind_section_indices.append(&mut compact_unwind_section_indices); - if unwind_section_indices.len() != custom_sections.len() { - all_sections_are_eh_sections = false; - } else { - unwind_section_indices.sort_unstable(); - for (idx, section_idx) in unwind_section_indices.iter().enumerate() { - if idx as u32 != section_idx.as_u32() { - all_sections_are_eh_sections = false; - break; - } - } - } - if !all_sections_are_eh_sections { - return Err(CompileError::Codegen( - "trampoline generation produced non-eh custom sections".into(), - )); - } if !compiled_function.relocations.is_empty() { return Err(CompileError::Codegen( "trampoline generation produced relocations".into(), @@ -348,6 +363,65 @@ impl FuncTrampoline { } // Ignore CompiledFunctionFrameInfo. Extra frame info isn't a problem. + // Also append EH-related sections to the final module, since we expect + // dynamic trampolines to participate in unwinding + { + let first_section = final_module_custom_sections.len() as u32; + for (section_index, mut custom_section) in custom_sections.into_iter() { + for reloc in &mut custom_section.relocations { + if let RelocationTarget::CustomSection(index) = reloc.reloc_target { + reloc.reloc_target = RelocationTarget::CustomSection( + SectionIndex::from_u32(first_section + index.as_u32()), + ) + } + + if reloc.kind.needs_got() { + return Err(CompileError::Codegen( + "trampoline generation produced GOT relocation".into(), + )); + } + } + + if eh_frame_section_indices.contains(§ion_index) { + let offset = eh_frame_section_bytes.len() as u32; + for reloc in &mut custom_section.relocations { + reloc.offset += offset; + } + eh_frame_section_bytes.extend_from_slice(custom_section.bytes.as_slice()); + // Terminate the eh_frame info with a zero-length CIE. + eh_frame_section_bytes.extend_from_slice(&[0, 0, 0, 0]); + eh_frame_section_relocations.extend(custom_section.relocations); + // TODO: we do this to keep the count right, remove it. + final_module_custom_sections.push(CustomSection { + protection: CustomSectionProtection::Read, + alignment: None, + bytes: SectionBody::new_with_vec(vec![]), + relocations: vec![], + }); + } else if compact_unwind_section_indices.contains(§ion_index) { + let offset = compact_unwind_section_bytes.len() as u32; + for reloc in &mut custom_section.relocations { + reloc.offset += offset; + } + compact_unwind_section_bytes.extend_from_slice(custom_section.bytes.as_slice()); + compact_unwind_section_relocations.extend(custom_section.relocations); + // TODO: we do this to keep the count right, remove it. + final_module_custom_sections.push(CustomSection { + protection: CustomSectionProtection::Read, + alignment: None, + bytes: SectionBody::new_with_vec(vec![]), + relocations: vec![], + }); + } else if gcc_except_table_section_indices.contains(§ion_index) { + final_module_custom_sections.push(custom_section); + } else { + return Err(CompileError::Codegen( + "trampoline generation produced non-eh custom sections".into(), + )); + } + } + } + Ok(FunctionBody { body: compiled_function.body.body, unwind_info: compiled_function.body.unwind_info, @@ -380,7 +454,7 @@ impl FuncTrampoline { _ => { return Err(CompileError::Codegen( "trampoline function unimplemented".to_string(), - )) + )); } }; @@ -431,10 +505,8 @@ impl FuncTrampoline { let global_ptr_ptr = err!(builder.build_bit_cast(global_ptr_ptr, intrinsics.ptr_ty, "")) .into_pointer_value(); - let global_ptr = err!(builder.build_load(intrinsics.ptr_ty, global_ptr_ptr, "")) - .into_pointer_value(); - global_ptr + err!(builder.build_load(intrinsics.ptr_ty, global_ptr_ptr, "")).into_pointer_value() }; let global_ptr = err!(builder.build_bit_cast( @@ -483,11 +555,9 @@ impl FuncTrampoline { let memory_definition_ptr_ptr = err!(builder.build_bit_cast(memory_definition_ptr_ptr, intrinsics.ptr_ty, "",)) .into_pointer_value(); - let memory_definition_ptr = - err!(builder.build_load(intrinsics.ptr_ty, memory_definition_ptr_ptr, "")) - .into_pointer_value(); - memory_definition_ptr + err!(builder.build_load(intrinsics.ptr_ty, memory_definition_ptr_ptr, "")) + .into_pointer_value() }; let memory_definition_ptr = err!(builder.build_bit_cast(memory_definition_ptr, intrinsics.ptr_ty, "",)) @@ -503,10 +573,7 @@ impl FuncTrampoline { let base_ptr = if let MemoryStyle::Dynamic { .. } = memory_style { base_ptr } else { - let base_ptr = - err!(builder.build_load(intrinsics.ptr_ty, base_ptr, "")).into_pointer_value(); - - base_ptr + err!(builder.build_load(intrinsics.ptr_ty, base_ptr, "")).into_pointer_value() }; base_ptr.set_name("trmpl_m0_base_ptr"); @@ -609,12 +676,14 @@ impl FuncTrampoline { "" )) .into_pointer_value(); - err!(builder.build_store( - ptr, - trampoline_func - .get_nth_param(i as u32 + first_user_param) - .unwrap(), - )); + err!( + builder.build_store( + ptr, + trampoline_func + .get_nth_param(i as u32 + first_user_param) + .unwrap(), + ) + ); } let callee_ptr_ty = intrinsics.void_ty.fn_type( diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index 6991054b0c..99af165e35 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -2,12 +2,13 @@ use std::collections::HashMap; use super::{ intrinsics::{ - tbaa_label, type_to_llvm, CtxType, FunctionCache, GlobalCache, Intrinsics, MemoryCache, + CtxType, FunctionCache, GlobalCache, Intrinsics, MemoryCache, tbaa_label, type_to_llvm, }, // stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry, ValueSemantic}, state::{ControlFrame, ExtraInfo, IfElseState, State, TagCatchInfo}, }; use inkwell::{ + AddressSpace, AtomicOrdering, AtomicRMWBinOp, DLLStorageClass, FloatPredicate, IntPredicate, attributes::AttributeLoc, builder::Builder, context::Context, @@ -16,37 +17,37 @@ use inkwell::{ targets::{FileType, TargetMachine}, types::{BasicType, BasicTypeEnum, FloatMathType, IntType, PointerType, VectorType}, values::{ - AnyValue, BasicMetadataValueEnum, BasicValue, BasicValueEnum, CallSiteValue, FloatValue, + BasicMetadataValueEnum, BasicValue, BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, InstructionOpcode, InstructionValue, IntValue, PhiValue, PointerValue, VectorValue, }, - AddressSpace, AtomicOrdering, AtomicRMWBinOp, DLLStorageClass, FloatPredicate, IntPredicate, }; use itertools::Itertools; use smallvec::SmallVec; -use target_lexicon::BinaryFormat; +use target_lexicon::{BinaryFormat, OperatingSystem, Triple}; use crate::{ - abi::{get_abi, Abi, G0M0FunctionKind, LocalFunctionG0M0params}, - config::{CompiledKind, LLVM}, + abi::{Abi, G0M0FunctionKind, LocalFunctionG0M0params, get_abi}, + config::LLVM, error::{err, err_nt}, - object_file::{load_object_file, CompiledFunction}, + object_file::{CompiledFunction, load_object_file}, }; use wasmer_compiler::{ - from_binaryreadererror_wasmerror, + FunctionBinaryReader, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddlewareChain, + ModuleTranslationState, from_binaryreadererror_wasmerror, + misc::CompiledKind, types::{ relocation::RelocationTarget, symbols::{Symbol, SymbolRegistry}, }, wasmparser::{Catch, MemArg, Operator}, - wpheaptype_to_type, wptype_to_type, FunctionBinaryReader, FunctionBodyData, - MiddlewareBinaryReader, ModuleMiddlewareChain, ModuleTranslationState, + wpheaptype_to_type, wptype_to_type, }; -use wasmer_types::{entity::PrimaryMap, TagIndex}; use wasmer_types::{ CompileError, FunctionIndex, FunctionType, GlobalIndex, LocalFunctionIndex, MemoryIndex, ModuleInfo, SignatureIndex, TableIndex, Type, }; +use wasmer_types::{TagIndex, entity::PrimaryMap}; use wasmer_vm::{MemoryStyle, TableStyle, VMOffsets}; const FUNCTION_SECTION_ELF: &str = "__TEXT,wasmer_function"; @@ -84,7 +85,7 @@ impl FuncTranslator { _ => { return Err(CompileError::UnsupportedTarget(format!( "Unsupported binary format: {binary_fmt:?}" - ))) + ))); } }, binary_fmt, @@ -102,10 +103,12 @@ impl FuncTranslator { memory_styles: &PrimaryMap, _table_styles: &PrimaryMap, symbol_registry: &dyn SymbolRegistry, - ) -> Result { + target: &Triple, + ) -> Result, CompileError> { // The function type, used for the callbacks. - let function = CompiledKind::Local(*local_func_index); let func_index = wasm_module.func_index(*local_func_index); + let function = + CompiledKind::Local(*local_func_index, wasm_module.get_function_name(func_index)); let function_name = symbol_registry.symbol_to_name(Symbol::LocalFunction(*local_func_index)); @@ -148,7 +151,10 @@ impl FuncTranslator { func.add_attribute(*attr_loc, *attr); } - func.add_attribute(AttributeLoc::Function, intrinsics.stack_probe); + if !matches!(target.operating_system, OperatingSystem::Windows) { + func.add_attribute(AttributeLoc::Function, intrinsics.stack_probe); + } + func.add_attribute(AttributeLoc::Function, intrinsics.uwtable); func.add_attribute(AttributeLoc::Function, intrinsics.frame_pointer); @@ -161,7 +167,7 @@ impl FuncTranslator { return Err(CompileError::UnsupportedTarget(format!( "Unsupported binary format: {:?}", self.binary_fmt - ))) + ))); } }; @@ -209,11 +215,7 @@ impl FuncTranslator { let mut params = vec![]; let first_param = if func_type.get_return_type().is_none() && wasm_fn_type.results().len() > 1 { - if g0m0_is_enabled { - 4 - } else { - 2 - } + if g0m0_is_enabled { 4 } else { 2 } } else if g0m0_is_enabled { 3 } else { @@ -305,8 +307,6 @@ impl FuncTranslator { symbol_registry, abi: &*self.abi, config, - exception_types_cache: HashMap::new(), - vmctx_alloca: None, tags_cache: HashMap::new(), binary_fmt: self.binary_fmt, }; @@ -408,6 +408,7 @@ impl FuncTranslator { memory_styles: &PrimaryMap, table_styles: &PrimaryMap, symbol_registry: &dyn SymbolRegistry, + target: &Triple, ) -> Result { let module = self.translate_to_module( wasm_module, @@ -418,8 +419,12 @@ impl FuncTranslator { memory_styles, table_styles, symbol_registry, + target, )?; - let function = CompiledKind::Local(*local_func_index); + let function = CompiledKind::Local( + *local_func_index, + wasm_module.get_function_name(wasm_module.func_index(*local_func_index)), + ); let target_machine = &self.target_machine; let memory_buffer = target_machine .write_to_memory_buffer(&module, FileType::Object) @@ -473,20 +478,22 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ) -> Result, CompileError> { // Use insert_element to insert the element into an undef vector, then use // shuffle vector to copy that lane to all lanes. - err_nt!(self.builder.build_shuffle_vector( - err!(self.builder.build_insert_element( + err_nt!( + self.builder.build_shuffle_vector( + err!(self.builder.build_insert_element( + vec_ty.get_undef(), + value, + self.intrinsics.i32_zero, + "", + )), vec_ty.get_undef(), - value, - self.intrinsics.i32_zero, + self.intrinsics + .i32_ty + .vec_type(vec_ty.get_size()) + .const_zero(), "", - )), - vec_ty.get_undef(), - self.intrinsics - .i32_ty - .vec_type(vec_ty.get_size()) - .const_zero(), - "", - )) + ) + ) } // Convert floating point vector to integer and saturate when out of range. @@ -565,9 +572,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let lower_bound = self.splat_vector(lower_bound.as_basic_value_enum(), fvec_ty)?; let upper_bound = self.splat_vector(upper_bound.as_basic_value_enum(), fvec_ty)?; let nan_cmp = - err!(self - .builder - .build_float_compare(FloatPredicate::UNO, value, zero, "nan")); + err!( + self.builder + .build_float_compare(FloatPredicate::UNO, value, zero, "nan") + ); let above_upper_bound_cmp = err!(self.builder.build_float_compare( FloatPredicate::OGT, value, @@ -586,9 +594,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "not_representable_as_int", )); let value = - err!(self - .builder - .build_select(not_representable, zero, value, "safe_to_convert")) + err!( + self.builder + .build_select(not_representable, zero, value, "safe_to_convert") + ) .into_vector_value(); let value = if is_signed { self.builder @@ -600,14 +609,16 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let value = err!(value); let value = - err!(self - .builder - .build_select(above_upper_bound_cmp, int_max_value, value, "")) + err!( + self.builder + .build_select(above_upper_bound_cmp, int_max_value, value, "") + ) .into_vector_value(); - err_nt!(self - .builder - .build_select(below_lower_bound_cmp, int_min_value, value, "") - .map(|v| v.into_vector_value())) + err_nt!( + self.builder + .build_select(below_lower_bound_cmp, int_min_value, value, "") + .map(|v| v.into_vector_value()) + ) } // Convert floating point vector to integer and saturate when out of range. @@ -632,10 +643,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { int_max_value, value, )?; - err_nt!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "") - .map(|v| v.into_int_value())) + err_nt!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + .map(|v| v.into_int_value()) + ) } // Convert floating point vector to integer and saturate when out of range. @@ -698,9 +710,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let zero = value.get_type().const_zero(); let nan_cmp = - err!(self - .builder - .build_float_compare(FloatPredicate::UNO, value, zero, "nan")); + err!( + self.builder + .build_float_compare(FloatPredicate::UNO, value, zero, "nan") + ); let above_upper_bound_cmp = err!(self.builder.build_float_compare( FloatPredicate::OGT, value, @@ -719,34 +732,40 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "not_representable_as_int", )); let value = - err!(self - .builder - .build_select(not_representable, zero, value, "safe_to_convert")) + err!( + self.builder + .build_select(not_representable, zero, value, "safe_to_convert") + ) .into_float_value(); let value = if is_signed { - err!(self - .builder - .build_float_to_signed_int(value, int_ty, "as_int")) + err!( + self.builder + .build_float_to_signed_int(value, int_ty, "as_int") + ) } else { - err!(self - .builder - .build_float_to_unsigned_int(value, int_ty, "as_int")) + err!( + self.builder + .build_float_to_unsigned_int(value, int_ty, "as_int") + ) }; let value = - err!(self - .builder - .build_select(above_upper_bound_cmp, int_max_value, value, "")) + err!( + self.builder + .build_select(above_upper_bound_cmp, int_max_value, value, "") + ) .into_int_value(); let value = - err!(self - .builder - .build_select(below_lower_bound_cmp, int_min_value, value, "")) + err!( + self.builder + .build_select(below_lower_bound_cmp, int_min_value, value, "") + ) .into_int_value(); - err_nt!(self - .builder - .build_bit_cast(value, int_ty, "") - .map(|v| v.into_int_value())) + err_nt!( + self.builder + .build_bit_cast(value, int_ty, "") + .map(|v| v.into_int_value()) + ) } fn trap_if_not_representable_as_int( @@ -762,16 +781,18 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { self.intrinsics.i64_ty }; - let lower_bound = - err!(self - .builder - .build_bit_cast(int_ty.const_int(lower_bound, false), float_ty, "")) - .into_float_value(); - let upper_bound = - err!(self - .builder - .build_bit_cast(int_ty.const_int(upper_bound, false), float_ty, "")) - .into_float_value(); + let lower_bound = err!(self.builder.build_bit_cast( + int_ty.const_int(lower_bound, false), + float_ty, + "" + )) + .into_float_value(); + let upper_bound = err!(self.builder.build_bit_cast( + int_ty.const_int(upper_bound, false), + float_ty, + "" + )) + .into_float_value(); // The 'U' in the float predicate is short for "unordered" which means that // the comparison will compare true if either operand is a NaN. Thus, NaNs @@ -801,23 +822,26 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { .context .append_basic_block(self.function, "conversion_success_block"); - err!(self - .builder - .build_conditional_branch(out_of_bounds, failure_block, continue_block)); + err!( + self.builder + .build_conditional_branch(out_of_bounds, failure_block, continue_block) + ); self.builder.position_at_end(failure_block); let is_nan = - err!(self - .builder - .build_float_compare(FloatPredicate::UNO, value, value, "is_nan")); + err!( + self.builder + .build_float_compare(FloatPredicate::UNO, value, value, "is_nan") + ); let trap_code = err!(self.builder.build_select( is_nan, self.intrinsics.trap_bad_conversion_to_integer, self.intrinsics.trap_illegal_arithmetic, "", )); - err!(self - .builder - .build_call(self.intrinsics.throw_trap, &[trap_code.into()], "throw")); + err!( + self.builder + .build_call(self.intrinsics.throw_trap, &[trap_code.into()], "throw") + ); err!(self.builder.build_unreachable()); self.builder.position_at_end(continue_block); @@ -878,8 +902,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "should_trap_expect", )) .try_as_basic_value() - .left() - .unwrap() + .unwrap_basic() .into_int_value(); let shouldnt_trap_block = self @@ -900,9 +923,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { self.intrinsics.trap_illegal_arithmetic, "", )); - err!(self - .builder - .build_call(self.intrinsics.throw_trap, &[trap_code.into()], "throw")); + err!( + self.builder + .build_call(self.intrinsics.throw_trap, &[trap_code.into()], "throw") + ); err!(self.builder.build_unreachable()); self.builder.position_at_end(shouldnt_trap_block); @@ -927,8 +951,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "should_trap_expect", )) .try_as_basic_value() - .left() - .unwrap() + .unwrap_basic() .into_int_value(); let shouldnt_trap_block = self @@ -960,16 +983,22 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { info: ExtraInfo, int_vec_ty: VectorType<'ctx>, ) -> Result<(VectorValue<'ctx>, ExtraInfo), CompileError> { - let (value, info) = if info.has_pending_f32_nan() { - let value = err!(self - .builder - .build_bit_cast(value, self.intrinsics.f32x4_ty, "")); - (self.canonicalize_nans(value)?, info.strip_pending()) - } else if info.has_pending_f64_nan() { - let value = err!(self - .builder - .build_bit_cast(value, self.intrinsics.f64x2_ty, "")); - (self.canonicalize_nans(value)?, info.strip_pending()) + let (value, info) = if self.config.enable_nan_canonicalization { + if info.has_pending_f32_nan() { + let value = err!( + self.builder + .build_bit_cast(value, self.intrinsics.f32x4_ty, "") + ); + (self.canonicalize_nans(value)?, info.strip_pending()) + } else if info.has_pending_f64_nan() { + let value = err!( + self.builder + .build_bit_cast(value, self.intrinsics.f64x2_ty, "") + ); + (self.canonicalize_nans(value)?, info.strip_pending()) + } else { + (value, info) + } } else { (value, info) }; @@ -1018,18 +1047,21 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { value: BasicValueEnum<'ctx>, info: ExtraInfo, ) -> Result<(VectorValue<'ctx>, ExtraInfo), CompileError> { - let (value, info) = if info.has_pending_f64_nan() { - let value = err!(self - .builder - .build_bit_cast(value, self.intrinsics.f64x2_ty, "")); + let (value, info) = if self.config.enable_nan_canonicalization && info.has_pending_f64_nan() + { + let value = err!( + self.builder + .build_bit_cast(value, self.intrinsics.f64x2_ty, "") + ); (self.canonicalize_nans(value)?, info.strip_pending()) } else { (value, info) }; Ok(( - err!(self - .builder - .build_bit_cast(value, self.intrinsics.f32x4_ty, "")) + err!( + self.builder + .build_bit_cast(value, self.intrinsics.f32x4_ty, "") + ) .into_vector_value(), info, )) @@ -1042,18 +1074,21 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { value: BasicValueEnum<'ctx>, info: ExtraInfo, ) -> Result<(VectorValue<'ctx>, ExtraInfo), CompileError> { - let (value, info) = if info.has_pending_f32_nan() { - let value = err!(self - .builder - .build_bit_cast(value, self.intrinsics.f32x4_ty, "")); + let (value, info) = if self.config.enable_nan_canonicalization && info.has_pending_f32_nan() + { + let value = err!( + self.builder + .build_bit_cast(value, self.intrinsics.f32x4_ty, "") + ); (self.canonicalize_nans(value)?, info.strip_pending()) } else { (value, info) }; Ok(( - err!(self - .builder - .build_bit_cast(value, self.intrinsics.f64x2_ty, "")) + err!( + self.builder + .build_bit_cast(value, self.intrinsics.f64x2_ty, "") + ) .into_vector_value(), info, )) @@ -1073,9 +1108,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { || value.get_type() == self.intrinsics.i128_ty.as_basic_type_enum() { let ty = value.get_type(); - let value = err!(self - .builder - .build_bit_cast(value, self.intrinsics.f32x4_ty, "")); + let value = err!( + self.builder + .build_bit_cast(value, self.intrinsics.f32x4_ty, "") + ); let value = self.canonicalize_nans(value)?; err_nt!(self.builder.build_bit_cast(value, ty, "")) } else { @@ -1086,9 +1122,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { || value.get_type() == self.intrinsics.i128_ty.as_basic_type_enum() { let ty = value.get_type(); - let value = err!(self - .builder - .build_bit_cast(value, self.intrinsics.f64x2_ty, "")); + let value = err!( + self.builder + .build_bit_cast(value, self.intrinsics.f64x2_ty, "") + ); let value = self.canonicalize_nans(value)?; err_nt!(self.builder.build_bit_cast(value, ty, "")) } else { @@ -1114,74 +1151,35 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let f_ty = f_ty.into_vector_type(); let zero = f_ty.const_zero(); let nan_cmp = - err!(self - .builder - .build_float_compare(FloatPredicate::UNO, value, zero, "nan")); + err!( + self.builder + .build_float_compare(FloatPredicate::UNO, value, zero, "nan") + ); let canonical_qnan = f_ty .get_element_type() .into_float_type() .const_float(f64::NAN); let canonical_qnan = self.splat_vector(canonical_qnan.as_basic_value_enum(), f_ty)?; - err_nt!(self - .builder - .build_select(nan_cmp, canonical_qnan, value, "") - .map(|v| v.as_basic_value_enum())) + err_nt!( + self.builder + .build_select(nan_cmp, canonical_qnan, value, "") + .map(|v| v.as_basic_value_enum()) + ) } else { let value = value.into_float_value(); let f_ty = f_ty.into_float_type(); let zero = f_ty.const_zero(); let nan_cmp = - err!(self - .builder - .build_float_compare(FloatPredicate::UNO, value, zero, "nan")); + err!( + self.builder + .build_float_compare(FloatPredicate::UNO, value, zero, "nan") + ); let canonical_qnan = f_ty.const_float(f64::NAN); - err_nt!(self - .builder - .build_select(nan_cmp, canonical_qnan, value, "") - .map(|v| v.as_basic_value_enum())) - } - } - - fn quiet_nan(&self, value: BasicValueEnum<'ctx>) -> Result, CompileError> { - let intrinsic = if value - .get_type() - .eq(&self.intrinsics.f32_ty.as_basic_type_enum()) - { - Some(self.intrinsics.add_f32) - } else if value - .get_type() - .eq(&self.intrinsics.f64_ty.as_basic_type_enum()) - { - Some(self.intrinsics.add_f64) - } else if value - .get_type() - .eq(&self.intrinsics.f32x4_ty.as_basic_type_enum()) - { - Some(self.intrinsics.add_f32x4) - } else if value - .get_type() - .eq(&self.intrinsics.f64x2_ty.as_basic_type_enum()) - { - Some(self.intrinsics.add_f64x2) - } else { - None - }; - - match intrinsic { - Some(intrinsic) => err_nt!(self - .builder - .build_call( - intrinsic, - &[ - value.into(), - value.get_type().const_zero().into(), - self.intrinsics.fp_rounding_md, - self.intrinsics.fp_exception_md, - ], - "", - ) - .map(|v| v.try_as_basic_value().left().unwrap())), - None => Ok(value), + err_nt!( + self.builder + .build_select(nan_cmp, canonical_qnan, value, "") + .map(|v| v.as_basic_value_enum()) + ) } } @@ -1265,13 +1263,12 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let ptr_in_bounds = if offset.is_const() { // When the offset is constant, if it's below the minimum // memory size, we've statically shown that it's safe. - let load_offset_end = offset.const_add(value_size_v); - let ptr_in_bounds = load_offset_end.const_int_compare( - IntPredicate::ULE, - intrinsics.i64_ty.const_int(minimum.bytes().0 as u64, false), - ); - if ptr_in_bounds.get_zero_extended_constant() == Some(1) { - Some(ptr_in_bounds) + let load_offset_end = + offset.const_add(value_size_v).get_zero_extended_constant(); + if load_offset_end.is_some_and(|load_offset_end| { + load_offset_end <= minimum.bytes().0 as u64 + }) { + Some(intrinsics.i64_ty.const_int(1, false)) } else { None } @@ -1332,8 +1329,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "ptr_in_bounds_expect", )) .try_as_basic_value() - .left() - .unwrap() + .unwrap_basic() .into_int_value(); let in_bounds_continue_block = @@ -1371,9 +1367,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let value_ptr = unsafe { err!(builder.build_gep(self.intrinsics.i8_ty, base_ptr, &[offset], "mem_value_ptr")) }; - err_nt!(builder - .build_bit_cast(value_ptr, ptr_ty, "mem_value") - .map(|v| v.into_pointer_value())) + err_nt!( + builder + .build_bit_cast(value_ptr, ptr_ty, "mem_value") + .map(|v| v.into_pointer_value()) + ) } fn trap_if_misaligned( @@ -1385,10 +1383,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { if align <= 1 { return Ok(()); } - let value = - err!(self - .builder - .build_ptr_to_int(ptr, self.intrinsics.i64_ty, "mischeck_value")); + let value = err!(self.builder.build_ptr_to_int( + ptr, + self.intrinsics.i64_ty, + "mischeck_value" + )); let and = err!(self.builder.build_and( value, self.intrinsics.i64_ty.const_int((align - 1).into(), false), @@ -1409,8 +1408,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "is_aligned_expect", )) .try_as_basic_value() - .left() - .unwrap() + .unwrap_basic() .into_int_value(); let continue_block = self @@ -1419,9 +1417,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let not_aligned_block = self .context .append_basic_block(self.function, "misaligned_trap_block"); - err!(self - .builder - .build_conditional_branch(aligned, continue_block, not_aligned_block)); + err!( + self.builder + .build_conditional_branch(aligned, continue_block, not_aligned_block) + ); self.builder.position_at_end(not_aligned_block); err!(self.builder.build_call( @@ -1439,10 +1438,12 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let func_type = self.function.get_type(); let results = self.state.popn_save_extra(wasm_fn_type.results().len())?; - let results = err!(results - .into_iter() - .map(|(v, i)| self.apply_pending_canonicalization(v, i)) - .collect::, _>>()); + let results = err!( + results + .into_iter() + .map(|(v, i)| self.apply_pending_canonicalization(v, i)) + .collect::, _>>() + ); if wasm_fn_type.results().is_empty() { err!(self.builder.build_return(None)); @@ -1468,22 +1469,24 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )); struct_value = - err!(self - .builder - .build_insert_value(struct_value, value, idx as u32, "")) + err!( + self.builder + .build_insert_value(struct_value, value, idx as u32, "") + ) .into_struct_value(); } err!(self.builder.build_store(sret, struct_value)); err!(self.builder.build_return(None)); } else { - err!(self - .builder - .build_return(Some(&self.abi.pack_values_for_register_return( - self.intrinsics, - &self.builder, - &results, - &func_type, - )?))); + err!( + self.builder + .build_return(Some(&self.abi.pack_values_for_register_return( + self.intrinsics, + &self.builder, + &results, + &func_type, + )?)) + ); } Ok(()) } @@ -1528,25 +1531,6 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { tag_glbl } - fn get_or_insert_exception_type( - &mut self, - tag: u32, - signature: &FunctionType, - ) -> Result, CompileError> { - if let Some(ty) = self.exception_types_cache.get(&tag) { - return Ok(*ty); - } - let types = signature - .params() - .iter() - .map(|v| type_to_llvm(self.intrinsics, *v)) - .collect::, CompileError>>()?; - - let ty = self.context.struct_type(&types, false); - self.exception_types_cache.insert(tag, ty); - Ok(ty) - } - fn build_g0m0_indirect_call( &mut self, table_index: u32, @@ -1598,21 +1582,23 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let cont = self.context.append_basic_block(self.function, "cont"); - err!(self.builder.build_switch( - func_index, - unreachable_indirect_call_branch_block, - &local_func_indices - .into_iter() - .map(|v| ( - self.intrinsics.i32_ty.const_int(v as _, false), - local_idx_block - )) - .chain(foreign_func_indices.into_iter().map(|v| ( - self.intrinsics.i32_ty.const_int(v as _, false), - foreign_idx_block - ))) - .collect::>() - )); + err!( + self.builder.build_switch( + func_index, + unreachable_indirect_call_branch_block, + &local_func_indices + .into_iter() + .map(|v| ( + self.intrinsics.i32_ty.const_int(v as _, false), + local_idx_block + )) + .chain(foreign_func_indices.into_iter().map(|v| ( + self.intrinsics.i32_ty.const_int(v as _, false), + foreign_idx_block + ))) + .collect::>() + ) + ); self.builder .position_at_end(unreachable_indirect_call_branch_block); @@ -1784,17 +1770,19 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { self.builder.position_at_end(then_block); ret } else { - err!(self.builder.build_indirect_call( - llvm_func_type, - typed_func_ptr, - params - .iter() - .copied() - .map(Into::into) - .collect::>() - .as_slice(), - "indirect_call", - )) + err!( + self.builder.build_indirect_call( + llvm_func_type, + typed_func_ptr, + params + .iter() + .copied() + .map(Into::into) + .collect::>() + .as_slice(), + "indirect_call", + ) + ) }; for (attr, attr_loc) in llvm_func_attrs { call_site_local.add_attribute(attr_loc, attr); @@ -1802,21 +1790,6 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { Ok(call_site_local) } - - fn build_or_get_vmctx_alloca(&mut self) -> Result, CompileError> { - if let Some(vmctx_alloca) = self.vmctx_alloca { - return Ok(vmctx_alloca); - } - - let vmctx_alloca = err!(self - .alloca_builder - .build_alloca(self.intrinsics.ptr_ty, "vmctx")); - err!(self - .alloca_builder - .build_store(vmctx_alloca, self.ctx.basic())); - self.vmctx_alloca = Some(vmctx_alloca); - Ok(vmctx_alloca) - } } /* @@ -1932,12 +1905,131 @@ pub struct LLVMFunctionCodeGenerator<'ctx, 'a> { abi: &'a dyn Abi, config: &'a LLVM, tags_cache: HashMap>, - exception_types_cache: HashMap>, - vmctx_alloca: Option>, binary_fmt: target_lexicon::BinaryFormat, } impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { + fn quiet_nan(&self, value: BasicValueEnum<'ctx>) -> Result, CompileError> { + let intrinsic = if value + .get_type() + .eq(&self.intrinsics.f32_ty.as_basic_type_enum()) + { + Some(self.intrinsics.add_f32) + } else if value + .get_type() + .eq(&self.intrinsics.f64_ty.as_basic_type_enum()) + { + Some(self.intrinsics.add_f64) + } else if value + .get_type() + .eq(&self.intrinsics.f32x4_ty.as_basic_type_enum()) + { + Some(self.intrinsics.add_f32x4) + } else if value + .get_type() + .eq(&self.intrinsics.f64x2_ty.as_basic_type_enum()) + { + Some(self.intrinsics.add_f64x2) + } else { + None + }; + + match intrinsic { + Some(intrinsic) => err_nt!( + self.builder + .build_call( + intrinsic, + &[ + value.into(), + value.get_type().const_zero().into(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .map(|v| v.try_as_basic_value().unwrap_basic()) + ), + None => Ok(value), + } + } + + fn finalize_minmax_result( + &self, + value: BasicValueEnum<'ctx>, + ) -> Result, CompileError> { + let ty = value.get_type(); + if ty.eq(&self.intrinsics.f32_ty.as_basic_type_enum()) + || ty.eq(&self.intrinsics.f64_ty.as_basic_type_enum()) + { + let value = value.into_float_value(); + let is_nan = err!(self.builder.build_float_compare( + FloatPredicate::UNO, + value, + value, + "res_is_nan" + )); + let quiet = self.quiet_nan(value.as_basic_value_enum())?; + let result = + err!( + self.builder + .build_select(is_nan, quiet, value.as_basic_value_enum(), "") + ); + Ok(result.as_basic_value_enum()) + } else if ty.eq(&self.intrinsics.f32x4_ty.as_basic_type_enum()) { + let value = value.into_vector_value(); + let is_nan = err!(self.builder.build_call( + self.intrinsics.cmp_f32x4, + &[ + value.into(), + value.into(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + )) + .try_as_basic_value() + .unwrap_basic() + .into_vector_value(); + let quiet = self + .quiet_nan(value.as_basic_value_enum())? + .into_vector_value(); + let result = err!(self.builder.build_select( + is_nan, + quiet.as_basic_value_enum(), + value.as_basic_value_enum(), + "", + )); + Ok(result.as_basic_value_enum()) + } else if ty.eq(&self.intrinsics.f64x2_ty.as_basic_type_enum()) { + let value = value.into_vector_value(); + let is_nan = err!(self.builder.build_call( + self.intrinsics.cmp_f64x2, + &[ + value.into(), + value.into(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + )) + .try_as_basic_value() + .unwrap_basic() + .into_vector_value(); + let quiet = self + .quiet_nan(value.as_basic_value_enum())? + .into_vector_value(); + let result = err!(self.builder.build_select( + is_nan, + quiet.as_basic_value_enum(), + value.as_basic_value_enum(), + "", + )); + Ok(result.as_basic_value_enum()) + } else { + Ok(value) + } + } + fn translate_operator(&mut self, op: Operator, _source_loc: u32) -> Result<(), CompileError> { // TODO: remove this vmctx by moving everything into CtxType. Values // computed off vmctx usually benefit from caching. @@ -2427,9 +2519,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { } else { Default::default() }; - let f = err!(self - .builder - .build_bit_cast(bits, self.intrinsics.f32_ty, "f")); + let f = err!( + self.builder + .build_bit_cast(bits, self.intrinsics.f32_ty, "f") + ); self.state.push1_extra(f, info); } Operator::F64Const { value } => { @@ -2439,9 +2532,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { } else { Default::default() }; - let f = err!(self - .builder - .build_bit_cast(bits, self.intrinsics.f64_ty, "f")); + let f = err!( + self.builder + .build_bit_cast(bits, self.intrinsics.f64_ty, "f") + ); self.state.push1_extra(f, info); } Operator::V128Const { value } => { @@ -2479,49 +2573,56 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { Operator::I8x16Splat => { let (v, i) = self.state.pop1_extra()?; let v = v.into_int_value(); - let v = err!(self - .builder - .build_int_truncate(v, self.intrinsics.i8_ty, "")); + let v = err!( + self.builder + .build_int_truncate(v, self.intrinsics.i8_ty, "") + ); let res = self.splat_vector(v.as_basic_value_enum(), self.intrinsics.i8x16_ty)?; - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra(res, i); } Operator::I16x8Splat => { let (v, i) = self.state.pop1_extra()?; let v = v.into_int_value(); - let v = err!(self - .builder - .build_int_truncate(v, self.intrinsics.i16_ty, "")); + let v = err!( + self.builder + .build_int_truncate(v, self.intrinsics.i16_ty, "") + ); let res = self.splat_vector(v.as_basic_value_enum(), self.intrinsics.i16x8_ty)?; - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra(res, i); } Operator::I32x4Splat => { let (v, i) = self.state.pop1_extra()?; let res = self.splat_vector(v, self.intrinsics.i32x4_ty)?; - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra(res, i); } Operator::I64x2Splat => { let (v, i) = self.state.pop1_extra()?; let res = self.splat_vector(v, self.intrinsics.i64x2_ty)?; - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra(res, i); } Operator::F32x4Splat => { let (v, i) = self.state.pop1_extra()?; let res = self.splat_vector(v, self.intrinsics.f32x4_ty)?; - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); // The spec is unclear, we interpret splat as preserving NaN // payload bits. self.state.push1_extra(res, i); @@ -2529,9 +2630,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { Operator::F64x2Splat => { let (v, i) = self.state.pop1_extra()?; let res = self.splat_vector(v, self.intrinsics.f64x2_ty)?; - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); // The spec is unclear, we interpret splat as preserving NaN // payload bits. self.state.push1_extra(res, i); @@ -2634,7 +2736,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { return Err(CompileError::Codegen(format!( "global.set on immutable global index {}", global_index.as_u32() - ))) + ))); } GlobalCache::Mut { ptr_to_value, .. } => { let ptr_to_value = *ptr_to_value; @@ -2809,17 +2911,19 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { self.builder.position_at_end(then_block); ret } else { - err!(self.builder.build_indirect_call( - llvm_func_type, - func, - params - .iter() - .copied() - .map(Into::into) - .collect::>() - .as_slice(), - "", - )) + err!( + self.builder.build_indirect_call( + llvm_func_type, + func, + params + .iter() + .copied() + .map(Into::into) + .collect::>() + .as_slice(), + "", + ) + ) }; for (attr, attr_loc) in attrs { call_site.add_attribute(attr_loc, attr); @@ -2885,8 +2989,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "index_in_bounds_expect", )) .try_as_basic_value() - .left() - .unwrap() + .unwrap_basic() .into_int_value(); let in_bounds_continue_block = self @@ -2936,9 +3039,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { // trap if we're trying to call a null funcref { - let funcref_not_null = err!(self - .builder - .build_is_not_null(anyfunc_struct_ptr, "null funcref check")); + let funcref_not_null = err!( + self.builder + .build_is_not_null(anyfunc_struct_ptr, "null funcref check") + ); let funcref_continue_deref_block = self .context @@ -2991,17 +3095,20 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ) .unwrap(); let (func_ptr, found_dynamic_sigindex, ctx_ptr) = ( - err!(self - .builder - .build_load(self.intrinsics.ptr_ty, func_ptr_ptr, "func_ptr")) + err!( + self.builder + .build_load(self.intrinsics.ptr_ty, func_ptr_ptr, "func_ptr") + ) .into_pointer_value(), - err!(self - .builder - .build_load(self.intrinsics.i32_ty, sigindex_ptr, "sigindex")) + err!( + self.builder + .build_load(self.intrinsics.i32_ty, sigindex_ptr, "sigindex") + ) .into_int_value(), - err!(self - .builder - .build_load(self.intrinsics.ptr_ty, ctx_ptr_ptr, "ctx_ptr")), + err!( + self.builder + .build_load(self.intrinsics.ptr_ty, ctx_ptr_ptr, "ctx_ptr") + ), ); // Next, check if the table element is initialized. @@ -3018,10 +3125,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "sigindices_equal", )); - let initialized_and_sigindices_match = - err!(self - .builder - .build_and(elem_initialized, sigindices_equal, "")); + let initialized_and_sigindices_match = err!(self.builder.build_and( + elem_initialized, + sigindices_equal, + "" + )); // Tell llvm that `expected_dynamic_sigindex` should equal `found_dynamic_sigindex`. let initialized_and_sigindices_match = err!(self.builder.build_call( @@ -3033,8 +3141,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "initialized_and_sigindices_match_expect", )) .try_as_basic_value() - .left() - .unwrap() + .unwrap_basic() .into_int_value(); let continue_block = self @@ -3105,9 +3212,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; let res = err!(self.builder.build_int_add(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8Add => { @@ -3115,9 +3223,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; let res = err!(self.builder.build_int_add(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8ExtAddPairwiseI8x16S | Operator::I16x8ExtAddPairwiseI8x16U => { @@ -3167,9 +3276,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let right = err!(extend_op(self, right)); let res = err!(self.builder.build_int_add(left, right, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4Add => { @@ -3177,9 +3287,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; let res = err!(self.builder.build_int_add(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4ExtAddPairwiseI16x8S | Operator::I32x4ExtAddPairwiseI16x8U => { @@ -3221,9 +3332,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let right = err!(extend_op(self, right)); let res = err!(self.builder.build_int_add(left, right, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2Add => { @@ -3231,9 +3343,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i64x2(v1, i1)?; let (v2, _) = self.v128_into_i64x2(v2, i2)?; let res = err!(self.builder.build_int_add(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I8x16AddSatS => { @@ -3246,11 +3359,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "" )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8AddSatS => { @@ -3263,11 +3376,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "" )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I8x16AddSatU => { @@ -3280,11 +3393,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "" )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8AddSatU => { @@ -3297,11 +3410,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "" )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32Sub | Operator::I64Sub => { @@ -3317,9 +3430,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; let res = err!(self.builder.build_int_sub(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8Sub => { @@ -3327,9 +3441,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; let res = err!(self.builder.build_int_sub(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4Sub => { @@ -3337,9 +3452,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; let res = err!(self.builder.build_int_sub(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2Sub => { @@ -3347,9 +3463,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i64x2(v1, i1)?; let (v2, _) = self.v128_into_i64x2(v2, i2)?; let res = err!(self.builder.build_int_sub(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I8x16SubSatS => { @@ -3362,11 +3479,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "" )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8SubSatS => { @@ -3379,11 +3496,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "" )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I8x16SubSatU => { @@ -3396,11 +3513,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "" )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8SubSatU => { @@ -3413,11 +3530,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "" )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32Mul | Operator::I64Mul => { @@ -3433,9 +3550,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; let res = err!(self.builder.build_int_mul(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4Mul => { @@ -3443,9 +3561,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; let res = err!(self.builder.build_int_mul(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2Mul => { @@ -3453,9 +3572,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i64x2(v1, i1)?; let (v2, _) = self.v128_into_i64x2(v2, i2)?; let res = err!(self.builder.build_int_mul(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8Q15MulrSatS => { @@ -3466,12 +3586,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let max_value = self.intrinsics.i16_ty.const_int(i16::MAX as u64, false); let max_values = VectorType::const_vector(&[max_value; 8]); - let v1 = err!(self - .builder - .build_int_s_extend(v1, self.intrinsics.i32x8_ty, "")); - let v2 = err!(self - .builder - .build_int_s_extend(v2, self.intrinsics.i32x8_ty, "")); + let v1 = err!( + self.builder + .build_int_s_extend(v1, self.intrinsics.i32x8_ty, "") + ); + let v2 = err!( + self.builder + .build_int_s_extend(v2, self.intrinsics.i32x8_ty, "") + ); let res = err!(self.builder.build_int_mul(v1, v2, "")); // magic number specified by the spec @@ -3490,20 +3612,23 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { self.intrinsics.i32x8_ty, "" )); - err!(self - .builder - .build_int_compare(IntPredicate::SGT, res, max_values, "")) + err!( + self.builder + .build_int_compare(IntPredicate::SGT, res, max_values, "") + ) }; - let res = err!(self - .builder - .build_int_truncate(res, self.intrinsics.i16x8_ty, "")); + let res = err!( + self.builder + .build_int_truncate(res, self.intrinsics.i16x8_ty, "") + ); let res = err!(self.builder.build_select(saturate_up, max_values, res, "")) .into_vector_value(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8ExtMulLowI8x16S @@ -3564,9 +3689,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { )); let val2 = err!(extend_op(self, val2)); let res = err!(self.builder.build_int_mul(val1, val2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4ExtMulLowI16x8S @@ -3615,9 +3741,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { )); let val2 = err!(extend_op(self, val2)); let res = err!(self.builder.build_int_mul(val1, val2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2ExtMulLowI32x4S @@ -3660,9 +3787,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { )); let val2 = err!(extend_op(self, val2)); let res = err!(self.builder.build_int_mul(val1, val2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4DotI16x8S => { @@ -3687,47 +3815,52 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { VectorType::const_vector(&low_i16), "", )); - let v1_low = - err!(self - .builder - .build_int_s_extend(v1_low, self.intrinsics.i32x4_ty, "")); + let v1_low = err!(self.builder.build_int_s_extend( + v1_low, + self.intrinsics.i32x4_ty, + "" + )); let v1_high = err!(self.builder.build_shuffle_vector( v1, v1.get_type().get_undef(), VectorType::const_vector(&high_i16), "", )); - let v1_high = - err!(self - .builder - .build_int_s_extend(v1_high, self.intrinsics.i32x4_ty, "")); + let v1_high = err!(self.builder.build_int_s_extend( + v1_high, + self.intrinsics.i32x4_ty, + "" + )); let v2_low = err!(self.builder.build_shuffle_vector( v2, v2.get_type().get_undef(), VectorType::const_vector(&low_i16), "", )); - let v2_low = - err!(self - .builder - .build_int_s_extend(v2_low, self.intrinsics.i32x4_ty, "")); + let v2_low = err!(self.builder.build_int_s_extend( + v2_low, + self.intrinsics.i32x4_ty, + "" + )); let v2_high = err!(self.builder.build_shuffle_vector( v2, v2.get_type().get_undef(), VectorType::const_vector(&high_i16), "", )); - let v2_high = - err!(self - .builder - .build_int_s_extend(v2_high, self.intrinsics.i32x4_ty, "")); + let v2_high = err!(self.builder.build_int_s_extend( + v2_high, + self.intrinsics.i32x4_ty, + "" + )); let low_product = err!(self.builder.build_int_mul(v1_low, v2_low, "")); let high_product = err!(self.builder.build_int_mul(v1_high, v2_high, "")); let res = err!(self.builder.build_int_add(low_product, high_product, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32DivS | Operator::I64DivS => { @@ -3799,9 +3932,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "srem_will_overflow", )); let v1 = - err!(self - .builder - .build_select(will_overflow, int_type.const_zero(), v1, "")) + err!( + self.builder + .build_select(will_overflow, int_type.const_zero(), v1, "") + ) .into_int_value(); let res = err!(self.builder.build_int_signed_rem(v1, v2, "")); self.state.push1(res); @@ -3855,22 +3989,26 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let v1 = self.apply_pending_canonicalization(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let cond = self.apply_pending_canonicalization(cond, cond_info)?; - let v1 = err!(self - .builder - .build_bit_cast(v1, self.intrinsics.i1x128_ty, "")) + let v1 = err!( + self.builder + .build_bit_cast(v1, self.intrinsics.i1x128_ty, "") + ) .into_vector_value(); - let v2 = err!(self - .builder - .build_bit_cast(v2, self.intrinsics.i1x128_ty, "")) + let v2 = err!( + self.builder + .build_bit_cast(v2, self.intrinsics.i1x128_ty, "") + ) .into_vector_value(); - let cond = err!(self - .builder - .build_bit_cast(cond, self.intrinsics.i1x128_ty, "")) + let cond = err!( + self.builder + .build_bit_cast(cond, self.intrinsics.i1x128_ty, "") + ) .into_vector_value(); let res = err!(self.builder.build_select(cond, v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I8x16Bitmask => { @@ -3878,14 +4016,16 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v, _) = self.v128_into_i8x16(v, i)?; let zeros = self.intrinsics.i8x16_ty.const_zero(); - let res = err!(self - .builder - .build_int_compare(IntPredicate::SLT, v, zeros, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SLT, v, zeros, "") + ); let res = err!(self.builder.build_bit_cast(res, self.intrinsics.i16_ty, "")) .into_int_value(); - let res = err!(self - .builder - .build_int_z_extend(res, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(res, self.intrinsics.i32_ty, "") + ); self.state.push1(res); } Operator::I16x8Bitmask => { @@ -3893,14 +4033,16 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v, _) = self.v128_into_i16x8(v, i)?; let zeros = self.intrinsics.i16x8_ty.const_zero(); - let res = err!(self - .builder - .build_int_compare(IntPredicate::SLT, v, zeros, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SLT, v, zeros, "") + ); let res = err!(self.builder.build_bit_cast(res, self.intrinsics.i8_ty, "")) .into_int_value(); - let res = err!(self - .builder - .build_int_z_extend(res, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(res, self.intrinsics.i32_ty, "") + ); self.state.push1(res); } Operator::I32x4Bitmask => { @@ -3908,14 +4050,16 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v, _) = self.v128_into_i32x4(v, i)?; let zeros = self.intrinsics.i32x4_ty.const_zero(); - let res = err!(self - .builder - .build_int_compare(IntPredicate::SLT, v, zeros, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SLT, v, zeros, "") + ); let res = err!(self.builder.build_bit_cast(res, self.intrinsics.i4_ty, "")) .into_int_value(); - let res = err!(self - .builder - .build_int_z_extend(res, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(res, self.intrinsics.i32_ty, "") + ); self.state.push1(res); } Operator::I64x2Bitmask => { @@ -3923,14 +4067,16 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v, _) = self.v128_into_i64x2(v, i)?; let zeros = self.intrinsics.i64x2_ty.const_zero(); - let res = err!(self - .builder - .build_int_compare(IntPredicate::SLT, v, zeros, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SLT, v, zeros, "") + ); let res = err!(self.builder.build_bit_cast(res, self.intrinsics.i2_ty, "")) .into_int_value(); - let res = err!(self - .builder - .build_int_z_extend(res, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(res, self.intrinsics.i32_ty, "") + ); self.state.push1(res); } Operator::I32Shl => { @@ -3958,17 +4104,20 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i8x16(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let v2 = v2.into_int_value(); - let v2 = err!(self - .builder - .build_and(v2, self.intrinsics.i32_consts[7], "")); - let v2 = err!(self - .builder - .build_int_truncate(v2, self.intrinsics.i8_ty, "")); + let v2 = err!( + self.builder + .build_and(v2, self.intrinsics.i32_consts[7], "") + ); + let v2 = err!( + self.builder + .build_int_truncate(v2, self.intrinsics.i8_ty, "") + ); let v2 = self.splat_vector(v2.as_basic_value_enum(), self.intrinsics.i8x16_ty)?; let res = err!(self.builder.build_left_shift(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8Shl => { @@ -3976,17 +4125,20 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i16x8(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let v2 = v2.into_int_value(); - let v2 = err!(self - .builder - .build_and(v2, self.intrinsics.i32_consts[15], "")); - let v2 = err!(self - .builder - .build_int_truncate(v2, self.intrinsics.i16_ty, "")); + let v2 = err!( + self.builder + .build_and(v2, self.intrinsics.i32_consts[15], "") + ); + let v2 = err!( + self.builder + .build_int_truncate(v2, self.intrinsics.i16_ty, "") + ); let v2 = self.splat_vector(v2.as_basic_value_enum(), self.intrinsics.i16x8_ty)?; let res = err!(self.builder.build_left_shift(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4Shl => { @@ -4001,9 +4153,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { )); let v2 = self.splat_vector(v2.as_basic_value_enum(), self.intrinsics.i32x4_ty)?; let res = err!(self.builder.build_left_shift(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2Shl => { @@ -4016,14 +4169,16 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { self.intrinsics.i32_ty.const_int(63, false), "" )); - let v2 = err!(self - .builder - .build_int_z_extend(v2, self.intrinsics.i64_ty, "")); + let v2 = err!( + self.builder + .build_int_z_extend(v2, self.intrinsics.i64_ty, "") + ); let v2 = self.splat_vector(v2.as_basic_value_enum(), self.intrinsics.i64x2_ty)?; let res = err!(self.builder.build_left_shift(v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32ShrS => { @@ -4051,17 +4206,20 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i8x16(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let v2 = v2.into_int_value(); - let v2 = err!(self - .builder - .build_and(v2, self.intrinsics.i32_consts[7], "")); - let v2 = err!(self - .builder - .build_int_truncate(v2, self.intrinsics.i8_ty, "")); + let v2 = err!( + self.builder + .build_and(v2, self.intrinsics.i32_consts[7], "") + ); + let v2 = err!( + self.builder + .build_int_truncate(v2, self.intrinsics.i8_ty, "") + ); let v2 = self.splat_vector(v2.as_basic_value_enum(), self.intrinsics.i8x16_ty)?; let res = err!(self.builder.build_right_shift(v1, v2, true, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8ShrS => { @@ -4069,17 +4227,20 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i16x8(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let v2 = v2.into_int_value(); - let v2 = err!(self - .builder - .build_and(v2, self.intrinsics.i32_consts[15], "")); - let v2 = err!(self - .builder - .build_int_truncate(v2, self.intrinsics.i16_ty, "")); + let v2 = err!( + self.builder + .build_and(v2, self.intrinsics.i32_consts[15], "") + ); + let v2 = err!( + self.builder + .build_int_truncate(v2, self.intrinsics.i16_ty, "") + ); let v2 = self.splat_vector(v2.as_basic_value_enum(), self.intrinsics.i16x8_ty)?; let res = err!(self.builder.build_right_shift(v1, v2, true, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4ShrS => { @@ -4094,9 +4255,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { )); let v2 = self.splat_vector(v2.as_basic_value_enum(), self.intrinsics.i32x4_ty)?; let res = err!(self.builder.build_right_shift(v1, v2, true, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2ShrS => { @@ -4109,14 +4271,16 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { self.intrinsics.i32_ty.const_int(63, false), "" )); - let v2 = err!(self - .builder - .build_int_z_extend(v2, self.intrinsics.i64_ty, "")); + let v2 = err!( + self.builder + .build_int_z_extend(v2, self.intrinsics.i64_ty, "") + ); let v2 = self.splat_vector(v2.as_basic_value_enum(), self.intrinsics.i64x2_ty)?; let res = err!(self.builder.build_right_shift(v1, v2, true, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32ShrU => { @@ -4144,17 +4308,20 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i8x16(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let v2 = v2.into_int_value(); - let v2 = err!(self - .builder - .build_and(v2, self.intrinsics.i32_consts[7], "")); - let v2 = err!(self - .builder - .build_int_truncate(v2, self.intrinsics.i8_ty, "")); + let v2 = err!( + self.builder + .build_and(v2, self.intrinsics.i32_consts[7], "") + ); + let v2 = err!( + self.builder + .build_int_truncate(v2, self.intrinsics.i8_ty, "") + ); let v2 = self.splat_vector(v2.as_basic_value_enum(), self.intrinsics.i8x16_ty)?; let res = err!(self.builder.build_right_shift(v1, v2, false, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8ShrU => { @@ -4162,17 +4329,20 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i16x8(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let v2 = v2.into_int_value(); - let v2 = err!(self - .builder - .build_and(v2, self.intrinsics.i32_consts[15], "")); - let v2 = err!(self - .builder - .build_int_truncate(v2, self.intrinsics.i16_ty, "")); + let v2 = err!( + self.builder + .build_and(v2, self.intrinsics.i32_consts[15], "") + ); + let v2 = err!( + self.builder + .build_int_truncate(v2, self.intrinsics.i16_ty, "") + ); let v2 = self.splat_vector(v2.as_basic_value_enum(), self.intrinsics.i16x8_ty)?; let res = err!(self.builder.build_right_shift(v1, v2, false, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4ShrU => { @@ -4187,9 +4357,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { )); let v2 = self.splat_vector(v2.as_basic_value_enum(), self.intrinsics.i32x4_ty)?; let res = err!(self.builder.build_right_shift(v1, v2, false, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2ShrU => { @@ -4202,14 +4373,16 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { self.intrinsics.i32_ty.const_int(63, false), "" )); - let v2 = err!(self - .builder - .build_int_z_extend(v2, self.intrinsics.i64_ty, "")); + let v2 = err!( + self.builder + .build_int_z_extend(v2, self.intrinsics.i64_ty, "") + ); let v2 = self.splat_vector(v2.as_basic_value_enum(), self.intrinsics.i64x2_ty)?; let res = err!(self.builder.build_right_shift(v1, v2, false, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32Rotl => { @@ -4286,8 +4459,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I64Clz => { @@ -4300,8 +4472,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::I32Ctz => { @@ -4314,8 +4485,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I64Ctz => { @@ -4328,47 +4498,47 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::I8x16Popcnt => { let (v, i) = self.state.pop1_extra()?; let (v, _) = self.v128_into_i8x16(v, i)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.ctpop_i8x16, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!(self.builder.build_call( + self.intrinsics.ctpop_i8x16, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32Popcnt => { let (input, info) = self.state.pop1_extra()?; let input = self.apply_pending_canonicalization(input, info)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.ctpop_i32, &[input.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); + let res = err!(self.builder.build_call( + self.intrinsics.ctpop_i32, + &[input.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); self.state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I64Popcnt => { let (input, info) = self.state.pop1_extra()?; let input = self.apply_pending_canonicalization(input, info)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.ctpop_i64, &[input.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); + let res = err!(self.builder.build_call( + self.intrinsics.ctpop_i64, + &[input.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); self.state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::I32Eqz => { @@ -4379,9 +4549,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { self.intrinsics.i32_zero, "", )); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I64Eqz => { @@ -4392,9 +4563,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { self.intrinsics.i64_zero, "", )); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::I8x16Abs => { @@ -4406,9 +4578,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let all_sign_bits = err!(self.builder.build_right_shift(v, seven, true, "")); let xor = err!(self.builder.build_xor(v, all_sign_bits, "")); let res = err!(self.builder.build_int_sub(xor, all_sign_bits, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8Abs => { @@ -4420,9 +4593,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let all_sign_bits = err!(self.builder.build_right_shift(v, fifteen, true, "")); let xor = err!(self.builder.build_xor(v, all_sign_bits, "")); let res = err!(self.builder.build_int_sub(xor, all_sign_bits, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4Abs => { @@ -4434,9 +4608,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let all_sign_bits = err!(self.builder.build_right_shift(v, thirtyone, true, "")); let xor = err!(self.builder.build_xor(v, all_sign_bits, "")); let res = err!(self.builder.build_int_sub(xor, all_sign_bits, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2Abs => { @@ -4448,165 +4623,190 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let all_sign_bits = err!(self.builder.build_right_shift(v, sixtythree, true, "")); let xor = err!(self.builder.build_xor(v, all_sign_bits, "")); let res = err!(self.builder.build_int_sub(xor, all_sign_bits, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I8x16MinS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; - let cmp = err!(self - .builder - .build_int_compare(IntPredicate::SLT, v1, v2, "")); + let cmp = err!( + self.builder + .build_int_compare(IntPredicate::SLT, v1, v2, "") + ); let res = err!(self.builder.build_select(cmp, v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I8x16MinU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; - let cmp = err!(self - .builder - .build_int_compare(IntPredicate::ULT, v1, v2, "")); + let cmp = err!( + self.builder + .build_int_compare(IntPredicate::ULT, v1, v2, "") + ); let res = err!(self.builder.build_select(cmp, v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I8x16MaxS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; - let cmp = err!(self - .builder - .build_int_compare(IntPredicate::SGT, v1, v2, "")); + let cmp = err!( + self.builder + .build_int_compare(IntPredicate::SGT, v1, v2, "") + ); let res = err!(self.builder.build_select(cmp, v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I8x16MaxU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; - let cmp = err!(self - .builder - .build_int_compare(IntPredicate::UGT, v1, v2, "")); + let cmp = err!( + self.builder + .build_int_compare(IntPredicate::UGT, v1, v2, "") + ); let res = err!(self.builder.build_select(cmp, v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8MinS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; - let cmp = err!(self - .builder - .build_int_compare(IntPredicate::SLT, v1, v2, "")); + let cmp = err!( + self.builder + .build_int_compare(IntPredicate::SLT, v1, v2, "") + ); let res = err!(self.builder.build_select(cmp, v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8MinU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; - let cmp = err!(self - .builder - .build_int_compare(IntPredicate::ULT, v1, v2, "")); + let cmp = err!( + self.builder + .build_int_compare(IntPredicate::ULT, v1, v2, "") + ); let res = err!(self.builder.build_select(cmp, v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8MaxS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; - let cmp = err!(self - .builder - .build_int_compare(IntPredicate::SGT, v1, v2, "")); + let cmp = err!( + self.builder + .build_int_compare(IntPredicate::SGT, v1, v2, "") + ); let res = err!(self.builder.build_select(cmp, v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8MaxU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; - let cmp = err!(self - .builder - .build_int_compare(IntPredicate::UGT, v1, v2, "")); + let cmp = err!( + self.builder + .build_int_compare(IntPredicate::UGT, v1, v2, "") + ); let res = err!(self.builder.build_select(cmp, v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4MinS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; - let cmp = err!(self - .builder - .build_int_compare(IntPredicate::SLT, v1, v2, "")); + let cmp = err!( + self.builder + .build_int_compare(IntPredicate::SLT, v1, v2, "") + ); let res = err!(self.builder.build_select(cmp, v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4MinU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; - let cmp = err!(self - .builder - .build_int_compare(IntPredicate::ULT, v1, v2, "")); + let cmp = err!( + self.builder + .build_int_compare(IntPredicate::ULT, v1, v2, "") + ); let res = err!(self.builder.build_select(cmp, v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4MaxS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; - let cmp = err!(self - .builder - .build_int_compare(IntPredicate::SGT, v1, v2, "")); + let cmp = err!( + self.builder + .build_int_compare(IntPredicate::SGT, v1, v2, "") + ); let res = err!(self.builder.build_select(cmp, v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4MaxU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; - let cmp = err!(self - .builder - .build_int_compare(IntPredicate::UGT, v1, v2, "")); + let cmp = err!( + self.builder + .build_int_compare(IntPredicate::UGT, v1, v2, "") + ); let res = err!(self.builder.build_select(cmp, v1, v2, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I8x16AvgrU => { @@ -4636,12 +4836,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "" )); let res = err!(self.builder.build_right_shift(res, one, false, "")); - let res = err!(self - .builder - .build_int_truncate(res, self.intrinsics.i8x16_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_truncate(res, self.intrinsics.i8x16_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8AvgrU => { @@ -4671,12 +4873,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "" )); let res = err!(self.builder.build_right_shift(res, one, false, "")); - let res = err!(self - .builder - .build_int_truncate(res, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_truncate(res, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } @@ -4697,8 +4901,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1_extra( res, ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f32_nan())?, @@ -4718,8 +4921,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1_extra( res, ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f64_nan())?, @@ -4740,11 +4942,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra( res, ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f32_nan())?, @@ -4765,11 +4967,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra( res, ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f64_nan())?, @@ -4789,8 +4991,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1_extra( res, ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f32_nan())?, @@ -4810,8 +5011,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1_extra( res, ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f64_nan())?, @@ -4832,11 +5032,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra( res, ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f32_nan())?, @@ -4857,11 +5057,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra( res, ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f64_nan())?, @@ -4881,8 +5081,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1_extra( res, ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f32_nan())?, @@ -4902,8 +5101,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1_extra( res, ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f64_nan())?, @@ -4924,11 +5122,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra( res, ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f32_nan())?, @@ -4949,11 +5147,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra( res, ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f64_nan())?, @@ -4973,8 +5171,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64Div => { @@ -4991,8 +5188,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32x4Div => { @@ -5010,11 +5206,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64x2Div => { @@ -5032,1229 +5228,555 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32Sqrt => { let input = self.state.pop1()?; - let res = - err!(self - .builder - .build_call(self.intrinsics.sqrt_f32, &[input.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); + let res = err!(self.builder.build_call( + self.intrinsics.sqrt_f32, + &[input.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); self.state.push1_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64Sqrt => { let input = self.state.pop1()?; - let res = - err!(self - .builder - .build_call(self.intrinsics.sqrt_f64, &[input.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); + let res = err!(self.builder.build_call( + self.intrinsics.sqrt_f64, + &[input.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); self.state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32x4Sqrt => { let (v, i) = self.state.pop1_extra()?; let (v, _) = self.v128_into_f32x4(v, i)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.sqrt_f32x4, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); - let bits = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "bits")); + let res = err!(self.builder.build_call( + self.intrinsics.sqrt_f32x4, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); + let bits = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "bits") + ); self.state.push1_extra(bits, ExtraInfo::pending_f32_nan()); } Operator::F64x2Sqrt => { let (v, i) = self.state.pop1_extra()?; let (v, _) = self.v128_into_f64x2(v, i)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.sqrt_f64x2, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); - let bits = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "bits")); + let res = err!(self.builder.build_call( + self.intrinsics.sqrt_f64x2, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); + let bits = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "bits") + ); self.state.push1(bits); } Operator::F32Min => { - // This implements the same logic as LLVM's @llvm.minimum - // intrinsic would, but x86 lowering of that intrinsic - // encounters a fatal error in LLVM 11. - let (v1, v2) = self.state.pop2()?; - let v1 = self.canonicalize_nans(v1)?; - let v2 = self.canonicalize_nans(v2)?; + let ((lhs, lhs_info), (rhs, rhs_info)) = self.state.pop2_extra()?; + let lhs = self + .apply_pending_canonicalization(lhs, lhs_info)? + .into_float_value(); + let rhs = self + .apply_pending_canonicalization(rhs, rhs_info)? + .into_float_value(); - let v1_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f32, - &[ - v1.into(), - self.intrinsics.f32_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - let v2_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f32, - &[ - v2.into(), - self.intrinsics.f32_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - let v1_lt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f32, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_olt_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - let v1_gt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f32, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_ogt_md, - self.intrinsics.fp_exception_md, - ], + let res = err!(self.builder.build_call( + self.intrinsics.minimum_f32, + &[lhs.into(), rhs.into()], "", )) .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); + .unwrap_basic(); - let res = err!(self.builder.build_select( - v1_is_nan, - self.quiet_nan(v1)?, - err!(self.builder.build_select( - v2_is_nan, - self.quiet_nan(v2)?, - err!(self.builder.build_select( - v1_lt_v2, - v1, - err!(self.builder.build_select( - v1_gt_v2, - v2, - err!(self.builder.build_bit_cast( - err!(self.builder.build_or( - err!(self.builder.build_bit_cast( - v1, - self.intrinsics.i32_ty, - "" - )) - .into_int_value(), - err!(self.builder.build_bit_cast( - v2, - self.intrinsics.i32_ty, - "" - )) - .into_int_value(), - "", - )), - self.intrinsics.f32_ty, - "", - )), - "", - )), - "", - )), - "", - )), - "", - )); + let res = self.finalize_minmax_result(res.as_basic_value_enum())?; + let res = res.into_float_value(); - self.state.push1(res); + self.state.push1_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64Min => { - // This implements the same logic as LLVM's @llvm.minimum - // intrinsic would, but x86 lowering of that intrinsic - // encounters a fatal error in LLVM 11. - let (v1, v2) = self.state.pop2()?; - let v1 = self.canonicalize_nans(v1)?; - let v2 = self.canonicalize_nans(v2)?; + let ((lhs, lhs_info), (rhs, rhs_info)) = self.state.pop2_extra()?; + let lhs = self + .apply_pending_canonicalization(lhs, lhs_info)? + .into_float_value(); + let rhs = self + .apply_pending_canonicalization(rhs, rhs_info)? + .into_float_value(); - let v1_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f64, - &[ - v1.into(), - self.intrinsics.f64_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - let v2_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f64, - &[ - v2.into(), - self.intrinsics.f64_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - let v1_lt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f64, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_olt_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - let v1_gt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f64, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_ogt_md, - self.intrinsics.fp_exception_md, - ], + let res = err!(self.builder.build_call( + self.intrinsics.minimum_f64, + &[lhs.into(), rhs.into()], "", )) .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); + .unwrap_basic(); - let res = err!(self.builder.build_select( - v1_is_nan, - self.quiet_nan(v1)?, - err!(self.builder.build_select( - v2_is_nan, - self.quiet_nan(v2)?, - err!(self.builder.build_select( - v1_lt_v2, - v1, - err!(self.builder.build_select( - v1_gt_v2, - v2, - err!(self.builder.build_bit_cast( - err!(self.builder.build_or( - err!(self.builder.build_bit_cast( - v1, - self.intrinsics.i64_ty, - "" - )) - .into_int_value(), - err!(self.builder.build_bit_cast( - v2, - self.intrinsics.i64_ty, - "" - )) - .into_int_value(), - "", - )), - self.intrinsics.f64_ty, - "", - )), - "", - )), - "", - )), - "", - )), - "", - )); + let res = self.finalize_minmax_result(res.as_basic_value_enum())?; + let res = res.into_float_value(); - self.state.push1(res); + self.state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32x4Min => { - // This implements the same logic as LLVM's @llvm.minimum - // intrinsic would, but x86 lowering of that intrinsic - // encounters a fatal error in LLVM 11. let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f32x4(v1, i1)?; - let (v2, _) = self.v128_into_f32x4(v2, i2)?; - - let v1_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f32x4, - &[ - v1.into(), - self.intrinsics.f32x4_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); - let v2_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f32x4, - &[ - v2.into(), - self.intrinsics.f32x4_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); - let v1_lt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f32x4, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_olt_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); - let v1_gt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f32x4, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_ogt_md, - self.intrinsics.fp_exception_md, - ], + let (v1, i1) = self.v128_into_f32x4(v1, i1)?; + let (v2, i2) = self.v128_into_f32x4(v2, i2)?; + let res = err!(self.builder.build_call( + self.intrinsics.minimum_f32x4, + &[v1.into(), v2.into()], "", )) .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); + .unwrap_basic(); - let res = err!(self.builder.build_select( - v1_is_nan, - self.quiet_nan(v1.into())?.into_vector_value(), - err!(self.builder.build_select( - v2_is_nan, - self.quiet_nan(v2.into())?.into_vector_value(), - err!(self.builder.build_select( - v1_lt_v2, - v1.into(), - err!(self.builder.build_select( - v1_gt_v2, - v2.into(), - err!(self.builder.build_bit_cast( - err!(self.builder.build_or( - err!(self.builder.build_bit_cast( - v1, - self.intrinsics.i32x4_ty, - "", - )) - .into_vector_value(), - err!(self.builder.build_bit_cast( - v2, - self.intrinsics.i32x4_ty, - "", - )) - .into_vector_value(), - "", - )), - self.intrinsics.f32x4_ty, - "", - )), - "", - )), - "", - )) - .into_vector_value(), - "", - )) - .into_vector_value(), - "", - )); + let res = self.finalize_minmax_result(res.as_basic_value_enum())?; + let res = res.into_vector_value(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); - self.state.push1(res); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); + self.state.push1_extra( + res, + ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f32_nan())?, + ); } Operator::F32x4PMin => { // Pseudo-min: b < a ? b : a let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _i1) = self.v128_into_f32x4(v1, i1)?; let (v2, _i2) = self.v128_into_f32x4(v2, i2)?; - let cmp = err!(self - .builder - .build_float_compare(FloatPredicate::OLT, v2, v1, "")); + let cmp = err!( + self.builder + .build_float_compare(FloatPredicate::OLT, v2, v1, "") + ); let res = err!(self.builder.build_select(cmp, v2, v1, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F64x2Min => { - // This implements the same logic as LLVM's @llvm.minimum - // intrinsic would, but x86 lowering of that intrinsic - // encounters a fatal error in LLVM 11. let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f64x2(v1, i1)?; - let (v2, _) = self.v128_into_f64x2(v2, i2)?; - - let v1_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f64x2, - &[ - v1.into(), - self.intrinsics.f64x2_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); - let v2_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f64x2, - &[ - v2.into(), - self.intrinsics.f64x2_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); - let v1_lt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f64x2, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_olt_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); - let v1_gt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f64x2, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_ogt_md, - self.intrinsics.fp_exception_md, - ], + let (v1, i1) = self.v128_into_f64x2(v1, i1)?; + let (v2, i2) = self.v128_into_f64x2(v2, i2)?; + let res = err!(self.builder.build_call( + self.intrinsics.minimum_f64x2, + &[v1.into(), v2.into()], "", )) .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); + .unwrap_basic(); - let res = err!(self.builder.build_select( - v1_is_nan, - self.quiet_nan(v1.into())?.into_vector_value(), - err!(self.builder.build_select( - v2_is_nan, - self.quiet_nan(v2.into())?.into_vector_value(), - err!(self.builder.build_select( - v1_lt_v2, - v1.into(), - err!(self.builder.build_select( - v1_gt_v2, - v2.into(), - err!(self.builder.build_bit_cast( - err!(self.builder.build_or( - err!(self.builder.build_bit_cast( - v1, - self.intrinsics.i64x2_ty, - "", - )) - .into_vector_value(), - err!(self.builder.build_bit_cast( - v2, - self.intrinsics.i64x2_ty, - "", - )) - .into_vector_value(), - "", - )), - self.intrinsics.f64x2_ty, - "", - )), - "", - )), - "", - )) - .into_vector_value(), - "", - )) - .into_vector_value(), - "", - )); + let res = self.finalize_minmax_result(res.as_basic_value_enum())?; + let res = res.into_vector_value(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); - self.state.push1(res); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); + self.state.push1_extra( + res, + ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f64_nan())?, + ); } Operator::F64x2PMin => { // Pseudo-min: b < a ? b : a let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _i1) = self.v128_into_f64x2(v1, i1)?; let (v2, _i2) = self.v128_into_f64x2(v2, i2)?; - let cmp = err!(self - .builder - .build_float_compare(FloatPredicate::OLT, v2, v1, "")); + let cmp = err!( + self.builder + .build_float_compare(FloatPredicate::OLT, v2, v1, "") + ); let res = err!(self.builder.build_select(cmp, v2, v1, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F32Max => { - // This implements the same logic as LLVM's @llvm.maximum - // intrinsic would, but x86 lowering of that intrinsic - // encounters a fatal error in LLVM 11. - let (v1, v2) = self.state.pop2()?; - let v1 = self.canonicalize_nans(v1)?; - let v2 = self.canonicalize_nans(v2)?; + let ((lhs, lhs_info), (rhs, rhs_info)) = self.state.pop2_extra()?; + let lhs = self + .apply_pending_canonicalization(lhs, lhs_info)? + .into_float_value(); + let rhs = self + .apply_pending_canonicalization(rhs, rhs_info)? + .into_float_value(); - let v1_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f32, - &[ - v1.into(), - self.intrinsics.f32_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - let v2_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f32, - &[ - v2.into(), - self.intrinsics.f32_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - let v1_lt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f32, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_olt_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - let v1_gt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f32, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_ogt_md, - self.intrinsics.fp_exception_md, - ], + let res = err!(self.builder.build_call( + self.intrinsics.maximum_f32, + &[lhs.into(), rhs.into()], "", )) .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); + .unwrap_basic(); - let res = err!(self.builder.build_select( - v1_is_nan, - self.quiet_nan(v1)?, - err!(self.builder.build_select( - v2_is_nan, - self.quiet_nan(v2)?, - err!(self.builder.build_select( - v1_lt_v2, - v2, - err!(self.builder.build_select( - v1_gt_v2, - v1, - err!(self.builder.build_bit_cast( - err!(self.builder.build_and( - err!(self.builder.build_bit_cast( - v1, - self.intrinsics.i32_ty, - "" - )) - .into_int_value(), - err!(self.builder.build_bit_cast( - v2, - self.intrinsics.i32_ty, - "" - )) - .into_int_value(), - "", - )), - self.intrinsics.f32_ty, - "", - )), - "", - )), - "", - )), - "", - )), - "", - )); + let res = self.finalize_minmax_result(res.as_basic_value_enum())?; + let res = res.into_float_value(); - self.state.push1(res); + self.state.push1_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64Max => { - // This implements the same logic as LLVM's @llvm.maximum - // intrinsic would, but x86 lowering of that intrinsic - // encounters a fatal error in LLVM 11. - let (v1, v2) = self.state.pop2()?; - let v1 = self.canonicalize_nans(v1)?; - let v2 = self.canonicalize_nans(v2)?; + let ((lhs, lhs_info), (rhs, rhs_info)) = self.state.pop2_extra()?; + let lhs = self + .apply_pending_canonicalization(lhs, lhs_info)? + .into_float_value(); + let rhs = self + .apply_pending_canonicalization(rhs, rhs_info)? + .into_float_value(); - let v1_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f64, - &[ - v1.into(), - self.intrinsics.f64_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - let v2_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f64, - &[ - v2.into(), - self.intrinsics.f64_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - let v1_lt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f64, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_olt_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - let v1_gt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f64, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_ogt_md, - self.intrinsics.fp_exception_md, - ], + let res = err!(self.builder.build_call( + self.intrinsics.maximum_f64, + &[lhs.into(), rhs.into()], "", )) .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); + .unwrap_basic(); - let res = err!(self.builder.build_select( - v1_is_nan, - self.quiet_nan(v1)?, - err!(self.builder.build_select( - v2_is_nan, - self.quiet_nan(v2)?, - err!(self.builder.build_select( - v1_lt_v2, - v2, - err!(self.builder.build_select( - v1_gt_v2, - v1, - err!(self.builder.build_bit_cast( - err!(self.builder.build_and( - err!(self.builder.build_bit_cast( - v1, - self.intrinsics.i64_ty, - "" - )) - .into_int_value(), - err!(self.builder.build_bit_cast( - v2, - self.intrinsics.i64_ty, - "" - )) - .into_int_value(), - "", - )), - self.intrinsics.f64_ty, - "", - )), - "", - )), - "", - )), - "", - )), - "", - )); + let res = self.finalize_minmax_result(res.as_basic_value_enum())?; + let res = res.into_float_value(); - self.state.push1(res); + self.state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32x4Max => { - // This implements the same logic as LLVM's @llvm.maximum - // intrinsic would, but x86 lowering of that intrinsic - // encounters a fatal error in LLVM 11. let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f32x4(v1, i1)?; - let (v2, _) = self.v128_into_f32x4(v2, i2)?; - - let v1_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f32x4, - &[ - v1.into(), - self.intrinsics.f32x4_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); - let v2_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f32x4, - &[ - v2.into(), - self.intrinsics.f32x4_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); - let v1_lt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f32x4, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_olt_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); - let v1_gt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f32x4, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_ogt_md, - self.intrinsics.fp_exception_md, - ], + let (v1, i1) = self.v128_into_f32x4(v1, i1)?; + let (v2, i2) = self.v128_into_f32x4(v2, i2)?; + let res = err!(self.builder.build_call( + self.intrinsics.maximum_f32x4, + &[v1.into(), v2.into()], "", )) .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); + .unwrap_basic(); - let res = err!(self.builder.build_select( - v1_is_nan, - self.quiet_nan(v1.into())?.into_vector_value(), - err!(self.builder.build_select( - v2_is_nan, - self.quiet_nan(v2.into())?.into_vector_value(), - err!(self.builder.build_select( - v1_lt_v2, - v2.into(), - err!(self.builder.build_select( - v1_gt_v2, - v1.into(), - err!(self.builder.build_bit_cast( - err!(self.builder.build_and( - err!(self.builder.build_bit_cast( - v1, - self.intrinsics.i32x4_ty, - "", - )) - .into_vector_value(), - err!(self.builder.build_bit_cast( - v2, - self.intrinsics.i32x4_ty, - "", - )) - .into_vector_value(), - "", - )), - self.intrinsics.f32x4_ty, - "", - )), - "", - )), - "", - )) - .into_vector_value(), - "", - )) - .into_vector_value(), - "", - )); + let res = self.finalize_minmax_result(res.as_basic_value_enum())?; + let res = res.into_vector_value(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); - self.state.push1(res); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); + self.state.push1_extra( + res, + ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f32_nan())?, + ); } Operator::F32x4PMax => { // Pseudo-max: a < b ? b : a let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _i1) = self.v128_into_f32x4(v1, i1)?; let (v2, _i2) = self.v128_into_f32x4(v2, i2)?; - let cmp = err!(self - .builder - .build_float_compare(FloatPredicate::OLT, v1, v2, "")); + let cmp = err!( + self.builder + .build_float_compare(FloatPredicate::OLT, v1, v2, "") + ); let res = err!(self.builder.build_select(cmp, v2, v1, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F64x2Max => { - // This implements the same logic as LLVM's @llvm.maximum - // intrinsic would, but x86 lowering of that intrinsic - // encounters a fatal error in LLVM 11. let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f64x2(v1, i1)?; - let (v2, _) = self.v128_into_f64x2(v2, i2)?; - - let v1_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f64x2, - &[ - v1.into(), - self.intrinsics.f64x2_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); - let v2_is_nan = err!(self.builder.build_call( - self.intrinsics.cmp_f64x2, - &[ - v2.into(), - self.intrinsics.f64x2_zero.into(), - self.intrinsics.fp_uno_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); - let v1_lt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f64x2, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_olt_md, - self.intrinsics.fp_exception_md, - ], - "", - )) - .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); - let v1_gt_v2 = err!(self.builder.build_call( - self.intrinsics.cmp_f64x2, - &[ - v1.into(), - v2.into(), - self.intrinsics.fp_ogt_md, - self.intrinsics.fp_exception_md, - ], + let (v1, i1) = self.v128_into_f64x2(v1, i1)?; + let (v2, i2) = self.v128_into_f64x2(v2, i2)?; + let res = err!(self.builder.build_call( + self.intrinsics.maximum_f64x2, + &[v1.into(), v2.into()], "", )) .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(); + .unwrap_basic(); - let res = err!(self.builder.build_select( - v1_is_nan, - self.quiet_nan(v1.into())?.into_vector_value(), - err!(self.builder.build_select( - v2_is_nan, - self.quiet_nan(v2.into())?.into_vector_value(), - err!(self.builder.build_select( - v1_lt_v2, - v2.into(), - err!(self.builder.build_select( - v1_gt_v2, - v1.into(), - err!(self.builder.build_bit_cast( - err!(self.builder.build_and( - err!(self.builder.build_bit_cast( - v1, - self.intrinsics.i64x2_ty, - "", - )) - .into_vector_value(), - err!(self.builder.build_bit_cast( - v2, - self.intrinsics.i64x2_ty, - "", - )) - .into_vector_value(), - "", - )), - self.intrinsics.f64x2_ty, - "", - )), - "", - )), - "", - )) - .into_vector_value(), - "", - )) - .into_vector_value(), - "", - )); + let res = self.finalize_minmax_result(res.as_basic_value_enum())?; + let res = res.into_vector_value(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); - self.state.push1(res); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); + self.state.push1_extra( + res, + ((i1.strip_pending() & i2.strip_pending())? | ExtraInfo::pending_f64_nan())?, + ); } Operator::F64x2PMax => { // Pseudo-max: a < b ? b : a let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _i1) = self.v128_into_f64x2(v1, i1)?; let (v2, _i2) = self.v128_into_f64x2(v2, i2)?; - let cmp = err!(self - .builder - .build_float_compare(FloatPredicate::OLT, v1, v2, "")); + let cmp = err!( + self.builder + .build_float_compare(FloatPredicate::OLT, v1, v2, "") + ); let res = err!(self.builder.build_select(cmp, v2, v1, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F32Ceil => { let (input, info) = self.state.pop1_extra()?; - let res = - err!(self - .builder - .build_call(self.intrinsics.ceil_f32, &[input.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); + let res = err!(self.builder.build_call( + self.intrinsics.ceil_f32, + &[input.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); self.state .push1_extra(res, (info | ExtraInfo::pending_f32_nan())?); } Operator::F32x4Ceil => { let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_f32x4(v, i)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.ceil_f32x4, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let (v, _) = self.v128_into_f32x4(v, i)?; + let res = err!(self.builder.build_call( + self.intrinsics.ceil_f32x4, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state .push1_extra(res, (i | ExtraInfo::pending_f32_nan())?); } Operator::F64Ceil => { let (input, info) = self.state.pop1_extra()?; - let res = - err!(self - .builder - .build_call(self.intrinsics.ceil_f64, &[input.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); + let res = err!(self.builder.build_call( + self.intrinsics.ceil_f64, + &[input.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); self.state .push1_extra(res, (info | ExtraInfo::pending_f64_nan())?); } Operator::F64x2Ceil => { let (v, i) = self.state.pop1_extra()?; let (v, _) = self.v128_into_f64x2(v, i)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.ceil_f64x2, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!(self.builder.build_call( + self.intrinsics.ceil_f64x2, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state .push1_extra(res, (i | ExtraInfo::pending_f64_nan())?); } Operator::F32Floor => { let (input, info) = self.state.pop1_extra()?; - let res = - err!(self - .builder - .build_call(self.intrinsics.floor_f32, &[input.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); + let res = err!(self.builder.build_call( + self.intrinsics.floor_f32, + &[input.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); self.state .push1_extra(res, (info | ExtraInfo::pending_f32_nan())?); } Operator::F32x4Floor => { let (v, i) = self.state.pop1_extra()?; let (v, _) = self.v128_into_f32x4(v, i)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.floor_f32x4, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!(self.builder.build_call( + self.intrinsics.floor_f32x4, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state .push1_extra(res, (i | ExtraInfo::pending_f32_nan())?); } Operator::F64Floor => { let (input, info) = self.state.pop1_extra()?; - let res = - err!(self - .builder - .build_call(self.intrinsics.floor_f64, &[input.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); + let res = err!(self.builder.build_call( + self.intrinsics.floor_f64, + &[input.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); self.state .push1_extra(res, (info | ExtraInfo::pending_f64_nan())?); } Operator::F64x2Floor => { let (v, i) = self.state.pop1_extra()?; let (v, _) = self.v128_into_f64x2(v, i)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.floor_f64x2, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!(self.builder.build_call( + self.intrinsics.floor_f64x2, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state .push1_extra(res, (i | ExtraInfo::pending_f64_nan())?); } Operator::F32Trunc => { let (v, i) = self.state.pop1_extra()?; - let res = err!(self - .builder - .build_call(self.intrinsics.trunc_f32, &[v.into()], "")) + let res = err!( + self.builder + .build_call(self.intrinsics.trunc_f32, &[v.into()], "") + ) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state .push1_extra(res, (i | ExtraInfo::pending_f32_nan())?); } Operator::F32x4Trunc => { let (v, i) = self.state.pop1_extra()?; let (v, _) = self.v128_into_f32x4(v, i)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.trunc_f32x4, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!(self.builder.build_call( + self.intrinsics.trunc_f32x4, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state .push1_extra(res, (i | ExtraInfo::pending_f32_nan())?); } Operator::F64Trunc => { let (v, i) = self.state.pop1_extra()?; - let res = err!(self - .builder - .build_call(self.intrinsics.trunc_f64, &[v.into()], "")) + let res = err!( + self.builder + .build_call(self.intrinsics.trunc_f64, &[v.into()], "") + ) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state .push1_extra(res, (i | ExtraInfo::pending_f64_nan())?); } Operator::F64x2Trunc => { let (v, i) = self.state.pop1_extra()?; let (v, _) = self.v128_into_f64x2(v, i)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.trunc_f64x2, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!(self.builder.build_call( + self.intrinsics.trunc_f64x2, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state .push1_extra(res, (i | ExtraInfo::pending_f64_nan())?); } Operator::F32Nearest => { let (v, i) = self.state.pop1_extra()?; - let res = - err!(self - .builder - .build_call(self.intrinsics.nearbyint_f32, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); + let res = err!(self.builder.build_call( + self.intrinsics.nearbyint_f32, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); self.state .push1_extra(res, (i | ExtraInfo::pending_f32_nan())?); } Operator::F32x4Nearest => { let (v, i) = self.state.pop1_extra()?; let (v, _) = self.v128_into_f32x4(v, i)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.nearbyint_f32x4, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!(self.builder.build_call( + self.intrinsics.nearbyint_f32x4, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state .push1_extra(res, (i | ExtraInfo::pending_f32_nan())?); } Operator::F64Nearest => { let (v, i) = self.state.pop1_extra()?; - let res = - err!(self - .builder - .build_call(self.intrinsics.nearbyint_f64, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); + let res = err!(self.builder.build_call( + self.intrinsics.nearbyint_f64, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); self.state .push1_extra(res, (i | ExtraInfo::pending_f64_nan())?); } Operator::F64x2Nearest => { let (v, i) = self.state.pop1_extra()?; let (v, _) = self.v128_into_f64x2(v, i)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.nearbyint_f64x2, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!(self.builder.build_call( + self.intrinsics.nearbyint_f64x2, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state .push1_extra(res, (i | ExtraInfo::pending_f64_nan())?); } Operator::F32Abs => { let (v, i) = self.state.pop1_extra()?; let v = self.apply_pending_canonicalization(v, i)?; - let res = err!(self - .builder - .build_call(self.intrinsics.fabs_f32, &[v.into()], "")) + let res = err!( + self.builder + .build_call(self.intrinsics.fabs_f32, &[v.into()], "") + ) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); // The exact NaN returned by F32Abs is fully defined. Do not // adjust. self.state.push1_extra(res, i.strip_pending()); @@ -6262,12 +5784,12 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { Operator::F64Abs => { let (v, i) = self.state.pop1_extra()?; let v = self.apply_pending_canonicalization(v, i)?; - let res = err!(self - .builder - .build_call(self.intrinsics.fabs_f64, &[v.into()], "")) + let res = err!( + self.builder + .build_call(self.intrinsics.fabs_f64, &[v.into()], "") + ) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); // The exact NaN returned by F64Abs is fully defined. Do not // adjust. self.state.push1_extra(res, i.strip_pending()); @@ -6280,16 +5802,17 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "" )); let v = self.apply_pending_canonicalization(v, i)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.fabs_f32x4, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!(self.builder.build_call( + self.intrinsics.fabs_f32x4, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); // The exact NaN returned by F32x4Abs is fully defined. Do not // adjust. self.state.push1_extra(res, i.strip_pending()); @@ -6302,16 +5825,17 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "" )); let v = self.apply_pending_canonicalization(v, i)?; - let res = - err!(self - .builder - .build_call(self.intrinsics.fabs_f64x2, &[v.into()], "")) - .try_as_basic_value() - .left() - .unwrap(); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!(self.builder.build_call( + self.intrinsics.fabs_f64x2, + &[v.into()], + "" + )) + .try_as_basic_value() + .unwrap_basic(); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); // The exact NaN returned by F32x4Abs is fully defined. Do not // adjust. self.state.push1_extra(res, i.strip_pending()); @@ -6327,9 +5851,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { .apply_pending_canonicalization(v, i)? .into_vector_value(); let res = err!(self.builder.build_float_neg(v, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); // The exact NaN returned by F32x4Neg is fully defined. Do not // adjust. self.state.push1_extra(res, i.strip_pending()); @@ -6345,9 +5870,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { .apply_pending_canonicalization(v, i)? .into_vector_value(); let res = err!(self.builder.build_float_neg(v, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); // The exact NaN returned by F64x2Neg is fully defined. Do not // adjust. self.state.push1_extra(res, i.strip_pending()); @@ -6372,8 +5898,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "" )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); // The exact NaN returned by F32Copysign is fully defined. // Do not adjust. self.state.push1_extra(res, mag_info.strip_pending()); @@ -6388,8 +5913,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "" )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); // The exact NaN returned by F32Copysign is fully defined. // Do not adjust. self.state.push1_extra(res, mag_info.strip_pending()); @@ -6405,9 +5929,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let v2 = self.apply_pending_canonicalization(v2, i2)?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let cond = err!(self.builder.build_int_compare(IntPredicate::EQ, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -6418,12 +5943,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; let res = err!(self.builder.build_int_compare(IntPredicate::EQ, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i8x16_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i8x16_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8Eq => { @@ -6431,12 +5958,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; let res = err!(self.builder.build_int_compare(IntPredicate::EQ, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4Eq => { @@ -6444,12 +5973,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; let res = err!(self.builder.build_int_compare(IntPredicate::EQ, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2Eq => { @@ -6457,12 +5988,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i64x2(v1, i1)?; let (v2, _) = self.v128_into_i64x2(v2, i2)?; let res = err!(self.builder.build_int_compare(IntPredicate::EQ, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32Ne | Operator::I64Ne => { @@ -6471,9 +6004,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let v2 = self.apply_pending_canonicalization(v2, i2)?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let cond = err!(self.builder.build_int_compare(IntPredicate::NE, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -6484,12 +6018,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; let res = err!(self.builder.build_int_compare(IntPredicate::NE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i8x16_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i8x16_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8Ne => { @@ -6497,12 +6033,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; let res = err!(self.builder.build_int_compare(IntPredicate::NE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4Ne => { @@ -6510,12 +6048,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; let res = err!(self.builder.build_int_compare(IntPredicate::NE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2Ne => { @@ -6523,12 +6063,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v1, _) = self.v128_into_i64x2(v1, i1)?; let (v2, _) = self.v128_into_i64x2(v2, i2)?; let res = err!(self.builder.build_int_compare(IntPredicate::NE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32LtS | Operator::I64LtS => { @@ -6536,12 +6078,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let v1 = self.apply_pending_canonicalization(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = err!(self - .builder - .build_int_compare(IntPredicate::SLT, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let cond = err!( + self.builder + .build_int_compare(IntPredicate::SLT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -6551,60 +6095,72 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SLT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i8x16_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SLT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i8x16_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8LtS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SLT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SLT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4LtS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SLT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SLT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2LtS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i64x2(v1, i1)?; let (v2, _) = self.v128_into_i64x2(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SLT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SLT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32LtU | Operator::I64LtU => { @@ -6612,57 +6168,68 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let v1 = self.apply_pending_canonicalization(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = err!(self - .builder - .build_int_compare(IntPredicate::ULT, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let cond = err!( + self.builder + .build_int_compare(IntPredicate::ULT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1(res); } Operator::I8x16LtU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::ULT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i8x16_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::ULT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i8x16_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8LtU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::ULT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::ULT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4LtU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::ULT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::ULT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32LeS | Operator::I64LeS => { @@ -6670,12 +6237,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let v1 = self.apply_pending_canonicalization(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = err!(self - .builder - .build_int_compare(IntPredicate::SLE, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let cond = err!( + self.builder + .build_int_compare(IntPredicate::SLE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -6685,60 +6254,72 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SLE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i8x16_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SLE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i8x16_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8LeS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SLE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SLE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4LeS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SLE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SLE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2LeS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i64x2(v1, i1)?; let (v2, _) = self.v128_into_i64x2(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SLE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SLE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32LeU | Operator::I64LeU => { @@ -6746,12 +6327,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let v1 = self.apply_pending_canonicalization(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = err!(self - .builder - .build_int_compare(IntPredicate::ULE, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let cond = err!( + self.builder + .build_int_compare(IntPredicate::ULE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -6761,45 +6344,54 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::ULE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i8x16_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::ULE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i8x16_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8LeU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::ULE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::ULE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4LeU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::ULE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::ULE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32GtS | Operator::I64GtS => { @@ -6807,12 +6399,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let v1 = self.apply_pending_canonicalization(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = err!(self - .builder - .build_int_compare(IntPredicate::SGT, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let cond = err!( + self.builder + .build_int_compare(IntPredicate::SGT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -6822,60 +6416,72 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SGT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i8x16_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SGT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i8x16_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8GtS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SGT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SGT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4GtS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SGT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SGT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2GtS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i64x2(v1, i1)?; let (v2, _) = self.v128_into_i64x2(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SGT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SGT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32GtU | Operator::I64GtU => { @@ -6883,12 +6489,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let v1 = self.apply_pending_canonicalization(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = err!(self - .builder - .build_int_compare(IntPredicate::UGT, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let cond = err!( + self.builder + .build_int_compare(IntPredicate::UGT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -6898,45 +6506,54 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::UGT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i8x16_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::UGT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i8x16_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8GtU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::UGT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::UGT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4GtU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::UGT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::UGT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32GeS | Operator::I64GeS => { @@ -6944,72 +6561,86 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let v1 = self.apply_pending_canonicalization(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = err!(self - .builder - .build_int_compare(IntPredicate::SGE, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let cond = err!( + self.builder + .build_int_compare(IntPredicate::SGE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1(res); } Operator::I8x16GeS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SGE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i8x16_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SGE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i8x16_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8GeS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SGE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SGE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4GeS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SGE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SGE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2GeS => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i64x2(v1, i1)?; let (v2, _) = self.v128_into_i64x2(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::SGE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::SGE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32GeU | Operator::I64GeU => { @@ -7017,12 +6648,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let v1 = self.apply_pending_canonicalization(v1, i1)?; let v2 = self.apply_pending_canonicalization(v2, i2)?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let cond = err!(self - .builder - .build_int_compare(IntPredicate::UGE, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let cond = err!( + self.builder + .build_int_compare(IntPredicate::UGE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -7032,45 +6665,54 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i8x16(v1, i1)?; let (v2, _) = self.v128_into_i8x16(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::UGE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i8x16_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::UGE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i8x16_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8GeU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i16x8(v1, i1)?; let (v2, _) = self.v128_into_i16x8(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::UGE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::UGE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4GeU => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_i32x4(v1, i1)?; let (v2, _) = self.v128_into_i32x4(v2, i2)?; - let res = err!(self - .builder - .build_int_compare(IntPredicate::UGE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_compare(IntPredicate::UGE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } @@ -7081,12 +6723,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { Operator::F32Eq | Operator::F64Eq => { let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let cond = err!(self - .builder - .build_float_compare(FloatPredicate::OEQ, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let cond = err!( + self.builder + .build_float_compare(FloatPredicate::OEQ, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -7096,41 +6740,49 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_f32x4(v1, i1)?; let (v2, _) = self.v128_into_f32x4(v2, i2)?; - let res = err!(self - .builder - .build_float_compare(FloatPredicate::OEQ, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_float_compare(FloatPredicate::OEQ, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F64x2Eq => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_f64x2(v1, i1)?; let (v2, _) = self.v128_into_f64x2(v2, i2)?; - let res = err!(self - .builder - .build_float_compare(FloatPredicate::OEQ, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_float_compare(FloatPredicate::OEQ, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F32Ne | Operator::F64Ne => { let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let cond = err!(self - .builder - .build_float_compare(FloatPredicate::UNE, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let cond = err!( + self.builder + .build_float_compare(FloatPredicate::UNE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -7140,41 +6792,49 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_f32x4(v1, i1)?; let (v2, _) = self.v128_into_f32x4(v2, i2)?; - let res = err!(self - .builder - .build_float_compare(FloatPredicate::UNE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_float_compare(FloatPredicate::UNE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F64x2Ne => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_f64x2(v1, i1)?; let (v2, _) = self.v128_into_f64x2(v2, i2)?; - let res = err!(self - .builder - .build_float_compare(FloatPredicate::UNE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_float_compare(FloatPredicate::UNE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F32Lt | Operator::F64Lt => { let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let cond = err!(self - .builder - .build_float_compare(FloatPredicate::OLT, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let cond = err!( + self.builder + .build_float_compare(FloatPredicate::OLT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -7184,41 +6844,49 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_f32x4(v1, i1)?; let (v2, _) = self.v128_into_f32x4(v2, i2)?; - let res = err!(self - .builder - .build_float_compare(FloatPredicate::OLT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_float_compare(FloatPredicate::OLT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F64x2Lt => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_f64x2(v1, i1)?; let (v2, _) = self.v128_into_f64x2(v2, i2)?; - let res = err!(self - .builder - .build_float_compare(FloatPredicate::OLT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_float_compare(FloatPredicate::OLT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F32Le | Operator::F64Le => { let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let cond = err!(self - .builder - .build_float_compare(FloatPredicate::OLE, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let cond = err!( + self.builder + .build_float_compare(FloatPredicate::OLE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -7228,41 +6896,49 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_f32x4(v1, i1)?; let (v2, _) = self.v128_into_f32x4(v2, i2)?; - let res = err!(self - .builder - .build_float_compare(FloatPredicate::OLE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_float_compare(FloatPredicate::OLE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F64x2Le => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_f64x2(v1, i1)?; let (v2, _) = self.v128_into_f64x2(v2, i2)?; - let res = err!(self - .builder - .build_float_compare(FloatPredicate::OLE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_float_compare(FloatPredicate::OLE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F32Gt | Operator::F64Gt => { let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let cond = err!(self - .builder - .build_float_compare(FloatPredicate::OGT, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let cond = err!( + self.builder + .build_float_compare(FloatPredicate::OGT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -7272,41 +6948,49 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_f32x4(v1, i1)?; let (v2, _) = self.v128_into_f32x4(v2, i2)?; - let res = err!(self - .builder - .build_float_compare(FloatPredicate::OGT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_float_compare(FloatPredicate::OGT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F64x2Gt => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_f64x2(v1, i1)?; let (v2, _) = self.v128_into_f64x2(v2, i2)?; - let res = err!(self - .builder - .build_float_compare(FloatPredicate::OGT, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_float_compare(FloatPredicate::OGT, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F32Ge | Operator::F64Ge => { let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let cond = err!(self - .builder - .build_float_compare(FloatPredicate::OGE, v1, v2, "")); - let res = err!(self - .builder - .build_int_z_extend(cond, self.intrinsics.i32_ty, "")); + let cond = err!( + self.builder + .build_float_compare(FloatPredicate::OGE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_z_extend(cond, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -7316,30 +7000,36 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_f32x4(v1, i1)?; let (v2, _) = self.v128_into_f32x4(v2, i2)?; - let res = err!(self - .builder - .build_float_compare(FloatPredicate::OGE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_float_compare(FloatPredicate::OGE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F64x2Ge => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let (v1, _) = self.v128_into_f64x2(v1, i1)?; let (v2, _) = self.v128_into_f64x2(v2, i2)?; - let res = err!(self - .builder - .build_float_compare(FloatPredicate::OGE, v1, v2, "")); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_float_compare(FloatPredicate::OGE, v1, v2, "") + ); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } @@ -7351,27 +7041,30 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v, i) = self.state.pop1_extra()?; let v = self.apply_pending_canonicalization(v, i)?; let v = v.into_int_value(); - let res = err!(self - .builder - .build_int_truncate(v, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_truncate(v, self.intrinsics.i32_ty, "") + ); self.state.push1(res); } Operator::I64ExtendI32S => { let (v, i) = self.state.pop1_extra()?; let v = self.apply_pending_canonicalization(v, i)?; let v = v.into_int_value(); - let res = err!(self - .builder - .build_int_s_extend(v, self.intrinsics.i64_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(v, self.intrinsics.i64_ty, "") + ); self.state.push1(res); } Operator::I64ExtendI32U => { let (v, i) = self.state.pop1_extra()?; let v = self.apply_pending_canonicalization(v, i)?; let v = v.into_int_value(); - let res = err!(self - .builder - .build_int_z_extend(v, self.intrinsics.i64_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(v, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::I16x8ExtendLowI8x16S => { @@ -7392,12 +7085,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_int_s_extend(low, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(low, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8ExtendHighI8x16S => { @@ -7418,12 +7113,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_int_s_extend(low, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(low, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8ExtendLowI8x16U => { @@ -7444,12 +7141,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_int_z_extend(low, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(low, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8ExtendHighI8x16U => { @@ -7470,12 +7169,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_int_z_extend(low, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(low, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4ExtendLowI16x8S => { @@ -7492,12 +7193,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_int_s_extend(low, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(low, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4ExtendHighI16x8S => { @@ -7514,12 +7217,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_int_s_extend(low, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(low, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4ExtendLowI16x8U => { @@ -7536,12 +7241,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_int_z_extend(low, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(low, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4ExtendHighI16x8U => { @@ -7558,12 +7265,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_int_z_extend(low, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(low, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2ExtendLowI32x4U @@ -7597,9 +7306,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )); let res = err!(extend(self, low)); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I8x16NarrowI16x8S => { @@ -7611,21 +7321,25 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let min = VectorType::const_vector(&[min; 8]); let max = VectorType::const_vector(&[max; 8]); let apply_min_clamp_v1 = - err!(self - .builder - .build_int_compare(IntPredicate::SLT, v1, min, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SLT, v1, min, "") + ); let apply_max_clamp_v1 = - err!(self - .builder - .build_int_compare(IntPredicate::SGT, v1, max, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SGT, v1, max, "") + ); let apply_min_clamp_v2 = - err!(self - .builder - .build_int_compare(IntPredicate::SLT, v2, min, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SLT, v2, min, "") + ); let apply_max_clamp_v2 = - err!(self - .builder - .build_int_compare(IntPredicate::SGT, v2, max, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SGT, v2, max, "") + ); let v1 = err!(self.builder.build_select(apply_min_clamp_v1, min, v1, "")) .into_vector_value(); let v1 = err!(self.builder.build_select(apply_max_clamp_v1, max, v1, "")) @@ -7667,9 +7381,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I8x16NarrowI16x8U => { @@ -7680,21 +7395,25 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let max = self.intrinsics.i16_ty.const_int(0x00ff, false); let max = VectorType::const_vector(&[max; 8]); let apply_min_clamp_v1 = - err!(self - .builder - .build_int_compare(IntPredicate::SLT, v1, min, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SLT, v1, min, "") + ); let apply_max_clamp_v1 = - err!(self - .builder - .build_int_compare(IntPredicate::SGT, v1, max, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SGT, v1, max, "") + ); let apply_min_clamp_v2 = - err!(self - .builder - .build_int_compare(IntPredicate::SLT, v2, min, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SLT, v2, min, "") + ); let apply_max_clamp_v2 = - err!(self - .builder - .build_int_compare(IntPredicate::SGT, v2, max, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SGT, v2, max, "") + ); let v1 = err!(self.builder.build_select(apply_min_clamp_v1, min, v1, "")) .into_vector_value(); let v1 = err!(self.builder.build_select(apply_max_clamp_v1, max, v1, "")) @@ -7736,9 +7455,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8NarrowI32x4S => { @@ -7750,21 +7470,25 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let min = VectorType::const_vector(&[min; 4]); let max = VectorType::const_vector(&[max; 4]); let apply_min_clamp_v1 = - err!(self - .builder - .build_int_compare(IntPredicate::SLT, v1, min, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SLT, v1, min, "") + ); let apply_max_clamp_v1 = - err!(self - .builder - .build_int_compare(IntPredicate::SGT, v1, max, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SGT, v1, max, "") + ); let apply_min_clamp_v2 = - err!(self - .builder - .build_int_compare(IntPredicate::SLT, v2, min, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SLT, v2, min, "") + ); let apply_max_clamp_v2 = - err!(self - .builder - .build_int_compare(IntPredicate::SGT, v2, max, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SGT, v2, max, "") + ); let v1 = err!(self.builder.build_select(apply_min_clamp_v1, min, v1, "")) .into_vector_value(); let v1 = err!(self.builder.build_select(apply_max_clamp_v1, max, v1, "")) @@ -7798,9 +7522,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8NarrowI32x4U => { @@ -7811,21 +7536,25 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let max = self.intrinsics.i32_ty.const_int(0xffff, false); let max = VectorType::const_vector(&[max; 4]); let apply_min_clamp_v1 = - err!(self - .builder - .build_int_compare(IntPredicate::SLT, v1, min, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SLT, v1, min, "") + ); let apply_max_clamp_v1 = - err!(self - .builder - .build_int_compare(IntPredicate::SGT, v1, max, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SGT, v1, max, "") + ); let apply_min_clamp_v2 = - err!(self - .builder - .build_int_compare(IntPredicate::SLT, v2, min, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SLT, v2, min, "") + ); let apply_max_clamp_v2 = - err!(self - .builder - .build_int_compare(IntPredicate::SGT, v2, max, "")); + err!( + self.builder + .build_int_compare(IntPredicate::SGT, v2, max, "") + ); let v1 = err!(self.builder.build_select(apply_min_clamp_v1, min, v1, "")) .into_vector_value(); let v1 = err!(self.builder.build_select(apply_max_clamp_v1, max, v1, "")) @@ -7859,9 +7588,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4TruncSatF32x4S => { @@ -7932,9 +7662,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } // Operator::I64x2TruncSatF64x2S => { @@ -7974,10 +7705,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0x4effffff, // 2147483500.0 v1, )?; - let res = - err!(self - .builder - .build_float_to_signed_int(v1, self.intrinsics.i32_ty, "")); + let res = err!(self.builder.build_float_to_signed_int( + v1, + self.intrinsics.i32_ty, + "" + )); self.state.push1(res); } Operator::I32TruncF64S => { @@ -7987,10 +7719,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0x41dfffffffffffff, // 2147483647.9999998 v1, )?; - let res = - err!(self - .builder - .build_float_to_signed_int(v1, self.intrinsics.i32_ty, "")); + let res = err!(self.builder.build_float_to_signed_int( + v1, + self.intrinsics.i32_ty, + "" + )); self.state.push1(res); } Operator::I32TruncSatF32S => { @@ -8028,10 +7761,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0x5effffff, // 9223371500000000000.0 v1, )?; - let res = - err!(self - .builder - .build_float_to_signed_int(v1, self.intrinsics.i64_ty, "")); + let res = err!(self.builder.build_float_to_signed_int( + v1, + self.intrinsics.i64_ty, + "" + )); self.state.push1(res); } Operator::I64TruncF64S => { @@ -8041,10 +7775,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0x43dfffffffffffff, // 9223372036854775000.0 v1, )?; - let res = - err!(self - .builder - .build_float_to_signed_int(v1, self.intrinsics.i64_ty, "")); + let res = err!(self.builder.build_float_to_signed_int( + v1, + self.intrinsics.i64_ty, + "" + )); self.state.push1(res); } Operator::I64TruncSatF32S => { @@ -8082,10 +7817,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0x4f7fffff, // 4294967000.0 v1, )?; - let res = - err!(self - .builder - .build_float_to_unsigned_int(v1, self.intrinsics.i32_ty, "")); + let res = err!(self.builder.build_float_to_unsigned_int( + v1, + self.intrinsics.i32_ty, + "" + )); self.state.push1(res); } Operator::I32TruncF64U => { @@ -8095,10 +7831,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0x41efffffffffffff, // 4294967295.9999995 v1, )?; - let res = - err!(self - .builder - .build_float_to_unsigned_int(v1, self.intrinsics.i32_ty, "")); + let res = err!(self.builder.build_float_to_unsigned_int( + v1, + self.intrinsics.i32_ty, + "" + )); self.state.push1(res); } Operator::I32TruncSatF32U => { @@ -8136,10 +7873,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0x5f7fffff, // 18446743000000000000.0 v1, )?; - let res = - err!(self - .builder - .build_float_to_unsigned_int(v1, self.intrinsics.i64_ty, "")); + let res = err!(self.builder.build_float_to_unsigned_int( + v1, + self.intrinsics.i64_ty, + "" + )); self.state.push1(res); } Operator::I64TruncF64U => { @@ -8149,10 +7887,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0x43efffffffffffff, // 18446744073709550000.0 v1, )?; - let res = - err!(self - .builder - .build_float_to_unsigned_int(v1, self.intrinsics.i64_ty, "")); + let res = err!(self.builder.build_float_to_unsigned_int( + v1, + self.intrinsics.i64_ty, + "" + )); self.state.push1(res); } Operator::I64TruncSatF32U => { @@ -8196,8 +7935,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64PromoteF32 => { @@ -8209,74 +7947,81 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32ConvertI32S | Operator::F32ConvertI64S => { let (v, i) = self.state.pop1_extra()?; let v = self.apply_pending_canonicalization(v, i)?; let v = v.into_int_value(); - let res = - err!(self - .builder - .build_signed_int_to_float(v, self.intrinsics.f32_ty, "")); + let res = err!(self.builder.build_signed_int_to_float( + v, + self.intrinsics.f32_ty, + "" + )); self.state.push1(res); } Operator::F64ConvertI32S | Operator::F64ConvertI64S => { let (v, i) = self.state.pop1_extra()?; let v = self.apply_pending_canonicalization(v, i)?; let v = v.into_int_value(); - let res = - err!(self - .builder - .build_signed_int_to_float(v, self.intrinsics.f64_ty, "")); + let res = err!(self.builder.build_signed_int_to_float( + v, + self.intrinsics.f64_ty, + "" + )); self.state.push1(res); } Operator::F32ConvertI32U | Operator::F32ConvertI64U => { let (v, i) = self.state.pop1_extra()?; let v = self.apply_pending_canonicalization(v, i)?; let v = v.into_int_value(); - let res = - err!(self - .builder - .build_unsigned_int_to_float(v, self.intrinsics.f32_ty, "")); + let res = err!(self.builder.build_unsigned_int_to_float( + v, + self.intrinsics.f32_ty, + "" + )); self.state.push1(res); } Operator::F64ConvertI32U | Operator::F64ConvertI64U => { let (v, i) = self.state.pop1_extra()?; let v = self.apply_pending_canonicalization(v, i)?; let v = v.into_int_value(); - let res = - err!(self - .builder - .build_unsigned_int_to_float(v, self.intrinsics.f64_ty, "")); + let res = err!(self.builder.build_unsigned_int_to_float( + v, + self.intrinsics.f64_ty, + "" + )); self.state.push1(res); } Operator::F32x4ConvertI32x4S => { let v = self.state.pop1()?; let v = err!(self.builder.build_bit_cast(v, self.intrinsics.i32x4_ty, "")) .into_vector_value(); - let res = - err!(self - .builder - .build_signed_int_to_float(v, self.intrinsics.f32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!(self.builder.build_signed_int_to_float( + v, + self.intrinsics.f32x4_ty, + "" + )); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F32x4ConvertI32x4U => { let v = self.state.pop1()?; let v = err!(self.builder.build_bit_cast(v, self.intrinsics.i32x4_ty, "")) .into_vector_value(); - let res = - err!(self - .builder - .build_unsigned_int_to_float(v, self.intrinsics.f32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!(self.builder.build_unsigned_int_to_float( + v, + self.intrinsics.f32x4_ty, + "" + )); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F64x2ConvertLowI32x4S | Operator::F64x2ConvertLowI32x4U => { @@ -8301,13 +8046,15 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )); let res = err!(extend(self, low)); - let res = - err!(self - .builder - .build_signed_int_to_float(res, self.intrinsics.f64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!(self.builder.build_signed_int_to_float( + res, + self.intrinsics.f64x2_ty, + "" + )); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::F64x2PromoteLowF32x4 => { @@ -8322,12 +8069,14 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_float_ext(low, self.intrinsics.f64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_float_ext(low, self.intrinsics.f64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32x4DemoteF64x2Zero => { @@ -8347,9 +8096,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ]), "", )); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra(res, ExtraInfo::pending_f32_nan()); } // Operator::F64x2ConvertI64x2S => { @@ -8405,62 +8155,72 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ***************************/ Operator::I32Extend8S => { let value = self.state.pop1()?.into_int_value(); - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); - let extended_value = - err!(self - .builder - .build_int_s_extend(narrow_value, self.intrinsics.i32_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); + let extended_value = err!(self.builder.build_int_s_extend( + narrow_value, + self.intrinsics.i32_ty, + "" + )); self.state.push1(extended_value); } Operator::I32Extend16S => { let value = self.state.pop1()?.into_int_value(); - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); - let extended_value = - err!(self - .builder - .build_int_s_extend(narrow_value, self.intrinsics.i32_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); + let extended_value = err!(self.builder.build_int_s_extend( + narrow_value, + self.intrinsics.i32_ty, + "" + )); self.state.push1(extended_value); } Operator::I64Extend8S => { let value = self.state.pop1()?.into_int_value(); - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); - let extended_value = - err!(self - .builder - .build_int_s_extend(narrow_value, self.intrinsics.i64_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); + let extended_value = err!(self.builder.build_int_s_extend( + narrow_value, + self.intrinsics.i64_ty, + "" + )); self.state.push1(extended_value); } Operator::I64Extend16S => { let value = self.state.pop1()?.into_int_value(); - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); - let extended_value = - err!(self - .builder - .build_int_s_extend(narrow_value, self.intrinsics.i64_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); + let extended_value = err!(self.builder.build_int_s_extend( + narrow_value, + self.intrinsics.i64_ty, + "" + )); self.state.push1(extended_value); } Operator::I64Extend32S => { let value = self.state.pop1()?.into_int_value(); - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i32_ty, "")); - let extended_value = - err!(self - .builder - .build_int_s_extend(narrow_value, self.intrinsics.i64_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i32_ty, + "" + )); + let extended_value = err!(self.builder.build_int_s_extend( + narrow_value, + self.intrinsics.i64_ty, + "" + )); self.state.push1(extended_value); } @@ -8478,10 +8238,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 4, )?; - let result = - err!(self - .builder - .build_load(self.intrinsics.i32_ty, effective_address, "")); + let result = err!(self.builder.build_load( + self.intrinsics.i32_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8500,10 +8261,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 8, )?; - let result = - err!(self - .builder - .build_load(self.intrinsics.i64_ty, effective_address, "")); + let result = err!(self.builder.build_load( + self.intrinsics.i64_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8522,10 +8284,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 4, )?; - let result = - err!(self - .builder - .build_load(self.intrinsics.f32_ty, effective_address, "")); + let result = err!(self.builder.build_load( + self.intrinsics.f32_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8544,10 +8307,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 8, )?; - let result = - err!(self - .builder - .build_load(self.intrinsics.f64_ty, effective_address, "")); + let result = err!(self.builder.build_load( + self.intrinsics.f64_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8566,10 +8330,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 16, )?; - let result = - err!(self - .builder - .build_load(self.intrinsics.i128_ty, effective_address, "")); + let result = err!(self.builder.build_load( + self.intrinsics.i128_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8590,10 +8355,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 1, )?; - let element = - err!(self - .builder - .build_load(self.intrinsics.i8_ty, effective_address, "")); + let element = err!(self.builder.build_load( + self.intrinsics.i8_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8602,9 +8368,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { )?; let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = err!(self.builder.build_insert_element(v, element, idx, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::V128Load16Lane { ref memarg, lane } => { @@ -8619,10 +8386,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 2, )?; - let element = - err!(self - .builder - .build_load(self.intrinsics.i16_ty, effective_address, "")); + let element = err!(self.builder.build_load( + self.intrinsics.i16_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8631,9 +8399,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { )?; let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = err!(self.builder.build_insert_element(v, element, idx, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra(res, i); } Operator::V128Load32Lane { ref memarg, lane } => { @@ -8648,10 +8417,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 4, )?; - let element = - err!(self - .builder - .build_load(self.intrinsics.i32_ty, effective_address, "")); + let element = err!(self.builder.build_load( + self.intrinsics.i32_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8660,9 +8430,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { )?; let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = err!(self.builder.build_insert_element(v, element, idx, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra(res, i); } Operator::V128Load64Lane { ref memarg, lane } => { @@ -8677,10 +8448,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 8, )?; - let element = - err!(self - .builder - .build_load(self.intrinsics.i64_ty, effective_address, "")); + let element = err!(self.builder.build_load( + self.intrinsics.i64_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8689,9 +8461,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { )?; let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = err!(self.builder.build_insert_element(v, element, idx, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1_extra(res, i); } @@ -8706,10 +8479,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 4, )?; - let dead_load = - err!(self - .builder - .build_load(self.intrinsics.i32_ty, effective_address, "")); + let dead_load = err!(self.builder.build_load( + self.intrinsics.i32_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8730,10 +8504,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 8, )?; - let dead_load = - err!(self - .builder - .build_load(self.intrinsics.i64_ty, effective_address, "")); + let dead_load = err!(self.builder.build_load( + self.intrinsics.i64_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8755,10 +8530,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 4, )?; - let dead_load = - err!(self - .builder - .build_load(self.intrinsics.f32_ty, effective_address, "")); + let dead_load = err!(self.builder.build_load( + self.intrinsics.f32_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8780,10 +8556,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 8, )?; - let dead_load = - err!(self - .builder - .build_load(self.intrinsics.f64_ty, effective_address, "")); + let dead_load = err!(self.builder.build_load( + self.intrinsics.f64_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8805,10 +8582,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 16, )?; - let dead_load = - err!(self - .builder - .build_load(self.intrinsics.i128_ty, effective_address, "")); + let dead_load = err!(self.builder.build_load( + self.intrinsics.i128_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8831,10 +8609,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 1, )?; - let dead_load = - err!(self - .builder - .build_load(self.intrinsics.i8_ty, effective_address, "")); + let dead_load = err!(self.builder.build_load( + self.intrinsics.i8_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8859,10 +8638,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 2, )?; - let dead_load = - err!(self - .builder - .build_load(self.intrinsics.i16_ty, effective_address, "")); + let dead_load = err!(self.builder.build_load( + self.intrinsics.i16_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8887,10 +8667,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 4, )?; - let dead_load = - err!(self - .builder - .build_load(self.intrinsics.i32_ty, effective_address, "")); + let dead_load = err!(self.builder.build_load( + self.intrinsics.i32_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8915,10 +8696,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 8, )?; - let dead_load = - err!(self - .builder - .build_load(self.intrinsics.i64_ty, effective_address, "")); + let dead_load = err!(self.builder.build_load( + self.intrinsics.i64_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8940,10 +8722,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 1, )?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i8_ty, effective_address, "")); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i8_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8967,10 +8750,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 2, )?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i16_ty, effective_address, "")); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i16_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -8994,11 +8778,12 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 1, )?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i8_ty, effective_address, "")) - .into_int_value(); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i8_ty, + effective_address, + "" + )) + .into_int_value(); self.annotate_user_memaccess( memory_index, memarg, @@ -9022,11 +8807,12 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 2, )?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i16_ty, effective_address, "")) - .into_int_value(); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i16_ty, + effective_address, + "" + )) + .into_int_value(); self.annotate_user_memaccess( memory_index, memarg, @@ -9050,10 +8836,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 4, )?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i32_ty, effective_address, "")); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i32_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -9078,10 +8865,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 1, )?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i8_ty, effective_address, "")); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i8_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -9105,10 +8893,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 2, )?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i16_ty, effective_address, "")); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i16_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -9132,10 +8921,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 1, )?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i8_ty, effective_address, "")); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i8_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -9159,10 +8949,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 2, )?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i16_ty, effective_address, "")); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i16_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -9186,10 +8977,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 4, )?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i32_ty, effective_address, "")); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i32_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -9215,20 +9007,22 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 1, )?; - let dead_load = - err!(self - .builder - .build_load(self.intrinsics.i8_ty, effective_address, "")); + let dead_load = err!(self.builder.build_load( + self.intrinsics.i8_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, 1, dead_load.as_instruction_value().unwrap(), )?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); let store = err!(self.builder.build_store(effective_address, narrow_value)); self.annotate_user_memaccess(memory_index, memarg, 1, store)?; } @@ -9243,20 +9037,22 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 2, )?; - let dead_load = - err!(self - .builder - .build_load(self.intrinsics.i16_ty, effective_address, "")); + let dead_load = err!(self.builder.build_load( + self.intrinsics.i16_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, 1, dead_load.as_instruction_value().unwrap(), )?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); let store = err!(self.builder.build_store(effective_address, narrow_value)); self.annotate_user_memaccess(memory_index, memarg, 1, store)?; } @@ -9271,20 +9067,22 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 4, )?; - let dead_load = - err!(self - .builder - .build_load(self.intrinsics.i32_ty, effective_address, "")); + let dead_load = err!(self.builder.build_load( + self.intrinsics.i32_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, 1, dead_load.as_instruction_value().unwrap(), )?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i32_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i32_ty, + "" + )); let store = err!(self.builder.build_store(effective_address, narrow_value)); self.annotate_user_memaccess(memory_index, memarg, 1, store)?; } @@ -9292,36 +9090,40 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v, i) = self.state.pop1_extra()?; let (v, _) = self.v128_into_i8x16(v, i)?; let res = err!(self.builder.build_int_sub(v.get_type().const_zero(), v, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8Neg => { let (v, i) = self.state.pop1_extra()?; let (v, _) = self.v128_into_i16x8(v, i)?; let res = err!(self.builder.build_int_sub(v.get_type().const_zero(), v, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4Neg => { let (v, i) = self.state.pop1_extra()?; let (v, _) = self.v128_into_i32x4(v, i)?; let res = err!(self.builder.build_int_sub(v.get_type().const_zero(), v, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I64x2Neg => { let (v, i) = self.state.pop1_extra()?; let (v, _) = self.v128_into_i64x2(v, i)?; let res = err!(self.builder.build_int_sub(v.get_type().const_zero(), v, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::V128Not => { @@ -9340,9 +9142,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { v.get_type().const_zero(), "", )); - let res = err!(self - .builder - .build_int_z_extend(res, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(res, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -9377,9 +9180,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { lane_int_ty.const_int(u64::MAX, true), "", )); - let res = err!(self - .builder - .build_int_z_extend(res, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(res, self.intrinsics.i32_ty, "") + ); self.state.push1_extra( res, (ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64())?, @@ -9390,9 +9194,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v, _) = self.v128_into_i8x16(v, i)?; let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = err!(self.builder.build_extract_element(v, idx, "")).into_int_value(); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32_ty, "") + ); self.state.push1(res); } Operator::I8x16ExtractLaneU { lane } => { @@ -9400,9 +9205,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v, _) = self.v128_into_i8x16(v, i)?; let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = err!(self.builder.build_extract_element(v, idx, "")).into_int_value(); - let res = err!(self - .builder - .build_int_z_extend(res, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(res, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I16x8ExtractLaneS { lane } => { @@ -9410,9 +9216,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v, _) = self.v128_into_i16x8(v, i)?; let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = err!(self.builder.build_extract_element(v, idx, "")).into_int_value(); - let res = err!(self - .builder - .build_int_s_extend(res, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(res, self.intrinsics.i32_ty, "") + ); self.state.push1(res); } Operator::I16x8ExtractLaneU { lane } => { @@ -9420,9 +9227,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let (v, _) = self.v128_into_i16x8(v, i)?; let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = err!(self.builder.build_extract_element(v, idx, "")).into_int_value(); - let res = err!(self - .builder - .build_int_z_extend(res, self.intrinsics.i32_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(res, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I32x4ExtractLane { lane } => { @@ -9460,9 +9268,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let v2 = err!(self.builder.build_int_cast(v2, self.intrinsics.i8_ty, "")); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = err!(self.builder.build_insert_element(v1, v2, idx, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I16x8ReplaceLane { lane } => { @@ -9472,9 +9281,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let v2 = err!(self.builder.build_int_cast(v2, self.intrinsics.i16_ty, "")); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = err!(self.builder.build_insert_element(v1, v2, idx, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I32x4ReplaceLane { lane } => { @@ -9485,9 +9295,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let i2 = i2.strip_pending(); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = err!(self.builder.build_insert_element(v1, v2, idx, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state .push1_extra(res, ((i1 & i2)? & ExtraInfo::arithmetic_f32())?); } @@ -9499,9 +9310,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let i2 = i2.strip_pending(); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = err!(self.builder.build_insert_element(v1, v2, idx, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state .push1_extra(res, ((i1 & i2)? & ExtraInfo::arithmetic_f64())?); } @@ -9522,9 +9334,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { }; let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = err!(self.builder.build_insert_element(v1, v2, idx, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); let info = if push_pending_f32_nan_to_result { ExtraInfo::pending_f32_nan() } else { @@ -9549,9 +9362,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { }; let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = err!(self.builder.build_insert_element(v1, v2, idx, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); let info = if push_pending_f64_nan_to_result { ExtraInfo::pending_f64_nan() } else { @@ -9562,14 +9376,16 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { Operator::I8x16Swizzle => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let v1 = self.apply_pending_canonicalization(v1, i1)?; - let v1 = err!(self - .builder - .build_bit_cast(v1, self.intrinsics.i8x16_ty, "")) + let v1 = err!( + self.builder + .build_bit_cast(v1, self.intrinsics.i8x16_ty, "") + ) .into_vector_value(); let v2 = self.apply_pending_canonicalization(v2, i2)?; - let v2 = err!(self - .builder - .build_bit_cast(v2, self.intrinsics.i8x16_ty, "")) + let v2 = err!( + self.builder + .build_bit_cast(v2, self.intrinsics.i8x16_ty, "") + ) .into_vector_value(); let lanes = self.intrinsics.i8_ty.const_int(16, false); let lanes = @@ -9616,22 +9432,25 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )); } - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::I8x16Shuffle { lanes } => { let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; let v1 = self.apply_pending_canonicalization(v1, i1)?; - let v1 = err!(self - .builder - .build_bit_cast(v1, self.intrinsics.i8x16_ty, "")) + let v1 = err!( + self.builder + .build_bit_cast(v1, self.intrinsics.i8x16_ty, "") + ) .into_vector_value(); let v2 = self.apply_pending_canonicalization(v2, i2)?; - let v2 = err!(self - .builder - .build_bit_cast(v2, self.intrinsics.i8x16_ty, "")) + let v2 = err!( + self.builder + .build_bit_cast(v2, self.intrinsics.i8x16_ty, "") + ) .into_vector_value(); let mask = VectorType::const_vector( lanes @@ -9641,9 +9460,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { .as_slice(), ); let res = err!(self.builder.build_shuffle_vector(v1, v2, mask, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::V128Load8x8S { ref memarg } => { @@ -9656,20 +9476,24 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 8, )?; - let v = - err!(self - .builder - .build_load(self.intrinsics.i64_ty, effective_address, "")); - let v = err!(self - .builder - .build_bit_cast(v, self.intrinsics.i8_ty.vec_type(8), "")) + let v = err!(self.builder.build_load( + self.intrinsics.i64_ty, + effective_address, + "" + )); + let v = err!( + self.builder + .build_bit_cast(v, self.intrinsics.i8_ty.vec_type(8), "") + ) .into_vector_value(); - let res = err!(self - .builder - .build_int_s_extend(v, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_s_extend(v, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::V128Load8x8U { ref memarg } => { @@ -9682,20 +9506,24 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 8, )?; - let v = - err!(self - .builder - .build_load(self.intrinsics.i64_ty, effective_address, "")); - let v = err!(self - .builder - .build_bit_cast(v, self.intrinsics.i8_ty.vec_type(8), "")) + let v = err!(self.builder.build_load( + self.intrinsics.i64_ty, + effective_address, + "" + )); + let v = err!( + self.builder + .build_bit_cast(v, self.intrinsics.i8_ty.vec_type(8), "") + ) .into_vector_value(); - let res = err!(self - .builder - .build_int_z_extend(v, self.intrinsics.i16x8_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_int_z_extend(v, self.intrinsics.i16x8_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::V128Load16x4S { ref memarg } => { @@ -9708,21 +9536,25 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 8, )?; - let v = - err!(self - .builder - .build_load(self.intrinsics.i64_ty, effective_address, "")); - let v = - err!(self - .builder - .build_bit_cast(v, self.intrinsics.i16_ty.vec_type(4), "")) - .into_vector_value(); - let res = err!(self - .builder - .build_int_s_extend(v, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let v = err!(self.builder.build_load( + self.intrinsics.i64_ty, + effective_address, + "" + )); + let v = err!(self.builder.build_bit_cast( + v, + self.intrinsics.i16_ty.vec_type(4), + "" + )) + .into_vector_value(); + let res = err!( + self.builder + .build_int_s_extend(v, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::V128Load16x4U { ref memarg } => { @@ -9735,21 +9567,25 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 8, )?; - let v = - err!(self - .builder - .build_load(self.intrinsics.i64_ty, effective_address, "")); - let v = - err!(self - .builder - .build_bit_cast(v, self.intrinsics.i16_ty.vec_type(4), "")) - .into_vector_value(); - let res = err!(self - .builder - .build_int_z_extend(v, self.intrinsics.i32x4_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let v = err!(self.builder.build_load( + self.intrinsics.i64_ty, + effective_address, + "" + )); + let v = err!(self.builder.build_bit_cast( + v, + self.intrinsics.i16_ty.vec_type(4), + "" + )) + .into_vector_value(); + let res = err!( + self.builder + .build_int_z_extend(v, self.intrinsics.i32x4_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::V128Load32x2S { ref memarg } => { @@ -9762,21 +9598,25 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 8, )?; - let v = - err!(self - .builder - .build_load(self.intrinsics.i64_ty, effective_address, "")); - let v = - err!(self - .builder - .build_bit_cast(v, self.intrinsics.i32_ty.vec_type(2), "")) - .into_vector_value(); - let res = err!(self - .builder - .build_int_s_extend(v, self.intrinsics.i64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let v = err!(self.builder.build_load( + self.intrinsics.i64_ty, + effective_address, + "" + )); + let v = err!(self.builder.build_bit_cast( + v, + self.intrinsics.i32_ty.vec_type(2), + "" + )) + .into_vector_value(); + let res = err!( + self.builder + .build_int_s_extend(v, self.intrinsics.i64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::V128Load32x2U { ref memarg } => { @@ -9789,21 +9629,25 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 8, )?; - let v = - err!(self - .builder - .build_load(self.intrinsics.i64_ty, effective_address, "")); - let v = - err!(self - .builder - .build_bit_cast(v, self.intrinsics.i32_ty.vec_type(2), "")) - .into_vector_value(); - let res = err!(self - .builder - .build_int_z_extend(v, self.intrinsics.i64x2_ty, "")); - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let v = err!(self.builder.build_load( + self.intrinsics.i64_ty, + effective_address, + "" + )); + let v = err!(self.builder.build_bit_cast( + v, + self.intrinsics.i32_ty.vec_type(2), + "" + )) + .into_vector_value(); + let res = err!( + self.builder + .build_int_z_extend(v, self.intrinsics.i64x2_ty, "") + ); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::V128Load32Zero { ref memarg } => { @@ -9816,10 +9660,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 4, )?; - let elem = - err!(self - .builder - .build_load(self.intrinsics.i32_ty, effective_address, "")); + let elem = err!(self.builder.build_load( + self.intrinsics.i32_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -9843,10 +9688,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 8, )?; - let elem = - err!(self - .builder - .build_load(self.intrinsics.i64_ty, effective_address, "")); + let elem = err!(self.builder.build_load( + self.intrinsics.i64_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -9870,10 +9716,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 1, )?; - let elem = - err!(self - .builder - .build_load(self.intrinsics.i8_ty, effective_address, "")); + let elem = err!(self.builder.build_load( + self.intrinsics.i8_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -9881,9 +9728,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { elem.as_instruction_value().unwrap(), )?; let res = self.splat_vector(elem, self.intrinsics.i8x16_ty)?; - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::V128Load16Splat { ref memarg } => { @@ -9896,10 +9744,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 2, )?; - let elem = - err!(self - .builder - .build_load(self.intrinsics.i16_ty, effective_address, "")); + let elem = err!(self.builder.build_load( + self.intrinsics.i16_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -9907,9 +9756,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { elem.as_instruction_value().unwrap(), )?; let res = self.splat_vector(elem, self.intrinsics.i16x8_ty)?; - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::V128Load32Splat { ref memarg } => { @@ -9922,10 +9772,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 4, )?; - let elem = - err!(self - .builder - .build_load(self.intrinsics.i32_ty, effective_address, "")); + let elem = err!(self.builder.build_load( + self.intrinsics.i32_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -9933,9 +9784,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { elem.as_instruction_value().unwrap(), )?; let res = self.splat_vector(elem, self.intrinsics.i32x4_ty)?; - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::V128Load64Splat { ref memarg } => { @@ -9948,10 +9800,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { offset, 8, )?; - let elem = - err!(self - .builder - .build_load(self.intrinsics.i64_ty, effective_address, "")); + let elem = err!(self.builder.build_load( + self.intrinsics.i64_ty, + effective_address, + "" + )); self.annotate_user_memaccess( memory_index, memarg, @@ -9959,9 +9812,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { elem.as_instruction_value().unwrap(), )?; let res = self.splat_vector(elem, self.intrinsics.i64x2_ty)?; - let res = err!(self - .builder - .build_bit_cast(res, self.intrinsics.i128_ty, "")); + let res = err!( + self.builder + .build_bit_cast(res, self.intrinsics.i128_ty, "") + ); self.state.push1(res); } Operator::AtomicFence => { @@ -10006,10 +9860,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 8, )?; self.trap_if_misaligned(memarg, effective_address, 8)?; - let result = - err!(self - .builder - .build_load(self.intrinsics.i64_ty, effective_address, "")); + let result = err!(self.builder.build_load( + self.intrinsics.i64_ty, + effective_address, + "" + )); let load = result.as_instruction_value().unwrap(); self.annotate_user_memaccess(memory_index, memarg, 8, load)?; load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) @@ -10027,11 +9882,12 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i8_ty, effective_address, "")) - .into_int_value(); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i8_ty, + effective_address, + "" + )) + .into_int_value(); let load = narrow_result.as_instruction_value().unwrap(); self.annotate_user_memaccess(memory_index, memarg, 1, load)?; load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) @@ -10054,11 +9910,12 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i16_ty, effective_address, "")) - .into_int_value(); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i16_ty, + effective_address, + "" + )) + .into_int_value(); let load = narrow_result.as_instruction_value().unwrap(); self.annotate_user_memaccess(memory_index, memarg, 2, load)?; load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) @@ -10081,11 +9938,12 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i8_ty, effective_address, "")) - .into_int_value(); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i8_ty, + effective_address, + "" + )) + .into_int_value(); let load = narrow_result.as_instruction_value().unwrap(); self.annotate_user_memaccess(memory_index, memarg, 1, load)?; load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) @@ -10108,11 +9966,12 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i16_ty, effective_address, "")) - .into_int_value(); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i16_ty, + effective_address, + "" + )) + .into_int_value(); let load = narrow_result.as_instruction_value().unwrap(); self.annotate_user_memaccess(memory_index, memarg, 2, load)?; load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) @@ -10135,11 +9994,12 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 4, )?; self.trap_if_misaligned(memarg, effective_address, 4)?; - let narrow_result = - err!(self - .builder - .build_load(self.intrinsics.i32_ty, effective_address, "")) - .into_int_value(); + let narrow_result = err!(self.builder.build_load( + self.intrinsics.i32_ty, + effective_address, + "" + )) + .into_int_value(); let load = narrow_result.as_instruction_value().unwrap(); self.annotate_user_memaccess(memory_index, memarg, 4, load)?; load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) @@ -10199,10 +10059,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); let store = err!(self.builder.build_store(effective_address, narrow_value)); self.annotate_user_memaccess(memory_index, memarg, 1, store)?; store @@ -10222,10 +10083,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); let store = err!(self.builder.build_store(effective_address, narrow_value)); self.annotate_user_memaccess(memory_index, memarg, 2, store)?; store @@ -10244,10 +10106,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 4, )?; self.trap_if_misaligned(memarg, effective_address, 4)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i32_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i32_ty, + "" + )); let store = err!(self.builder.build_store(effective_address, narrow_value)); self.annotate_user_memaccess(memory_index, memarg, 4, store)?; store @@ -10266,10 +10129,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10285,9 +10149,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { format!("memory {}", memory_index.as_u32()), old.as_instruction_value().unwrap(), ); - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16AddU { ref memarg } => { @@ -10302,10 +10167,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10321,9 +10187,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { format!("memory {}", memory_index.as_u32()), old.as_instruction_value().unwrap(), ); - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwAdd { ref memarg } => { @@ -10367,10 +10234,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10386,9 +10254,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw16AddU { ref memarg } => { @@ -10403,10 +10272,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10422,9 +10292,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32AddU { ref memarg } => { @@ -10439,10 +10310,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 4, )?; self.trap_if_misaligned(memarg, effective_address, 4)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i32_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i32_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10458,9 +10330,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwAdd { ref memarg } => { @@ -10504,10 +10377,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10523,9 +10397,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16SubU { ref memarg } => { @@ -10540,10 +10415,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10559,9 +10435,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwSub { ref memarg } => { @@ -10605,10 +10482,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10624,9 +10502,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I64AtomicRmw16SubU { ref memarg } => { @@ -10641,10 +10520,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10660,9 +10540,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32SubU { ref memarg } => { @@ -10677,10 +10558,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 4, )?; self.trap_if_misaligned(memarg, effective_address, 4)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i32_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i32_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10696,9 +10578,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwSub { ref memarg } => { @@ -10742,10 +10625,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10761,9 +10645,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16AndU { ref memarg } => { @@ -10778,10 +10663,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10797,9 +10683,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwAnd { ref memarg } => { @@ -10843,10 +10730,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10862,9 +10750,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw16AndU { ref memarg } => { @@ -10879,10 +10768,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10898,9 +10788,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32AndU { ref memarg } => { @@ -10915,10 +10806,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 4, )?; self.trap_if_misaligned(memarg, effective_address, 4)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i32_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i32_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10934,9 +10826,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwAnd { ref memarg } => { @@ -10980,10 +10873,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -10999,9 +10893,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16OrU { ref memarg } => { @@ -11016,10 +10911,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -11035,9 +10931,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwOr { ref memarg } => { @@ -11067,9 +10964,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I64AtomicRmw8OrU { ref memarg } => { @@ -11084,10 +10982,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -11103,9 +11002,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw16OrU { ref memarg } => { @@ -11120,10 +11020,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -11139,9 +11040,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32OrU { ref memarg } => { @@ -11156,10 +11058,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 4, )?; self.trap_if_misaligned(memarg, effective_address, 4)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i32_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i32_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -11175,9 +11078,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwOr { ref memarg } => { @@ -11221,10 +11125,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -11240,9 +11145,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16XorU { ref memarg } => { @@ -11257,10 +11163,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -11276,9 +11183,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwXor { ref memarg } => { @@ -11322,10 +11230,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -11341,9 +11250,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw16XorU { ref memarg } => { @@ -11358,10 +11268,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -11377,9 +11288,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32XorU { ref memarg } => { @@ -11394,10 +11306,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 4, )?; self.trap_if_misaligned(memarg, effective_address, 4)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i32_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i32_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -11413,9 +11326,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwXor { ref memarg } => { @@ -11459,10 +11373,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -11478,9 +11393,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16XchgU { ref memarg } => { @@ -11495,10 +11411,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -11514,9 +11431,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwXchg { ref memarg } => { @@ -11560,10 +11478,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i8_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i8_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -11579,9 +11498,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw16XchgU { ref memarg } => { @@ -11596,10 +11516,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i16_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i16_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -11615,9 +11536,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32XchgU { ref memarg } => { @@ -11632,10 +11554,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 4, )?; self.trap_if_misaligned(memarg, effective_address, 4)?; - let narrow_value = - err!(self - .builder - .build_int_truncate(value, self.intrinsics.i32_ty, "")); + let narrow_value = err!(self.builder.build_int_truncate( + value, + self.intrinsics.i32_ty, + "" + )); let old = self .builder .build_atomicrmw( @@ -11651,9 +11574,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 0, old.as_instruction_value().unwrap(), )?; - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwXchg { ref memarg } => { @@ -11700,14 +11624,16 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_cmp = - err!(self - .builder - .build_int_truncate(cmp, self.intrinsics.i8_ty, "")); - let narrow_new = - err!(self - .builder - .build_int_truncate(new, self.intrinsics.i8_ty, "")); + let narrow_cmp = err!(self.builder.build_int_truncate( + cmp, + self.intrinsics.i8_ty, + "" + )); + let narrow_new = err!(self.builder.build_int_truncate( + new, + self.intrinsics.i8_ty, + "" + )); let old = self .builder .build_cmpxchg( @@ -11729,9 +11655,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { .build_extract_value(old, 0, "") .unwrap() .into_int_value(); - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16CmpxchgU { ref memarg } => { @@ -11749,14 +11676,16 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_cmp = - err!(self - .builder - .build_int_truncate(cmp, self.intrinsics.i16_ty, "")); - let narrow_new = - err!(self - .builder - .build_int_truncate(new, self.intrinsics.i16_ty, "")); + let narrow_cmp = err!(self.builder.build_int_truncate( + cmp, + self.intrinsics.i16_ty, + "" + )); + let narrow_new = err!(self.builder.build_int_truncate( + new, + self.intrinsics.i16_ty, + "" + )); let old = self .builder .build_cmpxchg( @@ -11778,9 +11707,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { .build_extract_value(old, 0, "") .unwrap() .into_int_value(); - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i32_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i32_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwCmpxchg { ref memarg } => { @@ -11832,14 +11762,16 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 1, )?; self.trap_if_misaligned(memarg, effective_address, 1)?; - let narrow_cmp = - err!(self - .builder - .build_int_truncate(cmp, self.intrinsics.i8_ty, "")); - let narrow_new = - err!(self - .builder - .build_int_truncate(new, self.intrinsics.i8_ty, "")); + let narrow_cmp = err!(self.builder.build_int_truncate( + cmp, + self.intrinsics.i8_ty, + "" + )); + let narrow_new = err!(self.builder.build_int_truncate( + new, + self.intrinsics.i8_ty, + "" + )); let old = self .builder .build_cmpxchg( @@ -11861,9 +11793,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { .build_extract_value(old, 0, "") .unwrap() .into_int_value(); - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw16CmpxchgU { ref memarg } => { @@ -11881,14 +11814,16 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 2, )?; self.trap_if_misaligned(memarg, effective_address, 2)?; - let narrow_cmp = - err!(self - .builder - .build_int_truncate(cmp, self.intrinsics.i16_ty, "")); - let narrow_new = - err!(self - .builder - .build_int_truncate(new, self.intrinsics.i16_ty, "")); + let narrow_cmp = err!(self.builder.build_int_truncate( + cmp, + self.intrinsics.i16_ty, + "" + )); + let narrow_new = err!(self.builder.build_int_truncate( + new, + self.intrinsics.i16_ty, + "" + )); let old = self .builder .build_cmpxchg( @@ -11910,9 +11845,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { .build_extract_value(old, 0, "") .unwrap() .into_int_value(); - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32CmpxchgU { ref memarg } => { @@ -11930,14 +11866,16 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { 4, )?; self.trap_if_misaligned(memarg, effective_address, 4)?; - let narrow_cmp = - err!(self - .builder - .build_int_truncate(cmp, self.intrinsics.i32_ty, "")); - let narrow_new = - err!(self - .builder - .build_int_truncate(new, self.intrinsics.i32_ty, "")); + let narrow_cmp = err!(self.builder.build_int_truncate( + cmp, + self.intrinsics.i32_ty, + "" + )); + let narrow_new = err!(self.builder.build_int_truncate( + new, + self.intrinsics.i32_ty, + "" + )); let old = self .builder .build_cmpxchg( @@ -11959,9 +11897,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { .build_extract_value(old, 0, "") .unwrap() .into_int_value(); - let old = err!(self - .builder - .build_int_z_extend(old, self.intrinsics.i64_ty, "")); + let old = err!( + self.builder + .build_int_z_extend(old, self.intrinsics.i64_ty, "") + ); self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwCmpxchg { ref memarg } => { @@ -12013,7 +11952,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ], "", )); - self.state.push1(grow.try_as_basic_value().left().unwrap()); + self.state.push1(grow.try_as_basic_value().unwrap_basic()); } Operator::MemorySize { mem } => { let memory_index = MemoryIndex::from_u32(mem); @@ -12028,7 +11967,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )); //size.add_attribute(AttributeLoc::Function, self.intrinsics.readonly); - self.state.push1(size.try_as_basic_value().left().unwrap()); + self.state.push1(size.try_as_basic_value().unwrap_basic()); } Operator::MemoryInit { data_index, mem } => { let (dest, src, len) = self.state.pop3()?; @@ -12117,10 +12056,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { Operator::RefIsNull => { let value = self.state.pop1()?.into_pointer_value(); let is_null = err!(self.builder.build_is_null(value, "")); - let is_null = - err!(self - .builder - .build_int_z_extend(is_null, self.intrinsics.i32_ty, "")); + let is_null = err!(self.builder.build_int_z_extend( + is_null, + self.intrinsics.i32_ty, + "" + )); self.state.push1(is_null); } Operator::RefFunc { function_index } => { @@ -12134,8 +12074,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1(value); } Operator::TableGet { table } => { @@ -12156,28 +12095,30 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); - let value = err!(self.builder.build_bit_cast( - value, - type_to_llvm( - self.intrinsics, - self.wasm_module - .tables - .get(TableIndex::from_u32(table)) - .unwrap() - .ty, - )?, - "", - )); + .unwrap_basic(); + let value = err!( + self.builder.build_bit_cast( + value, + type_to_llvm( + self.intrinsics, + self.wasm_module + .tables + .get(TableIndex::from_u32(table)) + .unwrap() + .ty, + )?, + "", + ) + ); self.state.push1(value); } Operator::TableSet { table } => { let table_index = self.intrinsics.i32_ty.const_int(table.into(), false); let (elem, value) = self.state.pop2()?; - let value = err!(self - .builder - .build_bit_cast(value, self.intrinsics.ptr_ty, "")); + let value = err!( + self.builder + .build_bit_cast(value, self.intrinsics.ptr_ty, "") + ); let table_set = if self .wasm_module .local_table_index(TableIndex::from_u32(table)) @@ -12246,9 +12187,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { Operator::TableFill { table } => { let table = self.intrinsics.i32_ty.const_int(table as u64, false); let (start, elem, len) = self.state.pop3()?; - let elem = err!(self - .builder - .build_bit_cast(elem, self.intrinsics.ptr_ty, "")); + let elem = err!( + self.builder + .build_bit_cast(elem, self.intrinsics.ptr_ty, "") + ); err!(self.builder.build_call( self.intrinsics.table_fill, &[ @@ -12263,9 +12205,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { } Operator::TableGrow { table } => { let (elem, delta) = self.state.pop2()?; - let elem = err!(self - .builder - .build_bit_cast(elem, self.intrinsics.ptr_ty, "")); + let elem = err!( + self.builder + .build_bit_cast(elem, self.intrinsics.ptr_ty, "") + ); let (table_grow, table_index) = if let Some(local_table_index) = self .wasm_module .local_table_index(TableIndex::from_u32(table)) @@ -12286,8 +12229,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1(size); } Operator::TableSize { table } => { @@ -12306,71 +12248,76 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { "", )) .try_as_basic_value() - .left() - .unwrap(); + .unwrap_basic(); self.state.push1(size); } Operator::MemoryAtomicWait32 { memarg } => { let memory_index = MemoryIndex::from_u32(memarg.memory); let (dst, val, timeout) = self.state.pop3()?; let wait32_fn_ptr = self.ctx.memory_wait32(memory_index, self.intrinsics)?; - let ret = err!(self.builder.build_indirect_call( - self.intrinsics.memory_wait32_ty, - wait32_fn_ptr, - &[ - vmctx.as_basic_value_enum().into(), - self.intrinsics - .i32_ty - .const_int(memarg.memory as u64, false) - .into(), - dst.into(), - val.into(), - timeout.into(), - ], - "", - )); - self.state.push1(ret.try_as_basic_value().left().unwrap()); + let ret = err!( + self.builder.build_indirect_call( + self.intrinsics.memory_wait32_ty, + wait32_fn_ptr, + &[ + vmctx.as_basic_value_enum().into(), + self.intrinsics + .i32_ty + .const_int(memarg.memory as u64, false) + .into(), + dst.into(), + val.into(), + timeout.into(), + ], + "", + ) + ); + self.state.push1(ret.try_as_basic_value().unwrap_basic()); } Operator::MemoryAtomicWait64 { memarg } => { let memory_index = MemoryIndex::from_u32(memarg.memory); let (dst, val, timeout) = self.state.pop3()?; let wait64_fn_ptr = self.ctx.memory_wait64(memory_index, self.intrinsics)?; - let ret = err!(self.builder.build_indirect_call( - self.intrinsics.memory_wait64_ty, - wait64_fn_ptr, - &[ - vmctx.as_basic_value_enum().into(), - self.intrinsics - .i32_ty - .const_int(memarg.memory as u64, false) - .into(), - dst.into(), - val.into(), - timeout.into(), - ], - "", - )); - self.state.push1(ret.try_as_basic_value().left().unwrap()); + let ret = err!( + self.builder.build_indirect_call( + self.intrinsics.memory_wait64_ty, + wait64_fn_ptr, + &[ + vmctx.as_basic_value_enum().into(), + self.intrinsics + .i32_ty + .const_int(memarg.memory as u64, false) + .into(), + dst.into(), + val.into(), + timeout.into(), + ], + "", + ) + ); + self.state.push1(ret.try_as_basic_value().unwrap_basic()); } Operator::MemoryAtomicNotify { memarg } => { let memory_index = MemoryIndex::from_u32(memarg.memory); let (dst, count) = self.state.pop2()?; let notify_fn_ptr = self.ctx.memory_notify(memory_index, self.intrinsics)?; - let cnt = err!(self.builder.build_indirect_call( - self.intrinsics.memory_notify_ty, - notify_fn_ptr, - &[ - vmctx.as_basic_value_enum().into(), - self.intrinsics - .i32_ty - .const_int(memarg.memory as u64, false) - .into(), - dst.into(), - count.into(), - ], - "", - )); - self.state.push1(cnt.try_as_basic_value().left().unwrap()); + let cnt = err!( + self.builder.build_indirect_call( + self.intrinsics.memory_notify_ty, + notify_fn_ptr, + &[ + vmctx.as_basic_value_enum().into(), + self.intrinsics + .i32_ty + .const_int(memarg.memory as u64, false) + .into(), + dst.into(), + count.into(), + ], + "", + ) + ); + self.state.push1(cnt.try_as_basic_value().unwrap_basic()); } Operator::TryTable { try_table } => { @@ -12417,10 +12364,6 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { // Build the landing pad. let null = self.intrinsics.ptr_ty.const_zero(); - let exception_type = self.context.struct_type( - &[self.intrinsics.ptr_ty.into(), self.intrinsics.i32_ty.into()], - false, - ); let mut catch_tag_values = vec![]; let mut lpad_clauses: Vec> = catches @@ -12477,7 +12420,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { self.builder.position_at_end(lpad_block); let res = err!(self.builder.build_landing_pad( - exception_type, + self.intrinsics.lpad_exception_ty, self.intrinsics.personality, &lpad_clauses, false, @@ -12508,15 +12451,9 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { err!(self.builder.build_unconditional_branch(catch_end_block)); self.builder.position_at_end(catch_specific_block); - let vmctx_alloca = err!(self.build_or_get_vmctx_alloca()); - let vmctx_ptr = err!(self.builder.build_load( - self.intrinsics.ptr_ty, - vmctx_alloca, - "vmctx" - )); let selector_value = err!(self.builder.build_call( self.intrinsics.personality2, - &[vmctx_ptr.into(), uw_exc.into()], + &[self.ctx.basic().into(), uw_exc.into()], "selector" )); err!(self.builder.build_unconditional_branch(catch_end_block)); @@ -12534,27 +12471,64 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { ( &selector_value .try_as_basic_value() - .left() - .unwrap() + .unwrap_basic() .into_int_value(), catch_specific_block, ), ]); - // The exception we get at this point is a wrapper around the [`WasmerException`] - // type. This is needed because when we create the exception to pass it to - // libunwind, the exception object needs to begin with a specific set of fields - // (those in `__Unwind_Exception`). During unwinding, libunwind uses some of these - // fields and we need to pass them back when rethrowing. This to say, we need to - // keep the original exception passed to us by libunwind to be able to rethrow it. + // Now we're done looking at the exception, it's time to deallocate and get + // the exnref out of it. When an exception is caught, "rethrowing" simply + // means starting another unwind by calling _Unwind_RaiseException with the + // same exception bits. Instead of keeping the same exception around, we + // deallocate the exception once it's caught, and if we need to rethrow, we + // just re-allocate a new exception. + // + // Note that this is different from how it's done in C++ land, where the + // exception object is kept around for rethrowing; this discrepency exists + // because in C++, exception handling is lexical (i.e. there's an implicit + // "current exception" in catch blocks) whereas in WASM, you rethrow with + // an exnref that may very well have come from somewhere else; consider this + // (badly implemented and erroneous) pseudo-module: + // + // (module + // (global $e (mut exnref) (ref.null exn)) + // ;; Store the given exnref, return the previous one + // (func $delay_exnref (param exnref) (result exnref) + // (global.get $e) + // (local.get 0) + // (global.set $e) + // ) + // (func foo + // (block $catch (result exnref) + // (try_table (catch_all_ref $catch) + // ... + // ) + // ) + // (call $delay_exnref) ;; store the exnref caught above + // throw_ref ;; throw the previous exnref + // ) + // ) + // + // Here, it's impossible to reuse the same exception object since the + // exnref given to throw_ref is a different one than the one we caught + // with the try_table. + // + // Another difference is that C++ exceptions may well carry lots of data + // around; a WASM exception is just an exnref, backed by a u32, which is + // just 4 bytes, and is cheap to reallocate. C++ exceptions may also carry + // things with dtors around; another thing that doesn't exist in WASM. + // + // All of this is to say that putting exception deallocation and exnref + // retrieval in the same function has been a very deliberate choice. let uw_exc = uw_exc.into_pointer_value(); - let wasmer_exc = err!(self.builder.build_call( - self.intrinsics.read_exception, + let exnref = err!(self.builder.build_call( + self.intrinsics.exception_into_exnref, &[uw_exc.into()], - "wasmer_exc_ptr" + "exnref" )); - let wasmer_exc = wasmer_exc.as_any_value_enum().into_pointer_value(); + let exnref = exnref.try_as_basic_value().unwrap_basic().into_int_value(); let selector = selector.as_basic_value().into_int_value(); for catch in catches.iter() { @@ -12569,65 +12543,52 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { err!(self.builder.build_unconditional_branch(*frame.br_dest())); self.builder.position_at_end(catch_end_block); - catch_blocks.push((b, None, None)); + catch_blocks.push((b, None)); } Catch::One { tag, label } => { let tag_idx = self.wasm_module.tags[TagIndex::from_u32(*tag)]; let signature = &self.wasm_module.signatures[tag_idx]; let params = signature.params(); - let b = self - .context - .append_basic_block(self.function, "catch_one_clause"); + let b = self.context.append_basic_block( + self.function, + format!("catch_one_clause_{tag}").as_str(), + ); self.builder.position_at_end(b); - let wasmer_exc_phi = err!(self - .builder - .build_phi(self.intrinsics.ptr_ty, "wasmer_exc_phi")); - wasmer_exc_phi.add_incoming(&[(&wasmer_exc, catch_end_block)]); - - // Get the type of the exception. - let inner_exc_ty = - self.get_or_insert_exception_type(*tag, signature)?; - - // Cast the outer exception - a pointer - to a pointer to a struct of - // type WasmerException. - // let wasmer_exc_ptr = err!(self.builder.build_pointer_cast( - // exc, - // self.intrinsics.exc_ty, - // "wasmer_exc_ptr" - // )); - // - // Not actually needed, since ptr is a single, unique type. - - // Points at the `data` field of the exception. - let wasmer_exc_data_ptr_ptr = err!(self.builder.build_struct_gep( - self.intrinsics.exc_ty, - wasmer_exc_phi.as_basic_value().into_pointer_value(), - 1, - "wasmer_exc_data_ptr_ptr" - )); + let exnref_phi = err!( + self.builder.build_phi(self.intrinsics.i32_ty, "exnref_phi") + ); + exnref_phi.add_incoming(&[(&exnref, catch_end_block)]); - let wasmer_exc_data_ptr = err!(self.builder.build_load( - self.intrinsics.ptr_ty, - wasmer_exc_data_ptr_ptr, - "wasmer_exc_data_ptr" + // Get the payload pointer. + let exn_payload_ptr = err!(self.builder.build_direct_call( + self.intrinsics.read_exnref, + &[self.ctx.basic().into(), exnref_phi.as_basic_value().into()], + "exn_ptr", )); - - let wasmer_exc_data_ptr = wasmer_exc_data_ptr.into_pointer_value(); + let exn_payload_ptr = exn_payload_ptr + .try_as_basic_value() + .unwrap_basic() + .into_pointer_value(); // Read each value from the data ptr. let values = params .iter() .enumerate() .map(|(i, v)| { - let name = format!("value{i}"); - let ptr = err!(self.builder.build_struct_gep( - inner_exc_ty, - wasmer_exc_data_ptr, - i as u32, - &(name.clone() + "ptr") - )); + let name = format!("value_{i}"); + let ptr = err!(unsafe { + self.builder.build_gep( + self.intrinsics.i128_ty, + exn_payload_ptr, + &[self + .intrinsics + .i32_ty + .const_int(i as u64, false)], + format!("{name}_ptr").as_str(), + ) + }); err_nt!(self.builder.build_load( type_to_llvm(self.intrinsics, *v)?, ptr, @@ -12638,8 +12599,6 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let frame = self.state.frame_at_depth(*label)?; - // todo: check that the types are compatible - for (phi, value) in frame.phis().iter().zip(values.iter()) { phi.add_incoming(&[(value, b)]) } @@ -12647,70 +12606,52 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { err!(self.builder.build_unconditional_branch(*frame.br_dest())); self.builder.position_at_end(catch_end_block); - catch_blocks.push((b, Some(wasmer_exc_phi), None)); + catch_blocks.push((b, Some(exnref_phi))); } Catch::OneRef { label, tag } => { let tag_idx = self.wasm_module.tags[TagIndex::from_u32(*tag)]; let signature = &self.wasm_module.signatures[tag_idx]; let params = signature.params(); - let b = self - .context - .append_basic_block(self.function, "catch_one_ref_clause"); + let b = self.context.append_basic_block( + self.function, + format!("catch_one_ref_clause_{tag}").as_str(), + ); self.builder.position_at_end(b); - let wasmer_exc_phi = err!(self - .builder - .build_phi(self.intrinsics.ptr_ty, "wasmer_exc_phi")); - wasmer_exc_phi.add_incoming(&[(&wasmer_exc, catch_end_block)]); - - let uw_exc_ptr_phi = err!(self - .builder - .build_phi(self.intrinsics.ptr_ty, "uw_exc_ptr_phi")); - uw_exc_ptr_phi.add_incoming(&[(&uw_exc, catch_end_block)]); - - // Get the type of the exception. - let inner_exc_ty = - self.get_or_insert_exception_type(*tag, signature)?; - - // Cast the outer exception - a pointer - to a pointer to a struct of - // type WasmerException. - // let wasmer_exc_ptr = err!(self.builder.build_pointer_cast( - // exc, - // self.intrinsics.exc_ty, - // "wasmer_exc_ptr" - // )); - // - // Not actually needed, since ptr is a single, unique type. - - // Points at the `data` field of the exception. - let wasmer_exc_data_ptr_ptr = err!(self.builder.build_struct_gep( - self.intrinsics.exc_ty, - wasmer_exc_phi.as_basic_value().into_pointer_value(), - 1, - "wasmer_exc_data_ptr" - )); + let exnref_phi = err!( + self.builder.build_phi(self.intrinsics.i32_ty, "exnref_phi") + ); + exnref_phi.add_incoming(&[(&exnref, catch_end_block)]); - let wasmer_exc_data_ptr = err!(self.builder.build_load( - self.intrinsics.ptr_ty, - wasmer_exc_data_ptr_ptr, - "wasmer_exc_data_ptr" + // Get the payload pointer. + let exn_payload_ptr = err!(self.builder.build_direct_call( + self.intrinsics.read_exnref, + &[self.ctx.basic().into(), exnref_phi.as_basic_value().into()], + "exn_ptr", )); - - let wasmer_exc_data_ptr = wasmer_exc_data_ptr.into_pointer_value(); + let exn_payload_ptr = exn_payload_ptr + .try_as_basic_value() + .unwrap_basic() + .into_pointer_value(); // Read each value from the data ptr. let mut values = params .iter() .enumerate() .map(|(i, v)| { - let name = format!("value{i}"); - let ptr = err!(self.builder.build_struct_gep( - inner_exc_ty, - wasmer_exc_data_ptr, - i as u32, - &(name.clone() + "ptr") - )); + let name = format!("value_{i}"); + let ptr = err!(unsafe { + self.builder.build_gep( + self.intrinsics.i128_ty, + exn_payload_ptr, + &[self + .intrinsics + .i32_ty + .const_int(i as u64, false)], + format!("{name}_ptr").as_str(), + ) + }); err_nt!(self.builder.build_load( type_to_llvm(self.intrinsics, *v)?, ptr, @@ -12719,12 +12660,10 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { }) .collect::, CompileError>>()?; - values.push(uw_exc_ptr_phi.as_basic_value()); + values.push(exnref_phi.as_basic_value()); let frame = self.state.frame_at_depth(*label)?; - // todo: check that the types are compatible - for (phi, value) in frame.phis().iter().zip(values.iter()) { phi.add_incoming(&[(value, b)]) } @@ -12732,7 +12671,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { err!(self.builder.build_unconditional_branch(*frame.br_dest())); self.builder.position_at_end(catch_end_block); - catch_blocks.push((b, Some(wasmer_exc_phi), Some(uw_exc_ptr_phi))); + catch_blocks.push((b, Some(exnref_phi))); } Catch::AllRef { label } => { let b = self @@ -12740,60 +12679,53 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { .append_basic_block(self.function, "catch_all_ref_clause"); self.builder.position_at_end(b); - let uw_exc_ptr_phi = err!(self - .builder - .build_phi(self.intrinsics.ptr_ty, "uw_exc_ptr_phi")); - uw_exc_ptr_phi.add_incoming(&[(&uw_exc, catch_end_block)]); + let exnref_phi = err!( + self.builder.build_phi(self.intrinsics.i32_ty, "exnref_phi") + ); + exnref_phi.add_incoming(&[(&exnref, catch_end_block)]); let frame = self.state.frame_at_depth(*label)?; let phis = frame.phis(); - // sanity check (todo): check that the phi has only one element - - for phi in phis.iter() { - phi.add_incoming(&[(&uw_exc_ptr_phi.as_basic_value(), b)]) - } + assert_eq!(phis.len(), 1); + phis[0].add_incoming(&[(&exnref_phi.as_basic_value(), b)]); err!(self.builder.build_unconditional_branch(*frame.br_dest())); self.builder.position_at_end(catch_end_block); - catch_blocks.push((b, None, Some(uw_exc_ptr_phi))); + catch_blocks.push((b, Some(exnref_phi))); } } } for catch_info in &outer_catch_blocks { - if let Some(phi) = catch_info.wasmer_exc_phi { - phi.add_incoming(&[( - &wasmer_exc.as_basic_value_enum(), - catch_end_block, - )]); - } - if let Some(phi) = catch_info.uw_exc_ptr_phi { - phi.add_incoming(&[(&uw_exc.as_basic_value_enum(), catch_end_block)]); + if let Some(phi) = catch_info.exnref_phi { + phi.add_incoming(&[(&exnref, catch_end_block)]); } } - err!(self.builder.build_switch( - selector, - rethrow_block, - catch_blocks - .iter() - .enumerate() - .map(|(i, v)| ( - self.intrinsics - .i32_ty - .const_int(catch_tag_values[i] as _, false), - v.0 - )) - .chain(outer_catch_blocks.iter().map(|catch_info| ( - self.intrinsics.i32_ty.const_int(catch_info.tag as _, false), - catch_info.catch_block - ))) - .collect::>() - .as_slice() - )); + err!( + self.builder.build_switch( + selector, + rethrow_block, + catch_blocks + .iter() + .enumerate() + .map(|(i, v)| ( + self.intrinsics + .i32_ty + .const_int(catch_tag_values[i] as _, false), + v.0 + )) + .chain(outer_catch_blocks.iter().map(|catch_info| ( + self.intrinsics.i32_ty.const_int(catch_info.tag as _, false), + catch_info.catch_block + ))) + .collect::>() + .as_slice() + ) + ); // -- end @@ -12801,8 +12733,8 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { self.builder.position_at_end(rethrow_block); err!(self.builder.build_call( - self.intrinsics.rethrow, - &[uw_exc.into()], + self.intrinsics.throw, + &[self.ctx.basic().into(), exnref.into()], "rethrow" )); // can't reach after an explicit throw! @@ -12819,14 +12751,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { let catch_tags_and_blocks = catch_tag_values .into_iter() .zip(catch_blocks) - .map( - |(tag, (block, wasmer_exc_phi, uw_exc_ptr_phi))| TagCatchInfo { - tag, - catch_block: block, - wasmer_exc_phi, - uw_exc_ptr_phi, - }, - ) + .map(|(tag, (block, exnref_phi))| TagCatchInfo { + tag, + catch_block: block, + exnref_phi, + }) .collect::>(); self.state.push_landingpad( maybe_lpad_block, @@ -12845,17 +12774,11 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { .get_insert_block() .ok_or_else(|| CompileError::Codegen("not currently in a block".to_string()))?; - let tag = self.wasm_module.tags[TagIndex::from_u32(tag_index)]; - let signature = &self.wasm_module.signatures[tag]; + let sig_index = self.wasm_module.tags[TagIndex::from_u32(tag_index)]; + let signature = &self.wasm_module.signatures[sig_index]; let params = signature.params(); let values = self.state.popn_save_extra(params.len())?; - let vmctx_alloca = err!(self.build_or_get_vmctx_alloca()); - let vmctx_ptr = - err!(self - .builder - .build_load(self.intrinsics.ptr_ty, vmctx_alloca, "vmctx")); - values.iter().enumerate().try_for_each(|(i, (v, _))| { let t = type_to_llvm(self.intrinsics, params[i])?; if t != v.get_type() { @@ -12869,27 +12792,41 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { Ok(()) })?; - let exception_type: inkwell::types::StructType = - self.get_or_insert_exception_type(tag_index, signature)?; - - let size = exception_type.size_of().unwrap(); - // Allocate the necessary bytes for the exception. - let exc = err!(self.builder.build_direct_call( - self.intrinsics.alloc_exception, - &[size.into()], - "exception_ptr", + let exnref = err!( + self.builder.build_direct_call( + self.intrinsics.alloc_exception, + &[ + self.ctx.basic().into(), + self.intrinsics + .i32_ty + .const_int(tag_index as _, false) + .into() + ], + "exnref", + ) + ); + let exnref = exnref.try_as_basic_value().unwrap_basic(); + + let exn_payload_ptr = err!(self.builder.build_direct_call( + self.intrinsics.read_exnref, + &[self.ctx.basic().into(), exnref.into()], + "exn_ptr", )); - let exc = exc.try_as_basic_value().left().unwrap(); - let exc = exc.into_pointer_value(); + let exn_payload_ptr = exn_payload_ptr + .try_as_basic_value() + .unwrap_basic() + .into_pointer_value(); for (i, value) in values.into_iter().enumerate() { - let ptr = err!(self.builder.build_struct_gep( - exception_type, - exc, - i as u32, - i.to_string().as_str(), - )); + let ptr = err!(unsafe { + self.builder.build_gep( + self.intrinsics.i128_ty, + exn_payload_ptr, + &[self.intrinsics.i32_ty.const_int(i as u64, false)], + format!("value_{i}_ptr").as_str(), + ) + }); err!(self.builder.build_store(ptr, value.0)); } @@ -12900,15 +12837,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { err!(self.builder.build_invoke( self.intrinsics.throw, - &[ - self.intrinsics - .i32_ty - .const_int(tag_index as _, false) - .into(), - vmctx_ptr, - exc.into(), - size.into() - ], + &[self.ctx.basic(), exnref], unreachable_block, pad, "throw", @@ -12922,17 +12851,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { } else { err!(self.builder.build_call( self.intrinsics.throw, - &[ - // We pass in the module-local tag index, but it'll be translated - // to a store-unique index in the `throw` intrinsic. - self.intrinsics - .i32_ty - .const_int(tag_index as _, false) - .into(), - vmctx_ptr.into(), - exc.into(), - size.into() - ], + &[self.ctx.basic().into(), exnref.into()], "throw" )); // can't reach after an explicit throw! @@ -12947,7 +12866,7 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { .get_insert_block() .ok_or_else(|| CompileError::Codegen("not currently in a block".to_string()))?; - let exc = self.state.pop1()?; + let exnref = self.state.pop1()?; if let Some(pad) = self.state.get_innermost_landingpad() { let unreachable_block = self @@ -12955,8 +12874,8 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { .append_basic_block(self.function, "_rethrow_unreachable"); err!(self.builder.build_invoke( - self.intrinsics.rethrow, - &[exc], + self.intrinsics.throw, + &[self.ctx.basic(), exnref], unreachable_block, pad, "throw", @@ -12969,9 +12888,9 @@ impl<'ctx> LLVMFunctionCodeGenerator<'ctx, '_> { self.builder.position_at_end(current_block); } else { err!(self.builder.build_call( - self.intrinsics.rethrow, - &[exc.into(),], - "rethrow" + self.intrinsics.throw, + &[self.ctx.basic().into(), exnref.into()], + "throw" )); // can't reach after an explicit throw! err!(self.builder.build_unreachable()); diff --git a/lib/compiler-llvm/src/translator/intrinsics.rs b/lib/compiler-llvm/src/translator/intrinsics.rs index 661fe5b7c5..1aa8905c1a 100644 --- a/lib/compiler-llvm/src/translator/intrinsics.rs +++ b/lib/compiler-llvm/src/translator/intrinsics.rs @@ -4,11 +4,12 @@ //! //! [llvm-intrinsics]: https://llvm.org/docs/LangRef.html#intrinsic-functions +use crate::LLVM; use crate::abi::Abi; use crate::error::err; -use crate::LLVM; use inkwell::values::BasicMetadataValueEnum; use inkwell::{ + AddressSpace, attributes::{Attribute, AttributeLoc}, builder::Builder, context::Context, @@ -22,9 +23,8 @@ use inkwell::{ BasicValue, BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue, PointerValue, VectorValue, }, - AddressSpace, }; -use std::collections::{hash_map::Entry, HashMap}; +use std::collections::{HashMap, hash_map::Entry}; use wasmer_types::entity::{EntityRef, PrimaryMap}; use wasmer_types::{ CompileError, FunctionIndex, FunctionType as FuncType, GlobalIndex, LocalFunctionIndex, @@ -50,9 +50,8 @@ pub fn type_to_llvm<'ctx>( Type::F32 => Ok(intrinsics.f32_ty.as_basic_type_enum()), Type::F64 => Ok(intrinsics.f64_ty.as_basic_type_enum()), Type::V128 => Ok(intrinsics.i128_ty.as_basic_type_enum()), - Type::FuncRef | Type::ExceptionRef | Type::ExternRef => { - Ok(intrinsics.ptr_ty.as_basic_type_enum()) - } + Type::ExceptionRef => Ok(intrinsics.i32_ty.as_basic_type_enum()), + Type::FuncRef | Type::ExternRef => Ok(intrinsics.ptr_ty.as_basic_type_enum()), } } @@ -105,6 +104,16 @@ pub struct Intrinsics<'ctx> { pub cmp_f32x4: FunctionValue<'ctx>, pub cmp_f64x2: FunctionValue<'ctx>, + pub minimum_f32: FunctionValue<'ctx>, + pub minimum_f64: FunctionValue<'ctx>, + pub minimum_f32x4: FunctionValue<'ctx>, + pub minimum_f64x2: FunctionValue<'ctx>, + + pub maximum_f32: FunctionValue<'ctx>, + pub maximum_f64: FunctionValue<'ctx>, + pub maximum_f32x4: FunctionValue<'ctx>, + pub maximum_f64x2: FunctionValue<'ctx>, + pub ceil_f32: FunctionValue<'ctx>, pub ceil_f64: FunctionValue<'ctx>, pub ceil_f32x4: FunctionValue<'ctx>, @@ -158,6 +167,8 @@ pub struct Intrinsics<'ctx> { pub stack_probe: Attribute, pub uwtable: Attribute, pub frame_pointer: Attribute, + // Stack probe function used on Windows MSVC + pub chkstk: FunctionValue<'ctx>, pub void_ty: VoidType<'ctx>, pub i1_ty: IntType<'ctx>, @@ -184,7 +195,6 @@ pub struct Intrinsics<'ctx> { pub ptr_ty: PointerType<'ctx>, pub anyfunc_ty: StructType<'ctx>, - pub exc_ty: StructType<'ctx>, pub i1_zero: IntValue<'ctx>, pub i8_zero: IntValue<'ctx>, @@ -246,10 +256,10 @@ pub struct Intrinsics<'ctx> { // EH pub throw: FunctionValue<'ctx>, - pub rethrow: FunctionValue<'ctx>, pub alloc_exception: FunctionValue<'ctx>, - pub delete_exception: FunctionValue<'ctx>, - pub read_exception: FunctionValue<'ctx>, + pub read_exnref: FunctionValue<'ctx>, + pub exception_into_exnref: FunctionValue<'ctx>, + pub lpad_exception_ty: StructType<'ctx>, // Debug pub debug_ptr: FunctionValue<'ctx>, @@ -626,6 +636,32 @@ impl<'ctx> Intrinsics<'ctx> { None, ), + minimum_f32: module.add_function("llvm.minimum.f32", ret_f32_take_f32_f32, None), + minimum_f64: module.add_function("llvm.minimum.f64", ret_f64_take_f64_f64, None), + minimum_f32x4: module.add_function( + "llvm.minimum.v4f32", + ret_f32x4_take_f32x4_f32x4, + None, + ), + minimum_f64x2: module.add_function( + "llvm.minimum.v2f64", + ret_f64x2_take_f64x2_f64x2, + None, + ), + + maximum_f32: module.add_function("llvm.maximum.f32", ret_f32_take_f32_f32, None), + maximum_f64: module.add_function("llvm.maximum.f64", ret_f64_take_f64_f64, None), + maximum_f32x4: module.add_function( + "llvm.maximum.v4f32", + ret_f32x4_take_f32x4_f32x4, + None, + ), + maximum_f64x2: module.add_function( + "llvm.maximum.v2f64", + ret_f64x2_take_f64x2_f64x2, + None, + ), + fpext_f32: module.add_function( "llvm.experimental.constrained.fpext.f64.f32", ret_f64_take_f32_md, @@ -730,6 +766,7 @@ impl<'ctx> Intrinsics<'ctx> { stack_probe: context.create_string_attribute("probe-stack", "inline-asm"), uwtable: context.create_enum_attribute(Attribute::get_named_enum_kind_id("uwtable"), 1), frame_pointer: context.create_string_attribute("frame-pointer", "non-leaf"), + chkstk: module.add_function("__chkstk", void_ty.fn_type(&[], false), None), void_ty, i1_ty, i2_ty, @@ -753,7 +790,6 @@ impl<'ctx> Intrinsics<'ctx> { i32x8_ty, anyfunc_ty, - exc_ty: context.struct_type(&[i32_ty.into(), ptr_ty.into(), i64_ty.into()], false), i1_zero, i8_zero, i32_zero, @@ -1028,32 +1064,25 @@ impl<'ctx> Intrinsics<'ctx> { throw: module.add_function( "wasmer_vm_throw", - void_ty.fn_type( - &[i32_ty.into(), ptr_ty.into(), ptr_ty.into(), i64_ty.into()], - false, - ), - None, - ), - rethrow: module.add_function( - "wasmer_vm_rethrow", - void_ty.fn_type(&[ptr_ty.into()], false), + void_ty.fn_type(&[ptr_ty.into(), i32_ty.into()], false), None, ), alloc_exception: module.add_function( "wasmer_vm_alloc_exception", - ptr_ty.fn_type(&[i64_ty.into()], false), + i32_ty.fn_type(&[ptr_ty.into(), i32_ty.into()], false), None, ), - delete_exception: module.add_function( - "wasmer_vm_delete_exception", - void_ty.fn_type(&[ptr_ty.into()], false), + read_exnref: module.add_function( + "wasmer_vm_read_exnref", + ptr_ty.fn_type(&[ptr_ty.into(), i32_ty.into()], false), None, ), - read_exception: module.add_function( - "wasmer_vm_read_exception", - ptr_ty.fn_type(&[ptr_ty.into()], false), + exception_into_exnref: module.add_function( + "wasmer_vm_exception_into_exnref", + i32_ty.fn_type(&[ptr_ty.into()], false), None, ), + lpad_exception_ty: context.struct_type(&[ptr_ty.into(), i32_ty.into()], false), debug_ptr: module.add_function( "wasmer_vm_dbg_usize", diff --git a/lib/compiler-llvm/src/translator/mod.rs b/lib/compiler-llvm/src/translator/mod.rs index ac546687d3..1789470525 100644 --- a/lib/compiler-llvm/src/translator/mod.rs +++ b/lib/compiler-llvm/src/translator/mod.rs @@ -1,6 +1,5 @@ mod code; pub mod intrinsics; -//mod stackmap; mod state; pub use self::code::FuncTranslator; diff --git a/lib/compiler-llvm/src/translator/stackmap.rs b/lib/compiler-llvm/src/translator/stackmap.rs deleted file mode 100644 index cb6abc48fb..0000000000 --- a/lib/compiler-llvm/src/translator/stackmap.rs +++ /dev/null @@ -1,570 +0,0 @@ -// https://llvm.org/docs/StackMaps.html#stackmap-section - -use byteorder::{LittleEndian, ReadBytesExt}; -use std::io::{self, Cursor}; -use wasmer_vm_core::vm::Ctx; -use wasmer_vm_core::{ - module::Module, - structures::TypedIndex, - types::{GlobalIndex, LocalOrImport, TableIndex}, -}; - -#[derive(Default, Debug, Clone)] -pub struct StackmapRegistry { - pub entries: Vec, -} - -#[derive(Debug, Clone)] -pub struct StackmapEntry { - pub kind: StackmapEntryKind, - pub local_function_id: usize, - pub opcode_offset: usize, - pub value_semantics: Vec, - pub local_count: usize, - pub stack_count: usize, - pub is_start: bool, -} - -#[derive(Debug, Clone)] -pub enum ValueSemantic { - WasmLocal(usize), - WasmStack(usize), - Ctx, - SignalMem, - PointerToMemoryBase, - PointerToMemoryBound, // 64-bit - MemoryBase, - MemoryBound, // 64-bit - PointerToGlobal(usize), - Global(usize), - PointerToTableBase, - PointerToTableBound, - ImportedFuncPointer(usize), - ImportedFuncCtx(usize), - DynamicSigindice(usize), -} - -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum StackmapEntryKind { - FunctionHeader, - Loop, - Call, - Trappable, -} - -impl StackmapEntry { - #[cfg(all( - any(target_os = "freebsd", target_os = "linux", target_vendor = "apple"), - target_arch = "x86_64" - ))] - pub fn populate_msm( - &self, - module_info: &ModuleInfo, - code_addr: usize, - llvm_map: &StackMap, - size_record: &StkSizeRecord, - map_record: &StkMapRecord, - end: Option<(&StackmapEntry, &StkMapRecord)>, - msm: &mut wasmer_vm_core::state::ModuleStateMap, - ) { - use std::collections::{BTreeMap, HashMap}; - use wasmer_vm_core::state::{ - x64::{new_machine_state, X64Register, GPR}, - FunctionStateMap, MachineStateDiff, MachineValue, OffsetInfo, RegisterIndex, - SuspendOffset, WasmAbstractValue, - }; - use wasmer_vm_core::vm; - - let func_base_addr = (size_record.function_address as usize) - .checked_sub(code_addr) - .unwrap(); - let target_offset = func_base_addr + map_record.instruction_offset as usize; - assert!(self.is_start); - - if msm.local_functions.len() == self.local_function_id { - assert_eq!(self.kind, StackmapEntryKind::FunctionHeader); - msm.local_functions.insert( - target_offset, - FunctionStateMap::new(new_machine_state(), self.local_function_id, 0, vec![]), - ); - } else if msm.local_functions.len() == self.local_function_id + 1 { - } else { - panic!("unordered local functions"); - } - - let (_, fsm) = msm.local_functions.iter_mut().last().unwrap(); - - assert_eq!(self.value_semantics.len(), map_record.locations.len()); - - // System V requires 16-byte alignment before each call instruction. - // Considering the saved rbp we need to ensure the stack size % 16 always equals to 8. - assert!(size_record.stack_size % 16 == 8); - - // Layout begins just below saved rbp. (push rbp; mov rbp, rsp) - let mut machine_stack_half_layout: Vec = - vec![MachineValue::Undefined; (size_record.stack_size - 8) as usize / 4]; - let mut regs: Vec<(RegisterIndex, MachineValue)> = vec![]; - let mut stack_constants: HashMap = HashMap::new(); - - let mut prev_frame_diff: BTreeMap> = BTreeMap::new(); - - let mut wasm_locals: Vec = vec![]; - let mut wasm_stack: Vec = vec![]; - - for (i, loc) in map_record.locations.iter().enumerate() { - let mv = match self.value_semantics[i] { - ValueSemantic::WasmLocal(x) => { - if x != wasm_locals.len() { - panic!("unordered local values"); - } - wasm_locals.push(WasmAbstractValue::Runtime); - MachineValue::WasmLocal(x) - } - ValueSemantic::WasmStack(x) => { - if x != wasm_stack.len() { - panic!("unordered stack values"); - } - wasm_stack.push(WasmAbstractValue::Runtime); - MachineValue::WasmStack(x) - } - ValueSemantic::Ctx => MachineValue::Vmctx, - ValueSemantic::SignalMem => { - MachineValue::VmctxDeref(vec![Ctx::offset_interrupt_signal_mem() as usize, 0]) - } - ValueSemantic::PointerToMemoryBase => { - MachineValue::VmctxDeref(vec![Ctx::offset_memory_base() as usize]) - } - ValueSemantic::PointerToMemoryBound => { - MachineValue::VmctxDeref(vec![Ctx::offset_memory_bound() as usize]) - } - ValueSemantic::MemoryBase => { - MachineValue::VmctxDeref(vec![Ctx::offset_memory_base() as usize, 0]) - } - ValueSemantic::MemoryBound => { - MachineValue::VmctxDeref(vec![Ctx::offset_memory_bound() as usize, 0]) - } - ValueSemantic::PointerToGlobal(idx) => { - MachineValue::VmctxDeref(deref_global(module_info, idx, false)) - } - ValueSemantic::Global(idx) => { - MachineValue::VmctxDeref(deref_global(module_info, idx, true)) - } - ValueSemantic::PointerToTableBase => { - MachineValue::VmctxDeref(deref_table_base(module_info, 0, false)) - } - ValueSemantic::PointerToTableBound => { - MachineValue::VmctxDeref(deref_table_bound(module_info, 0, false)) - } - ValueSemantic::ImportedFuncPointer(idx) => MachineValue::VmctxDeref(vec![ - Ctx::offset_imported_funcs() as usize, - vm::ImportedFunc::size() as usize * idx - + vm::ImportedFunc::offset_func() as usize, - 0, - ]), - ValueSemantic::ImportedFuncCtx(idx) => MachineValue::VmctxDeref(vec![ - Ctx::offset_imported_funcs() as usize, - vm::ImportedFunc::size() as usize * idx - + vm::ImportedFunc::offset_func_ctx() as usize, - 0, - ]), - ValueSemantic::DynamicSigindice(idx) => { - MachineValue::VmctxDeref(vec![Ctx::offset_signatures() as usize, idx * 4, 0]) - } - }; - match loc.ty { - LocationType::Register => { - let index = X64Register::from_dwarf_regnum(loc.dwarf_regnum) - .expect("invalid regnum") - .to_index(); - regs.push((index, mv)); - } - LocationType::Constant => { - let v = loc.offset_or_small_constant as u32 as u64; - match mv { - MachineValue::WasmStack(x) => { - stack_constants.insert(x, v); - *wasm_stack.last_mut().unwrap() = WasmAbstractValue::Const(v); - } - _ => {} // TODO - } - } - LocationType::ConstantIndex => { - let v = - llvm_map.constants[loc.offset_or_small_constant as usize].large_constant; - match mv { - MachineValue::WasmStack(x) => { - stack_constants.insert(x, v); - *wasm_stack.last_mut().unwrap() = WasmAbstractValue::Const(v); - } - _ => {} // TODO - } - } - LocationType::Direct => match mv { - MachineValue::WasmLocal(_) => { - assert_eq!(loc.location_size, 8); // the pointer itself - assert!( - X64Register::from_dwarf_regnum(loc.dwarf_regnum).unwrap() - == X64Register::GPR(GPR::RBP) - ); - if loc.offset_or_small_constant >= 0 { - assert!(loc.offset_or_small_constant >= 16); // (saved_rbp, return_address) - assert!(loc.offset_or_small_constant % 8 == 0); - prev_frame_diff - .insert((loc.offset_or_small_constant as usize - 16) / 8, Some(mv)); - } else { - let stack_offset = ((-loc.offset_or_small_constant) / 4) as usize; - assert!( - stack_offset > 0 && stack_offset <= machine_stack_half_layout.len() - ); - machine_stack_half_layout[stack_offset - 1] = mv; - } - } - _ => unreachable!( - "Direct location type is not expected for values other than local" - ), - }, - LocationType::Indirect => { - assert!(loc.offset_or_small_constant < 0); - assert!( - X64Register::from_dwarf_regnum(loc.dwarf_regnum).unwrap() - == X64Register::GPR(GPR::RBP) - ); - let stack_offset = ((-loc.offset_or_small_constant) / 4) as usize; - assert!(stack_offset > 0 && stack_offset <= machine_stack_half_layout.len()); - machine_stack_half_layout[stack_offset - 1] = mv; - } - } - } - - assert_eq!(wasm_stack.len(), self.stack_count); - assert_eq!(wasm_locals.len(), self.local_count); - - let mut machine_stack_layout: Vec = - Vec::with_capacity(machine_stack_half_layout.len() / 2); - - for i in 0..machine_stack_half_layout.len() / 2 { - let major = &machine_stack_half_layout[i * 2 + 1]; // mod 8 == 0 - let minor = &machine_stack_half_layout[i * 2]; // mod 8 == 4 - let only_major = match *minor { - MachineValue::Undefined => true, - _ => false, - }; - if only_major { - machine_stack_layout.push(major.clone()); - } else { - machine_stack_layout.push(MachineValue::TwoHalves(Box::new(( - major.clone(), - minor.clone(), - )))); - } - } - - let diff = MachineStateDiff { - last: None, - stack_push: machine_stack_layout, - stack_pop: 0, - prev_frame_diff, - reg_diff: regs, - wasm_stack_push: wasm_stack, - wasm_stack_pop: 0, - wasm_inst_offset: self.opcode_offset, - }; - let diff_id = fsm.diffs.len(); - fsm.diffs.push(diff); - - match self.kind { - StackmapEntryKind::FunctionHeader => { - fsm.locals = wasm_locals; - } - _ => { - assert_eq!(fsm.locals, wasm_locals); - } - } - - let end_offset = { - if let Some(end) = end { - let (end_entry, end_record) = end; - assert_eq!(end_entry.is_start, false); - assert_eq!(self.opcode_offset, end_entry.opcode_offset); - let end_offset = func_base_addr + end_record.instruction_offset as usize; - assert!(end_offset >= target_offset); - end_offset - } else { - target_offset + 1 - } - }; - - match self.kind { - StackmapEntryKind::Loop => { - fsm.wasm_offset_to_target_offset - .insert(self.opcode_offset, SuspendOffset::Loop(target_offset)); - fsm.loop_offsets.insert( - target_offset, - OffsetInfo { - end_offset, - diff_id, - activate_offset: target_offset, - }, - ); - } - StackmapEntryKind::Call => { - fsm.wasm_offset_to_target_offset - .insert(self.opcode_offset, SuspendOffset::Call(target_offset)); - fsm.call_offsets.insert( - target_offset, - OffsetInfo { - end_offset: end_offset + 1, // The return address is just after 'call' instruction. Offset by one here. - diff_id, - activate_offset: target_offset, - }, - ); - } - StackmapEntryKind::Trappable => { - fsm.wasm_offset_to_target_offset - .insert(self.opcode_offset, SuspendOffset::Trappable(target_offset)); - fsm.trappable_offsets.insert( - target_offset, - OffsetInfo { - end_offset, - diff_id, - activate_offset: target_offset, - }, - ); - } - StackmapEntryKind::FunctionHeader => { - fsm.wasm_function_header_target_offset = Some(SuspendOffset::Loop(target_offset)); - fsm.loop_offsets.insert( - target_offset, - OffsetInfo { - end_offset, - diff_id, - activate_offset: target_offset, - }, - ); - } - } - } -} - -#[derive(Clone, Debug, Default)] -pub struct StackMap { - pub version: u8, - pub stk_size_records: Vec, - pub constants: Vec, - pub stk_map_records: Vec, -} - -#[derive(Copy, Clone, Debug, Default)] -pub struct StkSizeRecord { - pub function_address: u64, - pub stack_size: u64, - pub record_count: u64, -} - -#[derive(Copy, Clone, Debug, Default)] -pub struct Constant { - pub large_constant: u64, -} - -#[derive(Clone, Debug, Default)] -pub struct StkMapRecord { - pub patchpoint_id: u64, - pub instruction_offset: u32, - pub locations: Vec, - pub live_outs: Vec, -} - -#[derive(Copy, Clone, Debug)] -pub struct Location { - pub ty: LocationType, - pub location_size: u16, - pub dwarf_regnum: u16, - pub offset_or_small_constant: i32, -} - -#[derive(Copy, Clone, Debug, Default)] -pub struct LiveOut { - pub dwarf_regnum: u16, - pub size_in_bytes: u8, -} - -#[derive(Copy, Clone, Debug)] -pub enum LocationType { - Register, - Direct, - Indirect, - Constant, - ConstantIndex, -} - -impl StackMap { - pub fn parse(raw: &[u8]) -> io::Result { - let mut reader = Cursor::new(raw); - let mut map = StackMap::default(); - - let version = reader.read_u8()?; - if version != 3 { - return Err(io::Error::new(io::ErrorKind::Other, "version is not 3")); - } - map.version = version; - if reader.read_u8()? != 0 { - return Err(io::Error::new( - io::ErrorKind::Other, - "reserved field is not zero (1)", - )); - } - if reader.read_u16::()? != 0 { - return Err(io::Error::new( - io::ErrorKind::Other, - "reserved field is not zero (2)", - )); - } - let num_functions = reader.read_u32::()?; - let num_constants = reader.read_u32::()?; - let num_records = reader.read_u32::()?; - for _ in 0..num_functions { - let mut record = StkSizeRecord::default(); - record.function_address = reader.read_u64::()?; - record.stack_size = reader.read_u64::()?; - record.record_count = reader.read_u64::()?; - map.stk_size_records.push(record); - } - for _ in 0..num_constants { - map.constants.push(Constant { - large_constant: reader.read_u64::()?, - }); - } - for _ in 0..num_records { - let mut record = StkMapRecord::default(); - - record.patchpoint_id = reader.read_u64::()?; - record.instruction_offset = reader.read_u32::()?; - if reader.read_u16::()? != 0 { - return Err(io::Error::new( - io::ErrorKind::Other, - "reserved field is not zero (3)", - )); - } - let num_locations = reader.read_u16::()?; - for _ in 0..num_locations { - let ty = reader.read_u8()?; - - let mut location = Location { - ty: match ty { - 1 => LocationType::Register, - 2 => LocationType::Direct, - 3 => LocationType::Indirect, - 4 => LocationType::Constant, - 5 => LocationType::ConstantIndex, - _ => { - return Err(io::Error::new( - io::ErrorKind::Other, - "unknown location type", - )) - } - }, - location_size: 0, - dwarf_regnum: 0, - offset_or_small_constant: 0, - }; - - if reader.read_u8()? != 0 { - return Err(io::Error::new( - io::ErrorKind::Other, - "reserved field is not zero (4)", - )); - } - location.location_size = reader.read_u16::()?; - location.dwarf_regnum = reader.read_u16::()?; - if reader.read_u16::()? != 0 { - return Err(io::Error::new( - io::ErrorKind::Other, - "reserved field is not zero (5)", - )); - } - location.offset_or_small_constant = reader.read_i32::()?; - - record.locations.push(location); - } - if reader.position() % 8 != 0 { - if reader.read_u32::()? != 0 { - return Err(io::Error::new( - io::ErrorKind::Other, - "reserved field is not zero (6)", - )); - } - } - if reader.read_u16::()? != 0 { - return Err(io::Error::new( - io::ErrorKind::Other, - "reserved field is not zero (7)", - )); - } - let num_live_outs = reader.read_u16::()?; - for _ in 0..num_live_outs { - let mut liveout = LiveOut::default(); - - liveout.dwarf_regnum = reader.read_u16::()?; - if reader.read_u8()? != 0 { - return Err(io::Error::new( - io::ErrorKind::Other, - "reserved field is not zero (8)", - )); - } - liveout.size_in_bytes = reader.read_u8()?; - - record.live_outs.push(liveout); - } - if reader.position() % 8 != 0 { - if reader.read_u32::()? != 0 { - return Err(io::Error::new( - io::ErrorKind::Other, - "reserved field is not zero (9)", - )); - } - } - - map.stk_map_records.push(record); - } - Ok(map) - } -} - -fn deref_global(info: &ModuleInfo, idx: usize, deref_into_value: bool) -> Vec { - let mut x: Vec = match GlobalIndex::new(idx).local_or_import(info) { - LocalOrImport::Local(idx) => vec![Ctx::offset_globals() as usize, idx.index() * 8, 0], - LocalOrImport::Import(idx) => { - vec![Ctx::offset_imported_globals() as usize, idx.index() * 8, 0] - } - }; - if deref_into_value { - x.push(0); - } - x -} - -fn deref_table_base(info: &ModuleInfo, idx: usize, deref_into_value: bool) -> Vec { - let mut x: Vec = match TableIndex::new(idx).local_or_import(info) { - LocalOrImport::Local(idx) => vec![Ctx::offset_tables() as usize, idx.index() * 8, 0], - LocalOrImport::Import(idx) => { - vec![Ctx::offset_imported_tables() as usize, idx.index() * 8, 0] - } - }; - if deref_into_value { - x.push(0); - } - x -} - -fn deref_table_bound(info: &ModuleInfo, idx: usize, deref_into_value: bool) -> Vec { - let mut x: Vec = match TableIndex::new(idx).local_or_import(info) { - LocalOrImport::Local(idx) => vec![Ctx::offset_tables() as usize, idx.index() * 8, 8], - LocalOrImport::Import(idx) => { - vec![Ctx::offset_imported_tables() as usize, idx.index() * 8, 8] - } - }; - if deref_into_value { - x.push(0); - } - x -} diff --git a/lib/compiler-llvm/src/translator/state.rs b/lib/compiler-llvm/src/translator/state.rs index be9188fc54..345009f8c9 100644 --- a/lib/compiler-llvm/src/translator/state.rs +++ b/lib/compiler-llvm/src/translator/state.rs @@ -50,38 +50,35 @@ pub enum IfElseState { impl<'ctx> ControlFrame<'ctx> { pub fn code_after(&self) -> &BasicBlock<'ctx> { match self { - ControlFrame::Block { ref next, .. } - | ControlFrame::Loop { ref next, .. } - | ControlFrame::Landingpad { ref next, .. } - | ControlFrame::IfElse { ref next, .. } => next, + ControlFrame::Block { next, .. } + | ControlFrame::Loop { next, .. } + | ControlFrame::Landingpad { next, .. } + | ControlFrame::IfElse { next, .. } => next, } } pub fn br_dest(&self) -> &BasicBlock<'ctx> { match self { - ControlFrame::Block { ref next, .. } - | ControlFrame::IfElse { ref next, .. } - | ControlFrame::Landingpad { ref next, .. } => next, - ControlFrame::Loop { ref body, .. } => body, + ControlFrame::Block { next, .. } + | ControlFrame::IfElse { next, .. } + | ControlFrame::Landingpad { next, .. } => next, + ControlFrame::Loop { body, .. } => body, } } pub fn phis(&self) -> &[PhiValue<'ctx>] { match self { - ControlFrame::Block { ref phis, .. } | ControlFrame::Loop { ref phis, .. } => { - phis.as_slice() + ControlFrame::Block { phis, .. } | ControlFrame::Loop { phis, .. } => phis.as_slice(), + ControlFrame::IfElse { next_phis, .. } | ControlFrame::Landingpad { next_phis, .. } => { + next_phis.as_slice() } - ControlFrame::IfElse { ref next_phis, .. } - | ControlFrame::Landingpad { ref next_phis, .. } => next_phis.as_slice(), } } /// PHI nodes for stack values in the loop body. pub fn loop_body_phis(&self) -> &[PhiValue<'ctx>] { match self { - ControlFrame::Loop { - ref loop_body_phis, .. - } => loop_body_phis.as_slice(), + ControlFrame::Loop { loop_body_phis, .. } => loop_body_phis.as_slice(), _ => &[], } } @@ -223,11 +220,9 @@ pub struct TagCatchInfo<'ctx> { pub tag: u32, // The catch block pub catch_block: BasicBlock<'ctx>, - // The PHI node to receive the exception object - pub wasmer_exc_phi: Option>, - // The PHI node to receive the libunwind exception pointer, - // which stands in as the exnref for now - pub uw_exc_ptr_phi: Option>, + // The PHI node to receive the exnref, if needed; catch_all + // blocks don't need the exnref. + pub exnref_phi: Option>, } #[derive(Debug)] diff --git a/lib/compiler-singlepass/Cargo.toml b/lib/compiler-singlepass/Cargo.toml index a0d961288b..87569cae6e 100644 --- a/lib/compiler-singlepass/Cargo.toml +++ b/lib/compiler-singlepass/Cargo.toml @@ -14,28 +14,31 @@ rust-version.workspace = true version.workspace = true [dependencies] -wasmer-compiler = { path = "../compiler", version = "=6.1.0", features = ["translator", "compiler"], default-features = false } -wasmer-types = { path = "../types", version = "=6.1.0", default-features = false, features = ["std"] } +wasmer-compiler = { path = "../compiler", version = "=6.1.0", features = ["translator", "compiler"] } +wasmer-types = { path = "../types", version = "=6.1.0", features = ["std"], default-features = false } hashbrown = { workspace = true, optional = true } gimli = { workspace = true, optional = true } enumset.workspace = true more-asserts.workspace = true -dynasm = "4.0.0" -dynasmrt = "4.0.0" +dynasm.workspace = true +dynasmrt.workspace = true byteorder.workspace = true smallvec.workspace = true +tempfile.workspace = true +itertools.workspace = true +target-lexicon.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] rayon = { workspace = true, optional = true } [dev-dependencies] -target-lexicon = { workspace = true, default-features = false } +target-lexicon = { workspace = true } [badges] maintenance = { status = "actively-developed" } [features] -default = ["std", "rayon", "unwind", "avx"] +default = ["std", "rayon", "unwind", "avx", "riscv"] wasm = ["std", "unwind", "avx"] std = ["wasmer-compiler/std", "wasmer-types/std"] core = ["hashbrown", "wasmer-types/core"] @@ -43,6 +46,7 @@ unwind = ["gimli"] sse = [] avx = [] enable-serde = [] +riscv = [] [package.metadata.docs.rs] rustc-args = ["--cfg", "docsrs"] diff --git a/lib/compiler-singlepass/LICENSE b/lib/compiler-singlepass/LICENSE index aa292ec0ad..498ee6ea6a 100644 --- a/lib/compiler-singlepass/LICENSE +++ b/lib/compiler-singlepass/LICENSE @@ -4,7 +4,7 @@ License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. Parameters Licensor: Wasmer, Inc. -Licensed Work: Wasmer Singlepass Version 6.0.0 or later. The Licensed Work is +Licensed Work: Wasmer Singlepass Version 6.1.0 or later. The Licensed Work is (c) 2025 Wasmer, Inc. Additional Use Grant: You may make production use of the Licensed Work provided you are either a Sponsor under the Wasmer Sponsorhip Program or an entity @@ -34,6 +34,12 @@ Additional Use Grant: You may make production use of the Licensed Work provided that of your associated Sponsor is terminated for any reason, the additional rights granted under this Sponsor Exception shall immediately revert to the standard limitations of BUSL 1.1. + + For purposes of this License, any code, binaries, or other output + generated by the Licensed Work ("Generated Code") shall be deemed part + of the Licensed Work and subject to the same terms, conditions, and + restrictions as the Licensed Work itself, including the limitations on + production use and the Change Date. Change Date: Four years from the date the Licensed Work is published Change License: MPL 2.0 diff --git a/lib/compiler-singlepass/README.md b/lib/compiler-singlepass/README.md index 48a0d6dde0..955f7c68dc 100644 --- a/lib/compiler-singlepass/README.md +++ b/lib/compiler-singlepass/README.md @@ -2,7 +2,10 @@ [![Build Status](https://github.com/wasmerio/wasmer/actions/workflows/build.yml/badge.svg?style=flat-square)](https://github.com/wasmerio/wasmer/actions?query=workflow%3Abuild) [![Join Wasmer Slack](https://img.shields.io/static/v1?label=Slack&message=join%20chat&color=brighgreen&style=flat-square)](https://slack.wasmer.io) [![MIT License](https://img.shields.io/github/license/wasmerio/wasmer.svg?style=flat-square)](https://github.com/wasmerio/wasmer/blob/main/LICENSE) [![crates.io](https://img.shields.io/crates/v/wasmer-compiler-singlepass.svg)](https://crates.io/crates/wasmer-compiler-singlepass) This crate contains a compiler implementation based on the Singlepass linear compiler. - +Supported targets: +- x86_64 +- aarch64 +- riscv64 (experimental) ## Usage ```rust diff --git a/lib/compiler-singlepass/src/address_map.rs b/lib/compiler-singlepass/src/address_map.rs index 666000f07b..7e5505841c 100644 --- a/lib/compiler-singlepass/src/address_map.rs +++ b/lib/compiler-singlepass/src/address_map.rs @@ -1,5 +1,5 @@ -use wasmer_compiler::types::address_map::{FunctionAddressMap, InstructionAddressMap}; use wasmer_compiler::FunctionBodyData; +use wasmer_compiler::types::address_map::{FunctionAddressMap, InstructionAddressMap}; use wasmer_types::SourceLoc; pub fn get_function_address_map( diff --git a/lib/compiler-singlepass/src/arm64_decl.rs b/lib/compiler-singlepass/src/arm64_decl.rs index e3deca42b1..993baf630c 100644 --- a/lib/compiler-singlepass/src/arm64_decl.rs +++ b/lib/compiler-singlepass/src/arm64_decl.rs @@ -1,14 +1,52 @@ //! ARM64 structures. -use crate::{ - common_decl::{MachineState, MachineValue, RegisterIndex}, - location::{CombinedRegister, Reg as AbstractReg}, -}; -use std::collections::BTreeMap; +use crate::location::{CombinedRegister, Reg as AbstractReg}; use std::slice::Iter; use wasmer_types::target::CallingConvention; use wasmer_types::{CompileError, Type}; +/* +Register definition: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#611general-purpose-registers + ++------+-----------+--------------------------------------------+-------------------+ +| Reg | ABI Name | Description | Saved by Callee | ++------+-----------+--------------------------------------------+-------------------+ +| x0 | a0 | argument / return value 0 | -R | +| x1 | a1 | argument / return value 1 | -R | +| x2 | a2 | argument 2 | -R | +| x3 | a3 | argument 3 | -R | +| x4 | a4 | argument 4 | -R | +| x5 | a5 | argument 5 | -R | +| x6 | a6 | argument 6 | -R | +| x7 | a7 | argument 7 | -R | +| x8 | x8 (IP0) | indirect result / scratch (IP0) | -R | +| x9 | x9 (IP1) | scratch / intra-proc-call temporary | -R | +| x10 | x10 | scratch / temporary | -R | +| x11 | x11 | scratch / temporary | -R | +| x12 | x12 | scratch / temporary | -R | +| x13 | x13 | scratch / temporary | -R | +| x14 | x14 | scratch / temporary | -R | +| x15 | x15 | scratch / temporary | -R | +| x16 | ip0 | intra-procedure-call scratch (IP0) | -R | +| x17 | ip1 | intra-procedure-call scratch (IP1) | -R | +| x18 | pr | platform register (varies by OS/platform) | - | +| x19 | s0 | callee-saved register 0 | -E | +| x20 | s1 | callee-saved register 1 | -E | +| x21 | s2 | callee-saved register 2 | -E | +| x22 | s3 | callee-saved register 3 | -E | +| x23 | s4 | callee-saved register 4 | -E | +| x24 | s5 | callee-saved register 5 | -E | +| x25 | s6 | callee-saved register 6 | -E | +| x26 | s7 | callee-saved register 7 | -E | +| x27 | s8 | callee-saved register 8 | -E | +| x28 | s9 | callee-saved register 9 | -E | +| x29 | fp / s10 | frame pointer / callee-saved register 10 | -E | +| x30 | lr | link register (return address) | -R | +| x31 | sp / wzr | stack pointer (sp) or zero register (wzr) | - | ++------+-----------+--------------------------------------------+-------------------+ +Legend: -R = caller-saved, -E = callee-saved, - = not saved +*/ + /// General-purpose registers. #[repr(u8)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] @@ -101,12 +139,6 @@ impl From for u8 { } impl AbstractReg for GPR { - fn is_callee_save(self) -> bool { - self as usize > 18 - } - fn is_reserved(self) -> bool { - !matches!(self.into_index(), 0..=16 | 19..=27) - } fn into_index(self) -> usize { self as usize } @@ -153,18 +185,48 @@ impl AbstractReg for GPR { ]; GPRS.iter() } - fn to_dwarf(self) -> u16 { - self.into_index() as u16 + #[cfg(feature = "unwind")] + fn to_dwarf(self) -> gimli::Register { + use gimli::AArch64; + + match self { + GPR::X0 => AArch64::X0, + GPR::X1 => AArch64::X1, + GPR::X2 => AArch64::X2, + GPR::X3 => AArch64::X3, + GPR::X4 => AArch64::X4, + GPR::X5 => AArch64::X5, + GPR::X6 => AArch64::X6, + GPR::X7 => AArch64::X7, + GPR::X8 => AArch64::X8, + GPR::X9 => AArch64::X9, + GPR::X10 => AArch64::X10, + GPR::X11 => AArch64::X11, + GPR::X12 => AArch64::X12, + GPR::X13 => AArch64::X13, + GPR::X14 => AArch64::X14, + GPR::X15 => AArch64::X15, + GPR::X16 => AArch64::X16, + GPR::X17 => AArch64::X17, + GPR::X18 => AArch64::X18, + GPR::X19 => AArch64::X19, + GPR::X20 => AArch64::X20, + GPR::X21 => AArch64::X21, + GPR::X22 => AArch64::X22, + GPR::X23 => AArch64::X23, + GPR::X24 => AArch64::X24, + GPR::X25 => AArch64::X25, + GPR::X26 => AArch64::X26, + GPR::X27 => AArch64::X27, + GPR::X28 => AArch64::X28, + GPR::X29 => AArch64::X29, + GPR::X30 => AArch64::X30, + GPR::XzrSp => AArch64::SP, + } } } impl AbstractReg for NEON { - fn is_callee_save(self) -> bool { - self as usize > 16 - } - fn is_reserved(self) -> bool { - false - } fn into_index(self) -> usize { self as usize } @@ -211,8 +273,44 @@ impl AbstractReg for NEON { ]; NEONS.iter() } - fn to_dwarf(self) -> u16 { - self.into_index() as u16 + 64 + #[cfg(feature = "unwind")] + fn to_dwarf(self) -> gimli::Register { + use gimli::AArch64; + + match self { + NEON::V0 => AArch64::V0, + NEON::V1 => AArch64::V1, + NEON::V2 => AArch64::V2, + NEON::V3 => AArch64::V3, + NEON::V4 => AArch64::V4, + NEON::V5 => AArch64::V5, + NEON::V6 => AArch64::V6, + NEON::V7 => AArch64::V7, + NEON::V8 => AArch64::V8, + NEON::V9 => AArch64::V9, + NEON::V10 => AArch64::V10, + NEON::V11 => AArch64::V11, + NEON::V12 => AArch64::V12, + NEON::V13 => AArch64::V13, + NEON::V14 => AArch64::V14, + NEON::V15 => AArch64::V15, + NEON::V16 => AArch64::V16, + NEON::V17 => AArch64::V17, + NEON::V18 => AArch64::V18, + NEON::V19 => AArch64::V19, + NEON::V20 => AArch64::V20, + NEON::V21 => AArch64::V21, + NEON::V22 => AArch64::V22, + NEON::V23 => AArch64::V23, + NEON::V24 => AArch64::V24, + NEON::V25 => AArch64::V25, + NEON::V26 => AArch64::V26, + NEON::V27 => AArch64::V27, + NEON::V28 => AArch64::V28, + NEON::V29 => AArch64::V29, + NEON::V30 => AArch64::V30, + NEON::V31 => AArch64::V31, + } } } @@ -227,13 +325,6 @@ pub enum ARM64Register { } impl CombinedRegister for ARM64Register { - /// Returns the index of the register. - fn to_index(&self) -> RegisterIndex { - match *self { - ARM64Register::GPR(x) => RegisterIndex(x as usize), - ARM64Register::NEON(x) => RegisterIndex(x as usize + 64), - } - } /// Convert from a GPR register fn from_gpr(x: u16) -> Self { ARM64Register::GPR(GPR::from_index(x as usize).unwrap()) @@ -242,15 +333,6 @@ impl CombinedRegister for ARM64Register { fn from_simd(x: u16) -> Self { ARM64Register::NEON(NEON::from_index(x as usize).unwrap()) } - - /// Converts a DWARF regnum to ARM64Register. - fn _from_dwarf_regnum(x: u16) -> Option { - Some(match x { - 0..=31 => ARM64Register::GPR(GPR::from_index(x as usize).unwrap()), - 64..=95 => ARM64Register::NEON(NEON::from_index(x as usize - 64).unwrap()), - _ => return None, - }) - } } /// An allocator that allocates registers for function arguments according to the System V ABI. @@ -311,28 +393,17 @@ impl ArgumentRegisterAllocator { _ => { return Err(CompileError::Codegen(format!( "No register available for {calling_convention:?} and type {ty}" - ))) + ))); } } } _ => { return Err(CompileError::Codegen(format!( "No register available for {calling_convention:?} and type {ty}" - ))) + ))); } }; Ok(ret) } } - -/// Create a new `MachineState` with default values. -pub fn new_machine_state() -> MachineState { - MachineState { - stack_values: vec![], - register_values: vec![MachineValue::Undefined; 32 + 32], - prev_frame: BTreeMap::new(), - wasm_stack: vec![], - wasm_inst_offset: usize::MAX, - } -} diff --git a/lib/compiler-singlepass/src/codegen.rs b/lib/compiler-singlepass/src/codegen.rs index 795d9665d3..0e333afdcb 100644 --- a/lib/compiler-singlepass/src/codegen.rs +++ b/lib/compiler-singlepass/src/codegen.rs @@ -7,15 +7,21 @@ use crate::{ common_decl::*, config::Singlepass, location::{Location, Reg}, - machine::{Label, Machine, MachineStackOffset, NATIVE_PAGE_SIZE}, + machine::{ + AssemblyComment, FinalizedAssembly, Label, Machine, NATIVE_PAGE_SIZE, UnsignedCondition, + }, unwind::UnwindFrame, }; #[cfg(feature = "unwind")] use gimli::write::Address; -use smallvec::{smallvec, SmallVec}; -use std::{cmp, iter}; +use itertools::Itertools; +use smallvec::{SmallVec, smallvec}; +use std::{cmp, collections::HashMap, iter, ops::Neg}; +use target_lexicon::Architecture; use wasmer_compiler::{ + FunctionBodyData, + misc::CompiledKind, types::{ function::{CompiledFunction, CompiledFunctionFrameInfo, FunctionBody}, relocation::{Relocation, RelocationTarget}, @@ -25,7 +31,6 @@ use wasmer_compiler::{ BlockType as WpTypeOrFuncType, HeapType as WpHeapType, Operator, RefType as WpRefType, ValType as WpType, }, - FunctionBodyData, }; #[cfg(feature = "unwind")] @@ -33,11 +38,15 @@ use wasmer_compiler::types::unwind::CompiledFunctionUnwindInfo; use wasmer_types::target::CallingConvention; use wasmer_types::{ - entity::{EntityRef, PrimaryMap}, CompileError, FunctionIndex, FunctionType, GlobalIndex, LocalFunctionIndex, LocalMemoryIndex, MemoryIndex, MemoryStyle, ModuleInfo, SignatureIndex, TableIndex, TableStyle, TrapCode, Type, VMBuiltinFunctionIndex, VMOffsets, + entity::{EntityRef, PrimaryMap}, }; + +#[allow(type_alias_bounds)] +type LocationWithCanonicalization = (Location, CanonicalizeType); + /// The singlepass per-function code generator. pub struct FuncGen<'a, M: Machine> { // Immutable properties assigned at creation time. @@ -66,21 +75,15 @@ pub struct FuncGen<'a, M: Machine> { local_types: Vec, /// Value stack. - value_stack: Vec>, - - /// Metadata about floating point values on the stack. - fp_stack: Vec, + value_stack: Vec>, /// A list of frames describing the current control stack. - control_stack: Vec, - - stack_offset: MachineStackOffset, + control_stack: Vec>, - save_area_offset: Option, + /// Stack offset tracking in bytes. + stack_offset: usize, - state: MachineState, - - track_state: bool, + save_area_offset: Option, /// Low-level machine state. machine: M, @@ -88,8 +91,8 @@ pub struct FuncGen<'a, M: Machine> { /// Nesting level of unreachable code. unreachable_depth: usize, - /// Function state map. Not yet used in the reborn version but let's keep it. - fsm: FunctionStateMap, + /// Index of a function defined locally inside the WebAssembly module. + local_func_index: LocalFunctionIndex, /// Relocation information. relocations: Vec, @@ -99,6 +102,12 @@ pub struct FuncGen<'a, M: Machine> { /// Calling convention to use. calling_convention: CallingConvention, + + /// Name of the function. + function_name: String, + + /// Assembly comments. + assembly_comments: HashMap, } struct SpecialLabelSet { @@ -111,105 +120,38 @@ struct SpecialLabelSet { unaligned_atomic: Label, } -/// Metadata about a floating-point value. -#[derive(Copy, Clone, Debug)] -struct FloatValue { - /// Do we need to canonicalize the value before its bit pattern is next observed? If so, how? - canonicalization: Option, - - /// Corresponding depth in the main value stack. - depth: usize, -} - -impl FloatValue { - fn new(depth: usize) -> Self { - FloatValue { - canonicalization: None, - depth, - } - } - - fn cncl_f32(depth: usize) -> Self { - FloatValue { - canonicalization: Some(CanonicalizeType::F32), - depth, - } - } - - fn cncl_f64(depth: usize) -> Self { - FloatValue { - canonicalization: Some(CanonicalizeType::F64), - depth, - } - } - - fn promote(self, depth: usize) -> Result { - let ret = FloatValue { - canonicalization: match self.canonicalization { - Some(CanonicalizeType::F32) => Some(CanonicalizeType::F64), - Some(CanonicalizeType::F64) => codegen_error!("cannot promote F64"), - None => None, - }, - depth, - }; - Ok(ret) - } - - fn demote(self, depth: usize) -> Result { - let ret = FloatValue { - canonicalization: match self.canonicalization { - Some(CanonicalizeType::F64) => Some(CanonicalizeType::F32), - Some(CanonicalizeType::F32) => codegen_error!("cannot demote F32"), - None => None, - }, - depth, - }; - Ok(ret) - } -} - /// Type of a pending canonicalization floating point value. /// Sometimes we don't have the type information elsewhere and therefore we need to track it here. #[derive(Copy, Clone, Debug)] -enum CanonicalizeType { +pub(crate) enum CanonicalizeType { + None, F32, F64, } impl CanonicalizeType { - fn to_size(self) -> Size { + fn to_size(self) -> Option { match self { - CanonicalizeType::F32 => Size::S32, - CanonicalizeType::F64 => Size::S64, + CanonicalizeType::F32 => Some(Size::S32), + CanonicalizeType::F64 => Some(Size::S64), + CanonicalizeType::None => None, } } -} - -trait PopMany { - fn peek1(&self) -> Result<&T, CompileError>; - fn pop1(&mut self) -> Result; - fn pop2(&mut self) -> Result<(T, T), CompileError>; -} -impl PopMany for Vec { - fn peek1(&self) -> Result<&T, CompileError> { - self.last() - .ok_or_else(|| CompileError::Codegen("peek1() expects at least 1 element".to_owned())) - } - fn pop1(&mut self) -> Result { - self.pop() - .ok_or_else(|| CompileError::Codegen("pop1() expects at least 1 element".to_owned())) - } - fn pop2(&mut self) -> Result<(T, T), CompileError> { - if self.len() < 2 { - return Err(CompileError::Codegen( - "pop2() expects at least 2 elements".to_owned(), - )); + fn promote(self) -> Result { + match self { + CanonicalizeType::None => Ok(CanonicalizeType::None), + CanonicalizeType::F32 => Ok(CanonicalizeType::F64), + CanonicalizeType::F64 => codegen_error!("cannot promote F64"), } + } - let right = self.pop().unwrap(); - let left = self.pop().unwrap(); - Ok((left, right)) + fn demote(self) -> Result { + match self { + CanonicalizeType::None => Ok(CanonicalizeType::None), + CanonicalizeType::F32 => codegen_error!("cannot demote F64"), + CanonicalizeType::F64 => Ok(CanonicalizeType::F32), + } } } @@ -223,26 +165,51 @@ impl WpTypeExt for WpType { } } -#[derive(Debug, Clone)] -pub struct ControlFrame { +#[derive(Clone)] +pub enum ControlState { + Function, + Block, + Loop, + If { + label_else: Label, + // Store the input parameters for the If block, as they'll need to be + // restored when processing the Else block (if present). + inputs: SmallVec<[LocationWithCanonicalization; 1]>, + }, + Else, +} + +#[derive(Clone)] +struct ControlFrame { + pub state: ControlState, pub label: Label, - pub loop_like: bool, - pub if_else: IfElseState, - pub returns: SmallVec<[WpType; 1]>, - pub value_stack_depth: usize, - pub fp_stack_depth: usize, - pub state: MachineState, - pub state_diff_id: usize, + pub param_types: SmallVec<[WpType; 8]>, + pub return_types: SmallVec<[WpType; 1]>, + /// Value stack depth at the beginning of the frame (including params and results). + value_stack_depth: usize, } -#[derive(Debug, Copy, Clone)] -pub enum IfElseState { - None, - If(Label), - Else, +impl ControlFrame { + // Get value stack depth at the end of the frame. + fn value_stack_depth_after(&self) -> usize { + let mut depth: usize = self.value_stack_depth - self.param_types.len(); + + // For Loop, we have to use another slot for params that implements the PHI operation. + if matches!(self.state, ControlState::Loop) { + depth -= self.param_types.len(); + } + + depth + } + + /// Returns the value stack depth at which resources should be deallocated. + /// For loops, this preserves PHI arguments by excluding them from deallocation. + fn value_stack_depth_for_release(&self) -> usize { + self.value_stack_depth - self.param_types.len() + } } -fn type_to_wp_type(ty: Type) -> WpType { +fn type_to_wp_type(ty: &Type) -> WpType { match ty { Type::I32 => WpType::I32, Type::I64 => WpType::I64, @@ -263,263 +230,195 @@ struct I2O1 { ret: Location, } -impl<'a, M: Machine> FuncGen<'a, M> { - fn get_stack_offset(&self) -> usize { - self.stack_offset.0 - } +/// Type of native call we emit. +enum NativeCallType { + IncludeVMCtxArgument, + Unreachable, +} - /// Acquires locations from the machine state. +impl<'a, M: Machine> FuncGen<'a, M> { + /// Acquires location from the machine state. /// - /// If the returned locations are used for stack value, `release_location` needs to be called on them; - /// Otherwise, if the returned locations are used for locals, `release_location` does not need to be called on them. - #[allow(clippy::type_complexity)] - fn acquire_locations( - &mut self, - tys: &[(WpType, MachineValue)], - zeroed: bool, - ) -> Result; 1]>, CompileError> { - let mut ret = smallvec![]; - let mut delta_stack_offset: usize = 0; - - for (ty, mv) in tys { - let loc = match *ty { - WpType::F32 | WpType::F64 => self.machine.pick_simd().map(Location::SIMD), - WpType::I32 | WpType::I64 => self.machine.pick_gpr().map(Location::GPR), - WpType::Ref(ty) if ty.is_extern_ref() || ty.is_func_ref() => { - self.machine.pick_gpr().map(Location::GPR) - } - _ => codegen_error!("can't acquire location for type {:?}", ty), - }; + /// If the returned location is used for stack value, `release_location` needs to be called on it; + /// Otherwise, if the returned locations is used for a local, `release_location` does not need to be called on it. + fn acquire_location(&mut self, ty: &WpType) -> Result, CompileError> { + let loc = match *ty { + WpType::F32 | WpType::F64 => self.machine.pick_simd().map(Location::SIMD), + WpType::I32 | WpType::I64 => self.machine.pick_gpr().map(Location::GPR), + WpType::Ref(ty) if ty.is_extern_ref() || ty.is_func_ref() => { + self.machine.pick_gpr().map(Location::GPR) + } + _ => codegen_error!("can't acquire location for type {:?}", ty), + }; - let loc = if let Some(x) = loc { - x - } else { - self.stack_offset.0 += 8; - delta_stack_offset += 8; - self.machine.local_on_stack(self.stack_offset.0 as i32) - }; - if let Location::GPR(x) = loc { - self.machine.reserve_gpr(x); - self.state.register_values[self.machine.index_from_gpr(x).0] = mv.clone(); - } else if let Location::SIMD(x) = loc { - self.machine.reserve_simd(x); - self.state.register_values[self.machine.index_from_simd(x).0] = mv.clone(); - } else { - self.state.stack_values.push(mv.clone()); - } - self.state.wasm_stack.push(WasmAbstractValue::Runtime); - ret.push(loc); - } + let Some(loc) = loc else { + return self.acquire_location_on_stack(); + }; - let delta_stack_offset = self.machine.round_stack_adjust(delta_stack_offset); - if delta_stack_offset != 0 { - self.machine.adjust_stack(delta_stack_offset as u32)?; + if let Location::GPR(x) = loc { + self.machine.reserve_gpr(x); + } else if let Location::SIMD(x) = loc { + self.machine.reserve_simd(x); } - if zeroed { - for i in 0..tys.len() { - self.machine.zero_location(Size::S64, ret[i])?; - } - } - Ok(ret) + Ok(loc) + } + + /// Acquire location that will live on the stack. + fn acquire_location_on_stack(&mut self) -> Result, CompileError> { + self.stack_offset += 8; + let loc = self.machine.local_on_stack(self.stack_offset as i32); + self.machine + .extend_stack(self.machine.round_stack_adjust(8) as u32)?; + + Ok(loc) } /// Releases locations used for stack value. fn release_locations( &mut self, - locs: &[Location], + locs: &[LocationWithCanonicalization], ) -> Result<(), CompileError> { - let mut delta_stack_offset: usize = 0; - - for loc in locs.iter().rev() { - match *loc { - Location::GPR(ref x) => { - self.machine.release_gpr(*x); - self.state.register_values[self.machine.index_from_gpr(*x).0] = - MachineValue::Undefined; - } - Location::SIMD(ref x) => { - self.machine.release_simd(*x); - self.state.register_values[self.machine.index_from_simd(*x).0] = - MachineValue::Undefined; - } - Location::Memory(y, x) => { - if y == self.machine.local_pointer() { - if x >= 0 { - codegen_error!("Invalid memory offset {}", x); - } - let offset = (-x) as usize; - if offset != self.stack_offset.0 { - codegen_error!( - "Invalid memory offset {}!={}", - offset, - self.stack_offset.0 - ); - } - self.stack_offset.0 -= 8; - delta_stack_offset += 8; - self.state - .stack_values - .pop() - .ok_or_else(|| CompileError::Codegen("Empty stack_value".to_owned()))?; - } - } - _ => {} - } - self.state - .wasm_stack - .pop() - .ok_or_else(|| CompileError::Codegen("Pop with wasm stack empty".to_owned()))?; - } - let delta_stack_offset = self.machine.round_stack_adjust(delta_stack_offset); - if delta_stack_offset != 0 { - self.machine.restore_stack(delta_stack_offset as u32)?; - } - Ok(()) + self.release_stack_locations(locs)?; + self.release_reg_locations(locs) } - /// Releases locations used for stack value. - fn release_locations_value(&mut self, stack_depth: usize) -> Result<(), CompileError> { - let mut delta_stack_offset: usize = 0; - let locs: &[Location] = &self.value_stack[stack_depth..]; - for loc in locs.iter().rev() { + fn release_reg_locations( + &mut self, + locs: &[LocationWithCanonicalization], + ) -> Result<(), CompileError> { + for (loc, _) in locs.iter().rev() { match *loc { Location::GPR(ref x) => { self.machine.release_gpr(*x); - self.state.register_values[self.machine.index_from_gpr(*x).0] = - MachineValue::Undefined; } Location::SIMD(ref x) => { self.machine.release_simd(*x); - self.state.register_values[self.machine.index_from_simd(*x).0] = - MachineValue::Undefined; - } - Location::Memory(y, x) => { - if y == self.machine.local_pointer() { - if x >= 0 { - codegen_error!("Invalid memory offset {}", x); - } - let offset = (-x) as usize; - if offset != self.stack_offset.0 { - codegen_error!( - "Invalid memory offset {}!={}", - offset, - self.stack_offset.0 - ); - } - self.stack_offset.0 -= 8; - delta_stack_offset += 8; - self.state.stack_values.pop().ok_or_else(|| { - CompileError::Codegen("Pop with values stack empty".to_owned()) - })?; - } } _ => {} } - self.state - .wasm_stack - .pop() - .ok_or_else(|| CompileError::Codegen("Pop with wasm stack empty".to_owned()))?; - } - - let delta_stack_offset = self.machine.round_stack_adjust(delta_stack_offset); - if delta_stack_offset != 0 { - self.machine.adjust_stack(delta_stack_offset as u32)?; } Ok(()) } - fn release_locations_only_regs( + fn release_stack_locations( &mut self, - locs: &[Location], + locs: &[LocationWithCanonicalization], ) -> Result<(), CompileError> { - for loc in locs.iter().rev() { - match *loc { - Location::GPR(ref x) => { - self.machine.release_gpr(*x); - self.state.register_values[self.machine.index_from_gpr(*x).0] = - MachineValue::Undefined; - } - Location::SIMD(ref x) => { - self.machine.release_simd(*x); - self.state.register_values[self.machine.index_from_simd(*x).0] = - MachineValue::Undefined; - } - _ => {} + for (loc, _) in locs.iter().rev() { + if let Location::Memory(..) = *loc { + self.check_location_on_stack(loc, self.stack_offset)?; + self.stack_offset -= 8; + self.machine + .truncate_stack(self.machine.round_stack_adjust(8) as u32)?; } - // Wasm state popping is deferred to `release_locations_only_osr_state`. } + Ok(()) } - fn release_locations_only_stack( + fn release_stack_locations_keep_stack_offset( &mut self, - locs: &[Location], + stack_depth: usize, ) -> Result<(), CompileError> { - let mut delta_stack_offset: usize = 0; + let mut stack_offset = self.stack_offset; + let locs = &self.value_stack[stack_depth..]; - for loc in locs.iter().rev() { - if let Location::Memory(y, x) = *loc { - if y == self.machine.local_pointer() { - if x >= 0 { - codegen_error!("Invalid memory offset {}", x); - } - let offset = (-x) as usize; - if offset != self.stack_offset.0 { - codegen_error!("Invalid memory offset {}!={}", offset, self.stack_offset.0); - } - self.stack_offset.0 -= 8; - delta_stack_offset += 8; - self.state.stack_values.pop().ok_or_else(|| { - CompileError::Codegen("Pop on empty value stack".to_owned()) - })?; - } + for (loc, _) in locs.iter().rev() { + if let Location::Memory(..) = *loc { + self.check_location_on_stack(loc, stack_offset)?; + stack_offset -= 8; + self.machine + .truncate_stack(self.machine.round_stack_adjust(8) as u32)?; } - // Wasm state popping is deferred to `release_locations_only_osr_state`. } - let delta_stack_offset = self.machine.round_stack_adjust(delta_stack_offset); - if delta_stack_offset != 0 { - self.machine.pop_stack_locals(delta_stack_offset as u32)?; - } Ok(()) } - fn release_locations_only_osr_state(&mut self, n: usize) -> Result<(), CompileError> { - let new_length = self - .state - .wasm_stack - .len() - .checked_sub(n) - .expect("release_locations_only_osr_state: length underflow"); - self.state.wasm_stack.truncate(new_length); + fn check_location_on_stack( + &self, + loc: &Location, + expected_stack_offset: usize, + ) -> Result<(), CompileError> { + let Location::Memory(reg, offset) = loc else { + codegen_error!("Expected stack memory location"); + }; + if reg != &self.machine.local_pointer() { + codegen_error!("Expected location pointer for value on stack"); + } + if *offset >= 0 { + codegen_error!("Invalid memory offset {offset}"); + } + let offset = offset.neg() as usize; + if offset != expected_stack_offset { + codegen_error!("Invalid memory offset {offset}!={}", self.stack_offset); + } Ok(()) } - fn release_locations_keep_state(&mut self, stack_depth: usize) -> Result<(), CompileError> { - let mut delta_stack_offset: usize = 0; - let mut stack_offset = self.stack_offset.0; - let locs = &self.value_stack[stack_depth..]; + /// Allocate return slots for block operands (Block, If, Loop) and swap them with + /// the corresponding input parameters on the value stack. + /// + /// This method reserves memory slots that can accommodate both integer and + /// floating-point types, then swaps these slots with the last `stack_slots` + /// values on the stack to position them correctly for the block's return values. + /// that are already present at the value stack. + fn allocate_return_slots_and_swap( + &mut self, + stack_slots: usize, + return_slots: usize, + ) -> Result<(), CompileError> { + // No shuffling needed. + if return_slots == 0 { + return Ok(()); + } - for loc in locs.iter().rev() { - if let Location::Memory(y, x) = *loc { - if y == self.machine.local_pointer() { - if x >= 0 { - codegen_error!("Invalid memory offset {}", x); - } - let offset = (-x) as usize; - if offset != stack_offset { - codegen_error!("Invalid memory offset {}!={}", offset, self.stack_offset.0); - } - stack_offset -= 8; - delta_stack_offset += 8; + /* To allocate N return slots, we first allocate N additional stack (memory) slots and then "shift" the + existing stack slots. This results in the layout: [value stack before frame, ret0, ret1, ret2, ..., retN, arg0, arg1, ..., argN], + where some of the argN values may reside in registers and others in memory on the stack. */ + let latest_slots = self + .value_stack + .drain(self.value_stack.len() - stack_slots..) + .collect_vec(); + let extra_slots = (0..return_slots) + .map(|_| self.acquire_location_on_stack()) + .collect::, _>>()?; + + let mut all_memory_slots = latest_slots + .iter() + .filter_map(|(loc, _)| { + if let Location::Memory(..) = loc { + Some(loc) + } else { + None } - } - } + }) + .chain(extra_slots.iter()) + .collect_vec(); - let delta_stack_offset = self.machine.round_stack_adjust(delta_stack_offset); - if delta_stack_offset != 0 { - self.machine.pop_stack_locals(delta_stack_offset as u32)?; + // First put the newly allocated return values to the value stack. + self.value_stack.extend( + all_memory_slots + .iter() + .take(return_slots) + .map(|loc| (**loc, CanonicalizeType::None)), + ); + + // Then map all memory stack slots to a new location (in reverse order). + let mut new_params_reversed = Vec::new(); + for (loc, canonicalize) in latest_slots.iter().rev() { + let mapped_loc = if matches!(loc, Location::Memory(..)) { + let dest = all_memory_slots.pop().unwrap(); + self.machine.emit_relaxed_mov(Size::S64, *loc, *dest)?; + *dest + } else { + *loc + }; + new_params_reversed.push((mapped_loc, *canonicalize)); } + self.value_stack + .extend(new_params_reversed.into_iter().rev()); + Ok(()) } @@ -530,6 +429,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { sig: FunctionType, calling_convention: CallingConvention, ) -> Result>, CompileError> { + self.add_assembly_comment(AssemblyComment::InitializeLocals); + // How many machine stack slots will all the locals use? let num_mem_slots = (0..n) .filter(|&x| self.machine.is_local_on_stack(x)) @@ -579,52 +480,32 @@ impl<'a, M: Machine> FuncGen<'a, M> { self.machine.zero_location(Size::S64, locations[i])?; } - self.machine.adjust_stack(static_area_size as _)?; + self.machine.extend_stack(static_area_size as _)?; // Save callee-saved registers. for loc in locations.iter() { - if let Location::GPR(x) = *loc { - self.stack_offset.0 += 8; - self.machine.move_local(self.stack_offset.0 as i32, *loc)?; - self.state.stack_values.push(MachineValue::PreserveRegister( - self.machine.index_from_gpr(x), - )); + if let Location::GPR(_) = *loc { + self.stack_offset += 8; + self.machine.move_local(self.stack_offset as i32, *loc)?; } } // Save the Reg use for vmctx. - self.stack_offset.0 += 8; + self.stack_offset += 8; self.machine.move_local( - self.stack_offset.0 as i32, + self.stack_offset as i32, Location::GPR(self.machine.get_vmctx_reg()), )?; - self.state.stack_values.push(MachineValue::PreserveRegister( - self.machine.index_from_gpr(self.machine.get_vmctx_reg()), - )); // Check if need to same some CallingConvention specific regs let regs_to_save = self.machine.list_to_save(calling_convention); for loc in regs_to_save.iter() { - self.stack_offset.0 += 8; - self.machine.move_local(self.stack_offset.0 as i32, *loc)?; + self.stack_offset += 8; + self.machine.move_local(self.stack_offset as i32, *loc)?; } // Save the offset of register save area. - self.save_area_offset = Some(MachineStackOffset(self.stack_offset.0)); - - // Save location information for locals. - for (i, loc) in locations.iter().enumerate() { - match *loc { - Location::GPR(x) => { - self.state.register_values[self.machine.index_from_gpr(x).0] = - MachineValue::WasmLocal(i); - } - Location::Memory(_, _) => { - self.state.stack_values.push(MachineValue::WasmLocal(i)); - } - _ => codegen_error!("singlpass init_local unreachable"), - } - } + self.save_area_offset = Some(self.stack_offset); // Load in-register parameters into the allocated locations. // Locals are allocated on the stack from higher address to lower address, @@ -638,6 +519,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { _ => codegen_error!("singlepass init_local unimplemented"), }; let loc = self.machine.get_call_param_location( + sig.results().len(), i + 1, sz, &mut stack_offset, @@ -650,8 +532,10 @@ impl<'a, M: Machine> FuncGen<'a, M> { // Load vmctx into it's GPR. self.machine.move_location( Size::S64, - self.machine - .get_simple_param_location(0, calling_convention), + Location::GPR( + self.machine + .get_simple_param_location(0, calling_convention), + ), Location::GPR(self.machine.get_vmctx_reg()), )?; @@ -676,7 +560,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { } // Add the size of all locals allocated to stack. - self.stack_offset.0 += static_area_size - callee_saved_regs_size; + self.stack_offset += static_area_size - callee_saved_regs_size; Ok(locations) } @@ -687,7 +571,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { ) -> Result<(), CompileError> { // Unwind stack to the "save area". self.machine - .restore_saved_area(self.save_area_offset.as_ref().unwrap().0 as i32)?; + .restore_saved_area(self.save_area_offset.unwrap() as i32)?; let regs_to_save = self.machine.list_to_save(calling_convention); for loc in regs_to_save.iter().rev() { @@ -714,121 +598,100 @@ impl<'a, M: Machine> FuncGen<'a, M> { fn get_location_released( &mut self, - loc: Location, - ) -> Result, CompileError> { + loc: (Location, CanonicalizeType), + ) -> Result, CompileError> { self.release_locations(&[loc])?; Ok(loc) } - fn pop_value_released(&mut self) -> Result, CompileError> { + fn pop_value_released(&mut self) -> Result, CompileError> { let loc = self.value_stack.pop().ok_or_else(|| { CompileError::Codegen("pop_value_released: value stack is empty".to_owned()) })?; - self.get_location_released(loc) + self.get_location_released(loc)?; + Ok(loc) } /// Prepare data for binary operator with 2 inputs and 1 output. - fn i2o1_prepare(&mut self, ty: WpType) -> Result, CompileError> { - let loc_b = self.pop_value_released()?; - let loc_a = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(ty, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + fn i2o1_prepare( + &mut self, + ty: WpType, + canonicalize: CanonicalizeType, + ) -> Result, CompileError> { + let loc_b = self.pop_value_released()?.0; + let loc_a = self.pop_value_released()?.0; + let ret = self.acquire_location(&ty)?; + self.value_stack.push((ret, canonicalize)); Ok(I2O1 { loc_a, loc_b, ret }) } - fn mark_trappable(&mut self) { - let state_diff_id = self.get_state_diff(); - let offset = self.machine.assembler_get_offset().0; - self.fsm.trappable_offsets.insert( - offset, - OffsetInfo { - end_offset: offset + 1, - activate_offset: offset, - diff_id: state_diff_id, - }, - ); - self.fsm.wasm_offset_to_target_offset.insert( - self.state.wasm_inst_offset, - SuspendOffset::Trappable(offset), - ); - } - fn mark_offset_trappable(&mut self, offset: usize) { - let state_diff_id = self.get_state_diff(); - self.fsm.trappable_offsets.insert( - offset, - OffsetInfo { - end_offset: offset + 1, - activate_offset: offset, - diff_id: state_diff_id, - }, - ); - self.fsm.wasm_offset_to_target_offset.insert( - self.state.wasm_inst_offset, - SuspendOffset::Trappable(offset), - ); - } - /// Emits a Native ABI call sequence. /// /// The caller MUST NOT hold any temporary registers allocated by `acquire_temp_gpr` when calling /// this function. fn emit_call_native< - I: Iterator>, + I: Iterator, CanonicalizeType)>, J: Iterator, + K: Iterator, F: FnOnce(&mut Self) -> Result<(), CompileError>, >( &mut self, cb: F, params: I, params_type: J, + return_types: K, + call_type: NativeCallType, ) -> Result<(), CompileError> { - // Values pushed in this function are above the shadow region. - self.state.stack_values.push(MachineValue::ExplicitShadow); - - let params: Vec<_> = params.collect(); - let params_size: Vec<_> = params_type - .map(|x| match x { - WpType::F32 | WpType::I32 => Size::S32, - WpType::V128 => unimplemented!(), - _ => Size::S64, + let params = params.collect_vec(); + let stack_params = params + .iter() + .copied() + .filter(|(param, _)| { + if let Location::Memory(reg, _) = param { + debug_assert_eq!(reg, &self.machine.local_pointer()); + true + } else { + false + } }) - .collect(); + .collect_vec(); + let get_size = |param_type: WpType| match param_type { + WpType::F32 | WpType::I32 => Size::S32, + WpType::V128 => unimplemented!(), + _ => Size::S64, + }; + let param_sizes = params_type.map(get_size).collect_vec(); + let return_value_sizes = return_types.map(get_size).collect_vec(); + + /* We're going to reuse the memory param locations for the return values. Any extra needed slots will be allocated on stack. */ + let used_stack_params = stack_params + .iter() + .take(return_value_sizes.len()) + .copied() + .collect_vec(); + let mut return_values = used_stack_params.clone(); + let extra_return_values = (0..return_value_sizes.len().saturating_sub(stack_params.len())) + .map(|_| -> Result<_, CompileError> { + Ok((self.acquire_location_on_stack()?, CanonicalizeType::None)) + }) + .collect::, _>>()?; + return_values.extend(extra_return_values); + + // Release the parameter slots that live in registers. + self.release_reg_locations(¶ms)?; // Save used GPRs. Preserve correct stack alignment let used_gprs = self.machine.get_used_gprs(); let mut used_stack = self.machine.push_used_gpr(&used_gprs)?; - for r in used_gprs.iter() { - let content = self.state.register_values[self.machine.index_from_gpr(*r).0].clone(); - if content == MachineValue::Undefined { - return Err(CompileError::Codegen( - "emit_call_native: Undefined used_gprs content".to_owned(), - )); - } - self.state.stack_values.push(content); - } // Save used SIMD registers. let used_simds = self.machine.get_used_simd(); if !used_simds.is_empty() { used_stack += self.machine.push_used_simd(&used_simds)?; - - for r in used_simds.iter().rev() { - let content = - self.state.register_values[self.machine.index_from_simd(*r).0].clone(); - if content == MachineValue::Undefined { - return Err(CompileError::Codegen( - "emit_call_native: Undefined used_simds content".to_owned(), - )); - } - self.state.stack_values.push(content); - } } // mark the GPR used for Call as used self.machine - .reserve_unused_temp_gpr(self.machine.get_grp_for_call()); + .reserve_unused_temp_gpr(self.machine.get_gpr_for_call()); let calling_convention = self.calling_convention; @@ -838,13 +701,25 @@ impl<'a, M: Machine> FuncGen<'a, M> { }; let mut stack_offset: usize = 0; - let mut args: Vec> = vec![]; - let mut pushed_args: usize = 0; - // Calculate stack offset. - for (i, _param) in params.iter().enumerate() { + // Allocate space for return values relative to SP (the allocation happens in reverse order, thus start with return slots). + let mut return_args = Vec::with_capacity(return_value_sizes.len()); + for i in 0..return_value_sizes.len() { + return_args.push(self.machine.get_return_value_location( + i, + &mut stack_offset, + self.calling_convention, + )); + } + + // Allocate space for arguments relative to SP. + let mut args = Vec::with_capacity(params.len()); + for (i, param_size) in param_sizes.iter().enumerate() { args.push(self.machine.get_param_location( - 1 + i, - params_size[i], + match call_type { + NativeCallType::IncludeVMCtxArgument => 1, + NativeCallType::Unreachable => 0, + } + i, + *param_size, &mut stack_offset, calling_convention, )); @@ -852,64 +727,29 @@ impl<'a, M: Machine> FuncGen<'a, M> { // Align stack to 16 bytes. let stack_unaligned = - (self.machine.round_stack_adjust(self.get_stack_offset()) + used_stack + stack_offset) - % 16; + (self.machine.round_stack_adjust(self.stack_offset) + used_stack + stack_offset) % 16; if stack_unaligned != 0 { stack_offset += 16 - stack_unaligned; } - self.machine.adjust_stack(stack_offset as u32)?; + self.machine.extend_stack(stack_offset as u32)?; #[allow(clippy::type_complexity)] let mut call_movs: Vec<(Location, M::GPR)> = vec![]; // Prepare register & stack parameters. - for (i, param) in params.iter().enumerate().rev() { + for (i, (param, _)) in params.iter().enumerate().rev() { let loc = args[i]; match loc { Location::GPR(x) => { call_movs.push((*param, x)); } Location::Memory(_, _) => { - pushed_args += 1; - match *param { - Location::GPR(x) => { - let content = self.state.register_values - [self.machine.index_from_gpr(x).0] - .clone(); - // FIXME: There might be some corner cases (release -> emit_call_native -> acquire?) that cause this assertion to fail. - // Hopefully nothing would be incorrect at runtime. - - //assert!(content != MachineValue::Undefined); - self.state.stack_values.push(content); - } - Location::SIMD(x) => { - let content = self.state.register_values - [self.machine.index_from_simd(x).0] - .clone(); - //assert!(content != MachineValue::Undefined); - self.state.stack_values.push(content); - } - Location::Memory(reg, offset) => { - if reg != self.machine.local_pointer() { - return Err(CompileError::Codegen( - "emit_call_native loc param: unreachable code".to_owned(), - )); - } - self.state - .stack_values - .push(MachineValue::CopyStackBPRelative(offset)); - // TODO: Read value at this offset - } - _ => { - self.state.stack_values.push(MachineValue::Undefined); - } - } self.machine - .move_location_for_native(params_size[i], *param, loc)?; + .move_location_for_native(param_sizes[i], *param, loc)?; } _ => { return Err(CompileError::Codegen( "emit_call_native loc: unreachable code".to_owned(), - )) + )); } } } @@ -925,107 +765,66 @@ impl<'a, M: Machine> FuncGen<'a, M> { } } - // Put vmctx as the first parameter. - self.machine.move_location( - Size::S64, - Location::GPR(self.machine.get_vmctx_reg()), - self.machine - .get_simple_param_location(0, calling_convention), - )?; // vmctx + if matches!(call_type, NativeCallType::IncludeVMCtxArgument) { + // Put vmctx as the first parameter. + self.machine.move_location( + Size::S64, + Location::GPR(self.machine.get_vmctx_reg()), + Location::GPR( + self.machine + .get_simple_param_location(0, calling_convention), + ), + )?; // vmctx + } if stack_padding > 0 { - self.machine.adjust_stack(stack_padding as u32)?; + self.machine.extend_stack(stack_padding as u32)?; } // release the GPR used for call - self.machine.release_gpr(self.machine.get_grp_for_call()); - cb(self)?; + self.machine.release_gpr(self.machine.get_gpr_for_call()); - // Offset needs to be after the 'call' instruction. - // TODO: Now the state information is also inserted for internal calls (e.g. MemoryGrow). Is this expected? - { - let state_diff_id = self.get_state_diff(); - let offset = self.machine.assembler_get_offset().0; - self.fsm.call_offsets.insert( - offset, - OffsetInfo { - end_offset: offset + 1, - activate_offset: offset, - diff_id: state_diff_id, - }, + let begin = self.machine.assembler_get_offset().0; + cb(self)?; + if matches!(call_type, NativeCallType::Unreachable) { + let end = self.machine.assembler_get_offset().0; + self.machine.mark_address_range_with_trap_code( + TrapCode::UnreachableCodeReached, + begin, + end, ); - self.fsm - .wasm_offset_to_target_offset - .insert(self.state.wasm_inst_offset, SuspendOffset::Call(offset)); + } + + // Take the returned values from the fn call. + for (i, &return_type) in return_value_sizes.iter().enumerate() { + self.machine.move_location_for_native( + return_type, + return_args[i], + return_values[i].0, + )?; } // Restore stack. if stack_offset + stack_padding > 0 { - self.machine.restore_stack( - self.machine - .round_stack_adjust(stack_offset + stack_padding) as u32, - )?; - if (stack_offset % 8) != 0 { - return Err(CompileError::Codegen( - "emit_call_native: Bad restoring stack alignement".to_owned(), - )); - } - for _ in 0..pushed_args { - self.state - .stack_values - .pop() - .ok_or_else(|| CompileError::Codegen("Pop an empty value stack".to_owned()))?; - } + self.machine + .truncate_stack((stack_offset + stack_padding) as u32)?; } // Restore SIMDs. if !used_simds.is_empty() { self.machine.pop_used_simd(&used_simds)?; - for _ in 0..used_simds.len() { - self.state - .stack_values - .pop() - .ok_or_else(|| CompileError::Codegen("Pop an empty value stack".to_owned()))?; - } } // Restore GPRs. self.machine.pop_used_gpr(&used_gprs)?; - for _ in used_gprs.iter().rev() { - self.state - .stack_values - .pop() - .ok_or_else(|| CompileError::Codegen("Pop an empty value stack".to_owned()))?; - } - if self - .state - .stack_values - .pop() - .ok_or_else(|| CompileError::Codegen("Pop an empty value stack".to_owned()))? - != MachineValue::ExplicitShadow - { - return Err(CompileError::Codegen( - "emit_call_native: Popped value is not ExplicitShadow".to_owned(), - )); - } - Ok(()) - } + // We are re-using the params for the return values, thus release just the chunk + // we're not planning to use! + let params_to_release = + &stack_params[cmp::min(stack_params.len(), return_value_sizes.len())..]; + self.release_stack_locations(params_to_release)?; + + self.value_stack.extend(return_values); - /// Emits a Native ABI call sequence, specialized for labels as the call target. - fn _emit_call_native_label< - I: Iterator>, - J: Iterator, - >( - &mut self, - label: Label, - params: I, - params_type: J, - ) -> Result<(), CompileError> { - self.emit_call_native( - |this| this.machine.emit_call_label(label), - params, - params_type, - )?; Ok(()) } @@ -1058,21 +857,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { ) } - pub fn get_state_diff(&mut self) -> usize { - if !self.track_state { - return usize::MAX; - } - let last_frame = self.control_stack.last_mut().unwrap(); - let mut diff = self.state.diff(&last_frame.state); - diff.last = Some(last_frame.state_diff_id); - let id = self.fsm.diffs.len(); - last_frame.state = self.state.clone(); - last_frame.state_diff_id = id; - self.fsm.diffs.push(diff); - id - } - fn emit_head(&mut self) -> Result<(), CompileError> { + self.add_assembly_comment(AssemblyComment::FunctionPrologue); self.machine.emit_function_prolog()?; // Initialize locals. @@ -1082,32 +868,32 @@ impl<'a, M: Machine> FuncGen<'a, M> { self.calling_convention, )?; - // Mark vmctx register. The actual loading of the vmctx value is handled by init_local. - self.state.register_values[self.machine.index_from_gpr(self.machine.get_vmctx_reg()).0] = - MachineValue::Vmctx; + // simulate "red zone" if not supported by the platform + self.add_assembly_comment(AssemblyComment::RedZone); + self.machine.extend_stack(32)?; - // TODO: Explicit stack check is not supported for now. - let diff = self.state.diff(&self.machine.new_machine_state()); - let state_diff_id = self.fsm.diffs.len(); - self.fsm.diffs.push(diff); + let return_types: SmallVec<_> = self + .signature + .results() + .iter() + .map(type_to_wp_type) + .collect(); - // simulate "red zone" if not supported by the platform - self.machine.adjust_stack(32)?; + // Push return value slots for the function return on the stack. + self.value_stack.extend((0..return_types.len()).map(|i| { + ( + self.machine + .get_call_return_value_location(i, self.calling_convention), + CanonicalizeType::None, + ) + })); self.control_stack.push(ControlFrame { + state: ControlState::Function, label: self.machine.get_label(), - loop_like: false, - if_else: IfElseState::None, - returns: self - .signature - .results() - .iter() - .map(|&x| type_to_wp_type(x)) - .collect(), - value_stack_depth: 0, - fp_stack_depth: 0, - state: self.state.clone(), - state_diff_id, + value_stack_depth: return_types.len(), + param_types: smallvec![], + return_types, }); // TODO: Full preemption by explicit signal checking @@ -1115,12 +901,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { // We insert set StackOverflow as the default trap that can happen // anywhere in the function prologue. self.machine.insert_stackoverflow(); + self.add_assembly_comment(AssemblyComment::FunctionBody); - if self.state.wasm_inst_offset != usize::MAX { - return Err(CompileError::Codegen( - "emit_head: wasm_inst_offset not usize::MAX".to_owned(), - )); - } Ok(()) } @@ -1140,11 +922,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { let sig_index = module.functions[func_index]; let signature = module.signatures[sig_index].clone(); - let mut local_types: Vec<_> = signature - .params() - .iter() - .map(|&x| type_to_wp_type(x)) - .collect(); + let mut local_types: Vec<_> = signature.params().iter().map(type_to_wp_type).collect(); local_types.extend_from_slice(local_types_excluding_arguments); let mut machine = machine; @@ -1157,15 +935,11 @@ impl<'a, M: Machine> FuncGen<'a, M> { bad_signature: machine.get_label(), unaligned_atomic: machine.get_label(), }; - - let fsm = FunctionStateMap::new( - machine.new_machine_state(), - local_func_index.index() as usize, - 32, - (0..local_types.len()) - .map(|_| WasmAbstractValue::Runtime) - .collect(), - ); + let function_name = module + .function_names + .get(&func_index) + .map(|fname| fname.to_string()) + .unwrap_or_else(|| format!("function_{}", func_index.as_u32())); let mut fg = FuncGen { module, @@ -1177,18 +951,17 @@ impl<'a, M: Machine> FuncGen<'a, M> { locals: vec![], // initialization deferred to emit_head local_types, value_stack: vec![], - fp_stack: vec![], control_stack: vec![], - stack_offset: MachineStackOffset(0), + stack_offset: 0, save_area_offset: None, - state: machine.new_machine_state(), - track_state: true, machine, unreachable_depth: 0, - fsm, + local_func_index, relocations: vec![], special_labels, calling_convention, + function_name, + assembly_comments: HashMap::new(), }; fg.emit_head()?; Ok(fg) @@ -1198,12 +971,87 @@ impl<'a, M: Machine> FuncGen<'a, M> { !self.control_stack.is_empty() } - pub fn feed_operator(&mut self, op: Operator) -> Result<(), CompileError> { - assert!(self.fp_stack.len() <= self.value_stack.len()); + /// Moves the top `return_values` items from the value stack into the + /// preallocated return slots starting at `value_stack_depth_after`. + /// + /// Used when completing Block/If/Loop constructs or returning from the + /// function. Applies NaN canonicalization when enabled and supported. + fn emit_return_values( + &mut self, + value_stack_depth_after: usize, + return_values: usize, + ) -> Result<(), CompileError> { + for (i, (stack_value, canonicalize)) in self + .value_stack + .iter() + .rev() + .take(return_values) + .enumerate() + { + let dst = self.value_stack[value_stack_depth_after - i - 1].0; + if let Some(canonicalize_size) = canonicalize.to_size() + && self.config.enable_nan_canonicalization + { + self.machine + .canonicalize_nan(canonicalize_size, *stack_value, dst)?; + } else { + self.machine + .emit_relaxed_mov(Size::S64, *stack_value, dst)?; + } + } + + Ok(()) + } + + /// Similar to `emit_return_values`, except it stores the `return_values` items into the slots + /// preallocated for parameters of a loop. + fn emit_loop_params_store( + &mut self, + value_stack_depth_after: usize, + param_count: usize, + ) -> Result<(), CompileError> { + for (i, (stack_value, _)) in self + .value_stack + .iter() + .rev() + .take(param_count) + .rev() + .enumerate() + { + let dst = self.value_stack[value_stack_depth_after + i].0; + self.machine + .emit_relaxed_mov(Size::S64, *stack_value, dst)?; + } - self.state.wasm_inst_offset = self.state.wasm_inst_offset.wrapping_add(1); + Ok(()) + } - //println!("{:?} {}", op, self.value_stack.len()); + fn return_types_for_block(&self, block_type: WpTypeOrFuncType) -> SmallVec<[WpType; 1]> { + match block_type { + WpTypeOrFuncType::Empty => smallvec![], + WpTypeOrFuncType::Type(inner_ty) => smallvec![inner_ty], + WpTypeOrFuncType::FuncType(sig_index) => SmallVec::from_iter( + self.module.signatures[SignatureIndex::from_u32(sig_index)] + .results() + .iter() + .map(type_to_wp_type), + ), + } + } + + fn param_types_for_block(&self, block_type: WpTypeOrFuncType) -> SmallVec<[WpType; 8]> { + match block_type { + WpTypeOrFuncType::Empty | WpTypeOrFuncType::Type(_) => smallvec![], + WpTypeOrFuncType::FuncType(sig_index) => SmallVec::from_iter( + self.module.signatures[SignatureIndex::from_u32(sig_index)] + .params() + .iter() + .map(type_to_wp_type), + ), + } + } + + pub fn feed_operator(&mut self, op: Operator) -> Result<(), CompileError> { let was_unreachable; if self.unreachable_depth > 0 { @@ -1218,12 +1066,13 @@ impl<'a, M: Machine> FuncGen<'a, M> { } Operator::Else => { // We are in a reachable true branch - if self.unreachable_depth == 1 { - if let Some(IfElseState::If(_)) = - self.control_stack.last().map(|x| x.if_else) - { - self.unreachable_depth -= 1; - } + if self.unreachable_depth == 1 + && self + .control_stack + .last() + .is_some_and(|frame| matches!(frame.state, ControlState::If { .. })) + { + self.unreachable_depth -= 1; } } _ => {} @@ -1239,15 +1088,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { Operator::GlobalGet { global_index } => { let global_index = GlobalIndex::from_u32(global_index); - let ty = type_to_wp_type(self.module.globals[global_index].ty); - if ty.is_float() { - self.fp_stack.push(FloatValue::new(self.value_stack.len())); - } - let loc = self.acquire_locations( - &[(ty, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(loc); + let ty = type_to_wp_type(&self.module.globals[global_index].ty); + let loc = self.acquire_location(&ty)?; + self.value_stack.push((loc, CanonicalizeType::None)); let tmp = self.machine.acquire_temp_gpr().unwrap(); @@ -1303,23 +1146,10 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; Location::Memory(tmp, 0) }; - let ty = type_to_wp_type(self.module.globals[global_index].ty); - let loc = self.pop_value_released()?; - if ty.is_float() { - let fp = self.fp_stack.pop1()?; - if self.machine.arch_supports_canonicalize_nan() - && self.config.enable_nan_canonicalization - && fp.canonicalization.is_some() - { - self.machine.canonicalize_nan( - match ty { - WpType::F32 => Size::S32, - WpType::F64 => Size::S64, - _ => codegen_error!("singlepass Operator::GlobalSet unreachable"), - }, - loc, - dst, - )?; + let (loc, canonicalize) = self.pop_value_released()?; + if let Some(canonicalize_size) = canonicalize.to_size() { + if self.config.enable_nan_canonicalization { + self.machine.canonicalize_nan(canonicalize_size, loc, dst)?; } else { self.machine.emit_relaxed_mov(Size::S64, loc, dst)?; } @@ -1330,34 +1160,21 @@ impl<'a, M: Machine> FuncGen<'a, M> { } Operator::LocalGet { local_index } => { let local_index = local_index as usize; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; + let ret = self.acquire_location(&WpType::I64)?; self.machine .emit_relaxed_mov(Size::S64, self.locals[local_index], ret)?; - self.value_stack.push(ret); - if self.local_types[local_index].is_float() { - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); - } + self.value_stack.push((ret, CanonicalizeType::None)); } Operator::LocalSet { local_index } => { let local_index = local_index as usize; - let loc = self.pop_value_released()?; + let (loc, canonicalize) = self.pop_value_released()?; - if self.local_types[local_index].is_float() { - let fp = self.fp_stack.pop1()?; - if self.machine.arch_supports_canonicalize_nan() - && self.config.enable_nan_canonicalization - && fp.canonicalization.is_some() - { + if self.local_types[local_index].is_float() + && let Some(canonicalize_size) = canonicalize.to_size() + { + if self.config.enable_nan_canonicalization { self.machine.canonicalize_nan( - match self.local_types[local_index] { - WpType::F32 => Size::S32, - WpType::F64 => Size::S64, - _ => codegen_error!("singlepass Operator::LocalSet unreachable"), - }, + canonicalize_size, loc, self.locals[local_index], ) @@ -1372,20 +1189,14 @@ impl<'a, M: Machine> FuncGen<'a, M> { } Operator::LocalTee { local_index } => { let local_index = local_index as usize; - let loc = *self.value_stack.last().unwrap(); + let (loc, canonicalize) = *self.value_stack.last().unwrap(); - if self.local_types[local_index].is_float() { - let fp = self.fp_stack.peek1()?; - if self.machine.arch_supports_canonicalize_nan() - && self.config.enable_nan_canonicalization - && fp.canonicalization.is_some() - { + if self.local_types[local_index].is_float() + && let Some(canonicalize_size) = canonicalize.to_size() + { + if self.config.enable_nan_canonicalization { self.machine.canonicalize_nan( - match self.local_types[local_index] { - WpType::F32 => Size::S32, - WpType::F64 => Size::S64, - _ => codegen_error!("singlepass Operator::LocalTee unreachable"), - }, + canonicalize_size, loc, self.locals[local_index], ) @@ -1399,351 +1210,358 @@ impl<'a, M: Machine> FuncGen<'a, M> { }?; } Operator::I32Const { value } => { - self.value_stack.push(Location::Imm32(value as u32)); - self.state - .wasm_stack - .push(WasmAbstractValue::Const(value as u32 as u64)); + self.value_stack + .push((Location::Imm32(value as u32), CanonicalizeType::None)); } Operator::I32Add => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.emit_binop_add32(loc_a, loc_b, ret)?; } Operator::I32Sub => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.emit_binop_sub32(loc_a, loc_b, ret)?; } Operator::I32Mul => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.emit_binop_mul32(loc_a, loc_b, ret)?; } Operator::I32DivU => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; - let offset = self.machine.emit_binop_udiv32( + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; + self.machine.emit_binop_udiv32( loc_a, loc_b, ret, self.special_labels.integer_division_by_zero, - self.special_labels.integer_overflow, )?; - self.mark_offset_trappable(offset); } Operator::I32DivS => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; - let offset = self.machine.emit_binop_sdiv32( + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; + self.machine.emit_binop_sdiv32( loc_a, loc_b, ret, self.special_labels.integer_division_by_zero, self.special_labels.integer_overflow, )?; - self.mark_offset_trappable(offset); } Operator::I32RemU => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; - let offset = self.machine.emit_binop_urem32( + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; + self.machine.emit_binop_urem32( loc_a, loc_b, ret, self.special_labels.integer_division_by_zero, - self.special_labels.integer_overflow, )?; - self.mark_offset_trappable(offset); } Operator::I32RemS => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; - let offset = self.machine.emit_binop_srem32( + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; + self.machine.emit_binop_srem32( loc_a, loc_b, ret, self.special_labels.integer_division_by_zero, - self.special_labels.integer_overflow, )?; - self.mark_offset_trappable(offset); } Operator::I32And => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.emit_binop_and32(loc_a, loc_b, ret)?; } Operator::I32Or => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.emit_binop_or32(loc_a, loc_b, ret)?; } Operator::I32Xor => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.emit_binop_xor32(loc_a, loc_b, ret)?; } Operator::I32Eq => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_cmp_eq(loc_a, loc_b, ret)?; } Operator::I32Ne => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_cmp_ne(loc_a, loc_b, ret)?; } Operator::I32Eqz => { - let loc_a = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; + let loc_a = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; self.machine.i32_cmp_eq(loc_a, Location::Imm32(0), ret)?; - self.value_stack.push(ret); + self.value_stack.push((ret, CanonicalizeType::None)); } Operator::I32Clz => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.i32_clz(loc, ret)?; } Operator::I32Ctz => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.i32_ctz(loc, ret)?; } Operator::I32Popcnt => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.i32_popcnt(loc, ret)?; } Operator::I32Shl => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_shl(loc_a, loc_b, ret)?; } Operator::I32ShrU => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_shr(loc_a, loc_b, ret)?; } Operator::I32ShrS => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_sar(loc_a, loc_b, ret)?; } Operator::I32Rotl => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_rol(loc_a, loc_b, ret)?; } Operator::I32Rotr => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_ror(loc_a, loc_b, ret)?; } Operator::I32LtU => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_cmp_lt_u(loc_a, loc_b, ret)?; } Operator::I32LeU => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_cmp_le_u(loc_a, loc_b, ret)?; } Operator::I32GtU => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_cmp_gt_u(loc_a, loc_b, ret)?; } Operator::I32GeU => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_cmp_ge_u(loc_a, loc_b, ret)?; } Operator::I32LtS => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_cmp_lt_s(loc_a, loc_b, ret)?; } Operator::I32LeS => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_cmp_le_s(loc_a, loc_b, ret)?; } Operator::I32GtS => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_cmp_gt_s(loc_a, loc_b, ret)?; } Operator::I32GeS => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.i32_cmp_ge_s(loc_a, loc_b, ret)?; } Operator::I64Const { value } => { let value = value as u64; - self.value_stack.push(Location::Imm64(value)); - self.state.wasm_stack.push(WasmAbstractValue::Const(value)); + self.value_stack + .push((Location::Imm64(value), CanonicalizeType::None)); } Operator::I64Add => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.emit_binop_add64(loc_a, loc_b, ret)?; } Operator::I64Sub => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.emit_binop_sub64(loc_a, loc_b, ret)?; } Operator::I64Mul => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.emit_binop_mul64(loc_a, loc_b, ret)?; } Operator::I64DivU => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; - let offset = self.machine.emit_binop_udiv64( + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; + self.machine.emit_binop_udiv64( loc_a, loc_b, ret, self.special_labels.integer_division_by_zero, - self.special_labels.integer_overflow, )?; - self.mark_offset_trappable(offset); } Operator::I64DivS => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; - let offset = self.machine.emit_binop_sdiv64( + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; + self.machine.emit_binop_sdiv64( loc_a, loc_b, ret, self.special_labels.integer_division_by_zero, self.special_labels.integer_overflow, )?; - self.mark_offset_trappable(offset); } Operator::I64RemU => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; - let offset = self.machine.emit_binop_urem64( + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; + self.machine.emit_binop_urem64( loc_a, loc_b, ret, self.special_labels.integer_division_by_zero, - self.special_labels.integer_overflow, )?; - self.mark_offset_trappable(offset); } Operator::I64RemS => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; - let offset = self.machine.emit_binop_srem64( + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; + self.machine.emit_binop_srem64( loc_a, loc_b, ret, self.special_labels.integer_division_by_zero, - self.special_labels.integer_overflow, )?; - self.mark_offset_trappable(offset); } Operator::I64And => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.emit_binop_and64(loc_a, loc_b, ret)?; } Operator::I64Or => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.emit_binop_or64(loc_a, loc_b, ret)?; } Operator::I64Xor => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.emit_binop_xor64(loc_a, loc_b, ret)?; } Operator::I64Eq => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_cmp_eq(loc_a, loc_b, ret)?; } Operator::I64Ne => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_cmp_ne(loc_a, loc_b, ret)?; } Operator::I64Eqz => { - let loc_a = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; + let loc_a = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; self.machine.i64_cmp_eq(loc_a, Location::Imm64(0), ret)?; - self.value_stack.push(ret); + self.value_stack.push((ret, CanonicalizeType::None)); } Operator::I64Clz => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.i64_clz(loc, ret)?; } Operator::I64Ctz => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.i64_ctz(loc, ret)?; } Operator::I64Popcnt => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.i64_popcnt(loc, ret)?; } Operator::I64Shl => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_shl(loc_a, loc_b, ret)?; } Operator::I64ShrU => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_shr(loc_a, loc_b, ret)?; } Operator::I64ShrS => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_sar(loc_a, loc_b, ret)?; } Operator::I64Rotl => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_rol(loc_a, loc_b, ret)?; } Operator::I64Rotr => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_ror(loc_a, loc_b, ret)?; } Operator::I64LtU => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_cmp_lt_u(loc_a, loc_b, ret)?; } Operator::I64LeU => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_cmp_le_u(loc_a, loc_b, ret)?; } Operator::I64GtU => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_cmp_gt_u(loc_a, loc_b, ret)?; } Operator::I64GeU => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_cmp_ge_u(loc_a, loc_b, ret)?; } Operator::I64LtS => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_cmp_lt_s(loc_a, loc_b, ret)?; } Operator::I64LeS => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_cmp_le_s(loc_a, loc_b, ret)?; } Operator::I64GtS => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_cmp_gt_s(loc_a, loc_b, ret)?; } Operator::I64GeS => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?; self.machine.i64_cmp_ge_s(loc_a, loc_b, ret)?; } Operator::I64ExtendI32U => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.emit_relaxed_mov(Size::S32, loc, ret)?; // A 32-bit memory write does not automatically clear the upper 32 bits of a 64-bit word. @@ -1757,255 +1575,178 @@ impl<'a, M: Machine> FuncGen<'a, M> { } } Operator::I64ExtendI32S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine .emit_relaxed_sign_extension(Size::S32, loc, Size::S64, ret)?; } Operator::I32Extend8S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine .emit_relaxed_sign_extension(Size::S8, loc, Size::S32, ret)?; } Operator::I32Extend16S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine .emit_relaxed_sign_extension(Size::S16, loc, Size::S32, ret)?; } Operator::I64Extend8S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine .emit_relaxed_sign_extension(Size::S8, loc, Size::S64, ret)?; } Operator::I64Extend16S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine .emit_relaxed_sign_extension(Size::S16, loc, Size::S64, ret)?; } Operator::I64Extend32S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine .emit_relaxed_sign_extension(Size::S32, loc, Size::S64, ret)?; } Operator::I32WrapI64 => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.emit_relaxed_mov(Size::S32, loc, ret)?; } Operator::F32Const { value } => { - self.value_stack.push(Location::Imm32(value.bits())); - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); - self.state - .wasm_stack - .push(WasmAbstractValue::Const(value.bits() as u64)); + self.value_stack + .push((Location::Imm32(value.bits()), CanonicalizeType::None)); } Operator::F32Add => { - self.fp_stack.pop2()?; - self.fp_stack - .push(FloatValue::cncl_f32(self.value_stack.len() - 2)); - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::F64)?; - + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::F64, CanonicalizeType::F32)?; self.machine.f32_add(loc_a, loc_b, ret)?; } Operator::F32Sub => { - self.fp_stack.pop2()?; - self.fp_stack - .push(FloatValue::cncl_f32(self.value_stack.len() - 2)); - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::F64)?; - + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::F64, CanonicalizeType::F32)?; self.machine.f32_sub(loc_a, loc_b, ret)?; } Operator::F32Mul => { - self.fp_stack.pop2()?; - self.fp_stack - .push(FloatValue::cncl_f32(self.value_stack.len() - 2)); - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::F64)?; - + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::F64, CanonicalizeType::F32)?; self.machine.f32_mul(loc_a, loc_b, ret)?; } Operator::F32Div => { - self.fp_stack.pop2()?; - self.fp_stack - .push(FloatValue::cncl_f32(self.value_stack.len() - 2)); - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::F64)?; - + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::F64, CanonicalizeType::F32)?; self.machine.f32_div(loc_a, loc_b, ret)?; } Operator::F32Max => { - self.fp_stack.pop2()?; - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 2)); - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::F64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::F64, CanonicalizeType::None)?; self.machine.f32_max(loc_a, loc_b, ret)?; } Operator::F32Min => { - self.fp_stack.pop2()?; - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 2)); - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::F64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::F64, CanonicalizeType::None)?; self.machine.f32_min(loc_a, loc_b, ret)?; } Operator::F32Eq => { - self.fp_stack.pop2()?; - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.f32_cmp_eq(loc_a, loc_b, ret)?; } Operator::F32Ne => { - self.fp_stack.pop2()?; - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.f32_cmp_ne(loc_a, loc_b, ret)?; } Operator::F32Lt => { - self.fp_stack.pop2()?; - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.f32_cmp_lt(loc_a, loc_b, ret)?; } Operator::F32Le => { - self.fp_stack.pop2()?; - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.f32_cmp_le(loc_a, loc_b, ret)?; } Operator::F32Gt => { - self.fp_stack.pop2()?; - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.f32_cmp_gt(loc_a, loc_b, ret)?; } Operator::F32Ge => { - self.fp_stack.pop2()?; - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.f32_cmp_ge(loc_a, loc_b, ret)?; } Operator::F32Nearest => { - self.fp_stack.pop1()?; - self.fp_stack - .push(FloatValue::cncl_f32(self.value_stack.len() - 1)); - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::F32)); self.machine.f32_nearest(loc, ret)?; } Operator::F32Floor => { - self.fp_stack.pop1()?; - self.fp_stack - .push(FloatValue::cncl_f32(self.value_stack.len() - 1)); - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::F32)); self.machine.f32_floor(loc, ret)?; } Operator::F32Ceil => { - self.fp_stack.pop1()?; - self.fp_stack - .push(FloatValue::cncl_f32(self.value_stack.len() - 1)); - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::F32)); self.machine.f32_ceil(loc, ret)?; } Operator::F32Trunc => { - self.fp_stack.pop1()?; - self.fp_stack - .push(FloatValue::cncl_f32(self.value_stack.len() - 1)); - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::F32)); self.machine.f32_trunc(loc, ret)?; } Operator::F32Sqrt => { - self.fp_stack.pop1()?; - self.fp_stack - .push(FloatValue::cncl_f32(self.value_stack.len() - 1)); - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::F32)); self.machine.f32_sqrt(loc, ret)?; } Operator::F32Copysign => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::F32)?; - - let (fp_src1, fp_src2) = self.fp_stack.pop2()?; - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); + let loc_b = self.pop_value_released()?; + let loc_a = self.pop_value_released()?; + let ret = self.acquire_location(&WpType::F32)?; + self.value_stack.push((ret, CanonicalizeType::None)); let tmp1 = self.machine.acquire_temp_gpr().unwrap(); let tmp2 = self.machine.acquire_temp_gpr().unwrap(); - if self.machine.arch_supports_canonicalize_nan() - && self.config.enable_nan_canonicalization - { - for (fp, loc, tmp) in [(fp_src1, loc_a, tmp1), (fp_src2, loc_b, tmp2)].iter() { - match fp.canonicalization { - Some(_) => { - self.machine - .canonicalize_nan(Size::S32, *loc, Location::GPR(*tmp)) - } - None => { - self.machine - .move_location(Size::S32, *loc, Location::GPR(*tmp)) - } - }?; + if self.config.enable_nan_canonicalization { + for ((loc, fp), tmp) in [(loc_a, tmp1), (loc_b, tmp2)] { + if fp.to_size().is_some() { + self.machine + .canonicalize_nan(Size::S32, loc, Location::GPR(tmp))? + } else { + self.machine + .move_location(Size::S32, loc, Location::GPR(tmp))? + } } } else { self.machine - .move_location(Size::S32, loc_a, Location::GPR(tmp1))?; + .move_location(Size::S32, loc_a.0, Location::GPR(tmp1))?; self.machine - .move_location(Size::S32, loc_b, Location::GPR(tmp2))?; + .move_location(Size::S32, loc_b.0, Location::GPR(tmp2))?; } self.machine.emit_i32_copysign(tmp1, tmp2)?; self.machine @@ -2017,12 +1758,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { Operator::F32Abs => { // Preserve canonicalization state. - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.f32_abs(loc, ret)?; } @@ -2030,191 +1768,132 @@ impl<'a, M: Machine> FuncGen<'a, M> { Operator::F32Neg => { // Preserve canonicalization state. - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.f32_neg(loc, ret)?; } Operator::F64Const { value } => { - self.value_stack.push(Location::Imm64(value.bits())); - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); - self.state - .wasm_stack - .push(WasmAbstractValue::Const(value.bits())); + self.value_stack + .push((Location::Imm64(value.bits()), CanonicalizeType::None)); } Operator::F64Add => { - self.fp_stack.pop2()?; - self.fp_stack - .push(FloatValue::cncl_f64(self.value_stack.len() - 2)); - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::F64)?; - + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::F64, CanonicalizeType::F64)?; self.machine.f64_add(loc_a, loc_b, ret)?; } Operator::F64Sub => { - self.fp_stack.pop2()?; - self.fp_stack - .push(FloatValue::cncl_f64(self.value_stack.len() - 2)); - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::F64)?; - + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::F64, CanonicalizeType::F64)?; self.machine.f64_sub(loc_a, loc_b, ret)?; } Operator::F64Mul => { - self.fp_stack.pop2()?; - self.fp_stack - .push(FloatValue::cncl_f64(self.value_stack.len() - 2)); - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::F64)?; - + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::F64, CanonicalizeType::F64)?; self.machine.f64_mul(loc_a, loc_b, ret)?; } Operator::F64Div => { - self.fp_stack.pop2()?; - self.fp_stack - .push(FloatValue::cncl_f64(self.value_stack.len() - 2)); - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::F64)?; - + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::F64, CanonicalizeType::F64)?; self.machine.f64_div(loc_a, loc_b, ret)?; } Operator::F64Max => { - self.fp_stack.pop2()?; - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 2)); - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::F64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::F64, CanonicalizeType::None)?; self.machine.f64_max(loc_a, loc_b, ret)?; } Operator::F64Min => { - self.fp_stack.pop2()?; - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 2)); - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::F64)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::F64, CanonicalizeType::None)?; self.machine.f64_min(loc_a, loc_b, ret)?; } Operator::F64Eq => { - self.fp_stack.pop2()?; - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.f64_cmp_eq(loc_a, loc_b, ret)?; } Operator::F64Ne => { - self.fp_stack.pop2()?; - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.f64_cmp_ne(loc_a, loc_b, ret)?; } Operator::F64Lt => { - self.fp_stack.pop2()?; - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.f64_cmp_lt(loc_a, loc_b, ret)?; } Operator::F64Le => { - self.fp_stack.pop2()?; - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.f64_cmp_le(loc_a, loc_b, ret)?; } Operator::F64Gt => { - self.fp_stack.pop2()?; - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.f64_cmp_gt(loc_a, loc_b, ret)?; } Operator::F64Ge => { - self.fp_stack.pop2()?; - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::I32)?; + let I2O1 { loc_a, loc_b, ret } = + self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?; self.machine.f64_cmp_ge(loc_a, loc_b, ret)?; } Operator::F64Nearest => { - self.fp_stack.pop1()?; - self.fp_stack - .push(FloatValue::cncl_f64(self.value_stack.len() - 1)); - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::F64)); self.machine.f64_nearest(loc, ret)?; } Operator::F64Floor => { - self.fp_stack.pop1()?; - self.fp_stack - .push(FloatValue::cncl_f64(self.value_stack.len() - 1)); - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::F64)); self.machine.f64_floor(loc, ret)?; } Operator::F64Ceil => { - self.fp_stack.pop1()?; - self.fp_stack - .push(FloatValue::cncl_f64(self.value_stack.len() - 1)); - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::F64)); self.machine.f64_ceil(loc, ret)?; } Operator::F64Trunc => { - self.fp_stack.pop1()?; - self.fp_stack - .push(FloatValue::cncl_f64(self.value_stack.len() - 1)); - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::F64)); self.machine.f64_trunc(loc, ret)?; } Operator::F64Sqrt => { - self.fp_stack.pop1()?; - self.fp_stack - .push(FloatValue::cncl_f64(self.value_stack.len() - 1)); - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::F64)); self.machine.f64_sqrt(loc, ret)?; } Operator::F64Copysign => { - let I2O1 { loc_a, loc_b, ret } = self.i2o1_prepare(WpType::F64)?; - - let (fp_src1, fp_src2) = self.fp_stack.pop2()?; - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); + let loc_b = self.pop_value_released()?; + let loc_a = self.pop_value_released()?; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::None)); let tmp1 = self.machine.acquire_temp_gpr().unwrap(); let tmp2 = self.machine.acquire_temp_gpr().unwrap(); - if self.machine.arch_supports_canonicalize_nan() - && self.config.enable_nan_canonicalization - { - for (fp, loc, tmp) in [(fp_src1, loc_a, tmp1), (fp_src2, loc_b, tmp2)].iter() { - match fp.canonicalization { - Some(_) => { - self.machine - .canonicalize_nan(Size::S64, *loc, Location::GPR(*tmp)) - } - None => { - self.machine - .move_location(Size::S64, *loc, Location::GPR(*tmp)) - } - }?; + if self.config.enable_nan_canonicalization { + for ((loc, fp), tmp) in [(loc_a, tmp1), (loc_b, tmp2)] { + if fp.to_size().is_some() { + self.machine + .canonicalize_nan(Size::S64, loc, Location::GPR(tmp))? + } else { + self.machine + .move_location(Size::S64, loc, Location::GPR(tmp))? + } } } else { self.machine - .move_location(Size::S64, loc_a, Location::GPR(tmp1))?; + .move_location(Size::S64, loc_a.0, Location::GPR(tmp1))?; self.machine - .move_location(Size::S64, loc_b, Location::GPR(tmp2))?; + .move_location(Size::S64, loc_b.0, Location::GPR(tmp2))?; } self.machine.emit_i64_copysign(tmp1, tmp2)?; self.machine @@ -2225,66 +1904,41 @@ impl<'a, M: Machine> FuncGen<'a, M> { } Operator::F64Abs => { - // Preserve canonicalization state. - - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let (loc, canonicalize) = self.pop_value_released()?; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, canonicalize)); self.machine.f64_abs(loc, ret)?; } Operator::F64Neg => { - // Preserve canonicalization state. - - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let (loc, canonicalize) = self.pop_value_released()?; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, canonicalize)); self.machine.f64_neg(loc, ret)?; } Operator::F64PromoteF32 => { - let fp = self.fp_stack.pop1()?; - self.fp_stack.push(fp.promote(self.value_stack.len() - 1)?); - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let (loc, canonicalize) = self.pop_value_released()?; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, canonicalize.promote()?)); self.machine.convert_f64_f32(loc, ret)?; } Operator::F32DemoteF64 => { - let fp = self.fp_stack.pop1()?; - self.fp_stack.push(fp.demote(self.value_stack.len() - 1)?); - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let (loc, canonicalize) = self.pop_value_released()?; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, canonicalize.demote()?)); self.machine.convert_f32_f64(loc, ret)?; } Operator::I32ReinterpretF32 => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - let fp = self.fp_stack.pop1()?; + let (loc, canonicalize) = self.pop_value_released()?; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); - if !self.machine.arch_supports_canonicalize_nan() - || !self.config.enable_nan_canonicalization - || fp.canonicalization.is_none() + if !self.config.enable_nan_canonicalization + || matches!(canonicalize, CanonicalizeType::None) { if loc != ret { self.machine.emit_relaxed_mov(Size::S32, loc, ret)?; @@ -2294,14 +1948,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { } } Operator::F32ReinterpretI32 => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F32)?; + self.value_stack.push((ret, CanonicalizeType::None)); if loc != ret { self.machine.emit_relaxed_mov(Size::S32, loc, ret)?; @@ -2309,17 +1958,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { } Operator::I64ReinterpretF64 => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - let fp = self.fp_stack.pop1()?; + let (loc, canonicalize) = self.pop_value_released()?; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); - if !self.machine.arch_supports_canonicalize_nan() - || !self.config.enable_nan_canonicalization - || fp.canonicalization.is_none() + if !self.config.enable_nan_canonicalization + || matches!(canonicalize, CanonicalizeType::None) { if loc != ret { self.machine.emit_relaxed_mov(Size::S64, loc, ret)?; @@ -2329,14 +1973,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { } } Operator::F64ReinterpretI64 => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::None)); if loc != ret { self.machine.emit_relaxed_mov(Size::S64, loc, ret)?; @@ -2344,289 +1983,185 @@ impl<'a, M: Machine> FuncGen<'a, M> { } Operator::I32TruncF32U => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i32_f32(loc, ret, false, false)?; } Operator::I32TruncSatF32U => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i32_f32(loc, ret, false, true)?; } Operator::I32TruncF32S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i32_f32(loc, ret, true, false)?; } Operator::I32TruncSatF32S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i32_f32(loc, ret, true, true)?; } Operator::I64TruncF32S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i64_f32(loc, ret, true, false)?; } Operator::I64TruncSatF32S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i64_f32(loc, ret, true, true)?; } Operator::I64TruncF32U => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i64_f32(loc, ret, false, false)?; } Operator::I64TruncSatF32U => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i64_f32(loc, ret, false, true)?; } Operator::I32TruncF64U => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i32_f64(loc, ret, false, false)?; } Operator::I32TruncSatF64U => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i32_f64(loc, ret, false, true)?; } Operator::I32TruncF64S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i32_f64(loc, ret, true, false)?; } Operator::I32TruncSatF64S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i32_f64(loc, ret, true, true)?; } Operator::I64TruncF64S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i64_f64(loc, ret, true, false)?; } Operator::I64TruncSatF64S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i64_f64(loc, ret, true, true)?; } Operator::I64TruncF64U => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i64_f64(loc, ret, false, false)?; } Operator::I64TruncSatF64U => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack.pop1()?; + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_i64_f64(loc, ret, false, true)?; } Operator::F32ConvertI32S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); // Converting i32 to f32 never results in NaN. + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_f32_i32(loc, true, ret)?; } Operator::F32ConvertI32U => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); // Converting i32 to f32 never results in NaN. + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_f32_i32(loc, false, ret)?; } Operator::F32ConvertI64S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); // Converting i64 to f32 never results in NaN. + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_f32_i64(loc, true, ret)?; } Operator::F32ConvertI64U => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); // Converting i64 to f32 never results in NaN. + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_f32_i64(loc, false, ret)?; } Operator::F64ConvertI32S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); // Converting i32 to f64 never results in NaN. + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_f64_i32(loc, true, ret)?; } Operator::F64ConvertI32U => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); // Converting i32 to f64 never results in NaN. + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_f64_i32(loc, false, ret)?; } Operator::F64ConvertI64S => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); // Converting i64 to f64 never results in NaN. + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_f64_i64(loc, true, ret)?; } Operator::F64ConvertI64U => { - let loc = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); // Converting i64 to f64 never results in NaN. + let loc = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.machine.convert_f64_i64(loc, false, ret)?; } @@ -2641,36 +2176,24 @@ impl<'a, M: Machine> FuncGen<'a, M> { .unwrap(); let sig = self.module.signatures.get(sig_index).unwrap(); let param_types: SmallVec<[WpType; 8]> = - sig.params().iter().cloned().map(type_to_wp_type).collect(); + sig.params().iter().map(type_to_wp_type).collect(); let return_types: SmallVec<[WpType; 1]> = - sig.results().iter().cloned().map(type_to_wp_type).collect(); + sig.results().iter().map(type_to_wp_type).collect(); let params: SmallVec<[_; 8]> = self .value_stack .drain(self.value_stack.len() - param_types.len()..) .collect(); - self.release_locations_only_regs(¶ms)?; - - self.release_locations_only_osr_state(params.len())?; // Pop arguments off the FP stack and canonicalize them if needed. // // Canonicalization state will be lost across function calls, so early canonicalization // is necessary here. - while let Some(fp) = self.fp_stack.last() { - if fp.depth >= self.value_stack.len() { - let index = fp.depth - self.value_stack.len(); - if self.machine.arch_supports_canonicalize_nan() - && self.config.enable_nan_canonicalization - && fp.canonicalization.is_some() - { - let size = fp.canonicalization.unwrap().to_size(); - self.machine - .canonicalize_nan(size, params[index], params[index])?; + if self.config.enable_nan_canonicalization { + for (loc, canonicalize) in params.iter() { + if let Some(size) = canonicalize.to_size() { + self.machine.canonicalize_nan(size, *loc, *loc)?; } - self.fp_stack.pop().unwrap(); - } else { - break; } } @@ -2698,35 +2221,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { }, params.iter().copied(), param_types.iter().copied(), + return_types.iter().copied(), + NativeCallType::IncludeVMCtxArgument, )?; - - self.release_locations_only_stack(¶ms)?; - - if !return_types.is_empty() { - let ret = self.acquire_locations( - &[( - return_types[0], - MachineValue::WasmStack(self.value_stack.len()), - )], - false, - )?[0]; - self.value_stack.push(ret); - if return_types[0].is_float() { - self.machine.move_location( - Size::S64, - Location::SIMD(self.machine.get_simd_for_ret()), - ret, - )?; - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); - } else { - self.machine.move_location( - Size::S64, - Location::GPR(self.machine.get_gpr_for_ret()), - ret, - )?; - } - } } Operator::CallIndirect { type_index, @@ -2738,36 +2235,26 @@ impl<'a, M: Machine> FuncGen<'a, M> { let index = SignatureIndex::new(type_index as usize); let sig = self.module.signatures.get(index).unwrap(); let param_types: SmallVec<[WpType; 8]> = - sig.params().iter().cloned().map(type_to_wp_type).collect(); + sig.params().iter().map(type_to_wp_type).collect(); let return_types: SmallVec<[WpType; 1]> = - sig.results().iter().cloned().map(type_to_wp_type).collect(); + sig.results().iter().map(type_to_wp_type).collect(); - let func_index = self.pop_value_released()?; + let func_index = self.pop_value_released()?.0; let params: SmallVec<[_; 8]> = self .value_stack .drain(self.value_stack.len() - param_types.len()..) .collect(); - self.release_locations_only_regs(¶ms)?; // Pop arguments off the FP stack and canonicalize them if needed. // // Canonicalization state will be lost across function calls, so early canonicalization // is necessary here. - while let Some(fp) = self.fp_stack.last() { - if fp.depth >= self.value_stack.len() { - let index = fp.depth - self.value_stack.len(); - if self.machine.arch_supports_canonicalize_nan() - && self.config.enable_nan_canonicalization - && fp.canonicalization.is_some() - { - let size = fp.canonicalization.unwrap().to_size(); - self.machine - .canonicalize_nan(size, params[index], params[index])?; + if self.config.enable_nan_canonicalization { + for (loc, canonicalize) in params.iter() { + if let Some(size) = canonicalize.to_size() { + self.machine.canonicalize_nan(size, *loc, *loc)?; } - self.fp_stack.pop().unwrap(); - } else { - break; } } @@ -2818,10 +2305,13 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } - self.machine - .location_cmp(Size::S32, func_index, Location::GPR(table_count))?; - self.machine - .jmp_on_belowequal(self.special_labels.table_access_oob)?; + self.machine.jmp_on_condition( + UnsignedCondition::BelowEqual, + Size::S32, + Location::GPR(table_count), + func_index, + self.special_labels.table_access_oob, + )?; self.machine .move_location(Size::S32, func_index, Location::GPR(table_count))?; self.machine.emit_imul_imm32( @@ -2843,13 +2333,13 @@ impl<'a, M: Machine> FuncGen<'a, M> { Location::GPR(table_count), )?; // Trap if the FuncRef is null - self.machine.location_cmp( + self.machine.jmp_on_condition( + UnsignedCondition::Equal, Size::S64, - Location::Imm32(0), Location::GPR(table_count), + Location::Imm32(0), + self.special_labels.indirect_call_null, )?; - self.machine - .jmp_on_equal(self.special_labels.indirect_call_null)?; self.machine.move_location( Size::S64, Location::Memory( @@ -2860,22 +2350,21 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; // Trap if signature mismatches. - self.machine.location_cmp( + self.machine.jmp_on_condition( + UnsignedCondition::NotEqual, Size::S32, Location::GPR(sigidx), Location::Memory( table_count, (self.vmoffsets.vmcaller_checked_anyfunc_type_index() as usize) as i32, ), + self.special_labels.bad_signature, )?; - self.machine - .jmp_on_different(self.special_labels.bad_signature)?; - self.machine.release_gpr(sigidx); self.machine.release_gpr(table_count); self.machine.release_gpr(table_base); - let gpr_for_call = self.machine.get_grp_for_call(); + let gpr_for_call = self.machine.get_gpr_for_call(); if table_count != gpr_for_call { self.machine.move_location( Size::S64, @@ -2884,8 +2373,6 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } - self.release_locations_only_osr_state(params.len())?; - let vmcaller_checked_anyfunc_func_ptr = self.vmoffsets.vmcaller_checked_anyfunc_func_ptr() as usize; let vmcaller_checked_anyfunc_vmctx = @@ -2894,243 +2381,232 @@ impl<'a, M: Machine> FuncGen<'a, M> { self.emit_call_native( |this| { - if this.machine.arch_requires_indirect_call_trampoline() { - this.machine - .arch_emit_indirect_call_with_trampoline(Location::Memory( - gpr_for_call, - vmcaller_checked_anyfunc_func_ptr as i32, - )) - } else { - let offset = this - .machine - .mark_instruction_with_trap_code(TrapCode::StackOverflow); - - // We set the context pointer - this.machine.move_location( - Size::S64, - Location::Memory( - gpr_for_call, - vmcaller_checked_anyfunc_vmctx as i32, - ), + let offset = this + .machine + .mark_instruction_with_trap_code(TrapCode::StackOverflow); + + // We set the context pointer + this.machine.move_location( + Size::S64, + Location::Memory(gpr_for_call, vmcaller_checked_anyfunc_vmctx as i32), + Location::GPR( this.machine .get_simple_param_location(0, calling_convention), - )?; + ), + )?; - this.machine.emit_call_location(Location::Memory( - gpr_for_call, - vmcaller_checked_anyfunc_func_ptr as i32, - ))?; - this.machine.mark_instruction_address_end(offset); - Ok(()) - } + this.machine.emit_call_location(Location::Memory( + gpr_for_call, + vmcaller_checked_anyfunc_func_ptr as i32, + ))?; + this.machine.mark_instruction_address_end(offset); + Ok(()) }, params.iter().copied(), param_types.iter().copied(), + return_types.iter().copied(), + NativeCallType::IncludeVMCtxArgument, )?; - - self.release_locations_only_stack(¶ms)?; - - if !return_types.is_empty() { - let ret = self.acquire_locations( - &[( - return_types[0], - MachineValue::WasmStack(self.value_stack.len()), - )], - false, - )?[0]; - self.value_stack.push(ret); - if return_types[0].is_float() { - self.machine.move_location( - Size::S64, - Location::SIMD(self.machine.get_simd_for_ret()), - ret, - )?; - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); - } else { - self.machine.move_location( - Size::S64, - Location::GPR(self.machine.get_gpr_for_ret()), - ret, - )?; - } - } } Operator::If { blockty } => { let label_end = self.machine.get_label(); let label_else = self.machine.get_label(); - let cond = self.pop_value_released()?; + let return_types = self.return_types_for_block(blockty); + let param_types = self.param_types_for_block(blockty); + self.allocate_return_slots_and_swap(param_types.len() + 1, return_types.len())?; + + let cond = self.pop_value_released()?.0; + + /* We might hit a situation where an Operator::If is missing an Operator::Else. In such a situation, + the result value just fallthrough from the If block inputs! However, we don't know the information upfront. */ + if param_types.len() == return_types.len() { + for (input, return_value) in self + .value_stack + .iter() + .rev() + .take(param_types.len()) + .zip(self.value_stack.iter().rev().skip(param_types.len())) + { + self.machine + .emit_relaxed_mov(Size::S64, input.0, return_value.0)?; + } + } let frame = ControlFrame { - label: label_end, - loop_like: false, - if_else: IfElseState::If(label_else), - returns: match blockty { - WpTypeOrFuncType::Empty => smallvec![], - WpTypeOrFuncType::Type(inner_ty) => smallvec![inner_ty], - _ => { - return Err(CompileError::Codegen( - "If: multi-value returns not yet implemented".to_owned(), - )) - } + state: ControlState::If { + label_else, + inputs: SmallVec::from_iter( + self.value_stack + .iter() + .rev() + .take(param_types.len()) + .rev() + .copied(), + ), }, + label: label_end, + param_types, + return_types, value_stack_depth: self.value_stack.len(), - fp_stack_depth: self.fp_stack.len(), - state: self.state.clone(), - state_diff_id: self.get_state_diff(), }; self.control_stack.push(frame); - self.machine - .emit_relaxed_cmp(Size::S32, Location::Imm32(0), cond)?; - self.machine.jmp_on_equal(label_else)?; + self.machine.jmp_on_condition( + UnsignedCondition::Equal, + Size::S32, + cond, + Location::Imm32(0), + label_else, + )?; } Operator::Else => { - let frame = self.control_stack.last_mut().unwrap(); - - if !was_unreachable && !frame.returns.is_empty() { - let first_return = frame.returns[0]; - let loc = *self.value_stack.last().unwrap(); - let canonicalize = if first_return.is_float() { - let fp = self.fp_stack.peek1()?; - self.machine.arch_supports_canonicalize_nan() - && self.config.enable_nan_canonicalization - && fp.canonicalization.is_some() - } else { - false - }; - self.machine - .emit_function_return_value(first_return, canonicalize, loc)?; + let frame = self.control_stack.last().unwrap(); + + if !was_unreachable && !frame.return_types.is_empty() { + self.emit_return_values( + frame.value_stack_depth_after(), + frame.return_types.len(), + )?; } let frame = &self.control_stack.last_mut().unwrap(); - let stack_depth = frame.value_stack_depth; - let fp_depth = frame.fp_stack_depth; - self.release_locations_value(stack_depth)?; - self.value_stack.truncate(stack_depth); - self.fp_stack.truncate(fp_depth); + let locs = self + .value_stack + .drain(frame.value_stack_depth_after()..) + .collect_vec(); + self.release_locations(&locs)?; let frame = &mut self.control_stack.last_mut().unwrap(); - match frame.if_else { - IfElseState::If(label) => { - self.machine.jmp_unconditionnal(frame.label)?; - self.machine.emit_label(label)?; - frame.if_else = IfElseState::Else; - } - _ => { - return Err(CompileError::Codegen( - "Else: frame.if_else unreachable code".to_owned(), - )) + // The Else block must be provided the very same inputs as the previous If block had, + // and so we need to copy the already consumed stack values. + let ControlState::If { + label_else, + ref inputs, + } = frame.state + else { + panic!("Operator::Else must be connected to Operator::If statement"); + }; + for (input, _) in inputs { + match input { + Location::GPR(x) => { + self.machine.reserve_gpr(*x); + } + Location::SIMD(x) => { + self.machine.reserve_simd(*x); + } + Location::Memory(reg, _) => { + debug_assert_eq!(reg, &self.machine.local_pointer()); + self.stack_offset += 8; + } + _ => {} } } + self.value_stack.extend(inputs); + + self.machine.jmp_unconditional(frame.label)?; + self.machine.emit_label(label_else)?; + frame.state = ControlState::Else; } // `TypedSelect` must be used for extern refs so ref counting should // be done with TypedSelect. But otherwise they're the same. Operator::TypedSelect { .. } | Operator::Select => { - let cond = self.pop_value_released()?; - let v_b = self.pop_value_released()?; - let v_a = self.pop_value_released()?; - let cncl: Option<(Option, Option)> = - if self.fp_stack.len() >= 2 - && self.fp_stack[self.fp_stack.len() - 2].depth == self.value_stack.len() - && self.fp_stack[self.fp_stack.len() - 1].depth - == self.value_stack.len() + 1 - { - let (left, right) = self.fp_stack.pop2()?; - self.fp_stack.push(FloatValue::new(self.value_stack.len())); - Some((left.canonicalization, right.canonicalization)) - } else { - None - }; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let cond = self.pop_value_released()?.0; + let (v_b, canonicalize_b) = self.pop_value_released()?; + let (v_a, canonicalize_a) = self.pop_value_released()?; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); let end_label = self.machine.get_label(); let zero_label = self.machine.get_label(); - self.machine - .emit_relaxed_cmp(Size::S32, Location::Imm32(0), cond)?; - self.machine.jmp_on_equal(zero_label)?; - match cncl { - Some((Some(fp), _)) - if self.machine.arch_supports_canonicalize_nan() - && self.config.enable_nan_canonicalization => - { - self.machine.canonicalize_nan(fp.to_size(), v_a, ret)?; - } - _ => { - if v_a != ret { - self.machine.emit_relaxed_mov(Size::S64, v_a, ret)?; - } - } + self.machine.jmp_on_condition( + UnsignedCondition::Equal, + Size::S32, + cond, + Location::Imm32(0), + zero_label, + )?; + if self.config.enable_nan_canonicalization + && let Some(size) = canonicalize_a.to_size() + { + self.machine.canonicalize_nan(size, v_a, ret)?; + } else if v_a != ret { + self.machine.emit_relaxed_mov(Size::S64, v_a, ret)?; } - self.machine.jmp_unconditionnal(end_label)?; + self.machine.jmp_unconditional(end_label)?; self.machine.emit_label(zero_label)?; - match cncl { - Some((_, Some(fp))) - if self.machine.arch_supports_canonicalize_nan() - && self.config.enable_nan_canonicalization => - { - self.machine.canonicalize_nan(fp.to_size(), v_b, ret)?; - } - _ => { - if v_b != ret { - self.machine.emit_relaxed_mov(Size::S64, v_b, ret)?; - } - } + if self.config.enable_nan_canonicalization + && let Some(size) = canonicalize_b.to_size() + { + self.machine.canonicalize_nan(size, v_b, ret)?; + } else if v_b != ret { + self.machine.emit_relaxed_mov(Size::S64, v_b, ret)?; } self.machine.emit_label(end_label)?; } Operator::Block { blockty } => { + let return_types = self.return_types_for_block(blockty); + let param_types = self.param_types_for_block(blockty); + self.allocate_return_slots_and_swap(param_types.len(), return_types.len())?; + let frame = ControlFrame { + state: ControlState::Block, label: self.machine.get_label(), - loop_like: false, - if_else: IfElseState::None, - returns: match blockty { - WpTypeOrFuncType::Empty => smallvec![], - WpTypeOrFuncType::Type(inner_ty) => smallvec![inner_ty], - _ => { - return Err(CompileError::Codegen( - "Block: multi-value returns not yet implemented".to_owned(), - )) - } - }, + param_types, + return_types, value_stack_depth: self.value_stack.len(), - fp_stack_depth: self.fp_stack.len(), - state: self.state.clone(), - state_diff_id: self.get_state_diff(), }; self.control_stack.push(frame); } Operator::Loop { blockty } => { self.machine.align_for_loop()?; let label = self.machine.get_label(); - let state_diff_id = self.get_state_diff(); - let _activate_offset = self.machine.assembler_get_offset().0; + + let return_types = self.return_types_for_block(blockty); + let param_types = self.param_types_for_block(blockty); + let params_count = param_types.len(); + // We need extra space for params as we need to implement the PHI operation. + self.allocate_return_slots_and_swap( + param_types.len(), + param_types.len() + return_types.len(), + )?; self.control_stack.push(ControlFrame { + state: ControlState::Loop, label, - loop_like: true, - if_else: IfElseState::None, - returns: match blockty { - WpTypeOrFuncType::Empty => smallvec![], - WpTypeOrFuncType::Type(inner_ty) => smallvec![inner_ty], - _ => { - return Err(CompileError::Codegen( - "Loop: multi-value returns not yet implemented".to_owned(), - )) - } - }, + param_types: param_types.clone(), + return_types: return_types.clone(), value_stack_depth: self.value_stack.len(), - fp_stack_depth: self.fp_stack.len(), - state: self.state.clone(), - state_diff_id, }); + + // For proper PHI implementation, we must copy pre-loop params to PHI params. + let params = self + .value_stack + .drain((self.value_stack.len() - params_count)..) + .collect_vec(); + for (param, phi_param) in params.iter().rev().zip(self.value_stack.iter().rev()) { + self.machine + .emit_relaxed_mov(Size::S64, param.0, phi_param.0)?; + } + self.release_locations(¶ms)?; + self.machine.emit_label(label)?; + // Put on the stack PHI inputs for further use. + let phi_params = self + .value_stack + .iter() + .rev() + .take(params_count) + .rev() + .copied() + .collect_vec(); + for (i, phi_param) in phi_params.into_iter().enumerate() { + let loc = self.acquire_location(¶m_types[i])?; + self.machine.emit_relaxed_mov(Size::S64, phi_param.0, loc)?; + self.value_stack.push((loc, phi_param.1)); + } + // TODO: Re-enable interrupt signal check without branching } Operator::Nop => {} @@ -3148,33 +2624,27 @@ impl<'a, M: Machine> FuncGen<'a, M> { }, ) as i32, ), - Location::GPR(self.machine.get_grp_for_call()), + Location::GPR(self.machine.get_gpr_for_call()), )?; self.emit_call_native( |this| { this.machine - .emit_call_register(this.machine.get_grp_for_call()) + .emit_call_register(this.machine.get_gpr_for_call()) }, // [vmctx, memory_index] - iter::once(Location::Imm32(memory_index.index() as u32)), + iter::once(( + Location::Imm32(memory_index.index() as u32), + CanonicalizeType::None, + )), iter::once(WpType::I64), - )?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.machine.move_location( - Size::S64, - Location::GPR(self.machine.get_gpr_for_ret()), - ret, + iter::once(WpType::I64), + NativeCallType::IncludeVMCtxArgument, )?; } Operator::MemoryInit { data_index, mem } => { let len = self.value_stack.pop().unwrap(); let src = self.value_stack.pop().unwrap(); let dst = self.value_stack.pop().unwrap(); - self.release_locations_only_regs(&[len, src, dst])?; self.machine.move_location( Size::S64, @@ -3184,21 +2654,18 @@ impl<'a, M: Machine> FuncGen<'a, M> { .vmctx_builtin_function(VMBuiltinFunctionIndex::get_memory_init_index()) as i32, ), - Location::GPR(self.machine.get_grp_for_call()), + Location::GPR(self.machine.get_gpr_for_call()), )?; - // TODO: should this be 3? - self.release_locations_only_osr_state(1)?; - self.emit_call_native( |this| { this.machine - .emit_call_register(this.machine.get_grp_for_call()) + .emit_call_register(this.machine.get_gpr_for_call()) }, // [vmctx, memory_index, data_index, dst, src, len] [ - Location::Imm32(mem), - Location::Imm32(data_index), + (Location::Imm32(mem), CanonicalizeType::None), + (Location::Imm32(data_index), CanonicalizeType::None), dst, src, len, @@ -3214,8 +2681,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { ] .iter() .cloned(), + iter::empty(), + NativeCallType::IncludeVMCtxArgument, )?; - self.release_locations_only_stack(&[dst, src, len])?; } Operator::DataDrop { data_index } => { self.machine.move_location( @@ -3226,26 +2694,26 @@ impl<'a, M: Machine> FuncGen<'a, M> { .vmctx_builtin_function(VMBuiltinFunctionIndex::get_data_drop_index()) as i32, ), - Location::GPR(self.machine.get_grp_for_call()), + Location::GPR(self.machine.get_gpr_for_call()), )?; self.emit_call_native( |this| { this.machine - .emit_call_register(this.machine.get_grp_for_call()) + .emit_call_register(this.machine.get_gpr_for_call()) }, // [vmctx, data_index] - iter::once(Location::Imm32(data_index)), + iter::once((Location::Imm32(data_index), CanonicalizeType::None)), iter::once(WpType::I64), + iter::empty(), + NativeCallType::IncludeVMCtxArgument, )?; } - Operator::MemoryCopy { dst_mem, src_mem } => { + Operator::MemoryCopy { src_mem, .. } => { // ignore until we support multiple memories - let _dst = dst_mem; let len = self.value_stack.pop().unwrap(); let src_pos = self.value_stack.pop().unwrap(); let dst_pos = self.value_stack.pop().unwrap(); - self.release_locations_only_regs(&[len, src_pos, dst_pos])?; let memory_index = MemoryIndex::new(src_mem as usize); let (memory_copy_index, memory_index) = @@ -3267,20 +2735,20 @@ impl<'a, M: Machine> FuncGen<'a, M> { self.machine.get_vmctx_reg(), self.vmoffsets.vmctx_builtin_function(memory_copy_index) as i32, ), - Location::GPR(self.machine.get_grp_for_call()), + Location::GPR(self.machine.get_gpr_for_call()), )?; - // TODO: should this be 3? - self.release_locations_only_osr_state(1)?; - self.emit_call_native( |this| { this.machine - .emit_call_register(this.machine.get_grp_for_call()) + .emit_call_register(this.machine.get_gpr_for_call()) }, // [vmctx, memory_index, dst, src, len] [ - Location::Imm32(memory_index.index() as u32), + ( + Location::Imm32(memory_index.index() as u32), + CanonicalizeType::None, + ), dst_pos, src_pos, len, @@ -3290,14 +2758,14 @@ impl<'a, M: Machine> FuncGen<'a, M> { [WpType::I32, WpType::I64, WpType::I64, WpType::I64] .iter() .cloned(), + iter::empty(), + NativeCallType::IncludeVMCtxArgument, )?; - self.release_locations_only_stack(&[dst_pos, src_pos, len])?; } Operator::MemoryFill { mem } => { let len = self.value_stack.pop().unwrap(); let val = self.value_stack.pop().unwrap(); let dst = self.value_stack.pop().unwrap(); - self.release_locations_only_regs(&[len, val, dst])?; let memory_index = MemoryIndex::new(mem as usize); let (memory_fill_index, memory_index) = @@ -3319,33 +2787,37 @@ impl<'a, M: Machine> FuncGen<'a, M> { self.machine.get_vmctx_reg(), self.vmoffsets.vmctx_builtin_function(memory_fill_index) as i32, ), - Location::GPR(self.machine.get_grp_for_call()), + Location::GPR(self.machine.get_gpr_for_call()), )?; - // TODO: should this be 3? - self.release_locations_only_osr_state(1)?; - self.emit_call_native( |this| { this.machine - .emit_call_register(this.machine.get_grp_for_call()) + .emit_call_register(this.machine.get_gpr_for_call()) }, // [vmctx, memory_index, dst, src, len] - [Location::Imm32(memory_index.index() as u32), dst, val, len] - .iter() - .cloned(), + [ + ( + Location::Imm32(memory_index.index() as u32), + CanonicalizeType::None, + ), + dst, + val, + len, + ] + .iter() + .cloned(), [WpType::I32, WpType::I64, WpType::I64, WpType::I64] .iter() .cloned(), + iter::empty(), + NativeCallType::IncludeVMCtxArgument, )?; - self.release_locations_only_stack(&[dst, val, len])?; } Operator::MemoryGrow { mem } => { let memory_index = MemoryIndex::new(mem as usize); let param_pages = self.value_stack.pop().unwrap(); - self.release_locations_only_regs(&[param_pages])?; - self.machine.move_location( Size::S64, Location::Memory( @@ -3358,42 +2830,33 @@ impl<'a, M: Machine> FuncGen<'a, M> { }, ) as i32, ), - Location::GPR(self.machine.get_grp_for_call()), + Location::GPR(self.machine.get_gpr_for_call()), )?; - self.release_locations_only_osr_state(1)?; - self.emit_call_native( |this| { this.machine - .emit_call_register(this.machine.get_grp_for_call()) + .emit_call_register(this.machine.get_gpr_for_call()) }, // [vmctx, val, memory_index] - iter::once(param_pages) - .chain(iter::once(Location::Imm32(memory_index.index() as u32))), + [ + param_pages, + ( + Location::Imm32(memory_index.index() as u32), + CanonicalizeType::None, + ), + ] + .iter() + .cloned(), [WpType::I64, WpType::I64].iter().cloned(), - )?; - - self.release_locations_only_stack(&[param_pages])?; - - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.machine.move_location( - Size::S64, - Location::GPR(self.machine.get_gpr_for_ret()), - ret, + iter::once(WpType::I64), + NativeCallType::IncludeVMCtxArgument, )?; } Operator::I32Load { ref memarg } => { - let target = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let target = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.op_memory( |this, need_check, @@ -3415,14 +2878,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::F32Load { ref memarg } => { - let target = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); + let target = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.op_memory( |this, need_check, @@ -3444,12 +2902,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I32Load8U { ref memarg } => { - let target = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let target = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.op_memory( |this, need_check, @@ -3471,12 +2926,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I32Load8S { ref memarg } => { - let target = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let target = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.op_memory( |this, need_check, @@ -3498,12 +2950,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I32Load16U { ref memarg } => { - let target = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let target = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.op_memory( |this, need_check, @@ -3525,12 +2974,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I32Load16S { ref memarg } => { - let target = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let target = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I32)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.op_memory( |this, need_check, @@ -3552,8 +2998,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I32Store { ref memarg } => { - let target_value = self.pop_value_released()?; - let target_addr = self.pop_value_released()?; + let target_value = self.pop_value_released()?.0; + let target_addr = self.pop_value_released()?.0; self.op_memory( |this, need_check, @@ -3575,10 +3021,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::F32Store { ref memarg } => { - let target_value = self.pop_value_released()?; - let target_addr = self.pop_value_released()?; - let fp = self.fp_stack.pop1()?; - let config_nan_canonicalization = self.config.enable_nan_canonicalization; + let (target_value, canonicalize) = self.pop_value_released()?; + let target_addr = self.pop_value_released()?.0; self.op_memory( |this, need_check, @@ -3590,7 +3034,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { target_value, memarg, target_addr, - config_nan_canonicalization && fp.canonicalization.is_some(), + self.config.enable_nan_canonicalization + && !matches!(canonicalize, CanonicalizeType::None), need_check, imported_memories, offset, @@ -3601,8 +3046,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I32Store8 { ref memarg } => { - let target_value = self.pop_value_released()?; - let target_addr = self.pop_value_released()?; + let target_value = self.pop_value_released()?.0; + let target_addr = self.pop_value_released()?.0; self.op_memory( |this, need_check, @@ -3624,8 +3069,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I32Store16 { ref memarg } => { - let target_value = self.pop_value_released()?; - let target_addr = self.pop_value_released()?; + let target_value = self.pop_value_released()?.0; + let target_addr = self.pop_value_released()?.0; self.op_memory( |this, need_check, @@ -3647,12 +3092,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I64Load { ref memarg } => { - let target = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let target = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.op_memory( |this, need_check, @@ -3674,14 +3116,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::F64Load { ref memarg } => { - let target = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); - self.fp_stack - .push(FloatValue::new(self.value_stack.len() - 1)); + let target = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::F64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.op_memory( |this, need_check, @@ -3703,12 +3140,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I64Load8U { ref memarg } => { - let target = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let target = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.op_memory( |this, need_check, @@ -3730,12 +3164,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I64Load8S { ref memarg } => { - let target = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let target = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.op_memory( |this, need_check, @@ -3757,12 +3188,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I64Load16U { ref memarg } => { - let target = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let target = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.op_memory( |this, need_check, @@ -3784,12 +3212,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I64Load16S { ref memarg } => { - let target = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let target = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.op_memory( |this, need_check, @@ -3811,12 +3236,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I64Load32U { ref memarg } => { - let target = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let target = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.op_memory( |this, need_check, @@ -3838,12 +3260,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I64Load32S { ref memarg } => { - let target = self.pop_value_released()?; - let ret = self.acquire_locations( - &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], - false, - )?[0]; - self.value_stack.push(ret); + let target = self.pop_value_released()?.0; + let ret = self.acquire_location(&WpType::I64)?; + self.value_stack.push((ret, CanonicalizeType::None)); self.op_memory( |this, need_check, @@ -3865,8 +3284,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I64Store { ref memarg } => { - let target_value = self.pop_value_released()?; - let target_addr = self.pop_value_released()?; + let target_value = self.pop_value_released()?.0; + let target_addr = self.pop_value_released()?.0; self.op_memory( |this, @@ -3889,10 +3308,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::F64Store { ref memarg } => { - let target_value = self.pop_value_released()?; - let target_addr = self.pop_value_released()?; - let fp = self.fp_stack.pop1()?; - let config_nan_canonicalization = self.config.enable_nan_canonicalization; + let (target_value, canonicalize) = self.pop_value_released()?; + let target_addr = self.pop_value_released()?.0; self.op_memory( |this, need_check, @@ -3904,7 +3321,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { target_value, memarg, target_addr, - config_nan_canonicalization && fp.canonicalization.is_some(), + self.config.enable_nan_canonicalization + && !matches!(canonicalize, CanonicalizeType::None), need_check, imported_memories, offset, @@ -3915,8 +3333,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I64Store8 { ref memarg } => { - let target_value = self.pop_value_released()?; - let target_addr = self.pop_value_released()?; + let target_value = self.pop_value_released()?.0; + let target_addr = self.pop_value_released()?.0; self.op_memory( |this, need_check, @@ -3938,8 +3356,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I64Store16 { ref memarg } => { - let target_value = self.pop_value_released()?; - let target_addr = self.pop_value_released()?; + let target_value = self.pop_value_released()?.0; + let target_addr = self.pop_value_released()?.0; self.op_memory( |this, need_check, @@ -3961,8 +3379,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::I64Store32 { ref memarg } => { - let target_value = self.pop_value_released()?; - let target_addr = self.pop_value_released()?; + let target_value = self.pop_value_released()?.0; + let target_addr = self.pop_value_released()?.0; self.op_memory( |this, need_check, @@ -3984,105 +3402,109 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?; } Operator::Unreachable => { - self.mark_trappable(); - self.machine - .emit_illegal_op(TrapCode::UnreachableCodeReached)?; + self.machine.move_location( + Size::S64, + Location::Memory( + self.machine.get_vmctx_reg(), + self.vmoffsets + .vmctx_builtin_function(VMBuiltinFunctionIndex::get_raise_trap_index()) + as i32, + ), + Location::GPR(self.machine.get_gpr_for_call()), + )?; + + self.emit_call_native( + |this| { + this.machine + .emit_call_register(this.machine.get_gpr_for_call()) + }, + // [trap_code] + [( + Location::Imm32(TrapCode::UnreachableCodeReached as u32), + CanonicalizeType::None, + )] + .iter() + .cloned(), + [WpType::I32].iter().cloned(), + iter::empty(), + NativeCallType::Unreachable, + )?; self.unreachable_depth = 1; } Operator::Return => { let frame = &self.control_stack[0]; - if !frame.returns.is_empty() { - if frame.returns.len() != 1 { - return Err(CompileError::Codegen( - "Return: incorrect frame.returns".to_owned(), - )); - } - let first_return = frame.returns[0]; - let loc = *self.value_stack.last().unwrap(); - let canonicalize = if first_return.is_float() { - let fp = self.fp_stack.peek1()?; - self.machine.arch_supports_canonicalize_nan() - && self.config.enable_nan_canonicalization - && fp.canonicalization.is_some() - } else { - false - }; - self.machine - .emit_function_return_value(first_return, canonicalize, loc)?; + if !frame.return_types.is_empty() { + self.emit_return_values( + frame.value_stack_depth_after(), + frame.return_types.len(), + )?; } let frame = &self.control_stack[0]; - let frame_depth = frame.value_stack_depth; + let frame_depth = frame.value_stack_depth_for_release(); let label = frame.label; - self.release_locations_keep_state(frame_depth)?; - self.machine.jmp_unconditionnal(label)?; + self.release_stack_locations_keep_stack_offset(frame_depth)?; + self.machine.jmp_unconditional(label)?; self.unreachable_depth = 1; } Operator::Br { relative_depth } => { let frame = &self.control_stack[self.control_stack.len() - 1 - (relative_depth as usize)]; - if !frame.loop_like && !frame.returns.is_empty() { - if frame.returns.len() != 1 { - return Err(CompileError::Codegen( - "Br: incorrect frame.returns".to_owned(), - )); - } - let first_return = frame.returns[0]; - let loc = *self.value_stack.last().unwrap(); - let canonicalize = if first_return.is_float() { - let fp = self.fp_stack.peek1()?; - self.machine.arch_supports_canonicalize_nan() - && self.config.enable_nan_canonicalization - && fp.canonicalization.is_some() + if !frame.return_types.is_empty() { + if matches!(frame.state, ControlState::Loop) { + // Store into the PHI params of the loop, not to the return values. + self.emit_loop_params_store( + frame.value_stack_depth_after(), + frame.param_types.len(), + )?; } else { - false - }; - self.machine - .emit_function_return_value(first_return, canonicalize, loc)?; + self.emit_return_values( + frame.value_stack_depth_after(), + frame.return_types.len(), + )?; + } } let stack_len = self.control_stack.len(); let frame = &mut self.control_stack[stack_len - 1 - (relative_depth as usize)]; - let frame_depth = frame.value_stack_depth; + let frame_depth = frame.value_stack_depth_for_release(); let label = frame.label; - self.release_locations_keep_state(frame_depth)?; - self.machine.jmp_unconditionnal(label)?; + self.release_stack_locations_keep_stack_offset(frame_depth)?; + self.machine.jmp_unconditional(label)?; self.unreachable_depth = 1; } Operator::BrIf { relative_depth } => { let after = self.machine.get_label(); - let cond = self.pop_value_released()?; - self.machine - .emit_relaxed_cmp(Size::S32, Location::Imm32(0), cond)?; - self.machine.jmp_on_equal(after)?; + let cond = self.pop_value_released()?.0; + self.machine.jmp_on_condition( + UnsignedCondition::Equal, + Size::S32, + cond, + Location::Imm32(0), + after, + )?; let frame = &self.control_stack[self.control_stack.len() - 1 - (relative_depth as usize)]; - if !frame.loop_like && !frame.returns.is_empty() { - if frame.returns.len() != 1 { - return Err(CompileError::Codegen( - "BrIf: incorrect frame.returns".to_owned(), - )); - } - - let first_return = frame.returns[0]; - let loc = *self.value_stack.last().unwrap(); - let canonicalize = if first_return.is_float() { - let fp = self.fp_stack.peek1()?; - self.machine.arch_supports_canonicalize_nan() - && self.config.enable_nan_canonicalization - && fp.canonicalization.is_some() + if !frame.return_types.is_empty() { + if matches!(frame.state, ControlState::Loop) { + // Store into the PHI params of the loop, not to the return values. + self.emit_loop_params_store( + frame.value_stack_depth_after(), + frame.param_types.len(), + )?; } else { - false - }; - self.machine - .emit_function_return_value(first_return, canonicalize, loc)?; + self.emit_return_values( + frame.value_stack_depth_after(), + frame.return_types.len(), + )?; + } } let stack_len = self.control_stack.len(); let frame = &mut self.control_stack[stack_len - 1 - (relative_depth as usize)]; - let stack_depth = frame.value_stack_depth; + let stack_depth = frame.value_stack_depth_for_release(); let label = frame.label; - self.release_locations_keep_state(stack_depth)?; - self.machine.jmp_unconditionnal(label)?; + self.release_stack_locations_keep_stack_offset(stack_depth)?; + self.machine.jmp_unconditional(label)?; self.machine.emit_label(after)?; } @@ -4092,16 +3514,17 @@ impl<'a, M: Machine> FuncGen<'a, M> { .targets() .collect::, _>>() .map_err(|e| CompileError::Codegen(format!("BrTable read_table: {e:?}")))?; - let cond = self.pop_value_released()?; + let cond = self.pop_value_released()?.0; let table_label = self.machine.get_label(); let mut table: Vec