diff --git a/.github/workflows/benchmark.yaml b/.github/workflows/benchmark.yaml index a95994c99..24ca80052 100644 --- a/.github/workflows/benchmark.yaml +++ b/.github/workflows/benchmark.yaml @@ -24,7 +24,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: 1.61 + toolchain: 1.63 - name: Configure cargo data directory # After this point, all cargo registry and crate data is stored in # $GITHUB_WORKSPACE/.cargo_home. This allows us to cache only the files diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 69e911f37..be8ae0880 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -100,7 +100,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: 1.61 + toolchain: 1.63 target: ${{ matrix.target }} - uses: Swatinem/rust-cache@v1 if: matrix.use_sccache != true @@ -264,6 +264,59 @@ jobs: if-no-files-found: error retention-days: 2 + windows_gnu: + name: Windows GNU + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - name: Install Windows-GNU linker + shell: bash + run: | + sudo apt install -y mingw-w64 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.61 + target: x86_64-pc-windows-gnu + - name: Install Windows-GNU target + shell: bash + run: | + rustup target add x86_64-pc-windows-gnu + - name: Install Windows 10 SDK with xwin + shell: bash + run: | + mkdir -p /tmp/xwin + mkdir -p /tmp/xwindownload + mkdir -p /tmp/xwincache + git clone https://github.com/wasmerio/xwin --depth=1 /tmp/xwin + cargo build --release --manifest-path=/tmp/xwin/Cargo.toml + /tmp/xwin/target/release/xwin --accept-license --cache-dir /tmp/xwincache splat --output /tmp/xwindownload + mkdir -p /tmp/winsdk + cp /tmp/xwindownload/sdk/lib/10.0.20348/um/x86_64/WS2_32.lib /tmp/winsdk/ + cp /tmp/xwindownload/sdk/lib/10.0.20348/um/x86_64/KERNEL32.lib /tmp/winsdk/ + cp /tmp/xwindownload/sdk/lib/10.0.20348/um/x86_64/BCRYPT.lib /tmp/winsdk/ + cp /tmp/xwindownload/sdk/lib/10.0.20348/um/x86_64/ADVAPI32.lib /tmp/winsdk/ + cp /tmp/xwindownload/sdk/lib/10.0.20348/um/x86_64/USERENV.lib /tmp/winsdk/ + echo "WinSDK files:" + ls -laH /tmp/winsdk + echo "" + mkdir -p package + mkdir -p package/winsdk + cp -r /tmp/winsdk/* package/winsdk + - name: Build Wasmer C-API without LLVM + shell: bash + run: | + cargo build --release --target x86_64-pc-windows-gnu --manifest-path lib/c-api/Cargo.toml --no-default-features --features wat,compiler,wasi,middlewares,webc_runner --features cranelift,singlepass,wasmer-artifact-create,static-artifact-create,wasmer-artifact-load,static-artifact-load + - name: Dist + run: | + make distribution-gnu + - name: Upload Artifacts + uses: actions/upload-artifact@v2 + with: + name: 'wasmer-windows-gnu64' + path: dist + if-no-files-found: error + retention-days: 2 + linux_aarch64: name: Linux aarch64 runs-on: ubuntu-latest @@ -331,7 +384,7 @@ jobs: retention-days: 2 release: - needs: [setup, build, linux_aarch64] + needs: [setup, build, linux_aarch64, windows_gnu] runs-on: ubuntu-latest if: needs.setup.outputs.DOING_RELEASE == '1' || github.event.inputs.release != '' steps: @@ -385,6 +438,15 @@ jobs: asset_path: artifacts/wasmer-linux-aarch64/wasmer.tar.gz asset_name: wasmer-linux-aarch64.tar.gz asset_content_type: application/gzip + - name: Upload Release Asset Windows gnu64 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: artifacts/wasmer-windows-gnu64/wasmer.tar.gz + asset_name: wasmer-windows-gnu64.tar.gz + asset_content_type: application/gzip - name: Upload Release Asset Linux amd64 (musl) id: upload-release-asset-linux-musl-amd64 uses: actions/upload-release-asset@v1 diff --git a/.github/workflows/cloudcompiler.yaml b/.github/workflows/cloudcompiler.yaml index a296b312f..4bd3f1f5c 100644 --- a/.github/workflows/cloudcompiler.yaml +++ b/.github/workflows/cloudcompiler.yaml @@ -21,7 +21,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: 1.61 + toolchain: 1.63 target: ${{ matrix.target }} - name: Install wasm32-wasi target shell: bash diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 545696a35..a26053c6c 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -1,40 +1,50 @@ -on: - push: - branches: - - '!trying' - - '!trying.tmp' - - '!staging' - - '!staging.tmp' - name: Coverage env: RUST_BACKTRACE: 1 RUSTFLAGS: "-Ccodegen-units=1 -Clink-dead-code -Coverflow-checks=off" -jobs: - coverage: - name: Coverage - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.61 - - name: Install LLVM (Linux) - run: | - curl --proto '=https' --tlsv1.2 -sSf https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz -L -o llvm.tar.xz - mkdir -p /opt/llvm-10 - tar xf llvm.tar.xz --strip-components=1 -C /opt/llvm-10 - echo '/opt/llvm-10/bin' >> $GITHUB_PATH - echo 'LLVM_SYS_100_PREFIX=/opt/llvm-10' >> $GITHUB_ENV - - name: Generate Coverage Report - run: | - cargo install cargo-tarpaulin - cargo tarpaulin --forward --release -t120 --out Xml --ignore-tests --workspace --exclude wasmer-wasi-experimental-io-devices --exclude wasmer-c-api -- --skip traps:: --skip spec::linking --test-threads=1 - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 - with: - token: ${{ secrets.CODECOV_TOKEN }} - file: ./cobertura.xml +on: + workflow_dispatch: + push: + branches: + - 'master' + - 'staging' + - 'trying' + paths: + - 'lib/**' + tags: + # this is _not_ a regex, see: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet + - '[0-9]+.[0-9]+.[0-9]+*' + pull_request: + paths: + - 'lib/**' + +coverage: + runs-on: ubuntu-latest + env: + CARGO_TERM_COLOR: always + steps: + - uses: actions/checkout@v3 + - name: Install Rust + run: rustup update stable + - name: Install LLVM (Linux) + run: | + curl --proto '=https' --tlsv1.2 -sSf https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz -L -o llvm.tar.xz + mkdir -p /opt/llvm-10 + tar xf llvm.tar.xz --strip-components=1 -C /opt/llvm-10 + echo '/opt/llvm-10/bin' >> $GITHUB_PATH + echo 'LLVM_SYS_100_PREFIX=/opt/llvm-10' >> $GITHUB_ENV + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@cargo-llvm-cov + - name: Generate code coverage + run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info + env: + WAPM_DEV_TOKEN: ${{ secrets.WAPM_DEV_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + files: lcov.info + fail_ci_if_error: true + diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 0096c315d..ae018dd31 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -16,7 +16,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: 1.61 + toolchain: 1.63 - name: Install LLVM shell: bash run: | diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 9e3a58101..65ef0043a 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -12,13 +12,18 @@ env: jobs: lint: name: Code lint - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v3 + - name: Set up libstdc++ on Linux + run: | + sudo apt-get update -y + sudo apt-get install -y --allow-downgrades libstdc++6=8.4.0-1ubuntu1~18.04 + sudo apt-get install --reinstall g++-8 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: 1.61 + toolchain: 1.63 components: rustfmt, clippy - name: Install LLVM (Linux) run: | diff --git a/.github/workflows/test-js.yaml b/.github/workflows/test-js.yaml index f83064f48..75ba39ca1 100644 --- a/.github/workflows/test-js.yaml +++ b/.github/workflows/test-js.yaml @@ -33,7 +33,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: 1.61 + toolchain: 1.63 - name: Install NodeJS uses: actions/setup-node@v2 diff --git a/.github/workflows/test-sys.yaml b/.github/workflows/test-sys.yaml index 46d4a7697..f440ede6f 100644 --- a/.github/workflows/test-sys.yaml +++ b/.github/workflows/test-sys.yaml @@ -97,6 +97,9 @@ jobs: SCCACHE_AZURE_CONNECTION_STRING: ${{ secrets.SCCACHE_AZURE_CONNECTION_STRING }} steps: - uses: actions/checkout@v3 + - uses: goto-bus-stop/setup-zig@v2 + with: + version: 0.10.0 - name: Set up libstdc++ on Linux if: matrix.build == 'linux-x64' run: | @@ -110,7 +113,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: 1.61 + toolchain: 1.63 target: ${{ matrix.target }} - uses: Swatinem/rust-cache@v1 if: matrix.use_sccache != true @@ -203,24 +206,37 @@ jobs: if: matrix.run_test && matrix.os != 'windows-2019' shell: bash run: | - make && make build-wasmer && make build-capi && make package-capi && make package - export WASMER_DIR=`pwd`/package - make test-integration-cli + make build-wasmer && make build-capi && make package-capi && make package && export WASMER_DIR=`pwd`/package && make test-integration-cli env: TARGET: ${{ matrix.target }} TARGET_DIR: target/${{ matrix.target }}/release CARGO_TARGET: --target ${{ matrix.target }} + WAPM_DEV_TOKEN: ${{ secrets.WAPM_DEV_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Test integration CLI if: matrix.run_test && matrix.os == 'windows-2019' shell: bash run: | - make && make build-wasmer && make build-capi && make package-capi && make package - export WASMER_DIR=`pwd`/package - make test-integration-cli + make build-wasmer && + cargo test --package wasmer-integration-tests-cli --test run -- test_wasmer_run_complex_url --exact --nocapture env: - TARGET: x86_64-pc-windows-msvc - TARGET_DIR: target/x86_64-pc-windows-msvc/release + TARGET: ${{ matrix.target }} + TARGET_DIR: target/${{ matrix.target }}/release CARGO_TARGET: --target x86_64-pc-windows-msvc + WAPM_DEV_TOKEN: ${{ secrets.WAPM_DEV_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # cargo test --package wasmer-integration-tests-cli --test run -- test_wasmer_run_complex_url --exact --nocapture + #- name: Test integration CLI + # if: matrix.run_test && matrix.os == 'windows-2019' + # shell: bash + # run: | + # make && make build-wasmer && make build-capi && make package-capi && make package + # export WASMER_DIR=`pwd`/package + # make test-integration-cli + # env: + # TARGET: x86_64-pc-windows-msvc + # TARGET_DIR: target/x86_64-pc-windows-msvc/release + # CARGO_TARGET: --target x86_64-pc-windows-msvc - name: Test if: matrix.run_test && matrix.os != 'windows-2019' run: | diff --git a/.gitignore b/.gitignore index b1166e461..24affcea4 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,8 @@ api-docs-repo/ /wapm-cli/ /src/windows-installer/WasmerInstaller.exe /lib/c-api/wasmer.h - +.xwin-cache # Generated by tests on Android /avd /core +out.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 859f9fa1e..4bf51f638 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,959 +1,1035 @@ -# Changelog - -*The format is based on [Keep a Changelog].* - -[Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ - -Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/CHANGELOG.md). - -## **Unreleased** - -## Added - -## Changed - -## Fixed - -## 3.0.0-rc.2 - 2022/11/02 - -## Fixed -- [#3268](https://github.com/wasmerio/wasmer/pulls/3268) Fix fd_right nightly test to avoid foo.txt file leftover -- [#3260](https://github.com/wasmerio/wasmer/pulls/3260) Fix bug in wasmer run -- [#3257](https://github.com/wasmerio/wasmer/pulls/3257) Fix linux-aarch64 build - -## 3.0.0-rc.1 - 2022/10/25 - -## Added - -- [#3215](https://github.com/wasmerio/wasmer/pull/3215) Update wasmer --version logic, integrate wapm-cli -- [#3218](https://github.com/wasmerio/wasmer/pull/3218) Seal `HostFunctionKind` -- [#3222](https://github.com/wasmerio/wasmer/pull/3222) Add function to retrieve function name from wasm_frame_t - -## Changed - -- [#3248](https://github.com/wasmerio/wasmer/pull/3248) Move loupe CHANGELOG entry from 2.3.0 to 3.x -- [#3230](https://github.com/wasmerio/wasmer/pull/3230) Remove test if dest file exist on path_rename wasi syscall (for #3228) -- [#3223](https://github.com/wasmerio/wasmer/pull/3223) Delete lib/wasi-types-generated directory - -## Fixed - -- [#3240](https://github.com/wasmerio/wasmer/pull/3240) Fix filesystem rights on WASI, add integration test for file permissions -- [#3238](https://github.com/wasmerio/wasmer/pull/3238) Fixed main README ocaml homepage link and added ocaml in other language README -- [#3229](https://github.com/wasmerio/wasmer/pull/3229) Fixed version to nightly-2022-10-09 for the CI build Minimal Wasmer Headless again -- [#3227](https://github.com/wasmerio/wasmer/pull/3227) Fixed version to nightly-2022-10-09 for the CI build Minimal Wasmer Headless -- [#3226](https://github.com/wasmerio/wasmer/pull/3226) Fixed version to nightly-2002-10-09 for the CI build Minimal Wasmer Headless -- [#3221](https://github.com/wasmerio/wasmer/pull/3221) Fix #3197 -- [#3211](https://github.com/wasmerio/wasmer/pull/3211) Fix popcnt for aarch64 -- [#3204](https://github.com/wasmerio/wasmer/pull/3204) Fixed a typo in README -- [#3199](https://github.com/wasmerio/wasmer/pull/3199) Release fixes - -## 3.0.0-beta.2 - 2022/09/26 - -## Added - -- [#3176](https://github.com/wasmerio/wasmer/pull/3176) Add support for `cargo-binstall` -- [#3117](https://github.com/wasmerio/wasmer/pull/3117) Add tests for wasmer-cli create-{exe,obj} commands -- [#3116](https://github.com/wasmerio/wasmer/pull/3116) Multithreading, full networking and RPC for WebAssembly -- [#3101](https://github.com/wasmerio/wasmer/pull/3101) CI/build.yaml: add libwasmer headless in default distribution -- [#3090](https://github.com/wasmerio/wasmer/pull/3090) Added version to the wasmer cli -- [#3089](https://github.com/wasmerio/wasmer/pull/3089) Add wasi_* C-API function changes in migration guide for 3.0.0 - -## Changed - -- [#3165](https://github.com/wasmerio/wasmer/pull/3165) Initial port of make test-js-core (port wasmer API to core) -- [#3164](https://github.com/wasmerio/wasmer/pull/3164) Synchronize between -sys and -js tests -- [#3142](https://github.com/wasmerio/wasmer/pull/3142) Bump rust toolchain -- [#3141](https://github.com/wasmerio/wasmer/pull/3141) The API breaking changes from future WASIX/Network/Threading addition -- [#3138](https://github.com/wasmerio/wasmer/pull/3138) Js imports revamp -- [#3134](https://github.com/wasmerio/wasmer/pull/3134) Bring libwasmer-headless.a from 22MiB to 7.2MiB (on my machine) -- [#3132](https://github.com/wasmerio/wasmer/pull/3132) Revert "Lower libwasmer headless size" -- [#3131](https://github.com/wasmerio/wasmer/pull/3131) Update for migration-to-3.0.0 for MemoryView changes -- [#3130](https://github.com/wasmerio/wasmer/pull/3130) Remove panics from Artifact::deserialize -- [#3128](https://github.com/wasmerio/wasmer/pull/3128) scripts/publish.py: validate crates version before publishing -- [#3126](https://github.com/wasmerio/wasmer/pull/3126) scripts/publish.py: replace toposort dependency with python std graphlib module -- [#3123](https://github.com/wasmerio/wasmer/pull/3123) Lower libwasmer headless size -- [#3122](https://github.com/wasmerio/wasmer/pull/3122) Update Cargo.lock dependencies -- [#3119](https://github.com/wasmerio/wasmer/pull/3119) Added LinearMemory trait -- [#3118](https://github.com/wasmerio/wasmer/pull/3118) Refactor Artifact enum into a struct -- [#3114](https://github.com/wasmerio/wasmer/pull/3114) Implemented shared memory for Wasmer in preparation for multithreading -- [#3104](https://github.com/wasmerio/wasmer/pull/3104) Re-enabled ExternRef tests -- [#3103](https://github.com/wasmerio/wasmer/pull/3103) create-exe: prefer libwasmer headless when cross-compiling -- [#3097](https://github.com/wasmerio/wasmer/pull/3097) MemoryView lifetime tied to memory and not StoreRef -- [#3096](https://github.com/wasmerio/wasmer/pull/3096) create-exe: use cached wasmer tarballs for network fetches -- [#3095](https://github.com/wasmerio/wasmer/pull/3095) create-exe: list supported cross-compilation target triples in help … -- [#3083](https://github.com/wasmerio/wasmer/pull/3083) Disable wasm build in build CI - -## Fixed - -- [#3185](https://github.com/wasmerio/wasmer/pull/3185) Fix `wasmer compile` command for non-x86 target -- [#3184](https://github.com/wasmerio/wasmer/pull/3184) Fix windows build -- [#3137](https://github.com/wasmerio/wasmer/pull/3137) Fix cache path not being present during installation of cross-tarball -- [#3129](https://github.com/wasmerio/wasmer/pull/3129) Fix differences between -sys and -js API -- [#3115](https://github.com/wasmerio/wasmer/pull/3115) Fix static object signature deserialization -- [#3093](https://github.com/wasmerio/wasmer/pull/3093) Fixed a potential issue when renaming a file -- [#3088](https://github.com/wasmerio/wasmer/pull/3088) Fixed an issue when renaming a file from a preopened dir directly (for 3084) - -## 3.0.0-beta - 2022/08/08 - -### Added -- [#3076](https://github.com/wasmerio/wasmer/pull/3076) Add support for cross-compiling in create-exe with zig cc - -### Changed -- [#3079](https://github.com/wasmerio/wasmer/pull/3079) Migrate CLI tools to `clap` from `structopt` -- [#3048](https://github.com/wasmerio/wasmer/pull/3048) Automatically publish wasmer as "cloudcompiler" package to wapm.dev on every release -- [#3075](https://github.com/wasmerio/wasmer/pull/3075) Remove __wbindgen_thread_id -- [#3072](https://github.com/wasmerio/wasmer/pull/3072) Add back `Function::*_with_env(…)` functions - -### Fixed - -## 3.0.0-alpha.4 - 2022/07/28 - -### Added -- [#3035](https://github.com/wasmerio/wasmer/pull/3035) Added a simple "divide by zero" wast test, for #1899, as the trap information are correctly tracked on singlepass now -- [#3021](https://github.com/wasmerio/wasmer/pull/3021) Add back missing Aarch64 relocations (needed for llvm compiler) -- [#3008](https://github.com/wasmerio/wasmer/pull/3008) Add a new cargo public-api CI check -- [#2941](https://github.com/wasmerio/wasmer/pull/2941) Implementation of WASIX and a fully networking for Web Assembly -- [#2952](https://github.com/wasmerio/wasmer/pull/2952) CI: add make build-wasmer-wasm test -- [#2982](https://github.com/wasmerio/wasmer/pull/2982) Add a rustfmt.toml file to the repository - -### Changed -- [#3047](https://github.com/wasmerio/wasmer/pull/3047) `Store::new` now takes an `impl Into`. -- [#3046](https://github.com/wasmerio/wasmer/pull/3046) Merge Backend into EngineBuilder and refactor feature flags -- [#3039](https://github.com/wasmerio/wasmer/pull/3039) Improved hashing/ids of function envs -- [#3031](https://github.com/wasmerio/wasmer/pull/3031) Update docs/migration_to_3.0.0.md -- [#3030](https://github.com/wasmerio/wasmer/pull/3030) Remove cranelift dependency from wasmer-wasi -- [#3029](https://github.com/wasmerio/wasmer/pull/3029) Removed Artifact, Engine traits. Renamed UniversalArtifact to Artifact, and UniversalEngine to Engine. -- [#3028](https://github.com/wasmerio/wasmer/pull/3028) Rename old variable names from ctx to env (in case of FunctionEnv usage) and from ctx to store in case of store usage -- [#3023](https://github.com/wasmerio/wasmer/pull/3023) Changed CI "rust install" action to dtolnay one -- [#3013](https://github.com/wasmerio/wasmer/pull/3013) Refactor Context API -- [#3003](https://github.com/wasmerio/wasmer/pull/3003) Remove RuntimeError::raise from public API -- [#3000](https://github.com/wasmerio/wasmer/pull/3001) Allow debugging of EXC_BAD_INSTRUCTION on macOS -- [#2999](https://github.com/wasmerio/wasmer/pull/2999) Allow `--invoke` CLI option for Emscripten files without a `main` function -- [#2996](https://github.com/wasmerio/wasmer/pull/2996) Migrated all examples to new Context API -- [#2946](https://github.com/wasmerio/wasmer/pull/2946) Remove dylib,staticlib engines in favor of a single Universal engine -- [#2949](https://github.com/wasmerio/wasmer/pull/2949) Switch back to using custom LLVM builds on CI -- [#2892](https://github.com/wasmerio/wasmer/pull/2892) Renamed `get_native_function` to `get_typed_function`, marked former as deprecated. -- [#2976](https://github.com/wasmerio/wasmer/pull/2976) Upgrade enumset minimum version to one that compiles -- [#2974](https://github.com/wasmerio/wasmer/pull/2974) Context api tests -- [#2973](https://github.com/wasmerio/wasmer/pull/2973) Port C API to new Context API -- [#2969](https://github.com/wasmerio/wasmer/pull/2969) Port JS API to new Context API -- [#2966](https://github.com/wasmerio/wasmer/pull/2966) Singlepass nopanic #2966 -- [#2957](https://github.com/wasmerio/wasmer/pull/2957) Enable multi-value handling in Singlepass compiler -- [#2954](https://github.com/wasmerio/wasmer/pull/2954) Some fixes to x86_64 Singlepass compiler, when using atomics -- [#2953](https://github.com/wasmerio/wasmer/pull/2953) Makefile: add check target -- [#2950](https://github.com/wasmerio/wasmer/pull/2950) compiler-cranelift: Fix typo in enum variant -- [#2947](https://github.com/wasmerio/wasmer/pull/2947) Converted the WASI js test into a generic stdio test that works for both sys and js versions of wasmer -- [#2940](https://github.com/wasmerio/wasmer/pull/2940) Merge wasmer3 back to master branch -- [#2939](https://github.com/wasmerio/wasmer/pull/2939) Rename NativeFunc to TypedFunction -- [#2868](https://github.com/wasmerio/wasmer/pull/2868) Removed loupe crate dependency - -### Fixed -- [#3045](https://github.com/wasmerio/wasmer/pull/3045) Fixed WASI fd_read syscall when reading multiple iovs and read is partial (for #2904) -- [#3027](https://github.com/wasmerio/wasmer/pull/3027) Fixed some residual doc issues that prevented make package-docs to build -- [#3026](https://github.com/wasmerio/wasmer/pull/3026) test-js.yaml: fix typo -- [#3017](https://github.com/wasmerio/wasmer/pull/3017) Fix typo in README.md -- [#3001](https://github.com/wasmerio/wasmer/pull/3001) Fix context capi ci errors -- [#2997](https://github.com/wasmerio/wasmer/pull/2997) Fix "run --invoke [function]" to behave the same as "run" -- [#2963](https://github.com/wasmerio/wasmer/pull/2963) Remove accidental dependency on libwayland and libxcb in ClI -- [#2942](https://github.com/wasmerio/wasmer/pull/2942) Fix clippy lints. -- [#2943](https://github.com/wasmerio/wasmer/pull/2943) Fix build error on some archs by using c_char instead of i8 -- [#2976](https://github.com/wasmerio/wasmer/pull/2976) Upgrade minimum enumset to one that compiles -- [#2988](https://github.com/wasmerio/wasmer/pull/2988) Have make targets install-capi-lib,install-pkgconfig work without building the wasmer binary -- [#2967](https://github.com/wasmerio/wasmer/pull/2967) Fix singlepass on arm64 that was trying to emit a sub opcode with a constant as destination (for #2959) -- [#2948](https://github.com/wasmerio/wasmer/pull/2948) Fix regression on gen_import_call_trampoline_arm64() -- [#2944](https://github.com/wasmerio/wasmer/pull/2944) Fix duplicate entries in the CHANGELOG - -## 2.3.0 - 2022/06/06 - -### Added -- [#2862](https://github.com/wasmerio/wasmer/pull/2862) Added CI builds for linux-aarch64 target. -- [#2811](https://github.com/wasmerio/wasmer/pull/2811) Added support for EH Frames in singlepass -- [#2851](https://github.com/wasmerio/wasmer/pull/2851) Allow Wasmer to compile to Wasm/WASI - -### Changed -- [#2807](https://github.com/wasmerio/wasmer/pull/2807) Run Wasm code in a separate stack -- [#2802](https://github.com/wasmerio/wasmer/pull/2802) Support Dylib engine with Singlepass -- [#2836](https://github.com/wasmerio/wasmer/pull/2836) Improve TrapInformation data stored at runtime -- [#2864](https://github.com/wasmerio/wasmer/pull/2864) `wasmer-cli`: remove wasi-experimental-io-devices from default builds -- [#2933](https://github.com/wasmerio/wasmer/pull/2933) Rename NativeFunc to TypedFunction. - -### Fixed -- [#2829](https://github.com/wasmerio/wasmer/pull/2829) Improve error message oriented from JS object. -- [#2828](https://github.com/wasmerio/wasmer/pull/2828) Fix JsImportObject resolver. -- [#2872](https://github.com/wasmerio/wasmer/pull/2872) Fix `WasmerEnv` finalizer -- [#2821](https://github.com/wasmerio/wasmer/pull/2821) Opt in `sys` feature - -## 2.2.1 - 2022/03/15 - -### Fixed -- [#2812](https://github.com/wasmerio/wasmer/pull/2812) Fixed another panic due to incorrect drop ordering. - -## 2.2.0 - 2022/02/28 - -### Added -- [#2775](https://github.com/wasmerio/wasmer/pull/2775) Added support for SSE 4.2 in the Singlepass compiler as an alternative to AVX. -- [#2805](https://github.com/wasmerio/wasmer/pull/2805) Enabled WASI experimental I/O devices by default in releases. - -### Fixed -- [#2795](https://github.com/wasmerio/wasmer/pull/2795) Fixed a bug in the Singlepass compiler introduced in #2775. -- [#2806](https://github.com/wasmerio/wasmer/pull/2806) Fixed a panic due to incorrect drop ordering of `Module` fields. - -## 2.2.0-rc2 - 2022/02/15 - -### Fixed -- [#2778](https://github.com/wasmerio/wasmer/pull/2778) Fixed f32_load/f64_load in Singlepass. Also fixed issues with out-of-range conditional branches. -- [#2786](https://github.com/wasmerio/wasmer/pull/2786) Fixed a potential integer overflow in WasmPtr memory access methods. -- [#2787](https://github.com/wasmerio/wasmer/pull/2787) Fixed a codegen regression in the Singlepass compiler due to non-determinism of `HashSet` iteration. - -## 2.2.0-rc1 - 2022/01/28 - -### Added -- [#2750](https://github.com/wasmerio/wasmer/pull/2750) Added Aarch64 support to Singlepass (both Linux and macOS). -- [#2753](https://github.com/wasmerio/wasmer/pull/2753) Re-add "dylib" to the list of default features. - -### Changed -- [#2747](https://github.com/wasmerio/wasmer/pull/2747) Use a standard header for metadata in all serialized modules. -- [#2759](https://github.com/wasmerio/wasmer/pull/2759) Use exact version for Wasmer crate dependencies. - -### Fixed -- [#2769](https://github.com/wasmerio/wasmer/pull/2769) Fixed deadlock in emscripten dynamic calls. -- [#2742](https://github.com/wasmerio/wasmer/pull/2742) Fixed WASMER_METADATA alignment in the dylib engine. -- [#2746](https://github.com/wasmerio/wasmer/pull/2746) Fixed invoking `wasmer binfmt register` from `$PATH`. -- [#2748](https://github.com/wasmerio/wasmer/pull/2748) Use trampolines for all libcalls in engine-universal and engine-dylib. -- [#2766](https://github.com/wasmerio/wasmer/pull/2766) Remove an attempt to reserve a GPR when no GPR clobbering is occurring. -- [#2768](https://github.com/wasmerio/wasmer/pull/2768) Fixed serialization of FrameInfo on Dylib engine. - -## 2.1.1 - 2021/12/20 - -### Added -- [#2726](https://github.com/wasmerio/wasmer/pull/2726) Added `externs_vec` method to `ImportObject`. -- [#2724](https://github.com/wasmerio/wasmer/pull/2724) Added access to the raw `Instance` JS object in Wsasmer-js. - -### CHanged -- [#2711](https://github.com/wasmerio/wasmer/pull/2711) Make C-API and Wasi dependencies more lean -- [#2706](https://github.com/wasmerio/wasmer/pull/2706) Refactored the Singlepass compiler in preparation for AArch64 support (no user visible changes). -### Fixed -- [#2717](https://github.com/wasmerio/wasmer/pull/2717) Allow `Exports` to be modified after being cloned. -- [#2719](https://github.com/wasmerio/wasmer/pull/2719) Fixed `wasm_importtype_new`'s Rust signature to not assume boxed vectors. -- [#2723](https://github.com/wasmerio/wasmer/pull/2723) Fixed a bug in parameter passing in the Singlepass compiler. -- [#2768](https://github.com/wasmerio/wasmer/pull/2768) Fixed issue with Frame Info on dylib engine. - -## 2.1.0 - 2021/11/30 - -### Added -- [#2574](https://github.com/wasmerio/wasmer/pull/2574) Added Windows support to Singlepass. -- [#2535](https://github.com/wasmerio/wasmer/pull/2435) Added iOS support for Wasmer. This relies on the `dylib-engine`. -- [#2460](https://github.com/wasmerio/wasmer/pull/2460) Wasmer can now compile to Javascript via `wasm-bindgen`. Use the `js-default` (and no default features) feature to try it!. -- [#2491](https://github.com/wasmerio/wasmer/pull/2491) Added support for WASI to Wasmer-js. -- [#2436](https://github.com/wasmerio/wasmer/pull/2436) Added the x86-32 bit variant support to LLVM compiler. -- [#2499](https://github.com/wasmerio/wasmer/pull/2499) Added a subcommand to linux wasmer-cli to register wasmer with binfmt_misc -- [#2511](https://github.com/wasmerio/wasmer/pull/2511) Added support for calling dynamic functions defined on the host -- [#2491](https://github.com/wasmerio/wasmer/pull/2491) Added support for WASI in Wasmer-js -- [#2592](https://github.com/wasmerio/wasmer/pull/2592) Added `ImportObject::get_namespace_exports` to allow modifying the contents of an existing namespace in an `ImportObject`. -- [#2694](https://github.com/wasmerio/wasmer/pull/2694) wasmer-js: Allow an `ImportObject` to be extended with a JS object. -- [#2698](https://github.com/wasmerio/wasmer/pull/2698) Provide WASI imports when invoking an explicit export from the CLI. -- [#2701](https://github.com/wasmerio/wasmer/pull/2701) Improved VFS API for usage from JS - -### Changed -- [#2460](https://github.com/wasmerio/wasmer/pull/2460) **breaking change** `wasmer` API usage with `no-default-features` requires now the `sys` feature to preserve old behavior. -- [#2476](https://github.com/wasmerio/wasmer/pull/2476) Removed unncessary abstraction `ModuleInfoTranslate` from `wasmer-compiler`. -- [#2442](https://github.com/wasmerio/wasmer/pull/2442) **breaking change** Improved `WasmPtr`, added `WasmCell` for host/guest interaction. `WasmPtr::deref` will now return `WasmCell<'a, T>` instead of `&'a Cell`, `WasmPtr::deref_mut` is now deleted from the API. -- [#2427](https://github.com/wasmerio/wasmer/pull/2427) Update `loupe` to 0.1.3. -- [#2685](https://github.com/wasmerio/wasmer/pull/2685) The minimum LLVM version for the LLVM compiler is now 12. LLVM 13 is used by default. -- [#2569](https://github.com/wasmerio/wasmer/pull/2569) Add `Send` and `Sync` to uses of the `LikeNamespace` trait object. -- [#2692](https://github.com/wasmerio/wasmer/pull/2692) Made module serialization deterministic. -- [#2693](https://github.com/wasmerio/wasmer/pull/2693) Validate CPU features when loading a deserialized module. - -### Fixed -- [#2599](https://github.com/wasmerio/wasmer/pull/2599) Fixed Universal engine for Linux/Aarch64 target. -- [#2587](https://github.com/wasmerio/wasmer/pull/2587) Fixed deriving `WasmerEnv` when aliasing `Result`. -- [#2518](https://github.com/wasmerio/wasmer/pull/2518) Remove temporary file used to creating an artifact when creating a Dylib engine artifact. -- [#2494](https://github.com/wasmerio/wasmer/pull/2494) Fixed `WasmerEnv` access when using `call_indirect` with the Singlepass compiler. -- [#2479](https://github.com/wasmerio/wasmer/pull/2479) Improved `wasmer validate` error message on non-wasm inputs. -- [#2454](https://github.com/wasmerio/wasmer/issues/2454) Won't set `WASMER_CACHE_DIR` for Windows. -- [#2426](https://github.com/wasmerio/wasmer/pull/2426) Fix the `wax` script generation. -- [#2635](https://github.com/wasmerio/wasmer/pull/2635) Fix cross-compilation for singlepass. -- [#2672](https://github.com/wasmerio/wasmer/pull/2672) Use `ENOENT` instead of `EINVAL` in some WASI syscalls for a non-existent file -- [#2547](https://github.com/wasmerio/wasmer/pull/2547) Delete temporary files created by the dylib engine. -- [#2548](https://github.com/wasmerio/wasmer/pull/2548) Fix stack probing on x86_64 linux with the cranelift compiler. -- [#2557](https://github.com/wasmerio/wasmer/pull/2557) [#2559](https://github.com/wasmerio/wasmer/pull/2559) Fix WASI dir path renaming. -- [#2560](https://github.com/wasmerio/wasmer/pull/2560) Fix signal handling on M1 MacOS. -- [#2474](https://github.com/wasmerio/wasmer/pull/2474) Fix permissions on `WASMER_CACHE_DIR` on Windows. -- [#2528](https://github.com/wasmerio/wasmer/pull/2528) [#2525](https://github.com/wasmerio/wasmer/pull/2525) [#2523](https://github.com/wasmerio/wasmer/pull/2523) [#2522](https://github.com/wasmerio/wasmer/pull/2522) [#2545](https://github.com/wasmerio/wasmer/pull/2545) [#2550](https://github.com/wasmerio/wasmer/pull/2550) [#2551](https://github.com/wasmerio/wasmer/pull/2551) Fix various bugs in the new VFS implementation. -- [#2552](https://github.com/wasmerio/wasmer/pull/2552) Fix stack guard handling on Windows. -- [#2585](https://github.com/wasmerio/wasmer/pull/2585) Fix build with 64-bit MinGW toolchain. -- [#2587](https://github.com/wasmerio/wasmer/pull/2587) Fix absolute import of `Result` in derive. -- [#2599](https://github.com/wasmerio/wasmer/pull/2599) Fix AArch64 support in the LLVM compiler. -- [#2655](https://github.com/wasmerio/wasmer/pull/2655) Fix argument parsing of `--dir` and `--mapdir`. -- [#2666](https://github.com/wasmerio/wasmer/pull/2666) Fix performance on Windows by using static memories by default. -- [#2667](https://github.com/wasmerio/wasmer/pull/2667) Fix error code for path_rename of a non-existant file -- [#2672](https://github.com/wasmerio/wasmer/pull/2672) Fix error code returned by some wasi fs syscalls for a non-existent file -- [#2673](https://github.com/wasmerio/wasmer/pull/2673) Fix BrTable codegen on the LLVM compiler -- [#2674](https://github.com/wasmerio/wasmer/pull/2674) Add missing `__WASI_RIGHT_FD_DATASYNC` for preopened directories -- [#2677](https://github.com/wasmerio/wasmer/pull/2677) Support 32-bit memories with 65536 pages -- [#2681](https://github.com/wasmerio/wasmer/pull/2681) Fix slow compilation in singlepass by using dynasm's `VecAssembler`. -- [#2690](https://github.com/wasmerio/wasmer/pull/2690) Fix memory leak when obtaining the stack bounds of a thread -- [#2699](https://github.com/wasmerio/wasmer/pull/2699) Partially fix unbounded memory leak from the FuncDataRegistry - -## 2.0.0 - 2021/06/16 - -### Added -- [#2411](https://github.com/wasmerio/wasmer/pull/2411) Extract types from `wasi` to a new `wasi-types` crate. -- [#2390](https://github.com/wasmerio/wasmer/pull/2390) Make `wasmer-vm` to compile on Windows 32bits. -- [#2402](https://github.com/wasmerio/wasmer/pull/2402) Add more examples and more doctests for `wasmer-middlewares`. - -### Changed -- [#2399](https://github.com/wasmerio/wasmer/pull/2399) Add the Dart integration in the `README.md`. - -### Fixed -- [#2386](https://github.com/wasmerio/wasmer/pull/2386) Handle properly when a module has no exported functions in the CLI. - -## 2.0.0-rc2 - 2021/06/03 - -### Fixed -- [#2383](https://github.com/wasmerio/wasmer/pull/2383) Fix bugs in the Wasmer CLI tool with the way `--version` and the name of the CLI tool itself were printed. - -## 2.0.0-rc1 - 2021/06/02 - -### Added -- [#2348](https://github.com/wasmerio/wasmer/pull/2348) Make Wasmer available on `aarch64-linux-android`. -- [#2315](https://github.com/wasmerio/wasmer/pull/2315) Make the Cranelift compiler working with the Native engine. -- [#2306](https://github.com/wasmerio/wasmer/pull/2306) Add support for the latest version of the Wasm SIMD proposal to compiler LLVM. -- [#2296](https://github.com/wasmerio/wasmer/pull/2296) Add support for the bulk memory proposal in compiler Singlepass and compiler LLVM. -- [#2291](https://github.com/wasmerio/wasmer/pull/2291) Type check tables when importing. -- [#2262](https://github.com/wasmerio/wasmer/pull/2262) Make parallelism optional for the Singlepass compiler. -- [#2249](https://github.com/wasmerio/wasmer/pull/2249) Make Cranelift unwind feature optional. -- [#2208](https://github.com/wasmerio/wasmer/pull/2208) Add a new CHANGELOG.md specific to our C API to make it easier for users primarily consuming our C API to keep up to date with changes that affect them. -- [#2154](https://github.com/wasmerio/wasmer/pull/2154) Implement Reference Types in the LLVM compiler. -- [#2003](https://github.com/wasmerio/wasmer/pull/2003) Wasmer works with musl, and is built, tested and packaged for musl. -- [#2250](https://github.com/wasmerio/wasmer/pull/2250) Use `rkyv` for the JIT/Universal engine. -- [#2190](https://github.com/wasmerio/wasmer/pull/2190) Use `rkyv` to read native `Module` artifact. -- [#2186](https://github.com/wasmerio/wasmer/pull/2186) Update and improve the Fuzz Testing infrastructure. -- [#2161](https://github.com/wasmerio/wasmer/pull/2161) Make NaN canonicalization configurable. -- [#2116](https://github.com/wasmerio/wasmer/pull/2116) Add a package for Windows that is not an installer, but all the `lib` and `include` files as for macOS and Linux. -- [#2123](https://github.com/wasmerio/wasmer/pull/2123) Use `ENABLE_{{compiler_name}}=(0|1)` to resp. force to disable or enable a compiler when running the `Makefile`, e.g. `ENABLE_LLVM=1 make build-wasmer`. -- [#2123](https://github.com/wasmerio/wasmer/pull/2123) `libwasmer` comes with all available compilers per target instead of Cranelift only. -- [#2135](https://github.com/wasmerio/wasmer/pull/2135) [Documentation](./PACKAGING.md) for Linux distribution maintainers -- [#2104](https://github.com/wasmerio/wasmer/pull/2104) Update WAsm core spectests and wasmparser. - -### Changed -- [#2369](https://github.com/wasmerio/wasmer/pull/2369) Remove the deprecated `--backend` option in the CLI. -- [#2368](https://github.com/wasmerio/wasmer/pull/2368) Remove the deprecated code in the `wasmer-wasi` crate. -- [#2367](https://github.com/wasmerio/wasmer/pull/2367) Remove the `deprecated` features and associated code in the `wasmer` crate. -- [#2366](https://github.com/wasmerio/wasmer/pull/2366) Remove the deprecated crates. -- [#2364](https://github.com/wasmerio/wasmer/pull/2364) Rename `wasmer-engine-object-file` to `wasmer-engine-staticlib`. -- [#2356](https://github.com/wasmerio/wasmer/pull/2356) Rename `wasmer-engine-native` to `wasmer-engine-dylib`. -- [#2340](https://github.com/wasmerio/wasmer/pull/2340) Rename `wasmer-engine-jit` to `wasmer-engine-universal`. -- [#2307](https://github.com/wasmerio/wasmer/pull/2307) Update Cranelift, implement low hanging fruit SIMD opcodes. -- [#2305](https://github.com/wasmerio/wasmer/pull/2305) Clean up and improve the trap API, more deterministic errors etc. -- [#2299](https://github.com/wasmerio/wasmer/pull/2299) Unused trap codes (due to Wasm spec changes), `HeapSetterOutOfBounds` and `TableSetterOutOfBounds` were removed from `wasmer_vm::TrapCode` and the numbering of the remaining variants has been adjusted. -- [#2293](https://github.com/wasmerio/wasmer/pull/2293) The `Memory::ty` trait method now returns `MemoryType` by value. `wasmer_vm::LinearMemory` now recomputes `MemoryType`'s `minimum` field when accessing its type. This behavior is what's expected by the latest spectests. `wasmer::Memory::ty` has also been updated to follow suit, it now returns `MemoryType` by value. -- [#2286](https://github.com/wasmerio/wasmer/pull/2286) Replace the `goblin` crate by the `object` crate. -- [#2281](https://github.com/wasmerio/wasmer/pull/2281) Refactor the `wasmer_vm` crate to remove unnecessary structs, reuse data when available etc. -- [#2251](https://github.com/wasmerio/wasmer/pull/2251) Wasmer CLI will now execute WASI modules with multiple WASI namespaces in them by default. Use `--allow-multiple-wasi-versions` to suppress the warning and use `--deny-multiple-wasi-versions` to make it an error. -- [#2201](https://github.com/wasmerio/wasmer/pull/2201) Implement `loupe::MemoryUsage` for `wasmer::Instance`. -- [#2200](https://github.com/wasmerio/wasmer/pull/2200) Implement `loupe::MemoryUsage` for `wasmer::Module`. -- [#2199](https://github.com/wasmerio/wasmer/pull/2199) Implement `loupe::MemoryUsage` for `wasmer::Store`. -- [#2195](https://github.com/wasmerio/wasmer/pull/2195) Remove dependency to `cranelift-entity`. -- [#2140](https://github.com/wasmerio/wasmer/pull/2140) Reduce the number of dependencies in the `wasmer.dll` shared library by statically compiling CRT. -- [#2113](https://github.com/wasmerio/wasmer/pull/2113) Bump minimum supported Rust version to 1.49 -- [#2144](https://github.com/wasmerio/wasmer/pull/2144) Bump cranelift version to 0.70 -- [#2149](https://github.com/wasmerio/wasmer/pull/2144) `wasmer-engine-native` looks for clang-11 instead of clang-10. -- [#2157](https://github.com/wasmerio/wasmer/pull/2157) Simplify the code behind `WasmPtr` - -### Fixed -- [#2397](https://github.com/wasmerio/wasmer/pull/2397) Fix WASI rename temporary file issue. -- [#2391](https://github.com/wasmerio/wasmer/pull/2391) Fix Singlepass emit bug, [#2347](https://github.com/wasmerio/wasmer/issues/2347) and [#2159](https://github.com/wasmerio/wasmer/issues/2159) -- [#2327](https://github.com/wasmerio/wasmer/pull/2327) Fix memory leak preventing internal instance memory from being freed when a WasmerEnv contained an exported extern (e.g. Memory, etc.). -- [#2247](https://github.com/wasmerio/wasmer/pull/2247) Internal WasiFS logic updated to be closer to what WASI libc does when finding a preopened fd for a path. -- [#2241](https://github.com/wasmerio/wasmer/pull/2241) Fix Undefined Behavior in setting memory in emscripten `EmEnv`. -- [#2224](https://github.com/wasmerio/wasmer/pull/2224) Enable SIMD based on actual Wasm features in the Cranelift compiler. -- [#2217](https://github.com/wasmerio/wasmer/pull/2217) Fix bug in `i64.rotr X 0` in the LLVM compiler. -- [#2290](https://github.com/wasmerio/wasmer/pull/2290) Handle Wasm modules with no imports in the CLI. -- [#2108](https://github.com/wasmerio/wasmer/pull/2108) The Object Native Engine generates code that now compiles correctly with C++. -- [#2125](https://github.com/wasmerio/wasmer/pull/2125) Fix RUSTSEC-2021-0023. -- [#2155](https://github.com/wasmerio/wasmer/pull/2155) Fix the implementation of shift and rotate in the LLVM compiler. -- [#2101](https://github.com/wasmerio/wasmer/pull/2101) cflags emitted by `wasmer config --pkg-config` are now correct. - -## 1.0.2 - 2021-02-04 - -### Added -- [#2053](https://github.com/wasmerio/wasmer/pull/2053) Implement the non-standard `wasi_get_unordered_imports` function in the C API. -- [#2072](https://github.com/wasmerio/wasmer/pull/2072) Add `wasm_config_set_target`, along with `wasm_target_t`, `wasm_triple_t` and `wasm_cpu_features_t` in the unstable C API. -- [#2059](https://github.com/wasmerio/wasmer/pull/2059) Ability to capture `stdout` and `stderr` with WASI in the C API. -- [#2040](https://github.com/wasmerio/wasmer/pull/2040) Add `InstanceHandle::vmoffsets` to expose the offsets of the `vmctx` region. -- [#2026](https://github.com/wasmerio/wasmer/pull/2026) Expose trap code of a `RuntimeError`, if it's a `Trap`. -- [#2054](https://github.com/wasmerio/wasmer/pull/2054) Add `wasm_config_delete` to the Wasm C API. -- [#2072](https://github.com/wasmerio/wasmer/pull/2072) Added cross-compilation to Wasm C API. - -### Changed -- [#2085](https://github.com/wasmerio/wasmer/pull/2085) Update to latest inkwell and LLVM 11. -- [#2037](https://github.com/wasmerio/wasmer/pull/2037) Improved parallelism of LLVM with the Native/Object engine -- [#2012](https://github.com/wasmerio/wasmer/pull/2012) Refactor Singlepass init stack assembly (more performant now) -- [#2036](https://github.com/wasmerio/wasmer/pull/2036) Optimize memory allocated for Function type definitions -- [#2083](https://github.com/wasmerio/wasmer/pull/2083) Mark `wasi_env_set_instance` and `wasi_env_set_memory` as deprecated. You may simply remove the calls with no side-effect. -- [#2056](https://github.com/wasmerio/wasmer/pull/2056) Change back to depend on the `enumset` crate instead of `wasmer_enumset` - -### Fixed -- [#2066](https://github.com/wasmerio/wasmer/pull/2066) Include 'extern "C"' in our C headers when included by C++ code. -- [#2090](https://github.com/wasmerio/wasmer/pull/2090) `wasi_env_t` needs to be freed with `wasi_env_delete` in the C API. -- [#2084](https://github.com/wasmerio/wasmer/pull/2084) Avoid calling the function environment finalizer more than once when the environment has been cloned in the C API. -- [#2069](https://github.com/wasmerio/wasmer/pull/2069) Use the new documentation for `include/README.md` in the Wasmer package. -- [#2042](https://github.com/wasmerio/wasmer/pull/2042) Parse more exotic environment variables in `wasmer run`. -- [#2041](https://github.com/wasmerio/wasmer/pull/2041) Documentation diagrams now have a solid white background rather than a transparent background. -- [#2070](https://github.com/wasmerio/wasmer/pull/2070) Do not drain the entire captured stream at first read with `wasi_env_read_stdout` or `_stderr` in the C API. -- [#2058](https://github.com/wasmerio/wasmer/pull/2058) Expose WASI versions to C correctly. -- [#2044](https://github.com/wasmerio/wasmer/pull/2044) Do not build C headers on docs.rs. - -## 1.0.1 - 2021-01-12 - -This release includes a breaking change in the API (changing the trait `enumset::EnumsetType` to `wasmer_enumset::EnumSetType` and changing `enumset::EnumSet` in signatures to `wasmer_enumset::EnumSet` to work around a breaking change introduced by `syn`) but is being released as a minor version because `1.0.0` is also in a broken state due to a breaking change introduced by `syn` which affects `enumset` and thus `wasmer`. - -This change is unlikely to affect any users of `wasmer`, but if it does please change uses of the `enumset` crate to the `wasmer_enumset` crate where possible. - -### Added -- [#2010](https://github.com/wasmerio/wasmer/pull/2010) A new, experimental, minified build of `wasmer` called `wasmer-headless` will now be included with releases. `wasmer-headless` is the `wasmer` VM without any compilers attached, so it can only run precompiled Wasm modules. -- [#2005](https://github.com/wasmerio/wasmer/pull/2005) Added the arguments `alias` and `optional` to `WasmerEnv` derive's `export` attribute. - -### Changed -- [#2006](https://github.com/wasmerio/wasmer/pull/2006) Use `wasmer_enumset`, a fork of the `enumset` crate to work around a breaking change in `syn` -- [#1985](https://github.com/wasmerio/wasmer/pull/1985) Bump minimum supported Rust version to 1.48 - -### Fixed -- [#2007](https://github.com/wasmerio/wasmer/pull/2007) Fix packaging of wapm on Windows -- [#2005](https://github.com/wasmerio/wasmer/pull/2005) Emscripten is now working again. - -## 1.0.0 - 2021-01-05 - -### Added - -- [#1969](https://github.com/wasmerio/wasmer/pull/1969) Added D integration to the README - -### Changed -- [#1979](https://github.com/wasmerio/wasmer/pull/1979) `WasmPtr::get_utf8_string` was renamed to `WasmPtr::get_utf8_str` and made `unsafe`. - -### Fixed -- [#1979](https://github.com/wasmerio/wasmer/pull/1979) `WasmPtr::get_utf8_string` now returns a `String`, fixing a soundness issue in certain circumstances. The old functionality is available under a new `unsafe` function, `WasmPtr::get_utf8_str`. - -## 1.0.0-rc1 - 2020-12-23 - -### Added - -* [#1894](https://github.com/wasmerio/wasmer/pull/1894) Added exports `wasmer::{CraneliftOptLevel, LLVMOptLevel}` to allow using `Cranelift::opt_level` and `LLVM::opt_level` directly via the `wasmer` crate - -### Changed - -* [#1941](https://github.com/wasmerio/wasmer/pull/1941) Turn `get_remaining_points`/`set_remaining_points` of the `Metering` middleware into free functions to allow using them in an ahead-of-time compilation setup -* [#1955](https://github.com/wasmerio/wasmer/pull/1955) Set `jit` as a default feature of the `wasmer-wasm-c-api` crate -* [#1944](https://github.com/wasmerio/wasmer/pull/1944) Require `WasmerEnv` to be `Send + Sync` even in dynamic functions. -* [#1963](https://github.com/wasmerio/wasmer/pull/1963) Removed `to_wasm_error` in favour of `impl From for WasmError` -* [#1962](https://github.com/wasmerio/wasmer/pull/1962) Replace `wasmparser::Result<()>` with `Result<(), MiddlewareError>` in middleware, allowing implementors to return errors in `FunctionMiddleware::feed` - -### Fixed - -- [#1949](https://github.com/wasmerio/wasmer/pull/1949) `wasm__vec_delete` functions no longer crash when the given vector is uninitialized, in the Wasmer C API -- [#1949](https://github.com/wasmerio/wasmer/pull/1949) The `wasm_frame_vec_t`, `wasm_functype_vec_t`, `wasm_globaltype_vec_t`, `wasm_memorytype_vec_t`, and `wasm_tabletype_vec_t` are now boxed vectors in the Wasmer C API - -## 1.0.0-beta2 - 2020-12-16 - -### Added - -* [#1916](https://github.com/wasmerio/wasmer/pull/1916) Add the `WASMER_VERSION*` constants with the `wasmer_version*` functions in the Wasmer C API -* [#1867](https://github.com/wasmerio/wasmer/pull/1867) Added `Metering::get_remaining_points` and `Metering::set_remaining_points` -* [#1881](https://github.com/wasmerio/wasmer/pull/1881) Added `UnsupportedTarget` error to `CompileError` -* [#1908](https://github.com/wasmerio/wasmer/pull/1908) Implemented `TryFrom>` for `i32`/`u32`/`i64`/`u64`/`f32`/`f64` -* [#1927](https://github.com/wasmerio/wasmer/pull/1927) Added mmap support in `Engine::deserialize_from_file` to speed up artifact loading -* [#1911](https://github.com/wasmerio/wasmer/pull/1911) Generalized signature type in `Function::new` and `Function::new_with_env` to accept owned and reference `FunctionType` as well as array pairs. This allows users to define signatures as constants. Implemented `From<([Type; $N], [Type; $M])>` for `FunctionType` to support this. - -### Changed - -- [#1865](https://github.com/wasmerio/wasmer/pull/1865) Require that implementors of `WasmerEnv` also implement `Send`, `Sync`, and `Clone`. -- [#1851](https://github.com/wasmerio/wasmer/pull/1851) Improve test suite and documentation of the Wasmer C API -- [#1874](https://github.com/wasmerio/wasmer/pull/1874) Set `CompilerConfig` to be owned (following wasm-c-api) -- [#1880](https://github.com/wasmerio/wasmer/pull/1880) Remove cmake dependency for tests -- [#1924](https://github.com/wasmerio/wasmer/pull/1924) Rename reference implementation `wasmer::Tunables` to `wasmer::BaseTunables`. Export trait `wasmer_engine::Tunables` as `wasmer::Tunables`. - -### Fixed - -- [#1865](https://github.com/wasmerio/wasmer/pull/1865) Fix memory leaks with host function environments. -- [#1870](https://github.com/wasmerio/wasmer/pull/1870) Fixed Trap instruction address maps in Singlepass -* [#1914](https://github.com/wasmerio/wasmer/pull/1914) Implemented `TryFrom for Pages` instead of `From for Pages` to properly handle overflow errors - -## 1.0.0-beta1 - 2020-12-01 - -### Added - -- [#1839](https://github.com/wasmerio/wasmer/pull/1839) Added support for Metering Middleware -- [#1837](https://github.com/wasmerio/wasmer/pull/1837) It is now possible to use exports of an `Instance` even after the `Instance` has been freed -- [#1831](https://github.com/wasmerio/wasmer/pull/1831) Added support for Apple Silicon chips (`arm64-apple-darwin`) -- [#1739](https://github.com/wasmerio/wasmer/pull/1739) Improved function environment setup via `WasmerEnv` proc macro. -- [#1649](https://github.com/wasmerio/wasmer/pull/1649) Add outline of migration to 1.0.0 docs. - -### Changed - -- [#1739](https://github.com/wasmerio/wasmer/pull/1739) Environments passed to host function- must now implement the `WasmerEnv` trait. You can implement it on your existing type with `#[derive(WasmerEnv)]`. -- [#1838](https://github.com/wasmerio/wasmer/pull/1838) Deprecate `WasiEnv::state_mut`: prefer `WasiEnv::state` instead. -- [#1663](https://github.com/wasmerio/wasmer/pull/1663) Function environments passed to host functions now must be passed by `&` instead of `&mut`. This is a breaking change. This change fixes a race condition when a host function is called from multiple threads. If you need mutability in your environment, consider using `std::sync::Mutex` or other synchronization primitives. -- [#1830](https://github.com/wasmerio/wasmer/pull/1830) Minimum supported Rust version bumped to 1.47.0 -- [#1810](https://github.com/wasmerio/wasmer/pull/1810) Make the `state` field of `WasiEnv` public - -### Fixed - -- [#1857](https://github.com/wasmerio/wasmer/pull/1857) Fix dynamic function with new Environment API -- [#1855](https://github.com/wasmerio/wasmer/pull/1855) Fix memory leak when using `wat2wasm` in the C API, the function now takes its output parameter by pointer rather than returning an allocated `wasm_byte_vec_t`. -- [#1841](https://github.com/wasmerio/wasmer/pull/1841) We will now panic when attempting to use a native function with a captured env as a host function. Previously this would silently do the wrong thing. See [#1840](https://github.com/wasmerio/wasmer/pull/1840) for info about Wasmer's support of closures as host functions. -- [#1764](https://github.com/wasmerio/wasmer/pull/1764) Fix bug in WASI `path_rename` allowing renamed files to be 1 directory below a preopened directory. - -## 1.0.0-alpha5 - 2020-11-06 - -### Added - -- [#1761](https://github.com/wasmerio/wasmer/pull/1761) Implement the `wasm_trap_t**` argument of `wasm_instance_new` in the Wasm C API. -- [#1687](https://github.com/wasmerio/wasmer/pull/1687) Add basic table example; fix ownership of local memory and local table metadata in the VM. -- [#1751](https://github.com/wasmerio/wasmer/pull/1751) Implement `wasm_trap_t` inside a function declared with `wasm_func_new_with_env` in the Wasm C API. -- [#1741](https://github.com/wasmerio/wasmer/pull/1741) Implement `wasm_memory_type` in the Wasm C API. -- [#1736](https://github.com/wasmerio/wasmer/pull/1736) Implement `wasm_global_type` in the Wasm C API. -- [#1699](https://github.com/wasmerio/wasmer/pull/1699) Update `wasm.h` to its latest version. -- [#1685](https://github.com/wasmerio/wasmer/pull/1685) Implement `wasm_exporttype_delete` in the Wasm C API. -- [#1725](https://github.com/wasmerio/wasmer/pull/1725) Implement `wasm_func_type` in the Wasm C API. -- [#1715](https://github.com/wasmerio/wasmer/pull/1715) Register errors from `wasm_module_serialize` in the Wasm C API. -- [#1709](https://github.com/wasmerio/wasmer/pull/1709) Implement `wasm_module_name` and `wasm_module_set_name` in the Wasm(er) C API. -- [#1700](https://github.com/wasmerio/wasmer/pull/1700) Implement `wasm_externtype_copy` in the Wasm C API. -- [#1785](https://github.com/wasmerio/wasmer/pull/1785) Add more examples on the Rust API. -- [#1783](https://github.com/wasmerio/wasmer/pull/1783) Handle initialized but empty results in `wasm_func_call` in the Wasm C API. -- [#1780](https://github.com/wasmerio/wasmer/pull/1780) Implement new SIMD zero-extend loads in compiler-llvm. -- [#1754](https://github.com/wasmerio/wasmer/pull/1754) Implement aarch64 ABI for compiler-llvm. -- [#1693](https://github.com/wasmerio/wasmer/pull/1693) Add `wasmer create-exe` subcommand. - -### Changed - -- [#1772](https://github.com/wasmerio/wasmer/pull/1772) Remove lifetime parameter from `NativeFunc`. -- [#1762](https://github.com/wasmerio/wasmer/pull/1762) Allow the `=` sign in a WASI environment variable value. -- [#1710](https://github.com/wasmerio/wasmer/pull/1710) Memory for function call trampolines is now owned by the Artifact. -- [#1781](https://github.com/wasmerio/wasmer/pull/1781) Cranelift upgrade to 0.67. -- [#1777](https://github.com/wasmerio/wasmer/pull/1777) Wasmparser update to 0.65. -- [#1775](https://github.com/wasmerio/wasmer/pull/1775) Improve LimitingTunables implementation. -- [#1720](https://github.com/wasmerio/wasmer/pull/1720) Autodetect llvm regardless of architecture. - -### Fixed - -- [#1718](https://github.com/wasmerio/wasmer/pull/1718) Fix panic in the API in some situations when the memory's min bound was greater than the memory's max bound. -- [#1731](https://github.com/wasmerio/wasmer/pull/1731) In compiler-llvm always load before store, to trigger any traps before any bytes are written. - -## 1.0.0-alpha4 - 2020-10-08 - -### Added -- [#1635](https://github.com/wasmerio/wasmer/pull/1635) Implement `wat2wasm` in the Wasm C API. -- [#1636](https://github.com/wasmerio/wasmer/pull/1636) Implement `wasm_module_validate` in the Wasm C API. -- [#1657](https://github.com/wasmerio/wasmer/pull/1657) Implement `wasm_trap_t` and `wasm_frame_t` for Wasm C API; add examples in Rust and C of exiting early with a host function. - -### Fixed -- [#1690](https://github.com/wasmerio/wasmer/pull/1690) Fix `wasm_memorytype_limits` where `min` and `max` represents pages, not bytes. Additionally, fixes the max limit sentinel value. -- [#1671](https://github.com/wasmerio/wasmer/pull/1671) Fix probestack firing inappropriately, and sometimes over/under allocating stack. -- [#1660](https://github.com/wasmerio/wasmer/pull/1660) Fix issue preventing map-dir aliases starting with `/` from working properly. -- [#1624](https://github.com/wasmerio/wasmer/pull/1624) Add Value::I32/Value::I64 converters from unsigned ints. - -### Changed -- [#1682](https://github.com/wasmerio/wasmer/pull/1682) Improve error reporting when making a memory with invalid settings. -- [#1691](https://github.com/wasmerio/wasmer/pull/1691) Bump minimum supported Rust version to 1.46.0 -- [#1645](https://github.com/wasmerio/wasmer/pull/1645) Move the install script to https://github.com/wasmerio/wasmer-install - -## 1.0.0-alpha3 - 2020-09-14 - -### Fixed - -- [#1620](https://github.com/wasmerio/wasmer/pull/1620) Fix bug causing the Wapm binary to not be packaged with the release -- [#1619](https://github.com/wasmerio/wasmer/pull/1619) Improve error message in engine-native when C compiler is missing - -## 1.0.0-alpha02.0 - 2020-09-11 - -### Added - -- [#1566](https://github.com/wasmerio/wasmer/pull/1566) Add support for opening special Unix files to the WASI FS - -### Fixed - -- [#1602](https://github.com/wasmerio/wasmer/pull/1602) Fix panic when calling host functions with negative numbers in certain situations -- [#1590](https://github.com/wasmerio/wasmer/pull/1590) Fix soundness issue in API of vm::Global - -## TODO: 1.0.0-alpha01.0 - -- Wasmer refactor lands - -## 0.17.1 - 2020-06-24 - -### Changed -- [#1439](https://github.com/wasmerio/wasmer/pull/1439) Move `wasmer-interface-types` into its own repository - -### Fixed - -- [#1554](https://github.com/wasmerio/wasmer/pull/1554) Update supported stable Rust version to 1.45.2. -- [#1552](https://github.com/wasmerio/wasmer/pull/1552) Disable `sigint` handler by default. - -## 0.17.0 - 2020-05-11 - -### Added -- [#1331](https://github.com/wasmerio/wasmer/pull/1331) Implement the `record` type and instrutions for WIT -- [#1345](https://github.com/wasmerio/wasmer/pull/1345) Adding ARM testing in Azure Pipelines -- [#1329](https://github.com/wasmerio/wasmer/pull/1329) New numbers and strings instructions for WIT -- [#1285](https://github.com/wasmerio/wasmer/pull/1285) Greatly improve errors in `wasmer-interface-types` -- [#1303](https://github.com/wasmerio/wasmer/pull/1303) NaN canonicalization for singlepass backend. -- [#1313](https://github.com/wasmerio/wasmer/pull/1313) Add new high-level public API through `wasmer` crate. Includes many updates including: - - Minor improvement: `imports!` macro now handles no trailing comma as well as a trailing comma in namespaces and between namespaces. - - New methods on `Module`: `exports`, `imports`, and `custom_sections`. - - New way to get exports from an instance with `let func_name: Func = instance.exports.get("func_name");`. - - Improved `Table` APIs including `set` which now allows setting functions directly. TODO: update this more if `Table::get` gets made public in this PR - - TODO: finish the list of changes here -- [#1305](https://github.com/wasmerio/wasmer/pull/1305) Handle panics from DynamicFunc. -- [#1300](https://github.com/wasmerio/wasmer/pull/1300) Add support for multiple versions of WASI tests: wasitests now test all versions of WASI. -- [#1292](https://github.com/wasmerio/wasmer/pull/1292) Experimental Support for Android (x86_64 and AArch64) - -### Fixed -- [#1283](https://github.com/wasmerio/wasmer/pull/1283) Workaround for floating point arguments and return values in `DynamicFunc`s. - -### Changed -- [#1401](https://github.com/wasmerio/wasmer/pull/1401) Make breaking change to `RuntimeError`: `RuntimeError` is now more explicit about its possible error values allowing for better insight into why a call into Wasm failed. -- [#1382](https://github.com/wasmerio/wasmer/pull/1382) Refactored test infranstructure (part 2) -- [#1380](https://github.com/wasmerio/wasmer/pull/1380) Refactored test infranstructure (part 1) -- [#1357](https://github.com/wasmerio/wasmer/pull/1357) Refactored bin commands into separate files -- [#1335](https://github.com/wasmerio/wasmer/pull/1335) Change mutability of `memory` to `const` in `wasmer_memory_data_length` in the C API -- [#1332](https://github.com/wasmerio/wasmer/pull/1332) Add option to `CompilerConfig` to force compiler IR verification off even when `debug_assertions` are enabled. This can be used to make debug builds faster, which may be important if you're creating a library that wraps Wasmer and depend on the speed of debug builds. -- [#1320](https://github.com/wasmerio/wasmer/pull/1320) Change `custom_sections` field in `ModuleInfo` to be more standards compliant by allowing multiple custom sections with the same name. To get the old behavior with the new API, you can add `.last().unwrap()` to accesses. For example, `module_info.custom_sections["custom_section_name"].last().unwrap()`. -- [#1301](https://github.com/wasmerio/wasmer/pull/1301) Update supported stable Rust version to 1.41.1. - -## 0.16.2 - 2020-03-11 - -### Fixed - -- [#1294](https://github.com/wasmerio/wasmer/pull/1294) Fix bug related to system calls in WASI that rely on reading from WasmPtrs as arrays of length 0. `WasmPtr` will now succeed on length 0 arrays again. - -## 0.16.1 - 2020-03-11 - -### Fixed - -- [#1291](https://github.com/wasmerio/wasmer/pull/1291) Fix installation packaging script to package the `wax` command. - -## 0.16.0 - 2020-03-11 - -### Added -- [#1286](https://github.com/wasmerio/wasmer/pull/1286) Updated Windows Wasmer icons. Add wax -- [#1284](https://github.com/wasmerio/wasmer/pull/1284) Implement string and memory instructions in `wasmer-interface-types` - -### Fixed -- [#1272](https://github.com/wasmerio/wasmer/pull/1272) Fix off-by-one error bug when accessing memory with a `WasmPtr` that contains the last valid byte of memory. Also changes the behavior of `WasmPtr` with a length of 0 and `WasmPtr` where `std::mem::size_of::()` is 0 to always return `None` - -## 0.15.0 - 2020-03-04 - -- [#1263](https://github.com/wasmerio/wasmer/pull/1263) Changed the behavior of some WASI syscalls to now handle preopened directories more properly. Changed default `--debug` logging to only show Wasmer-related messages. -- [#1217](https://github.com/wasmerio/wasmer/pull/1217) Polymorphic host functions based on dynamic trampoline generation. -- [#1252](https://github.com/wasmerio/wasmer/pull/1252) Allow `/` in wasi `--mapdir` wasm path. -- [#1212](https://github.com/wasmerio/wasmer/pull/1212) Add support for GDB JIT debugging: - - Add `--generate-debug-info` and `-g` flags to `wasmer run` to generate debug information during compilation. The debug info is passed via the GDB JIT interface to a debugger to allow source-level debugging of Wasm files. Currently only available on clif-backend. - - Break public middleware APIs: there is now a `source_loc` parameter that should be passed through if applicable. - - Break compiler trait methods such as `feed_local`, `feed_event` as well as `ModuleCodeGenerator::finalize`. - -## 0.14.1 - 2020-02-24 - -- [#1245](https://github.com/wasmerio/wasmer/pull/1245) Use Ubuntu 16.04 in CI so that we use an earlier version of GLIBC. -- [#1234](https://github.com/wasmerio/wasmer/pull/1234) Check for unused excluded spectest failures. -- [#1232](https://github.com/wasmerio/wasmer/pull/1232) `wasmer-interface-types` has a WAT decoder. - -## 0.14.0 - 2020-02-20 - -- [#1233](https://github.com/wasmerio/wasmer/pull/1233) Improved Wasmer C API release artifacts. -- [#1216](https://github.com/wasmerio/wasmer/pull/1216) `wasmer-interface-types` receives a binary encoder. -- [#1228](https://github.com/wasmerio/wasmer/pull/1228) Singlepass cleanup: Resolve several FIXMEs and remove protect_unix. -- [#1218](https://github.com/wasmerio/wasmer/pull/1218) Enable Cranelift verifier in debug mode. Fix bug with table indices being the wrong type. -- [#787](https://github.com/wasmerio/wasmer/pull/787) New crate `wasmer-interface-types` to implement WebAssembly Interface Types. -- [#1213](https://github.com/wasmerio/wasmer/pull/1213) Fixed WASI `fdstat` to detect `isatty` properly. -- [#1192](https://github.com/wasmerio/wasmer/pull/1192) Use `ExceptionCode` for error representation. -- [#1191](https://github.com/wasmerio/wasmer/pull/1191) Fix singlepass miscompilation on `Operator::CallIndirect`. -- [#1180](https://github.com/wasmerio/wasmer/pull/1180) Fix compilation for target `x86_64-unknown-linux-musl`. -- [#1170](https://github.com/wasmerio/wasmer/pull/1170) Improve the WasiFs builder API with convenience methods for overriding stdin, stdout, and stderr as well as a new sub-builder for controlling the permissions and properties of preopened directories. Also breaks that implementations of `WasiFile` must be `Send` -- please file an issue if this change causes you any issues. -- [#1161](https://github.com/wasmerio/wasmer/pull/1161) Require imported functions to be `Send`. This is a breaking change that fixes a soundness issue in the API. -- [#1140](https://github.com/wasmerio/wasmer/pull/1140) Use [`blake3`](https://github.com/BLAKE3-team/BLAKE3) as default hashing algorithm for caching. -- [#1129](https://github.com/wasmerio/wasmer/pull/1129) Standard exception types for singlepass backend. - -## 0.13.1 - 2020-01-16 -- Fix bug in wapm related to the `package.wasmer_extra_flags` entry in the manifest - -## 0.13.0 - 2020-01-15 - -Special thanks to [@repi](https://github.com/repi) and [@srenatus](https://github.com/srenatus) for their contributions! - -- [#1153](https://github.com/wasmerio/wasmer/pull/1153) Added Wasmex, an Elixir language integration, to the README -- [#1133](https://github.com/wasmerio/wasmer/pull/1133) New `wasmer_trap` function in the C API, to properly error from within a host function -- [#1147](https://github.com/wasmerio/wasmer/pull/1147) Remove `log` and `trace` macros from `wasmer-runtime-core`, remove `debug` and `trace` features from `wasmer-*` crates, use the `log` crate for logging and use `fern` in the Wasmer CLI binary to output log messages. Colorized output will be enabled automatically if printing to a terminal, to force colorization on or off, set the `WASMER_COLOR` environment variable to `true` or `false`. -- [#1128](https://github.com/wasmerio/wasmer/pull/1128) Fix a crash when a host function is missing and the `allow_missing_functions` flag is enabled -- [#1099](https://github.com/wasmerio/wasmer/pull/1099) Remove `backend::Backend` from `wasmer_runtime_core` -- [#1097](https://github.com/wasmerio/wasmer/pull/1097) Move inline breakpoint outside of runtime backend -- [#1095](https://github.com/wasmerio/wasmer/pull/1095) Update to cranelift 0.52. -- [#1092](https://github.com/wasmerio/wasmer/pull/1092) Add `get_utf8_string_with_nul` to `WasmPtr` to read nul-terminated strings from memory. -- [#1071](https://github.com/wasmerio/wasmer/pull/1071) Add support for non-trapping float-to-int conversions, enabled by default. - -## 0.12.0 - 2019-12-18 - -Special thanks to [@ethanfrey](https://github.com/ethanfrey), [@AdamSLevy](https://github.com/AdamSLevy), [@Jasper-Bekkers](https://github.com/Jasper-Bekkers), [@srenatus](https://github.com/srenatus) for their contributions! - -- [#1078](https://github.com/wasmerio/wasmer/pull/1078) Increase the maximum number of parameters `Func` can take -- [#1062](https://github.com/wasmerio/wasmer/pull/1062) Expose some opt-in Emscripten functions to the C API -- [#1032](https://github.com/wasmerio/wasmer/pull/1032) Change the signature of the Emscripten `abort` function to work with Emscripten 1.38.30 -- [#1060](https://github.com/wasmerio/wasmer/pull/1060) Test the capi with all the backends -- [#1069](https://github.com/wasmerio/wasmer/pull/1069) Add function `get_memory_and_data` to `Ctx` to help prevent undefined behavior and mutable aliasing. It allows accessing memory while borrowing data mutably for the `Ctx` lifetime. This new function is now being used in `wasmer-wasi`. -- [#1058](https://github.com/wasmerio/wasmer/pull/1058) Fix minor panic issue when `wasmer::compile_with` called with llvm backend. -- [#858](https://github.com/wasmerio/wasmer/pull/858) Minor panic fix when wasmer binary with `loader` option run a module without exported `_start` function. -- [#1056](https://github.com/wasmerio/wasmer/pull/1056) Improved `--invoke` args parsing (supporting `i32`, `i64`, `f32` and `f32`) in Wasmer CLI -- [#1054](https://github.com/wasmerio/wasmer/pull/1054) Improve `--invoke` output in Wasmer CLI -- [#1053](https://github.com/wasmerio/wasmer/pull/1053) For RuntimeError and breakpoints, use Box instead of Box. -- [#1052](https://github.com/wasmerio/wasmer/pull/1052) Fix minor panic and improve Error handling in singlepass backend. -- [#1050](https://github.com/wasmerio/wasmer/pull/1050) Attach C & C++ headers to releases. -- [#1033](https://github.com/wasmerio/wasmer/pull/1033) Set cranelift backend as default compiler backend again, require at least one backend to be enabled for Wasmer CLI -- [#1044](https://github.com/wasmerio/wasmer/pull/1044) Enable AArch64 support in the LLVM backend. -- [#1030](https://github.com/wasmerio/wasmer/pull/1030) Ability to generate `ImportObject` for a specific version WASI version with the C API. -- [#1028](https://github.com/wasmerio/wasmer/pull/1028) Introduce strict/non-strict modes for `get_wasi_version` -- [#1029](https://github.com/wasmerio/wasmer/pull/1029) Add the “floating” `WasiVersion::Latest` version. -- [#1006](https://github.com/wasmerio/wasmer/pull/1006) Fix minor panic issue when `wasmer::compile_with` called with llvm backend -- [#1009](https://github.com/wasmerio/wasmer/pull/1009) Enable LLVM verifier for all tests, add new llvm-backend-tests crate. -- [#1022](https://github.com/wasmerio/wasmer/pull/1022) Add caching support for Singlepass backend. -- [#1004](https://github.com/wasmerio/wasmer/pull/1004) Add the Auto backend to enable to adapt backend usage depending on wasm file executed. -- [#1068](https://github.com/wasmerio/wasmer/pull/1068) Various cleanups for the singlepass backend on AArch64. - -## 0.11.0 - 2019-11-22 - -- [#713](https://github.com/wasmerio/wasmer/pull/713) Add AArch64 support for singlepass. -- [#995](https://github.com/wasmerio/wasmer/pull/995) Detect when a global is read without being initialized (emit a proper error instead of panicking) -- [#996](https://github.com/wasmerio/wasmer/pull/997) Refactored spectests, emtests and wasitests to use default compiler logic -- [#992](https://github.com/wasmerio/wasmer/pull/992) Updates WAPM version to 0.4.1, fix arguments issue introduced in #990 -- [#990](https://github.com/wasmerio/wasmer/pull/990) Default wasmer CLI to `run`. Wasmer will now attempt to parse unrecognized command line options as if they were applied to the run command: `wasmer mywasm.wasm --dir=.` now works! -- [#987](https://github.com/wasmerio/wasmer/pull/987) Fix `runtime-c-api` header files when compiled by gnuc. -- [#957](https://github.com/wasmerio/wasmer/pull/957) Change the meaning of `wasmer_wasi::is_wasi_module` to detect any type of WASI module, add support for new wasi snapshot_preview1 -- [#934](https://github.com/wasmerio/wasmer/pull/934) Simplify float expressions in the LLVM backend. - -## 0.10.2 - 2019-11-18 - -- [#968](https://github.com/wasmerio/wasmer/pull/968) Added `--invoke` option to the command -- [#964](https://github.com/wasmerio/wasmer/pull/964) Enable cross-compilation for specific target -- [#971](https://github.com/wasmerio/wasmer/pull/971) In LLVM backend, use unaligned loads and stores for non-atomic accesses to wasmer memory. -- [#960](https://github.com/wasmerio/wasmer/pull/960) Fix `runtime-c-api` header files when compiled by clang. -- [#925](https://github.com/wasmerio/wasmer/pull/925) Host functions can be closures with a captured environment. -- [#917](https://github.com/wasmerio/wasmer/pull/917) Host functions (aka imported functions) may not have `&mut vm::Ctx` as first argument, i.e. the presence of the `&mut vm::Ctx` argument is optional. -- [#915](https://github.com/wasmerio/wasmer/pull/915) All backends share the same definition of `Trampoline` (defined in `wasmer-runtime-core`). - -## 0.10.1 - 2019-11-11 - -- [#952](https://github.com/wasmerio/wasmer/pull/952) Use C preprocessor to properly hide trampoline functions on Windows and non-x86_64 targets. - -## 0.10.0 - 2019-11-11 - -Special thanks to [@newpavlov](https://github.com/newpavlov) and [@Maxgy](https://github.com/Maxgy) for their contributions! - -- [#942](https://github.com/wasmerio/wasmer/pull/942) Deny missing docs in runtime core and add missing docs -- [#939](https://github.com/wasmerio/wasmer/pull/939) Fix bug causing attempts to append to files with WASI to delete the contents of the file -- [#940](https://github.com/wasmerio/wasmer/pull/940) Update supported Rust version to 1.38+ -- [#923](https://github.com/wasmerio/wasmer/pull/923) Fix memory leak in the C API caused by an incorrect cast in `wasmer_trampoline_buffer_destroy` -- [#921](https://github.com/wasmerio/wasmer/pull/921) In LLVM backend, annotate all memory accesses with TBAA metadata. -- [#883](https://github.com/wasmerio/wasmer/pull/883) Allow floating point operations to have arbitrary inputs, even including SNaNs. -- [#856](https://github.com/wasmerio/wasmer/pull/856) Expose methods in the runtime C API to get a WASI import object - -## 0.9.0 - 2019-10-23 - -Special thanks to @alocquet for their contributions! - -- [#898](https://github.com/wasmerio/wasmer/pull/898) State tracking is now disabled by default in the LLVM backend. It can be enabled with `--track-state`. -- [#861](https://github.com/wasmerio/wasmer/pull/861) Add descriptions to `unimplemented!` macro in various places -- [#897](https://github.com/wasmerio/wasmer/pull/897) Removes special casing of stdin, stdout, and stderr in WASI. Closing these files now works. Removes `stdin`, `stdout`, and `stderr` from `WasiFS`, replaced by the methods `stdout`, `stdout_mut`, and so on. -- [#863](https://github.com/wasmerio/wasmer/pull/863) Fix min and max for cases involving NaN and negative zero when using the LLVM backend. - -## 0.8.0 - 2019-10-02 - -Special thanks to @jdanford for their contributions! - -- [#850](https://github.com/wasmerio/wasmer/pull/850) New `WasiStateBuilder` API. small, add misc. breaking changes to existing API (for example, changing the preopen dirs arg on `wasi::generate_import_object` from `Vec` to `Vec`) -- [#852](https://github.com/wasmerio/wasmer/pull/852) Make minor grammar/capitalization fixes to README.md -- [#841](https://github.com/wasmerio/wasmer/pull/841) Slightly improve rustdoc documentation and small updates to outdated info in readme files -- [#836](https://github.com/wasmerio/wasmer/pull/836) Update Cranelift fork version to `0.44.0` -- [#839](https://github.com/wasmerio/wasmer/pull/839) Change supported version to stable Rust 1.37+ -- [#834](https://github.com/wasmerio/wasmer/pull/834) Fix panic when unwraping `wasmer` arguments -- [#835](https://github.com/wasmerio/wasmer/pull/835) Add parallel execution example (independent instances created from the same `ImportObject` and `Module` run with rayon) -- [#834](https://github.com/wasmerio/wasmer/pull/834) Fix panic when parsing numerical arguments for no-ABI targets run with the wasmer binary -- [#833](https://github.com/wasmerio/wasmer/pull/833) Add doc example of using ImportObject's new `maybe_with_namespace` method -- [#832](https://github.com/wasmerio/wasmer/pull/832) Delete unused runtime ABI -- [#809](https://github.com/wasmerio/wasmer/pull/809) Fix bugs leading to panics in `LocalBacking`. -- [#831](https://github.com/wasmerio/wasmer/pull/831) Add support for atomic operations, excluding wait and notify, to singlepass. -- [#822](https://github.com/wasmerio/wasmer/pull/822) Update Cranelift fork version to `0.43.1` -- [#829](https://github.com/wasmerio/wasmer/pull/829) Fix deps on `make bench-*` commands; benchmarks don't compile other backends now -- [#807](https://github.com/wasmerio/wasmer/pull/807) Implement Send for `Instance`, breaking change on `ImportObject`, remove method `get_namespace` replaced with `with_namespace` and `maybe_with_namespace` -- [#817](https://github.com/wasmerio/wasmer/pull/817) Add document for tracking features across backends and language integrations, [docs/feature_matrix.md] -- [#823](https://github.com/wasmerio/wasmer/issues/823) Improved Emscripten / WASI integration -- [#821](https://github.com/wasmerio/wasmer/issues/821) Remove patch version on most deps Cargo manifests. This gives Wasmer library users more control over which versions of the deps they use. -- [#820](https://github.com/wasmerio/wasmer/issues/820) Remove null-pointer checks in `WasmPtr` from runtime-core, re-add them in Emscripten -- [#803](https://github.com/wasmerio/wasmer/issues/803) Add method to `Ctx` to invoke functions by their `TableIndex` -- [#790](https://github.com/wasmerio/wasmer/pull/790) Fix flaky test failure with LLVM, switch to large code model. -- [#788](https://github.com/wasmerio/wasmer/pull/788) Use union merge on the changelog file. -- [#785](https://github.com/wasmerio/wasmer/pull/785) Include Apache license file for spectests. -- [#786](https://github.com/wasmerio/wasmer/pull/786) In the LLVM backend, lower atomic wasm operations to atomic machine instructions. -- [#784](https://github.com/wasmerio/wasmer/pull/784) Fix help string for wasmer run. - -## 0.7.0 - 2019-09-12 - -Special thanks to @YaronWittenstein @penberg for their contributions. - -- [#776](https://github.com/wasmerio/wasmer/issues/776) Allow WASI preopened fds to be closed -- [#774](https://github.com/wasmerio/wasmer/issues/774) Add more methods to the `WasiFile` trait -- [#772](https://github.com/wasmerio/wasmer/issues/772) [#770](https://github.com/wasmerio/wasmer/issues/770) Handle more internal failures by passing back errors -- [#756](https://github.com/wasmerio/wasmer/issues/756) Allow NULL parameter and 0 arity in `wasmer_export_func_call` C API -- [#747](https://github.com/wasmerio/wasmer/issues/747) Return error instead of panicking on traps when using the Wasmer binary -- [#741](https://github.com/wasmerio/wasmer/issues/741) Add validate Wasm fuzz target -- [#733](https://github.com/wasmerio/wasmer/issues/733) Remove dependency on compiler backends for `middleware-common` -- [#732](https://github.com/wasmerio/wasmer/issues/732) [#731](https://github.com/wasmerio/wasmer/issues/731) WASI bug fixes and improvements -- [#726](https://github.com/wasmerio/wasmer/issues/726) Add serialization and deserialization for Wasi State -- [#716](https://github.com/wasmerio/wasmer/issues/716) Improve portability of install script -- [#714](https://github.com/wasmerio/wasmer/issues/714) Add Code of Conduct -- [#708](https://github.com/wasmerio/wasmer/issues/708) Remove unconditional dependency on Cranelift in the C API -- [#703](https://github.com/wasmerio/wasmer/issues/703) Fix compilation on AArch64 Linux -- [#702](https://github.com/wasmerio/wasmer/issues/702) Add SharedMemory to Wasmer. Add `--enable-threads` flag, add partial implementation of atomics to LLVM backend. -- [#698](https://github.com/wasmerio/wasmer/issues/698) [#690](https://github.com/wasmerio/wasmer/issues/690) [#687](https://github.com/wasmerio/wasmer/issues/690) Fix panics in Emscripten -- [#689](https://github.com/wasmerio/wasmer/issues/689) Replace `wasmer_runtime_code::memory::Atomic` with `std::sync::atomic` atomics, changing its interface -- [#680](https://github.com/wasmerio/wasmer/issues/680) [#673](https://github.com/wasmerio/wasmer/issues/673) [#669](https://github.com/wasmerio/wasmer/issues/669) [#660](https://github.com/wasmerio/wasmer/issues/660) [#659](https://github.com/wasmerio/wasmer/issues/659) Misc. runtime and singlepass fixes -- [#677](https://github.com/wasmerio/wasmer/issues/677) [#675](https://github.com/wasmerio/wasmer/issues/675) [#674](https://github.com/wasmerio/wasmer/issues/674) LLVM backend fixes and improvements -- [#671](https://github.com/wasmerio/wasmer/issues/671) Implement fs polling in `wasi::poll_oneoff` for Unix-like platforms -- [#656](https://github.com/wasmerio/wasmer/issues/656) Move CI to Azure Pipelines -- [#650](https://github.com/wasmerio/wasmer/issues/650) Implement `wasi::path_rename`, improve WASI FS public api, and allow open files to exist even when the underlying file is deleted -- [#643](https://github.com/wasmerio/wasmer/issues/643) Implement `wasi::path_symlink` and improve WASI FS public api IO error reporting -- [#608](https://github.com/wasmerio/wasmer/issues/608) Implement wasi syscalls `fd_allocate`, `fd_sync`, `fd_pread`, `path_link`, `path_filestat_set_times`; update WASI fs API in a WIP way; reduce coupling of WASI code to host filesystem; make debug messages from WASI more readable; improve rights-checking when calling syscalls; implement reference counting on inodes; misc bug fixes and improvements -- [#616](https://github.com/wasmerio/wasmer/issues/616) Create the import object separately from instance instantiation in `runtime-c-api` -- [#620](https://github.com/wasmerio/wasmer/issues/620) Replace one `throw()` with `noexcept` in llvm backend -- [#618](https://github.com/wasmerio/wasmer/issues/618) Implement `InternalEvent::Breakpoint` in the llvm backend to allow metering in llvm -- [#615](https://github.com/wasmerio/wasmer/issues/615) Eliminate `FunctionEnvironment` construction in `feed_event()` speeding up to 70% of compilation in clif -- [#609](https://github.com/wasmerio/wasmer/issues/609) Update dependencies -- [#602](https://github.com/wasmerio/wasmer/issues/602) C api extract instance context from instance -- [#590](https://github.com/wasmerio/wasmer/issues/590) Error visibility changes in wasmer-c-api -- [#589](https://github.com/wasmerio/wasmer/issues/589) Make `wasmer_byte_array` fields `public` in wasmer-c-api - -## 0.6.0 - 2019-07-31 -- [#603](https://github.com/wasmerio/wasmer/pull/603) Update Wapm-cli, bump version numbers -- [#595](https://github.com/wasmerio/wasmer/pull/595) Add unstable public API for interfacing with the WASI file system in plugin-like usecases -- [#598](https://github.com/wasmerio/wasmer/pull/598) LLVM Backend is now supported in Windows -- [#599](https://github.com/wasmerio/wasmer/pull/599) Fix llvm backend failures in fat spec tests and simd_binaryen spec test. -- [#579](https://github.com/wasmerio/wasmer/pull/579) Fix bug in caching with LLVM and Singlepass backends. - Add `default-backend-singlepass`, `default-backend-llvm`, and `default-backend-cranelift` features to `wasmer-runtime` - to control the `default_compiler()` function (this is a breaking change). Add `compiler_for_backend` function in `wasmer-runtime` -- [#561](https://github.com/wasmerio/wasmer/pull/561) Call the `data_finalizer` field on the `Ctx` -- [#576](https://github.com/wasmerio/wasmer/pull/576) fix `Drop` of uninit `Ctx` -- [#542](https://github.com/wasmerio/wasmer/pull/542) Add SIMD support to Wasmer (LLVM backend only) - - Updates LLVM to version 8.0 - -## 0.5.7 - 2019-07-23 -- [#575](https://github.com/wasmerio/wasmer/pull/575) Prepare for release; update wapm to 0.3.6 -- [#555](https://github.com/wasmerio/wasmer/pull/555) WASI filesystem rewrite. Major improvements - - adds virtual root showing all preopened directories - - improved sandboxing and code-reuse - - symlinks work in a lot more situations - - many misc. improvements to most syscalls touching the filesystem - -## 0.5.6 - 2019-07-16 -- [#565](https://github.com/wasmerio/wasmer/pull/565) Update wapm and bump version to 0.5.6 -- [#563](https://github.com/wasmerio/wasmer/pull/563) Improve wasi testing infrastructure - - fixes arg parsing from comments & fixes the mapdir test to have the native code doing the same thing as the WASI code - - makes wasitests-generate output stdout/stderr by default & adds function to print stdout and stderr for a command if it fails - - compiles wasm with size optimizations & strips generated wasm with wasm-strip -- [#554](https://github.com/wasmerio/wasmer/pull/554) Finish implementation of `wasi::fd_seek`, fix bug in filestat -- [#550](https://github.com/wasmerio/wasmer/pull/550) Fix singlepass compilation error with `imul` instruction - - -## 0.5.5 - 2019-07-10 -- [#541](https://github.com/wasmerio/wasmer/pull/541) Fix dependency graph by making separate test crates; ABI implementations should not depend on compilers. Add Cranelift fork as git submodule of clif-backend -- [#537](https://github.com/wasmerio/wasmer/pull/537) Add hidden flag (`--cache-key`) to use prehashed key into the compiled wasm cache and change compiler backend-specific caching to use directories -- [#536](https://github.com/wasmerio/wasmer/pull/536) ~Update cache to use compiler backend name in cache key~ - -## 0.5.4 - 2019-07-06 -- [#529](https://github.com/wasmerio/wasmer/pull/529) Updates the Wasm Interface library, which is used by wapm, with bug fixes and error message improvements - -## 0.5.3 - 2019-07-03 -- [#523](https://github.com/wasmerio/wasmer/pull/523) Update wapm version to fix bug related to signed packages in the global namespace and locally-stored public keys - -## 0.5.2 - 2019-07-02 -- [#516](https://github.com/wasmerio/wasmer/pull/516) Add workaround for singlepass miscompilation on GetLocal -- [#521](https://github.com/wasmerio/wasmer/pull/521) Update Wapm-cli, bump version numbers -- [#518](https://github.com/wasmerio/wasmer/pull/518) Update Cranelift and WasmParser -- [#514](https://github.com/wasmerio/wasmer/pull/514) [#519](https://github.com/wasmerio/wasmer/pull/519) Improved Emscripten network related calls, added a null check to `WasmPtr` -- [#515](https://github.com/wasmerio/wasmer/pull/515) Improved Emscripten dyncalls -- [#513](https://github.com/wasmerio/wasmer/pull/513) Fix emscripten lseek implementation. -- [#510](https://github.com/wasmerio/wasmer/pull/510) Simplify construction of floating point constants in LLVM backend. Fix LLVM assertion failure due to definition of %ctx. - -## 0.5.1 - 2019-06-24 -- [#508](https://github.com/wasmerio/wasmer/pull/508) Update wapm version, includes bug fixes - -## 0.5.0 - 2019-06-17 - -- [#471](https://github.com/wasmerio/wasmer/pull/471) Added missing functions to run Python. Improved Emscripten bindings -- [#494](https://github.com/wasmerio/wasmer/pull/494) Remove deprecated type aliases from libc in the runtime C API -- [#493](https://github.com/wasmerio/wasmer/pull/493) `wasmer_module_instantiate` has better error messages in the runtime C API -- [#474](https://github.com/wasmerio/wasmer/pull/474) Set the install name of the dylib to `@rpath` -- [#490](https://github.com/wasmerio/wasmer/pull/490) Add MiddlewareChain and StreamingCompiler to runtime -- [#487](https://github.com/wasmerio/wasmer/pull/487) Fix stack offset check in singlepass backend -- [#450](https://github.com/wasmerio/wasmer/pull/450) Added Metering -- [#481](https://github.com/wasmerio/wasmer/pull/481) Added context trampoline into runtime -- [#484](https://github.com/wasmerio/wasmer/pull/484) Fix bugs in emscripten socket syscalls -- [#476](https://github.com/wasmerio/wasmer/pull/476) Fix bug with wasi::environ_get, fix off by one error in wasi::environ_sizes_get -- [#470](https://github.com/wasmerio/wasmer/pull/470) Add mapdir support to Emscripten, implement getdents for Unix -- [#467](https://github.com/wasmerio/wasmer/pull/467) `wasmer_instantiate` returns better error messages in the runtime C API -- [#463](https://github.com/wasmerio/wasmer/pull/463) Fix bug in WASI path_open allowing one level above preopened dir to be accessed -- [#461](https://github.com/wasmerio/wasmer/pull/461) Prevent passing negative lengths in various places in the runtime C API -- [#459](https://github.com/wasmerio/wasmer/pull/459) Add monotonic and real time clocks for wasi on windows -- [#447](https://github.com/wasmerio/wasmer/pull/447) Add trace macro (`--features trace`) for more verbose debug statements -- [#451](https://github.com/wasmerio/wasmer/pull/451) Add `--mapdir=src:dest` flag to rename host directories in the guest context -- [#457](https://github.com/wasmerio/wasmer/pull/457) Implement file metadata for WASI, fix bugs in WASI clock code for Unix platforms - -## 0.4.2 - 2019-05-16 - -- [#416](https://github.com/wasmerio/wasmer/pull/416) Remote code loading framework -- [#449](https://github.com/wasmerio/wasmer/pull/449) Fix bugs: opening host files in filestat and opening with write permissions unconditionally in path_open -- [#442](https://github.com/wasmerio/wasmer/pull/442) Misc. WASI FS fixes and implement readdir -- [#440](https://github.com/wasmerio/wasmer/pull/440) Fix type mismatch between `wasmer_instance_call` and `wasmer_export_func_*_arity` functions in the runtime C API. -- [#269](https://github.com/wasmerio/wasmer/pull/269) Add better runtime docs -- [#432](https://github.com/wasmerio/wasmer/pull/432) Fix returned value of `wasmer_last_error_message` in the runtime C API -- [#429](https://github.com/wasmerio/wasmer/pull/429) Get wasi::path_filestat_get working for some programs; misc. minor WASI FS improvements -- [#413](https://github.com/wasmerio/wasmer/pull/413) Update LLVM backend to use new parser codegen traits - -## 0.4.1 - 2019-05-06 - -- [#426](https://github.com/wasmerio/wasmer/pull/426) Update wapm-cli submodule, bump version to 0.4.1 -- [#422](https://github.com/wasmerio/wasmer/pull/422) Improved Emscripten functions to run optipng and pngquant compiled to wasm -- [#409](https://github.com/wasmerio/wasmer/pull/409) Improved Emscripten functions to run JavascriptCore compiled to wasm -- [#399](https://github.com/wasmerio/wasmer/pull/399) Add example of using a plugin extended from WASI -- [#397](https://github.com/wasmerio/wasmer/pull/397) Fix WASI fs abstraction to work on Windows -- [#390](https://github.com/wasmerio/wasmer/pull/390) Pin released wapm version and add it as a git submodule -- [#408](https://github.com/wasmerio/wasmer/pull/408) Add images to windows installer and update installer to add wapm bin directory to path - -## 0.4.0 - 2019-04-23 - -- [#383](https://github.com/wasmerio/wasmer/pull/383) Hook up wasi exit code to wasmer cli. -- [#382](https://github.com/wasmerio/wasmer/pull/382) Improve error message on `--backend` flag to only suggest currently enabled backends -- [#381](https://github.com/wasmerio/wasmer/pull/381) Allow retrieving propagated user errors. -- [#379](https://github.com/wasmerio/wasmer/pull/379) Fix small return types from imported functions. -- [#371](https://github.com/wasmerio/wasmer/pull/371) Add more Debug impl for WASI types -- [#368](https://github.com/wasmerio/wasmer/pull/368) Fix issue with write buffering -- [#343](https://github.com/wasmerio/wasmer/pull/343) Implement preopened files for WASI and fix aligment issue when accessing WASI memory -- [#367](https://github.com/wasmerio/wasmer/pull/367) Add caching support to the LLVM backend. -- [#366](https://github.com/wasmerio/wasmer/pull/366) Remove `UserTrapper` trait to fix [#365](https://github.com/wasmerio/wasmer/issues/365). -- [#348](https://github.com/wasmerio/wasmer/pull/348) Refactor internal runtime ↔️ backend abstraction. -- [#355](https://github.com/wasmerio/wasmer/pull/355) Misc changes to `Cargo.toml`s for publishing -- [#352](https://github.com/wasmerio/wasmer/pull/352) Bump version numbers to 0.3.0 -- [#351](https://github.com/wasmerio/wasmer/pull/351) Add hidden option to specify wasm program name (can be used to improve error messages) -- [#350](https://github.com/wasmerio/wasmer/pull/350) Enforce that CHANGELOG.md is updated through CI. -- [#349](https://github.com/wasmerio/wasmer/pull/349) Add [CHANGELOG.md](https://github.com/wasmerio/wasmer/blob/master/CHANGELOG.md). - -## 0.3.0 - 2019-04-12 - -- [#276](https://github.com/wasmerio/wasmer/pull/276) [#288](https://github.com/wasmerio/wasmer/pull/288) [#344](https://github.com/wasmerio/wasmer/pull/344) Use new singlepass backend (with the `--backend=singlepass` when running Wasmer) -- [#338](https://github.com/wasmerio/wasmer/pull/338) Actually catch traps/panics/etc when using a typed func. -- [#325](https://github.com/wasmerio/wasmer/pull/325) Fixed func_index in debug mode -- [#323](https://github.com/wasmerio/wasmer/pull/323) Add validate subcommand to validate Wasm files -- [#321](https://github.com/wasmerio/wasmer/pull/321) Upgrade to Cranelift 0.3.0 -- [#319](https://github.com/wasmerio/wasmer/pull/319) Add Export and GlobalDescriptor to Runtime API -- [#310](https://github.com/wasmerio/wasmer/pull/310) Cleanup warnings -- [#299](https://github.com/wasmerio/wasmer/pull/299) [#300](https://github.com/wasmerio/wasmer/pull/300) [#301](https://github.com/wasmerio/wasmer/pull/301) [#303](https://github.com/wasmerio/wasmer/pull/303) [#304](https://github.com/wasmerio/wasmer/pull/304) [#305](https://github.com/wasmerio/wasmer/pull/305) [#306](https://github.com/wasmerio/wasmer/pull/306) [#307](https://github.com/wasmerio/wasmer/pull/307) Add support for WASI 🎉 -- [#286](https://github.com/wasmerio/wasmer/pull/286) Add extend to imports -- [#278](https://github.com/wasmerio/wasmer/pull/278) Add versioning to cache -- [#250](https://github.com/wasmerio/wasmer/pull/250) Setup bors +# Changelog + +*The format is based on [Keep a Changelog].* + +[Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ + +Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/CHANGELOG.md). + + +## **Unreleased** + +## 3.0.2 - 25/11/2022 + +## Added + + - [#3364](https://github.com/wasmerio/wasmer/pull/3364) Added the actual LZCNT / TZCNT implementation + - [#3361](https://github.com/wasmerio/wasmer/pull/3361) Give users feedback when they are running "wasmer add ..." + +## Changed + + - [#3368](https://github.com/wasmerio/wasmer/pull/3368) Remove wasi conditional compilation from wasmer-registry + - [#3367](https://github.com/wasmerio/wasmer/pull/3367) Change LLVM detection in Makefile + - [#3365](https://github.com/wasmerio/wasmer/pull/3365) Improve FreeBSD support + - [#3360](https://github.com/wasmerio/wasmer/pull/3360) Introduce a "wasmer_registry::queries" module with all GraphQL queries + +## Fixed + + - [#3371](https://github.com/wasmerio/wasmer/pull/3371) Fix cargo binstall + - [#3370](https://github.com/wasmerio/wasmer/pull/3370) Fix wasmer run not interpreting URLs correctly + display fixes + + +## 3.0.1 - 23/11/2022 + +## Added + + +## Changed + + - [#3344](https://github.com/wasmerio/wasmer/pull/3344) Revert #3145 + - [#3341](https://github.com/wasmerio/wasmer/pull/3341) Update CHANGELOG.md + +## Fixed + + - [#3342](https://github.com/wasmerio/wasmer/pull/3342) Fixes for 3.0.0 release + + + +## 3.0.0 - 20/11/2022 + +## Added + + - [#3338](https://github.com/wasmerio/wasmer/3338) Re-add codecov to get coverage reports + - [#3337](https://github.com/wasmerio/wasmer/3337) Add automation script to automate deploying releases on GitHub + +## Changed + + +## Fixed + + - [#3339](https://github.com/wasmerio/wasmer/3339) Fixes for wasmer login / wasmer add + + +## 3.0.0-rc.3 - 2022/11/18 + +## Added + +- [#3314](https://github.com/wasmerio/wasmer/pull/3314) Add windows-gnu workflow +- [#3317](https://github.com/wasmerio/wasmer/pull/3317) Add a `wasmer add` command for adding bindings to a WAPM package +- [#3297](https://github.com/wasmerio/wasmer/pull/3297) Implement wasmer login +- [#3311](https://github.com/wasmerio/wasmer/pull/3311) Export `Module::IoCompileError` + +## Changed + +- [#3319](https://github.com/wasmerio/wasmer/pull/3319) Disable 'Test integration CLI' on CI for the Windows platform as it's not working at all +- [#3318](https://github.com/wasmerio/wasmer/pull/3318) Bump the MSRV to 1.63 +- [#3293](https://github.com/wasmerio/wasmer/pull/3293) Removed call to to_vec() on assembler.finalise() +- [#3288](https://github.com/wasmerio/wasmer/pull/3288) Rollback all the TARGET_DIR changes +- [#3284](https://github.com/wasmerio/wasmer/pull/3284) Makefile now handle TARGET_DIR env. var. for build too +- [#3276](https://github.com/wasmerio/wasmer/pull/3276) Remove unnecessary checks to test internet connection +- [#3275](https://github.com/wasmerio/wasmer/pull/3275) Disable printing "local package ... not found" in release mode +- [#3273](https://github.com/wasmerio/wasmer/pull/3273) Undo Makefile commit + +## Fixed + +- [#3299](https://github.com/wasmerio/wasmer/pull/3299) Fix "create-exe" for windows-x86_64 target +- [#3294](https://github.com/wasmerio/wasmer/pull/3294) Fix test sys yaml syntax +- [#3287](https://github.com/wasmerio/wasmer/pull/3287) Fix Makefile with TARGET_DIR end with release folder, removing it +- [#3286](https://github.com/wasmerio/wasmer/pull/3286) Fix Makefile with TARGET_DIR end with release folder +- [#3285](https://github.com/wasmerio/wasmer/pull/3285) Fix CI to setup TARGET_DIR to target/release directly +- [#3277](https://github.com/wasmerio/wasmer/pull/3277) Fix red CI on master + +## 3.0.0-rc.2 - 2022/11/02 + +## Fixed +- [#3268](https://github.com/wasmerio/wasmer/pulls/3268) Fix fd_right nightly test to avoid foo.txt file leftover +- [#3260](https://github.com/wasmerio/wasmer/pulls/3260) Fix bug in wasmer run +- [#3257](https://github.com/wasmerio/wasmer/pulls/3257) Fix linux-aarch64 build + +## 3.0.0-rc.1 - 2022/10/25 + +## Added + +- [#3215](https://github.com/wasmerio/wasmer/pull/3215) Update wasmer --version logic, integrate wapm-cli +- [#3218](https://github.com/wasmerio/wasmer/pull/3218) Seal `HostFunctionKind` +- [#3222](https://github.com/wasmerio/wasmer/pull/3222) Add function to retrieve function name from wasm_frame_t + +## Changed + +- [#3248](https://github.com/wasmerio/wasmer/pull/3248) Move loupe CHANGELOG entry from 2.3.0 to 3.x +- [#3230](https://github.com/wasmerio/wasmer/pull/3230) Remove test if dest file exist on path_rename wasi syscall (for #3228) +- [#3223](https://github.com/wasmerio/wasmer/pull/3223) Delete lib/wasi-types-generated directory + +## Fixed + +- [#3145](https://github.com/wasmerio/wasmer/pull/3145) C-API: add functions to overwrite stdin / stdout / stderr handlers +- [#3240](https://github.com/wasmerio/wasmer/pull/3240) Fix filesystem rights on WASI, add integration test for file permissions +- [#3238](https://github.com/wasmerio/wasmer/pull/3238) Fixed main README ocaml homepage link and added ocaml in other language README +- [#3229](https://github.com/wasmerio/wasmer/pull/3229) Fixed version to nightly-2022-10-09 for the CI build Minimal Wasmer Headless again +- [#3227](https://github.com/wasmerio/wasmer/pull/3227) Fixed version to nightly-2022-10-09 for the CI build Minimal Wasmer Headless +- [#3226](https://github.com/wasmerio/wasmer/pull/3226) Fixed version to nightly-2002-10-09 for the CI build Minimal Wasmer Headless +- [#3221](https://github.com/wasmerio/wasmer/pull/3221) Fix #3197 +- [#3211](https://github.com/wasmerio/wasmer/pull/3211) Fix popcnt for aarch64 +- [#3204](https://github.com/wasmerio/wasmer/pull/3204) Fixed a typo in README +- [#3199](https://github.com/wasmerio/wasmer/pull/3199) Release fixes + +## 3.0.0-beta.2 - 2022/09/26 + +## Added + +- [#3176](https://github.com/wasmerio/wasmer/pull/3176) Add support for `cargo-binstall` +- [#3117](https://github.com/wasmerio/wasmer/pull/3117) Add tests for wasmer-cli create-{exe,obj} commands +- [#3116](https://github.com/wasmerio/wasmer/pull/3116) Multithreading, full networking and RPC for WebAssembly +- [#3101](https://github.com/wasmerio/wasmer/pull/3101) CI/build.yaml: add libwasmer headless in default distribution +- [#3090](https://github.com/wasmerio/wasmer/pull/3090) Added version to the wasmer cli +- [#3089](https://github.com/wasmerio/wasmer/pull/3089) Add wasi_* C-API function changes in migration guide for 3.0.0 + +## Changed + +- [#3165](https://github.com/wasmerio/wasmer/pull/3165) Initial port of make test-js-core (port wasmer API to core) +- [#3164](https://github.com/wasmerio/wasmer/pull/3164) Synchronize between -sys and -js tests +- [#3142](https://github.com/wasmerio/wasmer/pull/3142) Bump rust toolchain +- [#3141](https://github.com/wasmerio/wasmer/pull/3141) The API breaking changes from future WASIX/Network/Threading addition +- [#3138](https://github.com/wasmerio/wasmer/pull/3138) Js imports revamp +- [#3134](https://github.com/wasmerio/wasmer/pull/3134) Bring libwasmer-headless.a from 22MiB to 7.2MiB (on my machine) +- [#3132](https://github.com/wasmerio/wasmer/pull/3132) Revert "Lower libwasmer headless size" +- [#3131](https://github.com/wasmerio/wasmer/pull/3131) Update for migration-to-3.0.0 for MemoryView changes +- [#3130](https://github.com/wasmerio/wasmer/pull/3130) Remove panics from Artifact::deserialize +- [#3128](https://github.com/wasmerio/wasmer/pull/3128) scripts/publish.py: validate crates version before publishing +- [#3126](https://github.com/wasmerio/wasmer/pull/3126) scripts/publish.py: replace toposort dependency with python std graphlib module +- [#3123](https://github.com/wasmerio/wasmer/pull/3123) Lower libwasmer headless size +- [#3122](https://github.com/wasmerio/wasmer/pull/3122) Update Cargo.lock dependencies +- [#3119](https://github.com/wasmerio/wasmer/pull/3119) Added LinearMemory trait +- [#3118](https://github.com/wasmerio/wasmer/pull/3118) Refactor Artifact enum into a struct +- [#3114](https://github.com/wasmerio/wasmer/pull/3114) Implemented shared memory for Wasmer in preparation for multithreading +- [#3104](https://github.com/wasmerio/wasmer/pull/3104) Re-enabled ExternRef tests +- [#3103](https://github.com/wasmerio/wasmer/pull/3103) create-exe: prefer libwasmer headless when cross-compiling +- [#3097](https://github.com/wasmerio/wasmer/pull/3097) MemoryView lifetime tied to memory and not StoreRef +- [#3096](https://github.com/wasmerio/wasmer/pull/3096) create-exe: use cached wasmer tarballs for network fetches +- [#3095](https://github.com/wasmerio/wasmer/pull/3095) create-exe: list supported cross-compilation target triples in help … +- [#3083](https://github.com/wasmerio/wasmer/pull/3083) Disable wasm build in build CI + +## Fixed + +- [#3185](https://github.com/wasmerio/wasmer/pull/3185) Fix `wasmer compile` command for non-x86 target +- [#3184](https://github.com/wasmerio/wasmer/pull/3184) Fix windows build +- [#3137](https://github.com/wasmerio/wasmer/pull/3137) Fix cache path not being present during installation of cross-tarball +- [#3129](https://github.com/wasmerio/wasmer/pull/3129) Fix differences between -sys and -js API +- [#3115](https://github.com/wasmerio/wasmer/pull/3115) Fix static object signature deserialization +- [#3093](https://github.com/wasmerio/wasmer/pull/3093) Fixed a potential issue when renaming a file +- [#3088](https://github.com/wasmerio/wasmer/pull/3088) Fixed an issue when renaming a file from a preopened dir directly (for 3084) + +## 3.0.0-beta - 2022/08/08 + +### Added +- [#3076](https://github.com/wasmerio/wasmer/pull/3076) Add support for cross-compiling in create-exe with zig cc + +### Changed +- [#3079](https://github.com/wasmerio/wasmer/pull/3079) Migrate CLI tools to `clap` from `structopt` +- [#3048](https://github.com/wasmerio/wasmer/pull/3048) Automatically publish wasmer as "cloudcompiler" package to wapm.dev on every release +- [#3075](https://github.com/wasmerio/wasmer/pull/3075) Remove __wbindgen_thread_id +- [#3072](https://github.com/wasmerio/wasmer/pull/3072) Add back `Function::*_with_env(…)` functions + +### Fixed + +## 3.0.0-alpha.4 - 2022/07/28 + +### Added +- [#3035](https://github.com/wasmerio/wasmer/pull/3035) Added a simple "divide by zero" wast test, for #1899, as the trap information are correctly tracked on singlepass now +- [#3021](https://github.com/wasmerio/wasmer/pull/3021) Add back missing Aarch64 relocations (needed for llvm compiler) +- [#3008](https://github.com/wasmerio/wasmer/pull/3008) Add a new cargo public-api CI check +- [#2941](https://github.com/wasmerio/wasmer/pull/2941) Implementation of WASIX and a fully networking for Web Assembly +- [#2952](https://github.com/wasmerio/wasmer/pull/2952) CI: add make build-wasmer-wasm test +- [#2982](https://github.com/wasmerio/wasmer/pull/2982) Add a rustfmt.toml file to the repository + +### Changed +- [#3047](https://github.com/wasmerio/wasmer/pull/3047) `Store::new` now takes an `impl Into`. +- [#3046](https://github.com/wasmerio/wasmer/pull/3046) Merge Backend into EngineBuilder and refactor feature flags +- [#3039](https://github.com/wasmerio/wasmer/pull/3039) Improved hashing/ids of function envs +- [#3031](https://github.com/wasmerio/wasmer/pull/3031) Update docs/migration_to_3.0.0.md +- [#3030](https://github.com/wasmerio/wasmer/pull/3030) Remove cranelift dependency from wasmer-wasi +- [#3029](https://github.com/wasmerio/wasmer/pull/3029) Removed Artifact, Engine traits. Renamed UniversalArtifact to Artifact, and UniversalEngine to Engine. +- [#3028](https://github.com/wasmerio/wasmer/pull/3028) Rename old variable names from ctx to env (in case of FunctionEnv usage) and from ctx to store in case of store usage +- [#3023](https://github.com/wasmerio/wasmer/pull/3023) Changed CI "rust install" action to dtolnay one +- [#3013](https://github.com/wasmerio/wasmer/pull/3013) Refactor Context API +- [#3003](https://github.com/wasmerio/wasmer/pull/3003) Remove RuntimeError::raise from public API +- [#3000](https://github.com/wasmerio/wasmer/pull/3001) Allow debugging of EXC_BAD_INSTRUCTION on macOS +- [#2999](https://github.com/wasmerio/wasmer/pull/2999) Allow `--invoke` CLI option for Emscripten files without a `main` function +- [#2996](https://github.com/wasmerio/wasmer/pull/2996) Migrated all examples to new Context API +- [#2946](https://github.com/wasmerio/wasmer/pull/2946) Remove dylib,staticlib engines in favor of a single Universal engine +- [#2949](https://github.com/wasmerio/wasmer/pull/2949) Switch back to using custom LLVM builds on CI +- [#2892](https://github.com/wasmerio/wasmer/pull/2892) Renamed `get_native_function` to `get_typed_function`, marked former as deprecated. +- [#2976](https://github.com/wasmerio/wasmer/pull/2976) Upgrade enumset minimum version to one that compiles +- [#2974](https://github.com/wasmerio/wasmer/pull/2974) Context api tests +- [#2973](https://github.com/wasmerio/wasmer/pull/2973) Port C API to new Context API +- [#2969](https://github.com/wasmerio/wasmer/pull/2969) Port JS API to new Context API +- [#2966](https://github.com/wasmerio/wasmer/pull/2966) Singlepass nopanic #2966 +- [#2957](https://github.com/wasmerio/wasmer/pull/2957) Enable multi-value handling in Singlepass compiler +- [#2954](https://github.com/wasmerio/wasmer/pull/2954) Some fixes to x86_64 Singlepass compiler, when using atomics +- [#2953](https://github.com/wasmerio/wasmer/pull/2953) Makefile: add check target +- [#2950](https://github.com/wasmerio/wasmer/pull/2950) compiler-cranelift: Fix typo in enum variant +- [#2947](https://github.com/wasmerio/wasmer/pull/2947) Converted the WASI js test into a generic stdio test that works for both sys and js versions of wasmer +- [#2940](https://github.com/wasmerio/wasmer/pull/2940) Merge wasmer3 back to master branch +- [#2939](https://github.com/wasmerio/wasmer/pull/2939) Rename NativeFunc to TypedFunction +- [#2868](https://github.com/wasmerio/wasmer/pull/2868) Removed loupe crate dependency + +### Fixed +- [#3045](https://github.com/wasmerio/wasmer/pull/3045) Fixed WASI fd_read syscall when reading multiple iovs and read is partial (for #2904) +- [#3027](https://github.com/wasmerio/wasmer/pull/3027) Fixed some residual doc issues that prevented make package-docs to build +- [#3026](https://github.com/wasmerio/wasmer/pull/3026) test-js.yaml: fix typo +- [#3017](https://github.com/wasmerio/wasmer/pull/3017) Fix typo in README.md +- [#3001](https://github.com/wasmerio/wasmer/pull/3001) Fix context capi ci errors +- [#2997](https://github.com/wasmerio/wasmer/pull/2997) Fix "run --invoke [function]" to behave the same as "run" +- [#2963](https://github.com/wasmerio/wasmer/pull/2963) Remove accidental dependency on libwayland and libxcb in ClI +- [#2942](https://github.com/wasmerio/wasmer/pull/2942) Fix clippy lints. +- [#2943](https://github.com/wasmerio/wasmer/pull/2943) Fix build error on some archs by using c_char instead of i8 +- [#2976](https://github.com/wasmerio/wasmer/pull/2976) Upgrade minimum enumset to one that compiles +- [#2988](https://github.com/wasmerio/wasmer/pull/2988) Have make targets install-capi-lib,install-pkgconfig work without building the wasmer binary +- [#2967](https://github.com/wasmerio/wasmer/pull/2967) Fix singlepass on arm64 that was trying to emit a sub opcode with a constant as destination (for #2959) +- [#2948](https://github.com/wasmerio/wasmer/pull/2948) Fix regression on gen_import_call_trampoline_arm64() +- [#2944](https://github.com/wasmerio/wasmer/pull/2944) Fix duplicate entries in the CHANGELOG + +## 2.3.0 - 2022/06/06 + +### Added +- [#2862](https://github.com/wasmerio/wasmer/pull/2862) Added CI builds for linux-aarch64 target. +- [#2811](https://github.com/wasmerio/wasmer/pull/2811) Added support for EH Frames in singlepass +- [#2851](https://github.com/wasmerio/wasmer/pull/2851) Allow Wasmer to compile to Wasm/WASI + +### Changed +- [#2807](https://github.com/wasmerio/wasmer/pull/2807) Run Wasm code in a separate stack +- [#2802](https://github.com/wasmerio/wasmer/pull/2802) Support Dylib engine with Singlepass +- [#2836](https://github.com/wasmerio/wasmer/pull/2836) Improve TrapInformation data stored at runtime +- [#2864](https://github.com/wasmerio/wasmer/pull/2864) `wasmer-cli`: remove wasi-experimental-io-devices from default builds +- [#2933](https://github.com/wasmerio/wasmer/pull/2933) Rename NativeFunc to TypedFunction. + +### Fixed +- [#2829](https://github.com/wasmerio/wasmer/pull/2829) Improve error message oriented from JS object. +- [#2828](https://github.com/wasmerio/wasmer/pull/2828) Fix JsImportObject resolver. +- [#2872](https://github.com/wasmerio/wasmer/pull/2872) Fix `WasmerEnv` finalizer +- [#2821](https://github.com/wasmerio/wasmer/pull/2821) Opt in `sys` feature + +## 2.2.1 - 2022/03/15 + +### Fixed +- [#2812](https://github.com/wasmerio/wasmer/pull/2812) Fixed another panic due to incorrect drop ordering. + +## 2.2.0 - 2022/02/28 + +### Added +- [#2775](https://github.com/wasmerio/wasmer/pull/2775) Added support for SSE 4.2 in the Singlepass compiler as an alternative to AVX. +- [#2805](https://github.com/wasmerio/wasmer/pull/2805) Enabled WASI experimental I/O devices by default in releases. + +### Fixed +- [#2795](https://github.com/wasmerio/wasmer/pull/2795) Fixed a bug in the Singlepass compiler introduced in #2775. +- [#2806](https://github.com/wasmerio/wasmer/pull/2806) Fixed a panic due to incorrect drop ordering of `Module` fields. + +## 2.2.0-rc2 - 2022/02/15 + +### Fixed +- [#2778](https://github.com/wasmerio/wasmer/pull/2778) Fixed f32_load/f64_load in Singlepass. Also fixed issues with out-of-range conditional branches. +- [#2786](https://github.com/wasmerio/wasmer/pull/2786) Fixed a potential integer overflow in WasmPtr memory access methods. +- [#2787](https://github.com/wasmerio/wasmer/pull/2787) Fixed a codegen regression in the Singlepass compiler due to non-determinism of `HashSet` iteration. + +## 2.2.0-rc1 - 2022/01/28 + +### Added +- [#2750](https://github.com/wasmerio/wasmer/pull/2750) Added Aarch64 support to Singlepass (both Linux and macOS). +- [#2753](https://github.com/wasmerio/wasmer/pull/2753) Re-add "dylib" to the list of default features. + +### Changed +- [#2747](https://github.com/wasmerio/wasmer/pull/2747) Use a standard header for metadata in all serialized modules. +- [#2759](https://github.com/wasmerio/wasmer/pull/2759) Use exact version for Wasmer crate dependencies. + +### Fixed +- [#2769](https://github.com/wasmerio/wasmer/pull/2769) Fixed deadlock in emscripten dynamic calls. +- [#2742](https://github.com/wasmerio/wasmer/pull/2742) Fixed WASMER_METADATA alignment in the dylib engine. +- [#2746](https://github.com/wasmerio/wasmer/pull/2746) Fixed invoking `wasmer binfmt register` from `$PATH`. +- [#2748](https://github.com/wasmerio/wasmer/pull/2748) Use trampolines for all libcalls in engine-universal and engine-dylib. +- [#2766](https://github.com/wasmerio/wasmer/pull/2766) Remove an attempt to reserve a GPR when no GPR clobbering is occurring. +- [#2768](https://github.com/wasmerio/wasmer/pull/2768) Fixed serialization of FrameInfo on Dylib engine. + +## 2.1.1 - 2021/12/20 + +### Added +- [#2726](https://github.com/wasmerio/wasmer/pull/2726) Added `externs_vec` method to `ImportObject`. +- [#2724](https://github.com/wasmerio/wasmer/pull/2724) Added access to the raw `Instance` JS object in Wsasmer-js. + +### CHanged +- [#2711](https://github.com/wasmerio/wasmer/pull/2711) Make C-API and Wasi dependencies more lean +- [#2706](https://github.com/wasmerio/wasmer/pull/2706) Refactored the Singlepass compiler in preparation for AArch64 support (no user visible changes). +### Fixed +- [#2717](https://github.com/wasmerio/wasmer/pull/2717) Allow `Exports` to be modified after being cloned. +- [#2719](https://github.com/wasmerio/wasmer/pull/2719) Fixed `wasm_importtype_new`'s Rust signature to not assume boxed vectors. +- [#2723](https://github.com/wasmerio/wasmer/pull/2723) Fixed a bug in parameter passing in the Singlepass compiler. +- [#2768](https://github.com/wasmerio/wasmer/pull/2768) Fixed issue with Frame Info on dylib engine. + +## 2.1.0 - 2021/11/30 + +### Added +- [#2574](https://github.com/wasmerio/wasmer/pull/2574) Added Windows support to Singlepass. +- [#2535](https://github.com/wasmerio/wasmer/pull/2435) Added iOS support for Wasmer. This relies on the `dylib-engine`. +- [#2460](https://github.com/wasmerio/wasmer/pull/2460) Wasmer can now compile to Javascript via `wasm-bindgen`. Use the `js-default` (and no default features) feature to try it!. +- [#2491](https://github.com/wasmerio/wasmer/pull/2491) Added support for WASI to Wasmer-js. +- [#2436](https://github.com/wasmerio/wasmer/pull/2436) Added the x86-32 bit variant support to LLVM compiler. +- [#2499](https://github.com/wasmerio/wasmer/pull/2499) Added a subcommand to linux wasmer-cli to register wasmer with binfmt_misc +- [#2511](https://github.com/wasmerio/wasmer/pull/2511) Added support for calling dynamic functions defined on the host +- [#2491](https://github.com/wasmerio/wasmer/pull/2491) Added support for WASI in Wasmer-js +- [#2592](https://github.com/wasmerio/wasmer/pull/2592) Added `ImportObject::get_namespace_exports` to allow modifying the contents of an existing namespace in an `ImportObject`. +- [#2694](https://github.com/wasmerio/wasmer/pull/2694) wasmer-js: Allow an `ImportObject` to be extended with a JS object. +- [#2698](https://github.com/wasmerio/wasmer/pull/2698) Provide WASI imports when invoking an explicit export from the CLI. +- [#2701](https://github.com/wasmerio/wasmer/pull/2701) Improved VFS API for usage from JS + +### Changed +- [#2460](https://github.com/wasmerio/wasmer/pull/2460) **breaking change** `wasmer` API usage with `no-default-features` requires now the `sys` feature to preserve old behavior. +- [#2476](https://github.com/wasmerio/wasmer/pull/2476) Removed unncessary abstraction `ModuleInfoTranslate` from `wasmer-compiler`. +- [#2442](https://github.com/wasmerio/wasmer/pull/2442) **breaking change** Improved `WasmPtr`, added `WasmCell` for host/guest interaction. `WasmPtr::deref` will now return `WasmCell<'a, T>` instead of `&'a Cell`, `WasmPtr::deref_mut` is now deleted from the API. +- [#2427](https://github.com/wasmerio/wasmer/pull/2427) Update `loupe` to 0.1.3. +- [#2685](https://github.com/wasmerio/wasmer/pull/2685) The minimum LLVM version for the LLVM compiler is now 12. LLVM 13 is used by default. +- [#2569](https://github.com/wasmerio/wasmer/pull/2569) Add `Send` and `Sync` to uses of the `LikeNamespace` trait object. +- [#2692](https://github.com/wasmerio/wasmer/pull/2692) Made module serialization deterministic. +- [#2693](https://github.com/wasmerio/wasmer/pull/2693) Validate CPU features when loading a deserialized module. + +### Fixed +- [#2599](https://github.com/wasmerio/wasmer/pull/2599) Fixed Universal engine for Linux/Aarch64 target. +- [#2587](https://github.com/wasmerio/wasmer/pull/2587) Fixed deriving `WasmerEnv` when aliasing `Result`. +- [#2518](https://github.com/wasmerio/wasmer/pull/2518) Remove temporary file used to creating an artifact when creating a Dylib engine artifact. +- [#2494](https://github.com/wasmerio/wasmer/pull/2494) Fixed `WasmerEnv` access when using `call_indirect` with the Singlepass compiler. +- [#2479](https://github.com/wasmerio/wasmer/pull/2479) Improved `wasmer validate` error message on non-wasm inputs. +- [#2454](https://github.com/wasmerio/wasmer/issues/2454) Won't set `WASMER_CACHE_DIR` for Windows. +- [#2426](https://github.com/wasmerio/wasmer/pull/2426) Fix the `wax` script generation. +- [#2635](https://github.com/wasmerio/wasmer/pull/2635) Fix cross-compilation for singlepass. +- [#2672](https://github.com/wasmerio/wasmer/pull/2672) Use `ENOENT` instead of `EINVAL` in some WASI syscalls for a non-existent file +- [#2547](https://github.com/wasmerio/wasmer/pull/2547) Delete temporary files created by the dylib engine. +- [#2548](https://github.com/wasmerio/wasmer/pull/2548) Fix stack probing on x86_64 linux with the cranelift compiler. +- [#2557](https://github.com/wasmerio/wasmer/pull/2557) [#2559](https://github.com/wasmerio/wasmer/pull/2559) Fix WASI dir path renaming. +- [#2560](https://github.com/wasmerio/wasmer/pull/2560) Fix signal handling on M1 MacOS. +- [#2474](https://github.com/wasmerio/wasmer/pull/2474) Fix permissions on `WASMER_CACHE_DIR` on Windows. +- [#2528](https://github.com/wasmerio/wasmer/pull/2528) [#2525](https://github.com/wasmerio/wasmer/pull/2525) [#2523](https://github.com/wasmerio/wasmer/pull/2523) [#2522](https://github.com/wasmerio/wasmer/pull/2522) [#2545](https://github.com/wasmerio/wasmer/pull/2545) [#2550](https://github.com/wasmerio/wasmer/pull/2550) [#2551](https://github.com/wasmerio/wasmer/pull/2551) Fix various bugs in the new VFS implementation. +- [#2552](https://github.com/wasmerio/wasmer/pull/2552) Fix stack guard handling on Windows. +- [#2585](https://github.com/wasmerio/wasmer/pull/2585) Fix build with 64-bit MinGW toolchain. +- [#2587](https://github.com/wasmerio/wasmer/pull/2587) Fix absolute import of `Result` in derive. +- [#2599](https://github.com/wasmerio/wasmer/pull/2599) Fix AArch64 support in the LLVM compiler. +- [#2655](https://github.com/wasmerio/wasmer/pull/2655) Fix argument parsing of `--dir` and `--mapdir`. +- [#2666](https://github.com/wasmerio/wasmer/pull/2666) Fix performance on Windows by using static memories by default. +- [#2667](https://github.com/wasmerio/wasmer/pull/2667) Fix error code for path_rename of a non-existant file +- [#2672](https://github.com/wasmerio/wasmer/pull/2672) Fix error code returned by some wasi fs syscalls for a non-existent file +- [#2673](https://github.com/wasmerio/wasmer/pull/2673) Fix BrTable codegen on the LLVM compiler +- [#2674](https://github.com/wasmerio/wasmer/pull/2674) Add missing `__WASI_RIGHT_FD_DATASYNC` for preopened directories +- [#2677](https://github.com/wasmerio/wasmer/pull/2677) Support 32-bit memories with 65536 pages +- [#2681](https://github.com/wasmerio/wasmer/pull/2681) Fix slow compilation in singlepass by using dynasm's `VecAssembler`. +- [#2690](https://github.com/wasmerio/wasmer/pull/2690) Fix memory leak when obtaining the stack bounds of a thread +- [#2699](https://github.com/wasmerio/wasmer/pull/2699) Partially fix unbounded memory leak from the FuncDataRegistry + +## 2.0.0 - 2021/06/16 + +### Added +- [#2411](https://github.com/wasmerio/wasmer/pull/2411) Extract types from `wasi` to a new `wasi-types` crate. +- [#2390](https://github.com/wasmerio/wasmer/pull/2390) Make `wasmer-vm` to compile on Windows 32bits. +- [#2402](https://github.com/wasmerio/wasmer/pull/2402) Add more examples and more doctests for `wasmer-middlewares`. + +### Changed +- [#2399](https://github.com/wasmerio/wasmer/pull/2399) Add the Dart integration in the `README.md`. + +### Fixed +- [#2386](https://github.com/wasmerio/wasmer/pull/2386) Handle properly when a module has no exported functions in the CLI. + +## 2.0.0-rc2 - 2021/06/03 + +### Fixed +- [#2383](https://github.com/wasmerio/wasmer/pull/2383) Fix bugs in the Wasmer CLI tool with the way `--version` and the name of the CLI tool itself were printed. + +## 2.0.0-rc1 - 2021/06/02 + +### Added +- [#2348](https://github.com/wasmerio/wasmer/pull/2348) Make Wasmer available on `aarch64-linux-android`. +- [#2315](https://github.com/wasmerio/wasmer/pull/2315) Make the Cranelift compiler working with the Native engine. +- [#2306](https://github.com/wasmerio/wasmer/pull/2306) Add support for the latest version of the Wasm SIMD proposal to compiler LLVM. +- [#2296](https://github.com/wasmerio/wasmer/pull/2296) Add support for the bulk memory proposal in compiler Singlepass and compiler LLVM. +- [#2291](https://github.com/wasmerio/wasmer/pull/2291) Type check tables when importing. +- [#2262](https://github.com/wasmerio/wasmer/pull/2262) Make parallelism optional for the Singlepass compiler. +- [#2249](https://github.com/wasmerio/wasmer/pull/2249) Make Cranelift unwind feature optional. +- [#2208](https://github.com/wasmerio/wasmer/pull/2208) Add a new CHANGELOG.md specific to our C API to make it easier for users primarily consuming our C API to keep up to date with changes that affect them. +- [#2154](https://github.com/wasmerio/wasmer/pull/2154) Implement Reference Types in the LLVM compiler. +- [#2003](https://github.com/wasmerio/wasmer/pull/2003) Wasmer works with musl, and is built, tested and packaged for musl. +- [#2250](https://github.com/wasmerio/wasmer/pull/2250) Use `rkyv` for the JIT/Universal engine. +- [#2190](https://github.com/wasmerio/wasmer/pull/2190) Use `rkyv` to read native `Module` artifact. +- [#2186](https://github.com/wasmerio/wasmer/pull/2186) Update and improve the Fuzz Testing infrastructure. +- [#2161](https://github.com/wasmerio/wasmer/pull/2161) Make NaN canonicalization configurable. +- [#2116](https://github.com/wasmerio/wasmer/pull/2116) Add a package for Windows that is not an installer, but all the `lib` and `include` files as for macOS and Linux. +- [#2123](https://github.com/wasmerio/wasmer/pull/2123) Use `ENABLE_{{compiler_name}}=(0|1)` to resp. force to disable or enable a compiler when running the `Makefile`, e.g. `ENABLE_LLVM=1 make build-wasmer`. +- [#2123](https://github.com/wasmerio/wasmer/pull/2123) `libwasmer` comes with all available compilers per target instead of Cranelift only. +- [#2135](https://github.com/wasmerio/wasmer/pull/2135) [Documentation](./PACKAGING.md) for Linux distribution maintainers +- [#2104](https://github.com/wasmerio/wasmer/pull/2104) Update WAsm core spectests and wasmparser. + +### Changed +- [#2369](https://github.com/wasmerio/wasmer/pull/2369) Remove the deprecated `--backend` option in the CLI. +- [#2368](https://github.com/wasmerio/wasmer/pull/2368) Remove the deprecated code in the `wasmer-wasi` crate. +- [#2367](https://github.com/wasmerio/wasmer/pull/2367) Remove the `deprecated` features and associated code in the `wasmer` crate. +- [#2366](https://github.com/wasmerio/wasmer/pull/2366) Remove the deprecated crates. +- [#2364](https://github.com/wasmerio/wasmer/pull/2364) Rename `wasmer-engine-object-file` to `wasmer-engine-staticlib`. +- [#2356](https://github.com/wasmerio/wasmer/pull/2356) Rename `wasmer-engine-native` to `wasmer-engine-dylib`. +- [#2340](https://github.com/wasmerio/wasmer/pull/2340) Rename `wasmer-engine-jit` to `wasmer-engine-universal`. +- [#2307](https://github.com/wasmerio/wasmer/pull/2307) Update Cranelift, implement low hanging fruit SIMD opcodes. +- [#2305](https://github.com/wasmerio/wasmer/pull/2305) Clean up and improve the trap API, more deterministic errors etc. +- [#2299](https://github.com/wasmerio/wasmer/pull/2299) Unused trap codes (due to Wasm spec changes), `HeapSetterOutOfBounds` and `TableSetterOutOfBounds` were removed from `wasmer_vm::TrapCode` and the numbering of the remaining variants has been adjusted. +- [#2293](https://github.com/wasmerio/wasmer/pull/2293) The `Memory::ty` trait method now returns `MemoryType` by value. `wasmer_vm::LinearMemory` now recomputes `MemoryType`'s `minimum` field when accessing its type. This behavior is what's expected by the latest spectests. `wasmer::Memory::ty` has also been updated to follow suit, it now returns `MemoryType` by value. +- [#2286](https://github.com/wasmerio/wasmer/pull/2286) Replace the `goblin` crate by the `object` crate. +- [#2281](https://github.com/wasmerio/wasmer/pull/2281) Refactor the `wasmer_vm` crate to remove unnecessary structs, reuse data when available etc. +- [#2251](https://github.com/wasmerio/wasmer/pull/2251) Wasmer CLI will now execute WASI modules with multiple WASI namespaces in them by default. Use `--allow-multiple-wasi-versions` to suppress the warning and use `--deny-multiple-wasi-versions` to make it an error. +- [#2201](https://github.com/wasmerio/wasmer/pull/2201) Implement `loupe::MemoryUsage` for `wasmer::Instance`. +- [#2200](https://github.com/wasmerio/wasmer/pull/2200) Implement `loupe::MemoryUsage` for `wasmer::Module`. +- [#2199](https://github.com/wasmerio/wasmer/pull/2199) Implement `loupe::MemoryUsage` for `wasmer::Store`. +- [#2195](https://github.com/wasmerio/wasmer/pull/2195) Remove dependency to `cranelift-entity`. +- [#2140](https://github.com/wasmerio/wasmer/pull/2140) Reduce the number of dependencies in the `wasmer.dll` shared library by statically compiling CRT. +- [#2113](https://github.com/wasmerio/wasmer/pull/2113) Bump minimum supported Rust version to 1.49 +- [#2144](https://github.com/wasmerio/wasmer/pull/2144) Bump cranelift version to 0.70 +- [#2149](https://github.com/wasmerio/wasmer/pull/2144) `wasmer-engine-native` looks for clang-11 instead of clang-10. +- [#2157](https://github.com/wasmerio/wasmer/pull/2157) Simplify the code behind `WasmPtr` + +### Fixed +- [#2397](https://github.com/wasmerio/wasmer/pull/2397) Fix WASI rename temporary file issue. +- [#2391](https://github.com/wasmerio/wasmer/pull/2391) Fix Singlepass emit bug, [#2347](https://github.com/wasmerio/wasmer/issues/2347) and [#2159](https://github.com/wasmerio/wasmer/issues/2159) +- [#2327](https://github.com/wasmerio/wasmer/pull/2327) Fix memory leak preventing internal instance memory from being freed when a WasmerEnv contained an exported extern (e.g. Memory, etc.). +- [#2247](https://github.com/wasmerio/wasmer/pull/2247) Internal WasiFS logic updated to be closer to what WASI libc does when finding a preopened fd for a path. +- [#2241](https://github.com/wasmerio/wasmer/pull/2241) Fix Undefined Behavior in setting memory in emscripten `EmEnv`. +- [#2224](https://github.com/wasmerio/wasmer/pull/2224) Enable SIMD based on actual Wasm features in the Cranelift compiler. +- [#2217](https://github.com/wasmerio/wasmer/pull/2217) Fix bug in `i64.rotr X 0` in the LLVM compiler. +- [#2290](https://github.com/wasmerio/wasmer/pull/2290) Handle Wasm modules with no imports in the CLI. +- [#2108](https://github.com/wasmerio/wasmer/pull/2108) The Object Native Engine generates code that now compiles correctly with C++. +- [#2125](https://github.com/wasmerio/wasmer/pull/2125) Fix RUSTSEC-2021-0023. +- [#2155](https://github.com/wasmerio/wasmer/pull/2155) Fix the implementation of shift and rotate in the LLVM compiler. +- [#2101](https://github.com/wasmerio/wasmer/pull/2101) cflags emitted by `wasmer config --pkg-config` are now correct. + +## 1.0.2 - 2021-02-04 + +### Added +- [#2053](https://github.com/wasmerio/wasmer/pull/2053) Implement the non-standard `wasi_get_unordered_imports` function in the C API. +- [#2072](https://github.com/wasmerio/wasmer/pull/2072) Add `wasm_config_set_target`, along with `wasm_target_t`, `wasm_triple_t` and `wasm_cpu_features_t` in the unstable C API. +- [#2059](https://github.com/wasmerio/wasmer/pull/2059) Ability to capture `stdout` and `stderr` with WASI in the C API. +- [#2040](https://github.com/wasmerio/wasmer/pull/2040) Add `InstanceHandle::vmoffsets` to expose the offsets of the `vmctx` region. +- [#2026](https://github.com/wasmerio/wasmer/pull/2026) Expose trap code of a `RuntimeError`, if it's a `Trap`. +- [#2054](https://github.com/wasmerio/wasmer/pull/2054) Add `wasm_config_delete` to the Wasm C API. +- [#2072](https://github.com/wasmerio/wasmer/pull/2072) Added cross-compilation to Wasm C API. + +### Changed +- [#2085](https://github.com/wasmerio/wasmer/pull/2085) Update to latest inkwell and LLVM 11. +- [#2037](https://github.com/wasmerio/wasmer/pull/2037) Improved parallelism of LLVM with the Native/Object engine +- [#2012](https://github.com/wasmerio/wasmer/pull/2012) Refactor Singlepass init stack assembly (more performant now) +- [#2036](https://github.com/wasmerio/wasmer/pull/2036) Optimize memory allocated for Function type definitions +- [#2083](https://github.com/wasmerio/wasmer/pull/2083) Mark `wasi_env_set_instance` and `wasi_env_set_memory` as deprecated. You may simply remove the calls with no side-effect. +- [#2056](https://github.com/wasmerio/wasmer/pull/2056) Change back to depend on the `enumset` crate instead of `wasmer_enumset` + +### Fixed +- [#2066](https://github.com/wasmerio/wasmer/pull/2066) Include 'extern "C"' in our C headers when included by C++ code. +- [#2090](https://github.com/wasmerio/wasmer/pull/2090) `wasi_env_t` needs to be freed with `wasi_env_delete` in the C API. +- [#2084](https://github.com/wasmerio/wasmer/pull/2084) Avoid calling the function environment finalizer more than once when the environment has been cloned in the C API. +- [#2069](https://github.com/wasmerio/wasmer/pull/2069) Use the new documentation for `include/README.md` in the Wasmer package. +- [#2042](https://github.com/wasmerio/wasmer/pull/2042) Parse more exotic environment variables in `wasmer run`. +- [#2041](https://github.com/wasmerio/wasmer/pull/2041) Documentation diagrams now have a solid white background rather than a transparent background. +- [#2070](https://github.com/wasmerio/wasmer/pull/2070) Do not drain the entire captured stream at first read with `wasi_env_read_stdout` or `_stderr` in the C API. +- [#2058](https://github.com/wasmerio/wasmer/pull/2058) Expose WASI versions to C correctly. +- [#2044](https://github.com/wasmerio/wasmer/pull/2044) Do not build C headers on docs.rs. + +## 1.0.1 - 2021-01-12 + +This release includes a breaking change in the API (changing the trait `enumset::EnumsetType` to `wasmer_enumset::EnumSetType` and changing `enumset::EnumSet` in signatures to `wasmer_enumset::EnumSet` to work around a breaking change introduced by `syn`) but is being released as a minor version because `1.0.0` is also in a broken state due to a breaking change introduced by `syn` which affects `enumset` and thus `wasmer`. + +This change is unlikely to affect any users of `wasmer`, but if it does please change uses of the `enumset` crate to the `wasmer_enumset` crate where possible. + +### Added +- [#2010](https://github.com/wasmerio/wasmer/pull/2010) A new, experimental, minified build of `wasmer` called `wasmer-headless` will now be included with releases. `wasmer-headless` is the `wasmer` VM without any compilers attached, so it can only run precompiled Wasm modules. +- [#2005](https://github.com/wasmerio/wasmer/pull/2005) Added the arguments `alias` and `optional` to `WasmerEnv` derive's `export` attribute. + +### Changed +- [#2006](https://github.com/wasmerio/wasmer/pull/2006) Use `wasmer_enumset`, a fork of the `enumset` crate to work around a breaking change in `syn` +- [#1985](https://github.com/wasmerio/wasmer/pull/1985) Bump minimum supported Rust version to 1.48 + +### Fixed +- [#2007](https://github.com/wasmerio/wasmer/pull/2007) Fix packaging of wapm on Windows +- [#2005](https://github.com/wasmerio/wasmer/pull/2005) Emscripten is now working again. + +## 1.0.0 - 2021-01-05 + +### Added + +- [#1969](https://github.com/wasmerio/wasmer/pull/1969) Added D integration to the README + +### Changed +- [#1979](https://github.com/wasmerio/wasmer/pull/1979) `WasmPtr::get_utf8_string` was renamed to `WasmPtr::get_utf8_str` and made `unsafe`. + +### Fixed +- [#1979](https://github.com/wasmerio/wasmer/pull/1979) `WasmPtr::get_utf8_string` now returns a `String`, fixing a soundness issue in certain circumstances. The old functionality is available under a new `unsafe` function, `WasmPtr::get_utf8_str`. + +## 1.0.0-rc1 - 2020-12-23 + +### Added + +* [#1894](https://github.com/wasmerio/wasmer/pull/1894) Added exports `wasmer::{CraneliftOptLevel, LLVMOptLevel}` to allow using `Cranelift::opt_level` and `LLVM::opt_level` directly via the `wasmer` crate + +### Changed + +* [#1941](https://github.com/wasmerio/wasmer/pull/1941) Turn `get_remaining_points`/`set_remaining_points` of the `Metering` middleware into free functions to allow using them in an ahead-of-time compilation setup +* [#1955](https://github.com/wasmerio/wasmer/pull/1955) Set `jit` as a default feature of the `wasmer-wasm-c-api` crate +* [#1944](https://github.com/wasmerio/wasmer/pull/1944) Require `WasmerEnv` to be `Send + Sync` even in dynamic functions. +* [#1963](https://github.com/wasmerio/wasmer/pull/1963) Removed `to_wasm_error` in favour of `impl From for WasmError` +* [#1962](https://github.com/wasmerio/wasmer/pull/1962) Replace `wasmparser::Result<()>` with `Result<(), MiddlewareError>` in middleware, allowing implementors to return errors in `FunctionMiddleware::feed` + +### Fixed + +- [#1949](https://github.com/wasmerio/wasmer/pull/1949) `wasm__vec_delete` functions no longer crash when the given vector is uninitialized, in the Wasmer C API +- [#1949](https://github.com/wasmerio/wasmer/pull/1949) The `wasm_frame_vec_t`, `wasm_functype_vec_t`, `wasm_globaltype_vec_t`, `wasm_memorytype_vec_t`, and `wasm_tabletype_vec_t` are now boxed vectors in the Wasmer C API + +## 1.0.0-beta2 - 2020-12-16 + +### Added + +* [#1916](https://github.com/wasmerio/wasmer/pull/1916) Add the `WASMER_VERSION*` constants with the `wasmer_version*` functions in the Wasmer C API +* [#1867](https://github.com/wasmerio/wasmer/pull/1867) Added `Metering::get_remaining_points` and `Metering::set_remaining_points` +* [#1881](https://github.com/wasmerio/wasmer/pull/1881) Added `UnsupportedTarget` error to `CompileError` +* [#1908](https://github.com/wasmerio/wasmer/pull/1908) Implemented `TryFrom>` for `i32`/`u32`/`i64`/`u64`/`f32`/`f64` +* [#1927](https://github.com/wasmerio/wasmer/pull/1927) Added mmap support in `Engine::deserialize_from_file` to speed up artifact loading +* [#1911](https://github.com/wasmerio/wasmer/pull/1911) Generalized signature type in `Function::new` and `Function::new_with_env` to accept owned and reference `FunctionType` as well as array pairs. This allows users to define signatures as constants. Implemented `From<([Type; $N], [Type; $M])>` for `FunctionType` to support this. + +### Changed + +- [#1865](https://github.com/wasmerio/wasmer/pull/1865) Require that implementors of `WasmerEnv` also implement `Send`, `Sync`, and `Clone`. +- [#1851](https://github.com/wasmerio/wasmer/pull/1851) Improve test suite and documentation of the Wasmer C API +- [#1874](https://github.com/wasmerio/wasmer/pull/1874) Set `CompilerConfig` to be owned (following wasm-c-api) +- [#1880](https://github.com/wasmerio/wasmer/pull/1880) Remove cmake dependency for tests +- [#1924](https://github.com/wasmerio/wasmer/pull/1924) Rename reference implementation `wasmer::Tunables` to `wasmer::BaseTunables`. Export trait `wasmer_engine::Tunables` as `wasmer::Tunables`. + +### Fixed + +- [#1865](https://github.com/wasmerio/wasmer/pull/1865) Fix memory leaks with host function environments. +- [#1870](https://github.com/wasmerio/wasmer/pull/1870) Fixed Trap instruction address maps in Singlepass +* [#1914](https://github.com/wasmerio/wasmer/pull/1914) Implemented `TryFrom for Pages` instead of `From for Pages` to properly handle overflow errors + +## 1.0.0-beta1 - 2020-12-01 + +### Added + +- [#1839](https://github.com/wasmerio/wasmer/pull/1839) Added support for Metering Middleware +- [#1837](https://github.com/wasmerio/wasmer/pull/1837) It is now possible to use exports of an `Instance` even after the `Instance` has been freed +- [#1831](https://github.com/wasmerio/wasmer/pull/1831) Added support for Apple Silicon chips (`arm64-apple-darwin`) +- [#1739](https://github.com/wasmerio/wasmer/pull/1739) Improved function environment setup via `WasmerEnv` proc macro. +- [#1649](https://github.com/wasmerio/wasmer/pull/1649) Add outline of migration to 1.0.0 docs. + +### Changed + +- [#1739](https://github.com/wasmerio/wasmer/pull/1739) Environments passed to host function- must now implement the `WasmerEnv` trait. You can implement it on your existing type with `#[derive(WasmerEnv)]`. +- [#1838](https://github.com/wasmerio/wasmer/pull/1838) Deprecate `WasiEnv::state_mut`: prefer `WasiEnv::state` instead. +- [#1663](https://github.com/wasmerio/wasmer/pull/1663) Function environments passed to host functions now must be passed by `&` instead of `&mut`. This is a breaking change. This change fixes a race condition when a host function is called from multiple threads. If you need mutability in your environment, consider using `std::sync::Mutex` or other synchronization primitives. +- [#1830](https://github.com/wasmerio/wasmer/pull/1830) Minimum supported Rust version bumped to 1.47.0 +- [#1810](https://github.com/wasmerio/wasmer/pull/1810) Make the `state` field of `WasiEnv` public + +### Fixed + +- [#1857](https://github.com/wasmerio/wasmer/pull/1857) Fix dynamic function with new Environment API +- [#1855](https://github.com/wasmerio/wasmer/pull/1855) Fix memory leak when using `wat2wasm` in the C API, the function now takes its output parameter by pointer rather than returning an allocated `wasm_byte_vec_t`. +- [#1841](https://github.com/wasmerio/wasmer/pull/1841) We will now panic when attempting to use a native function with a captured env as a host function. Previously this would silently do the wrong thing. See [#1840](https://github.com/wasmerio/wasmer/pull/1840) for info about Wasmer's support of closures as host functions. +- [#1764](https://github.com/wasmerio/wasmer/pull/1764) Fix bug in WASI `path_rename` allowing renamed files to be 1 directory below a preopened directory. + +## 1.0.0-alpha5 - 2020-11-06 + +### Added + +- [#1761](https://github.com/wasmerio/wasmer/pull/1761) Implement the `wasm_trap_t**` argument of `wasm_instance_new` in the Wasm C API. +- [#1687](https://github.com/wasmerio/wasmer/pull/1687) Add basic table example; fix ownership of local memory and local table metadata in the VM. +- [#1751](https://github.com/wasmerio/wasmer/pull/1751) Implement `wasm_trap_t` inside a function declared with `wasm_func_new_with_env` in the Wasm C API. +- [#1741](https://github.com/wasmerio/wasmer/pull/1741) Implement `wasm_memory_type` in the Wasm C API. +- [#1736](https://github.com/wasmerio/wasmer/pull/1736) Implement `wasm_global_type` in the Wasm C API. +- [#1699](https://github.com/wasmerio/wasmer/pull/1699) Update `wasm.h` to its latest version. +- [#1685](https://github.com/wasmerio/wasmer/pull/1685) Implement `wasm_exporttype_delete` in the Wasm C API. +- [#1725](https://github.com/wasmerio/wasmer/pull/1725) Implement `wasm_func_type` in the Wasm C API. +- [#1715](https://github.com/wasmerio/wasmer/pull/1715) Register errors from `wasm_module_serialize` in the Wasm C API. +- [#1709](https://github.com/wasmerio/wasmer/pull/1709) Implement `wasm_module_name` and `wasm_module_set_name` in the Wasm(er) C API. +- [#1700](https://github.com/wasmerio/wasmer/pull/1700) Implement `wasm_externtype_copy` in the Wasm C API. +- [#1785](https://github.com/wasmerio/wasmer/pull/1785) Add more examples on the Rust API. +- [#1783](https://github.com/wasmerio/wasmer/pull/1783) Handle initialized but empty results in `wasm_func_call` in the Wasm C API. +- [#1780](https://github.com/wasmerio/wasmer/pull/1780) Implement new SIMD zero-extend loads in compiler-llvm. +- [#1754](https://github.com/wasmerio/wasmer/pull/1754) Implement aarch64 ABI for compiler-llvm. +- [#1693](https://github.com/wasmerio/wasmer/pull/1693) Add `wasmer create-exe` subcommand. + +### Changed + +- [#1772](https://github.com/wasmerio/wasmer/pull/1772) Remove lifetime parameter from `NativeFunc`. +- [#1762](https://github.com/wasmerio/wasmer/pull/1762) Allow the `=` sign in a WASI environment variable value. +- [#1710](https://github.com/wasmerio/wasmer/pull/1710) Memory for function call trampolines is now owned by the Artifact. +- [#1781](https://github.com/wasmerio/wasmer/pull/1781) Cranelift upgrade to 0.67. +- [#1777](https://github.com/wasmerio/wasmer/pull/1777) Wasmparser update to 0.65. +- [#1775](https://github.com/wasmerio/wasmer/pull/1775) Improve LimitingTunables implementation. +- [#1720](https://github.com/wasmerio/wasmer/pull/1720) Autodetect llvm regardless of architecture. + +### Fixed + +- [#1718](https://github.com/wasmerio/wasmer/pull/1718) Fix panic in the API in some situations when the memory's min bound was greater than the memory's max bound. +- [#1731](https://github.com/wasmerio/wasmer/pull/1731) In compiler-llvm always load before store, to trigger any traps before any bytes are written. + +## 1.0.0-alpha4 - 2020-10-08 + +### Added +- [#1635](https://github.com/wasmerio/wasmer/pull/1635) Implement `wat2wasm` in the Wasm C API. +- [#1636](https://github.com/wasmerio/wasmer/pull/1636) Implement `wasm_module_validate` in the Wasm C API. +- [#1657](https://github.com/wasmerio/wasmer/pull/1657) Implement `wasm_trap_t` and `wasm_frame_t` for Wasm C API; add examples in Rust and C of exiting early with a host function. + +### Fixed +- [#1690](https://github.com/wasmerio/wasmer/pull/1690) Fix `wasm_memorytype_limits` where `min` and `max` represents pages, not bytes. Additionally, fixes the max limit sentinel value. +- [#1671](https://github.com/wasmerio/wasmer/pull/1671) Fix probestack firing inappropriately, and sometimes over/under allocating stack. +- [#1660](https://github.com/wasmerio/wasmer/pull/1660) Fix issue preventing map-dir aliases starting with `/` from working properly. +- [#1624](https://github.com/wasmerio/wasmer/pull/1624) Add Value::I32/Value::I64 converters from unsigned ints. + +### Changed +- [#1682](https://github.com/wasmerio/wasmer/pull/1682) Improve error reporting when making a memory with invalid settings. +- [#1691](https://github.com/wasmerio/wasmer/pull/1691) Bump minimum supported Rust version to 1.46.0 +- [#1645](https://github.com/wasmerio/wasmer/pull/1645) Move the install script to https://github.com/wasmerio/wasmer-install + +## 1.0.0-alpha3 - 2020-09-14 + +### Fixed + +- [#1620](https://github.com/wasmerio/wasmer/pull/1620) Fix bug causing the Wapm binary to not be packaged with the release +- [#1619](https://github.com/wasmerio/wasmer/pull/1619) Improve error message in engine-native when C compiler is missing + +## 1.0.0-alpha02.0 - 2020-09-11 + +### Added + +- [#1566](https://github.com/wasmerio/wasmer/pull/1566) Add support for opening special Unix files to the WASI FS + +### Fixed + +- [#1602](https://github.com/wasmerio/wasmer/pull/1602) Fix panic when calling host functions with negative numbers in certain situations +- [#1590](https://github.com/wasmerio/wasmer/pull/1590) Fix soundness issue in API of vm::Global + +## TODO: 1.0.0-alpha01.0 + +- Wasmer refactor lands + +## 0.17.1 - 2020-06-24 + +### Changed +- [#1439](https://github.com/wasmerio/wasmer/pull/1439) Move `wasmer-interface-types` into its own repository + +### Fixed + +- [#1554](https://github.com/wasmerio/wasmer/pull/1554) Update supported stable Rust version to 1.45.2. +- [#1552](https://github.com/wasmerio/wasmer/pull/1552) Disable `sigint` handler by default. + +## 0.17.0 - 2020-05-11 + +### Added +- [#1331](https://github.com/wasmerio/wasmer/pull/1331) Implement the `record` type and instrutions for WIT +- [#1345](https://github.com/wasmerio/wasmer/pull/1345) Adding ARM testing in Azure Pipelines +- [#1329](https://github.com/wasmerio/wasmer/pull/1329) New numbers and strings instructions for WIT +- [#1285](https://github.com/wasmerio/wasmer/pull/1285) Greatly improve errors in `wasmer-interface-types` +- [#1303](https://github.com/wasmerio/wasmer/pull/1303) NaN canonicalization for singlepass backend. +- [#1313](https://github.com/wasmerio/wasmer/pull/1313) Add new high-level public API through `wasmer` crate. Includes many updates including: + - Minor improvement: `imports!` macro now handles no trailing comma as well as a trailing comma in namespaces and between namespaces. + - New methods on `Module`: `exports`, `imports`, and `custom_sections`. + - New way to get exports from an instance with `let func_name: Func = instance.exports.get("func_name");`. + - Improved `Table` APIs including `set` which now allows setting functions directly. TODO: update this more if `Table::get` gets made public in this PR + - TODO: finish the list of changes here +- [#1305](https://github.com/wasmerio/wasmer/pull/1305) Handle panics from DynamicFunc. +- [#1300](https://github.com/wasmerio/wasmer/pull/1300) Add support for multiple versions of WASI tests: wasitests now test all versions of WASI. +- [#1292](https://github.com/wasmerio/wasmer/pull/1292) Experimental Support for Android (x86_64 and AArch64) + +### Fixed +- [#1283](https://github.com/wasmerio/wasmer/pull/1283) Workaround for floating point arguments and return values in `DynamicFunc`s. + +### Changed +- [#1401](https://github.com/wasmerio/wasmer/pull/1401) Make breaking change to `RuntimeError`: `RuntimeError` is now more explicit about its possible error values allowing for better insight into why a call into Wasm failed. +- [#1382](https://github.com/wasmerio/wasmer/pull/1382) Refactored test infranstructure (part 2) +- [#1380](https://github.com/wasmerio/wasmer/pull/1380) Refactored test infranstructure (part 1) +- [#1357](https://github.com/wasmerio/wasmer/pull/1357) Refactored bin commands into separate files +- [#1335](https://github.com/wasmerio/wasmer/pull/1335) Change mutability of `memory` to `const` in `wasmer_memory_data_length` in the C API +- [#1332](https://github.com/wasmerio/wasmer/pull/1332) Add option to `CompilerConfig` to force compiler IR verification off even when `debug_assertions` are enabled. This can be used to make debug builds faster, which may be important if you're creating a library that wraps Wasmer and depend on the speed of debug builds. +- [#1320](https://github.com/wasmerio/wasmer/pull/1320) Change `custom_sections` field in `ModuleInfo` to be more standards compliant by allowing multiple custom sections with the same name. To get the old behavior with the new API, you can add `.last().unwrap()` to accesses. For example, `module_info.custom_sections["custom_section_name"].last().unwrap()`. +- [#1301](https://github.com/wasmerio/wasmer/pull/1301) Update supported stable Rust version to 1.41.1. + +## 0.16.2 - 2020-03-11 + +### Fixed + +- [#1294](https://github.com/wasmerio/wasmer/pull/1294) Fix bug related to system calls in WASI that rely on reading from WasmPtrs as arrays of length 0. `WasmPtr` will now succeed on length 0 arrays again. + +## 0.16.1 - 2020-03-11 + +### Fixed + +- [#1291](https://github.com/wasmerio/wasmer/pull/1291) Fix installation packaging script to package the `wax` command. + +## 0.16.0 - 2020-03-11 + +### Added +- [#1286](https://github.com/wasmerio/wasmer/pull/1286) Updated Windows Wasmer icons. Add wax +- [#1284](https://github.com/wasmerio/wasmer/pull/1284) Implement string and memory instructions in `wasmer-interface-types` + +### Fixed +- [#1272](https://github.com/wasmerio/wasmer/pull/1272) Fix off-by-one error bug when accessing memory with a `WasmPtr` that contains the last valid byte of memory. Also changes the behavior of `WasmPtr` with a length of 0 and `WasmPtr` where `std::mem::size_of::()` is 0 to always return `None` + +## 0.15.0 - 2020-03-04 + +- [#1263](https://github.com/wasmerio/wasmer/pull/1263) Changed the behavior of some WASI syscalls to now handle preopened directories more properly. Changed default `--debug` logging to only show Wasmer-related messages. +- [#1217](https://github.com/wasmerio/wasmer/pull/1217) Polymorphic host functions based on dynamic trampoline generation. +- [#1252](https://github.com/wasmerio/wasmer/pull/1252) Allow `/` in wasi `--mapdir` wasm path. +- [#1212](https://github.com/wasmerio/wasmer/pull/1212) Add support for GDB JIT debugging: + - Add `--generate-debug-info` and `-g` flags to `wasmer run` to generate debug information during compilation. The debug info is passed via the GDB JIT interface to a debugger to allow source-level debugging of Wasm files. Currently only available on clif-backend. + - Break public middleware APIs: there is now a `source_loc` parameter that should be passed through if applicable. + - Break compiler trait methods such as `feed_local`, `feed_event` as well as `ModuleCodeGenerator::finalize`. + +## 0.14.1 - 2020-02-24 + +- [#1245](https://github.com/wasmerio/wasmer/pull/1245) Use Ubuntu 16.04 in CI so that we use an earlier version of GLIBC. +- [#1234](https://github.com/wasmerio/wasmer/pull/1234) Check for unused excluded spectest failures. +- [#1232](https://github.com/wasmerio/wasmer/pull/1232) `wasmer-interface-types` has a WAT decoder. + +## 0.14.0 - 2020-02-20 + +- [#1233](https://github.com/wasmerio/wasmer/pull/1233) Improved Wasmer C API release artifacts. +- [#1216](https://github.com/wasmerio/wasmer/pull/1216) `wasmer-interface-types` receives a binary encoder. +- [#1228](https://github.com/wasmerio/wasmer/pull/1228) Singlepass cleanup: Resolve several FIXMEs and remove protect_unix. +- [#1218](https://github.com/wasmerio/wasmer/pull/1218) Enable Cranelift verifier in debug mode. Fix bug with table indices being the wrong type. +- [#787](https://github.com/wasmerio/wasmer/pull/787) New crate `wasmer-interface-types` to implement WebAssembly Interface Types. +- [#1213](https://github.com/wasmerio/wasmer/pull/1213) Fixed WASI `fdstat` to detect `isatty` properly. +- [#1192](https://github.com/wasmerio/wasmer/pull/1192) Use `ExceptionCode` for error representation. +- [#1191](https://github.com/wasmerio/wasmer/pull/1191) Fix singlepass miscompilation on `Operator::CallIndirect`. +- [#1180](https://github.com/wasmerio/wasmer/pull/1180) Fix compilation for target `x86_64-unknown-linux-musl`. +- [#1170](https://github.com/wasmerio/wasmer/pull/1170) Improve the WasiFs builder API with convenience methods for overriding stdin, stdout, and stderr as well as a new sub-builder for controlling the permissions and properties of preopened directories. Also breaks that implementations of `WasiFile` must be `Send` -- please file an issue if this change causes you any issues. +- [#1161](https://github.com/wasmerio/wasmer/pull/1161) Require imported functions to be `Send`. This is a breaking change that fixes a soundness issue in the API. +- [#1140](https://github.com/wasmerio/wasmer/pull/1140) Use [`blake3`](https://github.com/BLAKE3-team/BLAKE3) as default hashing algorithm for caching. +- [#1129](https://github.com/wasmerio/wasmer/pull/1129) Standard exception types for singlepass backend. + +## 0.13.1 - 2020-01-16 +- Fix bug in wapm related to the `package.wasmer_extra_flags` entry in the manifest + +## 0.13.0 - 2020-01-15 + +Special thanks to [@repi](https://github.com/repi) and [@srenatus](https://github.com/srenatus) for their contributions! + +- [#1153](https://github.com/wasmerio/wasmer/pull/1153) Added Wasmex, an Elixir language integration, to the README +- [#1133](https://github.com/wasmerio/wasmer/pull/1133) New `wasmer_trap` function in the C API, to properly error from within a host function +- [#1147](https://github.com/wasmerio/wasmer/pull/1147) Remove `log` and `trace` macros from `wasmer-runtime-core`, remove `debug` and `trace` features from `wasmer-*` crates, use the `log` crate for logging and use `fern` in the Wasmer CLI binary to output log messages. Colorized output will be enabled automatically if printing to a terminal, to force colorization on or off, set the `WASMER_COLOR` environment variable to `true` or `false`. +- [#1128](https://github.com/wasmerio/wasmer/pull/1128) Fix a crash when a host function is missing and the `allow_missing_functions` flag is enabled +- [#1099](https://github.com/wasmerio/wasmer/pull/1099) Remove `backend::Backend` from `wasmer_runtime_core` +- [#1097](https://github.com/wasmerio/wasmer/pull/1097) Move inline breakpoint outside of runtime backend +- [#1095](https://github.com/wasmerio/wasmer/pull/1095) Update to cranelift 0.52. +- [#1092](https://github.com/wasmerio/wasmer/pull/1092) Add `get_utf8_string_with_nul` to `WasmPtr` to read nul-terminated strings from memory. +- [#1071](https://github.com/wasmerio/wasmer/pull/1071) Add support for non-trapping float-to-int conversions, enabled by default. + +## 0.12.0 - 2019-12-18 + +Special thanks to [@ethanfrey](https://github.com/ethanfrey), [@AdamSLevy](https://github.com/AdamSLevy), [@Jasper-Bekkers](https://github.com/Jasper-Bekkers), [@srenatus](https://github.com/srenatus) for their contributions! + +- [#1078](https://github.com/wasmerio/wasmer/pull/1078) Increase the maximum number of parameters `Func` can take +- [#1062](https://github.com/wasmerio/wasmer/pull/1062) Expose some opt-in Emscripten functions to the C API +- [#1032](https://github.com/wasmerio/wasmer/pull/1032) Change the signature of the Emscripten `abort` function to work with Emscripten 1.38.30 +- [#1060](https://github.com/wasmerio/wasmer/pull/1060) Test the capi with all the backends +- [#1069](https://github.com/wasmerio/wasmer/pull/1069) Add function `get_memory_and_data` to `Ctx` to help prevent undefined behavior and mutable aliasing. It allows accessing memory while borrowing data mutably for the `Ctx` lifetime. This new function is now being used in `wasmer-wasi`. +- [#1058](https://github.com/wasmerio/wasmer/pull/1058) Fix minor panic issue when `wasmer::compile_with` called with llvm backend. +- [#858](https://github.com/wasmerio/wasmer/pull/858) Minor panic fix when wasmer binary with `loader` option run a module without exported `_start` function. +- [#1056](https://github.com/wasmerio/wasmer/pull/1056) Improved `--invoke` args parsing (supporting `i32`, `i64`, `f32` and `f32`) in Wasmer CLI +- [#1054](https://github.com/wasmerio/wasmer/pull/1054) Improve `--invoke` output in Wasmer CLI +- [#1053](https://github.com/wasmerio/wasmer/pull/1053) For RuntimeError and breakpoints, use Box instead of Box. +- [#1052](https://github.com/wasmerio/wasmer/pull/1052) Fix minor panic and improve Error handling in singlepass backend. +- [#1050](https://github.com/wasmerio/wasmer/pull/1050) Attach C & C++ headers to releases. +- [#1033](https://github.com/wasmerio/wasmer/pull/1033) Set cranelift backend as default compiler backend again, require at least one backend to be enabled for Wasmer CLI +- [#1044](https://github.com/wasmerio/wasmer/pull/1044) Enable AArch64 support in the LLVM backend. +- [#1030](https://github.com/wasmerio/wasmer/pull/1030) Ability to generate `ImportObject` for a specific version WASI version with the C API. +- [#1028](https://github.com/wasmerio/wasmer/pull/1028) Introduce strict/non-strict modes for `get_wasi_version` +- [#1029](https://github.com/wasmerio/wasmer/pull/1029) Add the “floating” `WasiVersion::Latest` version. +- [#1006](https://github.com/wasmerio/wasmer/pull/1006) Fix minor panic issue when `wasmer::compile_with` called with llvm backend +- [#1009](https://github.com/wasmerio/wasmer/pull/1009) Enable LLVM verifier for all tests, add new llvm-backend-tests crate. +- [#1022](https://github.com/wasmerio/wasmer/pull/1022) Add caching support for Singlepass backend. +- [#1004](https://github.com/wasmerio/wasmer/pull/1004) Add the Auto backend to enable to adapt backend usage depending on wasm file executed. +- [#1068](https://github.com/wasmerio/wasmer/pull/1068) Various cleanups for the singlepass backend on AArch64. + +## 0.11.0 - 2019-11-22 + +- [#713](https://github.com/wasmerio/wasmer/pull/713) Add AArch64 support for singlepass. +- [#995](https://github.com/wasmerio/wasmer/pull/995) Detect when a global is read without being initialized (emit a proper error instead of panicking) +- [#996](https://github.com/wasmerio/wasmer/pull/997) Refactored spectests, emtests and wasitests to use default compiler logic +- [#992](https://github.com/wasmerio/wasmer/pull/992) Updates WAPM version to 0.4.1, fix arguments issue introduced in #990 +- [#990](https://github.com/wasmerio/wasmer/pull/990) Default wasmer CLI to `run`. Wasmer will now attempt to parse unrecognized command line options as if they were applied to the run command: `wasmer mywasm.wasm --dir=.` now works! +- [#987](https://github.com/wasmerio/wasmer/pull/987) Fix `runtime-c-api` header files when compiled by gnuc. +- [#957](https://github.com/wasmerio/wasmer/pull/957) Change the meaning of `wasmer_wasi::is_wasi_module` to detect any type of WASI module, add support for new wasi snapshot_preview1 +- [#934](https://github.com/wasmerio/wasmer/pull/934) Simplify float expressions in the LLVM backend. + +## 0.10.2 - 2019-11-18 + +- [#968](https://github.com/wasmerio/wasmer/pull/968) Added `--invoke` option to the command +- [#964](https://github.com/wasmerio/wasmer/pull/964) Enable cross-compilation for specific target +- [#971](https://github.com/wasmerio/wasmer/pull/971) In LLVM backend, use unaligned loads and stores for non-atomic accesses to wasmer memory. +- [#960](https://github.com/wasmerio/wasmer/pull/960) Fix `runtime-c-api` header files when compiled by clang. +- [#925](https://github.com/wasmerio/wasmer/pull/925) Host functions can be closures with a captured environment. +- [#917](https://github.com/wasmerio/wasmer/pull/917) Host functions (aka imported functions) may not have `&mut vm::Ctx` as first argument, i.e. the presence of the `&mut vm::Ctx` argument is optional. +- [#915](https://github.com/wasmerio/wasmer/pull/915) All backends share the same definition of `Trampoline` (defined in `wasmer-runtime-core`). + +## 0.10.1 - 2019-11-11 + +- [#952](https://github.com/wasmerio/wasmer/pull/952) Use C preprocessor to properly hide trampoline functions on Windows and non-x86_64 targets. + +## 0.10.0 - 2019-11-11 + +Special thanks to [@newpavlov](https://github.com/newpavlov) and [@Maxgy](https://github.com/Maxgy) for their contributions! + +- [#942](https://github.com/wasmerio/wasmer/pull/942) Deny missing docs in runtime core and add missing docs +- [#939](https://github.com/wasmerio/wasmer/pull/939) Fix bug causing attempts to append to files with WASI to delete the contents of the file +- [#940](https://github.com/wasmerio/wasmer/pull/940) Update supported Rust version to 1.38+ +- [#923](https://github.com/wasmerio/wasmer/pull/923) Fix memory leak in the C API caused by an incorrect cast in `wasmer_trampoline_buffer_destroy` +- [#921](https://github.com/wasmerio/wasmer/pull/921) In LLVM backend, annotate all memory accesses with TBAA metadata. +- [#883](https://github.com/wasmerio/wasmer/pull/883) Allow floating point operations to have arbitrary inputs, even including SNaNs. +- [#856](https://github.com/wasmerio/wasmer/pull/856) Expose methods in the runtime C API to get a WASI import object + +## 0.9.0 - 2019-10-23 + +Special thanks to @alocquet for their contributions! + +- [#898](https://github.com/wasmerio/wasmer/pull/898) State tracking is now disabled by default in the LLVM backend. It can be enabled with `--track-state`. +- [#861](https://github.com/wasmerio/wasmer/pull/861) Add descriptions to `unimplemented!` macro in various places +- [#897](https://github.com/wasmerio/wasmer/pull/897) Removes special casing of stdin, stdout, and stderr in WASI. Closing these files now works. Removes `stdin`, `stdout`, and `stderr` from `WasiFS`, replaced by the methods `stdout`, `stdout_mut`, and so on. +- [#863](https://github.com/wasmerio/wasmer/pull/863) Fix min and max for cases involving NaN and negative zero when using the LLVM backend. + +## 0.8.0 - 2019-10-02 + +Special thanks to @jdanford for their contributions! + +- [#850](https://github.com/wasmerio/wasmer/pull/850) New `WasiStateBuilder` API. small, add misc. breaking changes to existing API (for example, changing the preopen dirs arg on `wasi::generate_import_object` from `Vec` to `Vec`) +- [#852](https://github.com/wasmerio/wasmer/pull/852) Make minor grammar/capitalization fixes to README.md +- [#841](https://github.com/wasmerio/wasmer/pull/841) Slightly improve rustdoc documentation and small updates to outdated info in readme files +- [#836](https://github.com/wasmerio/wasmer/pull/836) Update Cranelift fork version to `0.44.0` +- [#839](https://github.com/wasmerio/wasmer/pull/839) Change supported version to stable Rust 1.37+ +- [#834](https://github.com/wasmerio/wasmer/pull/834) Fix panic when unwraping `wasmer` arguments +- [#835](https://github.com/wasmerio/wasmer/pull/835) Add parallel execution example (independent instances created from the same `ImportObject` and `Module` run with rayon) +- [#834](https://github.com/wasmerio/wasmer/pull/834) Fix panic when parsing numerical arguments for no-ABI targets run with the wasmer binary +- [#833](https://github.com/wasmerio/wasmer/pull/833) Add doc example of using ImportObject's new `maybe_with_namespace` method +- [#832](https://github.com/wasmerio/wasmer/pull/832) Delete unused runtime ABI +- [#809](https://github.com/wasmerio/wasmer/pull/809) Fix bugs leading to panics in `LocalBacking`. +- [#831](https://github.com/wasmerio/wasmer/pull/831) Add support for atomic operations, excluding wait and notify, to singlepass. +- [#822](https://github.com/wasmerio/wasmer/pull/822) Update Cranelift fork version to `0.43.1` +- [#829](https://github.com/wasmerio/wasmer/pull/829) Fix deps on `make bench-*` commands; benchmarks don't compile other backends now +- [#807](https://github.com/wasmerio/wasmer/pull/807) Implement Send for `Instance`, breaking change on `ImportObject`, remove method `get_namespace` replaced with `with_namespace` and `maybe_with_namespace` +- [#817](https://github.com/wasmerio/wasmer/pull/817) Add document for tracking features across backends and language integrations, [docs/feature_matrix.md] +- [#823](https://github.com/wasmerio/wasmer/issues/823) Improved Emscripten / WASI integration +- [#821](https://github.com/wasmerio/wasmer/issues/821) Remove patch version on most deps Cargo manifests. This gives Wasmer library users more control over which versions of the deps they use. +- [#820](https://github.com/wasmerio/wasmer/issues/820) Remove null-pointer checks in `WasmPtr` from runtime-core, re-add them in Emscripten +- [#803](https://github.com/wasmerio/wasmer/issues/803) Add method to `Ctx` to invoke functions by their `TableIndex` +- [#790](https://github.com/wasmerio/wasmer/pull/790) Fix flaky test failure with LLVM, switch to large code model. +- [#788](https://github.com/wasmerio/wasmer/pull/788) Use union merge on the changelog file. +- [#785](https://github.com/wasmerio/wasmer/pull/785) Include Apache license file for spectests. +- [#786](https://github.com/wasmerio/wasmer/pull/786) In the LLVM backend, lower atomic wasm operations to atomic machine instructions. +- [#784](https://github.com/wasmerio/wasmer/pull/784) Fix help string for wasmer run. + +## 0.7.0 - 2019-09-12 + +Special thanks to @YaronWittenstein @penberg for their contributions. + +- [#776](https://github.com/wasmerio/wasmer/issues/776) Allow WASI preopened fds to be closed +- [#774](https://github.com/wasmerio/wasmer/issues/774) Add more methods to the `WasiFile` trait +- [#772](https://github.com/wasmerio/wasmer/issues/772) [#770](https://github.com/wasmerio/wasmer/issues/770) Handle more internal failures by passing back errors +- [#756](https://github.com/wasmerio/wasmer/issues/756) Allow NULL parameter and 0 arity in `wasmer_export_func_call` C API +- [#747](https://github.com/wasmerio/wasmer/issues/747) Return error instead of panicking on traps when using the Wasmer binary +- [#741](https://github.com/wasmerio/wasmer/issues/741) Add validate Wasm fuzz target +- [#733](https://github.com/wasmerio/wasmer/issues/733) Remove dependency on compiler backends for `middleware-common` +- [#732](https://github.com/wasmerio/wasmer/issues/732) [#731](https://github.com/wasmerio/wasmer/issues/731) WASI bug fixes and improvements +- [#726](https://github.com/wasmerio/wasmer/issues/726) Add serialization and deserialization for Wasi State +- [#716](https://github.com/wasmerio/wasmer/issues/716) Improve portability of install script +- [#714](https://github.com/wasmerio/wasmer/issues/714) Add Code of Conduct +- [#708](https://github.com/wasmerio/wasmer/issues/708) Remove unconditional dependency on Cranelift in the C API +- [#703](https://github.com/wasmerio/wasmer/issues/703) Fix compilation on AArch64 Linux +- [#702](https://github.com/wasmerio/wasmer/issues/702) Add SharedMemory to Wasmer. Add `--enable-threads` flag, add partial implementation of atomics to LLVM backend. +- [#698](https://github.com/wasmerio/wasmer/issues/698) [#690](https://github.com/wasmerio/wasmer/issues/690) [#687](https://github.com/wasmerio/wasmer/issues/690) Fix panics in Emscripten +- [#689](https://github.com/wasmerio/wasmer/issues/689) Replace `wasmer_runtime_code::memory::Atomic` with `std::sync::atomic` atomics, changing its interface +- [#680](https://github.com/wasmerio/wasmer/issues/680) [#673](https://github.com/wasmerio/wasmer/issues/673) [#669](https://github.com/wasmerio/wasmer/issues/669) [#660](https://github.com/wasmerio/wasmer/issues/660) [#659](https://github.com/wasmerio/wasmer/issues/659) Misc. runtime and singlepass fixes +- [#677](https://github.com/wasmerio/wasmer/issues/677) [#675](https://github.com/wasmerio/wasmer/issues/675) [#674](https://github.com/wasmerio/wasmer/issues/674) LLVM backend fixes and improvements +- [#671](https://github.com/wasmerio/wasmer/issues/671) Implement fs polling in `wasi::poll_oneoff` for Unix-like platforms +- [#656](https://github.com/wasmerio/wasmer/issues/656) Move CI to Azure Pipelines +- [#650](https://github.com/wasmerio/wasmer/issues/650) Implement `wasi::path_rename`, improve WASI FS public api, and allow open files to exist even when the underlying file is deleted +- [#643](https://github.com/wasmerio/wasmer/issues/643) Implement `wasi::path_symlink` and improve WASI FS public api IO error reporting +- [#608](https://github.com/wasmerio/wasmer/issues/608) Implement wasi syscalls `fd_allocate`, `fd_sync`, `fd_pread`, `path_link`, `path_filestat_set_times`; update WASI fs API in a WIP way; reduce coupling of WASI code to host filesystem; make debug messages from WASI more readable; improve rights-checking when calling syscalls; implement reference counting on inodes; misc bug fixes and improvements +- [#616](https://github.com/wasmerio/wasmer/issues/616) Create the import object separately from instance instantiation in `runtime-c-api` +- [#620](https://github.com/wasmerio/wasmer/issues/620) Replace one `throw()` with `noexcept` in llvm backend +- [#618](https://github.com/wasmerio/wasmer/issues/618) Implement `InternalEvent::Breakpoint` in the llvm backend to allow metering in llvm +- [#615](https://github.com/wasmerio/wasmer/issues/615) Eliminate `FunctionEnvironment` construction in `feed_event()` speeding up to 70% of compilation in clif +- [#609](https://github.com/wasmerio/wasmer/issues/609) Update dependencies +- [#602](https://github.com/wasmerio/wasmer/issues/602) C api extract instance context from instance +- [#590](https://github.com/wasmerio/wasmer/issues/590) Error visibility changes in wasmer-c-api +- [#589](https://github.com/wasmerio/wasmer/issues/589) Make `wasmer_byte_array` fields `public` in wasmer-c-api + +## 0.6.0 - 2019-07-31 +- [#603](https://github.com/wasmerio/wasmer/pull/603) Update Wapm-cli, bump version numbers +- [#595](https://github.com/wasmerio/wasmer/pull/595) Add unstable public API for interfacing with the WASI file system in plugin-like usecases +- [#598](https://github.com/wasmerio/wasmer/pull/598) LLVM Backend is now supported in Windows +- [#599](https://github.com/wasmerio/wasmer/pull/599) Fix llvm backend failures in fat spec tests and simd_binaryen spec test. +- [#579](https://github.com/wasmerio/wasmer/pull/579) Fix bug in caching with LLVM and Singlepass backends. + Add `default-backend-singlepass`, `default-backend-llvm`, and `default-backend-cranelift` features to `wasmer-runtime` + to control the `default_compiler()` function (this is a breaking change). Add `compiler_for_backend` function in `wasmer-runtime` +- [#561](https://github.com/wasmerio/wasmer/pull/561) Call the `data_finalizer` field on the `Ctx` +- [#576](https://github.com/wasmerio/wasmer/pull/576) fix `Drop` of uninit `Ctx` +- [#542](https://github.com/wasmerio/wasmer/pull/542) Add SIMD support to Wasmer (LLVM backend only) + - Updates LLVM to version 8.0 + +## 0.5.7 - 2019-07-23 +- [#575](https://github.com/wasmerio/wasmer/pull/575) Prepare for release; update wapm to 0.3.6 +- [#555](https://github.com/wasmerio/wasmer/pull/555) WASI filesystem rewrite. Major improvements + - adds virtual root showing all preopened directories + - improved sandboxing and code-reuse + - symlinks work in a lot more situations + - many misc. improvements to most syscalls touching the filesystem + +## 0.5.6 - 2019-07-16 +- [#565](https://github.com/wasmerio/wasmer/pull/565) Update wapm and bump version to 0.5.6 +- [#563](https://github.com/wasmerio/wasmer/pull/563) Improve wasi testing infrastructure + - fixes arg parsing from comments & fixes the mapdir test to have the native code doing the same thing as the WASI code + - makes wasitests-generate output stdout/stderr by default & adds function to print stdout and stderr for a command if it fails + - compiles wasm with size optimizations & strips generated wasm with wasm-strip +- [#554](https://github.com/wasmerio/wasmer/pull/554) Finish implementation of `wasi::fd_seek`, fix bug in filestat +- [#550](https://github.com/wasmerio/wasmer/pull/550) Fix singlepass compilation error with `imul` instruction + + +## 0.5.5 - 2019-07-10 +- [#541](https://github.com/wasmerio/wasmer/pull/541) Fix dependency graph by making separate test crates; ABI implementations should not depend on compilers. Add Cranelift fork as git submodule of clif-backend +- [#537](https://github.com/wasmerio/wasmer/pull/537) Add hidden flag (`--cache-key`) to use prehashed key into the compiled wasm cache and change compiler backend-specific caching to use directories +- [#536](https://github.com/wasmerio/wasmer/pull/536) ~Update cache to use compiler backend name in cache key~ + +## 0.5.4 - 2019-07-06 +- [#529](https://github.com/wasmerio/wasmer/pull/529) Updates the Wasm Interface library, which is used by wapm, with bug fixes and error message improvements + +## 0.5.3 - 2019-07-03 +- [#523](https://github.com/wasmerio/wasmer/pull/523) Update wapm version to fix bug related to signed packages in the global namespace and locally-stored public keys + +## 0.5.2 - 2019-07-02 +- [#516](https://github.com/wasmerio/wasmer/pull/516) Add workaround for singlepass miscompilation on GetLocal +- [#521](https://github.com/wasmerio/wasmer/pull/521) Update Wapm-cli, bump version numbers +- [#518](https://github.com/wasmerio/wasmer/pull/518) Update Cranelift and WasmParser +- [#514](https://github.com/wasmerio/wasmer/pull/514) [#519](https://github.com/wasmerio/wasmer/pull/519) Improved Emscripten network related calls, added a null check to `WasmPtr` +- [#515](https://github.com/wasmerio/wasmer/pull/515) Improved Emscripten dyncalls +- [#513](https://github.com/wasmerio/wasmer/pull/513) Fix emscripten lseek implementation. +- [#510](https://github.com/wasmerio/wasmer/pull/510) Simplify construction of floating point constants in LLVM backend. Fix LLVM assertion failure due to definition of %ctx. + +## 0.5.1 - 2019-06-24 +- [#508](https://github.com/wasmerio/wasmer/pull/508) Update wapm version, includes bug fixes + +## 0.5.0 - 2019-06-17 + +- [#471](https://github.com/wasmerio/wasmer/pull/471) Added missing functions to run Python. Improved Emscripten bindings +- [#494](https://github.com/wasmerio/wasmer/pull/494) Remove deprecated type aliases from libc in the runtime C API +- [#493](https://github.com/wasmerio/wasmer/pull/493) `wasmer_module_instantiate` has better error messages in the runtime C API +- [#474](https://github.com/wasmerio/wasmer/pull/474) Set the install name of the dylib to `@rpath` +- [#490](https://github.com/wasmerio/wasmer/pull/490) Add MiddlewareChain and StreamingCompiler to runtime +- [#487](https://github.com/wasmerio/wasmer/pull/487) Fix stack offset check in singlepass backend +- [#450](https://github.com/wasmerio/wasmer/pull/450) Added Metering +- [#481](https://github.com/wasmerio/wasmer/pull/481) Added context trampoline into runtime +- [#484](https://github.com/wasmerio/wasmer/pull/484) Fix bugs in emscripten socket syscalls +- [#476](https://github.com/wasmerio/wasmer/pull/476) Fix bug with wasi::environ_get, fix off by one error in wasi::environ_sizes_get +- [#470](https://github.com/wasmerio/wasmer/pull/470) Add mapdir support to Emscripten, implement getdents for Unix +- [#467](https://github.com/wasmerio/wasmer/pull/467) `wasmer_instantiate` returns better error messages in the runtime C API +- [#463](https://github.com/wasmerio/wasmer/pull/463) Fix bug in WASI path_open allowing one level above preopened dir to be accessed +- [#461](https://github.com/wasmerio/wasmer/pull/461) Prevent passing negative lengths in various places in the runtime C API +- [#459](https://github.com/wasmerio/wasmer/pull/459) Add monotonic and real time clocks for wasi on windows +- [#447](https://github.com/wasmerio/wasmer/pull/447) Add trace macro (`--features trace`) for more verbose debug statements +- [#451](https://github.com/wasmerio/wasmer/pull/451) Add `--mapdir=src:dest` flag to rename host directories in the guest context +- [#457](https://github.com/wasmerio/wasmer/pull/457) Implement file metadata for WASI, fix bugs in WASI clock code for Unix platforms + +## 0.4.2 - 2019-05-16 + +- [#416](https://github.com/wasmerio/wasmer/pull/416) Remote code loading framework +- [#449](https://github.com/wasmerio/wasmer/pull/449) Fix bugs: opening host files in filestat and opening with write permissions unconditionally in path_open +- [#442](https://github.com/wasmerio/wasmer/pull/442) Misc. WASI FS fixes and implement readdir +- [#440](https://github.com/wasmerio/wasmer/pull/440) Fix type mismatch between `wasmer_instance_call` and `wasmer_export_func_*_arity` functions in the runtime C API. +- [#269](https://github.com/wasmerio/wasmer/pull/269) Add better runtime docs +- [#432](https://github.com/wasmerio/wasmer/pull/432) Fix returned value of `wasmer_last_error_message` in the runtime C API +- [#429](https://github.com/wasmerio/wasmer/pull/429) Get wasi::path_filestat_get working for some programs; misc. minor WASI FS improvements +- [#413](https://github.com/wasmerio/wasmer/pull/413) Update LLVM backend to use new parser codegen traits + +## 0.4.1 - 2019-05-06 + +- [#426](https://github.com/wasmerio/wasmer/pull/426) Update wapm-cli submodule, bump version to 0.4.1 +- [#422](https://github.com/wasmerio/wasmer/pull/422) Improved Emscripten functions to run optipng and pngquant compiled to wasm +- [#409](https://github.com/wasmerio/wasmer/pull/409) Improved Emscripten functions to run JavascriptCore compiled to wasm +- [#399](https://github.com/wasmerio/wasmer/pull/399) Add example of using a plugin extended from WASI +- [#397](https://github.com/wasmerio/wasmer/pull/397) Fix WASI fs abstraction to work on Windows +- [#390](https://github.com/wasmerio/wasmer/pull/390) Pin released wapm version and add it as a git submodule +- [#408](https://github.com/wasmerio/wasmer/pull/408) Add images to windows installer and update installer to add wapm bin directory to path + +## 0.4.0 - 2019-04-23 + +- [#383](https://github.com/wasmerio/wasmer/pull/383) Hook up wasi exit code to wasmer cli. +- [#382](https://github.com/wasmerio/wasmer/pull/382) Improve error message on `--backend` flag to only suggest currently enabled backends +- [#381](https://github.com/wasmerio/wasmer/pull/381) Allow retrieving propagated user errors. +- [#379](https://github.com/wasmerio/wasmer/pull/379) Fix small return types from imported functions. +- [#371](https://github.com/wasmerio/wasmer/pull/371) Add more Debug impl for WASI types +- [#368](https://github.com/wasmerio/wasmer/pull/368) Fix issue with write buffering +- [#343](https://github.com/wasmerio/wasmer/pull/343) Implement preopened files for WASI and fix aligment issue when accessing WASI memory +- [#367](https://github.com/wasmerio/wasmer/pull/367) Add caching support to the LLVM backend. +- [#366](https://github.com/wasmerio/wasmer/pull/366) Remove `UserTrapper` trait to fix [#365](https://github.com/wasmerio/wasmer/issues/365). +- [#348](https://github.com/wasmerio/wasmer/pull/348) Refactor internal runtime ↔️ backend abstraction. +- [#355](https://github.com/wasmerio/wasmer/pull/355) Misc changes to `Cargo.toml`s for publishing +- [#352](https://github.com/wasmerio/wasmer/pull/352) Bump version numbers to 0.3.0 +- [#351](https://github.com/wasmerio/wasmer/pull/351) Add hidden option to specify wasm program name (can be used to improve error messages) +- [#350](https://github.com/wasmerio/wasmer/pull/350) Enforce that CHANGELOG.md is updated through CI. +- [#349](https://github.com/wasmerio/wasmer/pull/349) Add [CHANGELOG.md](https://github.com/wasmerio/wasmer/blob/master/CHANGELOG.md). + +## 0.3.0 - 2019-04-12 + +- [#276](https://github.com/wasmerio/wasmer/pull/276) [#288](https://github.com/wasmerio/wasmer/pull/288) [#344](https://github.com/wasmerio/wasmer/pull/344) Use new singlepass backend (with the `--backend=singlepass` when running Wasmer) +- [#338](https://github.com/wasmerio/wasmer/pull/338) Actually catch traps/panics/etc when using a typed func. +- [#325](https://github.com/wasmerio/wasmer/pull/325) Fixed func_index in debug mode +- [#323](https://github.com/wasmerio/wasmer/pull/323) Add validate subcommand to validate Wasm files +- [#321](https://github.com/wasmerio/wasmer/pull/321) Upgrade to Cranelift 0.3.0 +- [#319](https://github.com/wasmerio/wasmer/pull/319) Add Export and GlobalDescriptor to Runtime API +- [#310](https://github.com/wasmerio/wasmer/pull/310) Cleanup warnings +- [#299](https://github.com/wasmerio/wasmer/pull/299) [#300](https://github.com/wasmerio/wasmer/pull/300) [#301](https://github.com/wasmerio/wasmer/pull/301) [#303](https://github.com/wasmerio/wasmer/pull/303) [#304](https://github.com/wasmerio/wasmer/pull/304) [#305](https://github.com/wasmerio/wasmer/pull/305) [#306](https://github.com/wasmerio/wasmer/pull/306) [#307](https://github.com/wasmerio/wasmer/pull/307) Add support for WASI 🎉 +- [#286](https://github.com/wasmerio/wasmer/pull/286) Add extend to imports +- [#278](https://github.com/wasmerio/wasmer/pull/278) Add versioning to cache +- [#250](https://github.com/wasmerio/wasmer/pull/250) Setup bors diff --git a/Cargo.toml b/Cargo.toml index d14da278e..812fcf983 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-workspace" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Wasmer workspace" authors = ["Wasmer Engineering Team "] repository = "https://github.com/wasmerio/wasmer" @@ -10,18 +10,18 @@ publish = false autoexamples = false [dependencies] -wasmer = { version = "=3.0.0-rc.2", path = "lib/api", default-features = false } -wasmer-compiler = { version = "=3.0.0-rc.2", path = "lib/compiler", features = ["compiler"] } -wasmer-compiler-cranelift = { version = "=3.0.0-rc.2", path = "lib/compiler-cranelift", optional = true } -wasmer-compiler-singlepass = { version = "=3.0.0-rc.2", path = "lib/compiler-singlepass", optional = true } -wasmer-compiler-llvm = { version = "=3.0.0-rc.2", path = "lib/compiler-llvm", optional = true } -wasmer-emscripten = { version = "=3.0.0-rc.2", path = "lib/emscripten", optional = true } -wasmer-wasi = { version = "=3.0.0-rc.2", path = "lib/wasi", optional = true } -wasmer-wast = { version = "=3.0.0-rc.2", path = "tests/lib/wast", optional = true } -wasi-test-generator = { version = "=3.0.0-rc.2", path = "tests/wasi-wast", optional = true } -wasmer-cache = { version = "=3.0.0-rc.2", path = "lib/cache", optional = true } -wasmer-types = { version = "=3.0.0-rc.2", path = "lib/types" } -wasmer-middlewares = { version = "=3.0.0-rc.2", path = "lib/middlewares", optional = true } +wasmer = { version = "=3.0.2", path = "lib/api", default-features = false } +wasmer-compiler = { version = "=3.0.2", path = "lib/compiler", features = ["compiler"] } +wasmer-compiler-cranelift = { version = "=3.0.2", path = "lib/compiler-cranelift", optional = true } +wasmer-compiler-singlepass = { version = "=3.0.2", path = "lib/compiler-singlepass", optional = true } +wasmer-compiler-llvm = { version = "=3.0.2", path = "lib/compiler-llvm", optional = true } +wasmer-emscripten = { version = "=3.0.2", path = "lib/emscripten", optional = true } +wasmer-wasi = { version = "=3.0.2", path = "lib/wasi", optional = true } +wasmer-wast = { version = "=3.0.2", path = "tests/lib/wast", optional = true } +wasi-test-generator = { version = "=3.0.2", path = "tests/wasi-wast", optional = true } +wasmer-cache = { version = "=3.0.2", path = "lib/cache", optional = true } +wasmer-types = { version = "=3.0.2", path = "lib/types" } +wasmer-middlewares = { version = "=3.0.2", path = "lib/middlewares", optional = true } cfg-if = "1.0" [workspace] @@ -69,7 +69,7 @@ glob = "0.3" rustc_version = "0.4" [dev-dependencies] -wasmer = { version = "=3.0.0-rc.2", path = "lib/api", default-features = false, features = ["cranelift"] } +wasmer = { version = "=3.0.2", path = "lib/api", default-features = false, features = ["cranelift"] } anyhow = "1.0" criterion = "0.3" lazy_static = "1.4" diff --git a/Makefile b/Makefile index 7b319243b..f1d4e5078 100644 --- a/Makefile +++ b/Makefile @@ -40,6 +40,7 @@ SHELL=/usr/bin/env bash IS_DARWIN := 0 IS_LINUX := 0 +IS_FREEBSD := 0 IS_WINDOWS := 0 IS_AMD64 := 0 IS_AARCH64 := 0 @@ -57,6 +58,8 @@ else IS_DARWIN := 1 else ifeq ($(uname), Linux) IS_LINUX := 1 + else ifeq ($(uname), FreeBSD) + IS_FREEBSD := 1 else # We use spaces instead of tabs to indent `$(error)` # otherwise it's considered as a command outside a @@ -67,7 +70,7 @@ else # Architecture uname := $(shell uname -m) - ifeq ($(uname), x86_64) + ifneq (, $(filter $(uname), x86_64 amd64)) IS_AMD64 := 1 else ifneq (, $(filter $(uname), aarch64 arm64)) IS_AARCH64 := 1 @@ -117,33 +120,33 @@ endif ## # If the user didn't disable the LLVM compiler… -ifneq ($(ENABLE_LLVM), 0) +ifeq ($(ENABLE_LLVM), 0) + LLVM_VERSION := # … then maybe the user forced to enable the LLVM compiler. - ifeq ($(ENABLE_LLVM), 1) - LLVM_VERSION := $(shell llvm-config --version) - compilers += llvm - # … otherwise, we try to autodetect LLVM from `llvm-config` - else ifneq (, $(shell which llvm-config 2>/dev/null)) - LLVM_VERSION := $(shell llvm-config --version) - - # If findstring is not empty, then it have found the value - ifneq (, $(findstring 13,$(LLVM_VERSION))) - compilers += llvm - else ifneq (, $(findstring 12,$(LLVM_VERSION))) - compilers += llvm - endif +else ifeq ($(ENABLE_LLVM), 1) + LLVM_VERSION := $(shell llvm-config --version) + compilers += llvm # … or try to autodetect LLVM from `llvm-config-`. - else - ifneq (, $(shell which llvm-config-13 2>/dev/null)) - LLVM_VERSION := $(shell llvm-config-13 --version) - compilers += llvm - else ifneq (, $(shell which llvm-config-12 2>/dev/null)) - LLVM_VERSION := $(shell llvm-config-12 --version) - compilers += llvm - endif +else ifneq (, $(shell which llvm-config-13 2>/dev/null)) + LLVM_VERSION := $(shell llvm-config-13 --version) + compilers += llvm + # need force LLVM_SYS_120_PREFIX, or llvm_sys will not build in the case + export LLVM_SYS_120_PREFIX = $(shell llvm-config-13 --prefix) +else ifneq (, $(shell which llvm-config-12 2>/dev/null)) + LLVM_VERSION := $(shell llvm-config-12 --version) + compilers += llvm + # … otherwise, we try to autodetect LLVM from `llvm-config` +else ifneq (, $(shell which llvm-config 2>/dev/null)) + LLVM_VERSION := $(shell llvm-config --version) + ifneq (, $(findstring 13,$(LLVM_VERSION))) + compilers += llvm + else ifneq (, $(findstring 12,$(LLVM_VERSION))) + compilers += llvm 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 # Is failing to compile in Linux for some reason exclude_tests += --exclude wasmer-wasi-experimental-io-devices @@ -168,7 +171,7 @@ ifneq ($(ENABLE_SINGLEPASS), 0) ifeq ($(ENABLE_SINGLEPASS), 1) compilers += singlepass # … otherwise, we try to check whether Singlepass works on this host. - else ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX) $(IS_WINDOWS))) + else ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX) $(IS_FREEBSD) $(IS_WINDOWS))) ifeq ($(IS_AMD64), 1) compilers += singlepass endif @@ -215,7 +218,7 @@ endif ## ifeq ($(ENABLE_LLVM), 1) - ifneq (, $(filter 1, $(IS_WINDOWS) $(IS_DARWIN) $(IS_LINUX))) + ifneq (, $(filter 1, $(IS_WINDOWS) $(IS_DARWIN) $(IS_LINUX) $(IS_FREEBSD))) ifeq ($(IS_AMD64), 1) compilers_engines += llvm-universal else ifeq ($(IS_AARCH64), 1) @@ -229,7 +232,7 @@ endif ## ifeq ($(ENABLE_SINGLEPASS), 1) - ifneq (, $(filter 1, $(IS_WINDOWS) $(IS_DARWIN) $(IS_LINUX))) + ifneq (, $(filter 1, $(IS_WINDOWS) $(IS_DARWIN) $(IS_LINUX) $(IS_FREEBSD))) ifeq ($(IS_AMD64), 1) compilers_engines += singlepass-universal endif @@ -274,7 +277,7 @@ capi_compilers_engines := $(filter-out $(capi_compilers_engines_exclude),$(compi # ##### -ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX))) +ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX) $(IS_FREEBSD))) bold := $(shell tput bold 2>/dev/null || echo -n '') green := $(shell tput setaf 2 2>/dev/null || echo -n '') yellow := $(shell tput setaf 3 2>/dev/null || echo -n '') @@ -335,6 +338,8 @@ SEDI ?= ifeq ($(IS_DARWIN), 1) SEDI := "-i ''" +else ifeq ($(IS_FREEBSD), 1) + SEDI := "-i ''" else ifeq ($(IS_LINUX), 1) SEDI := "-i" endif @@ -528,6 +533,7 @@ test-capi-crate-%: --no-default-features --features wat,compiler,wasi,middlewares,webc_runner $(capi_compiler_features) -- --nocapture test-capi-integration-%: + # note: you need to do make build-capi and make package-capi first! # Test the Wasmer C API tests for C cd lib/c-api/tests; WASMER_CAPI_CONFIG=$(shell echo $@ | sed -e s/test-capi-integration-//) WASMER_DIR=`pwd`/../../../package make test # Test the Wasmer C API examples @@ -561,7 +567,7 @@ generate-wasi-tests: package-wapm: mkdir -p "package/bin" -ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX))) +ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX) $(IS_FREEBSD))) if [ -d "wapm-cli" ]; then \ cp wapm-cli/$(TARGET_DIR)/wapm package/bin/ ;\ echo -e "#!/bin/bash\nwapm execute \"\$$@\"" > package/bin/wax ;\ @@ -662,6 +668,38 @@ package-docs: build-docs build-docs-capi package: package-wasmer package-minimal-headless-wasmer package-capi +package-gnu: package-capi-gnu + +package-capi-gnu: + mkdir -p "package/include" + mkdir -p "package/lib" + cp lib/c-api/wasmer.h* package/include + cp lib/c-api/wasmer_wasm.h* package/include + cp lib/c-api/tests/wasm-c-api/include/wasm.h* package/include + cp lib/c-api/README.md package/include/README.md + if [ -f target/x86_64-pc-windows-gnu/release/wasmer.dll ]; then \ + cp target/x86_64-pc-windows-gnu/release/wasmer.dll package/lib/wasmer.dll ;\ + fi + + if [ -f target/x86_64-pc-windows-gnu/release/wasmer.dll.lib ]; then \ + cp target/x86_64-pc-windows-gnu/release/wasmer.dll.lib package/lib/wasmer.dll.lib ;\ + fi + + if [ -f target/x86_64-pc-windows-gnu/release/wasmer.lib ]; then \ + cp target/x86_64-pc-windows-gnu/release/wasmer.lib package/lib/wasmer.lib ;\ + fi + + if [ -f target/x86_64-pc-windows-gnu/release/libwasmer.a ]; then \ + cp target/x86_64-pc-windows-gnu/release/libwasmer.a package/lib/libwasmer.a ;\ + fi + +distribution-gnu: package-gnu + cp LICENSE package/LICENSE + cp ATTRIBUTIONS.md package/ATTRIBUTIONS + mkdir -p dist + tar -C package -zcvf wasmer.tar.gz lib include winsdk LICENSE ATTRIBUTIONS + mv wasmer.tar.gz dist/ + distribution: package cp LICENSE package/LICENSE cp ATTRIBUTIONS.md package/ATTRIBUTIONS @@ -749,3 +787,6 @@ install-local: package test-minimal-versions: rm -f Cargo.lock cargo +nightly build --tests -Z minimal-versions --all-features + +update-graphql-schema: + curl -sSfL https://registry.wapm.io/graphql/schema.graphql > lib/registry/graphql/schema.graphql diff --git a/README.md b/README.md index d6359c8bd..c1c25c3d0 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ curl https://get.wasmer.io -sSfL | sh * Cargo binstall ```sh - cargo binstall wasmer + cargo binstall wasmer-cli ``` * Cargo diff --git a/build.rs b/build.rs index c5d6b2229..d069178ba 100644 --- a/build.rs +++ b/build.rs @@ -42,6 +42,11 @@ fn main() -> anyhow::Result<()> { wast_processor, )?; test_directory_module(spectests, "tests/wast/spec/proposals/simd", wast_processor)?; + test_directory_module( + spectests, + "tests/wast/spec/proposals/threads", + wast_processor, + )?; // test_directory_module(spectests, "tests/wast/spec/proposals/bulk-memory-operations", wast_processor)?; Ok(()) })?; diff --git a/examples/wasi_pipes.rs b/examples/wasi_pipes.rs index 1a7317773..8f1c41c26 100644 --- a/examples/wasi_pipes.rs +++ b/examples/wasi_pipes.rs @@ -14,7 +14,7 @@ use std::io::{Read, Write}; use wasmer::{Instance, Module, Store}; use wasmer_compiler_cranelift::Cranelift; -use wasmer_wasi::{WasiBidirectionalSharedPipePair, WasiState}; +use wasmer_wasi::{Pipe, WasiState}; fn main() -> Result<(), Box> { let wasm_path = concat!( @@ -36,8 +36,8 @@ fn main() -> Result<(), Box> { println!("Creating `WasiEnv`..."); // First, we create the `WasiEnv` with the stdio pipes - let mut input = WasiBidirectionalSharedPipePair::new().with_blocking(false); - let mut output = WasiBidirectionalSharedPipePair::new().with_blocking(false); + let mut input = Pipe::new(); + let mut output = Pipe::new(); let wasi_env = WasiState::new("hello") .stdin(Box::new(input.clone())) .stdout(Box::new(output.clone())) diff --git a/lib/api/Cargo.toml b/lib/api/Cargo.toml index c5f505ffc..07b0dd5a9 100644 --- a/lib/api/Cargo.toml +++ b/lib/api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer" -version = "3.0.0-rc.2" +version = "3.0.2" description = "High-performance WebAssembly runtime" categories = ["wasm"] keywords = ["wasm", "webassembly", "runtime", "vm"] @@ -31,20 +31,19 @@ bytes = "1" # - Optional shared dependencies. wat = { version = "1.0", optional = true } tracing = { version = "0.1", optional = true } -rkyv = { version = "0.7.38", features = ["indexmap"], optional = true } # Dependencies and Development Dependencies for `sys`. [target.'cfg(not(target_arch = "wasm32"))'.dependencies] # - Mandatory dependencies for `sys`. -wasmer-vm = { path = "../vm", version = "=3.0.0-rc.2" } -wasmer-compiler = { path = "../compiler", version = "=3.0.0-rc.2", optional = true } -wasmer-derive = { path = "../derive", version = "=3.0.0-rc.2" } -wasmer-types = { path = "../types", version = "=3.0.0-rc.2" } +wasmer-vm = { path = "../vm", version = "=3.0.2" } +wasmer-compiler = { path = "../compiler", version = "=3.0.2" } +wasmer-derive = { path = "../derive", version = "=3.0.2" } +wasmer-types = { path = "../types", version = "=3.0.2" } target-lexicon = { version = "0.12.2", default-features = false } # - Optional dependencies for `sys`. -wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "=3.0.0-rc.2", optional = true } -wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "=3.0.0-rc.2", optional = true } -wasmer-compiler-llvm = { path = "../compiler-llvm", version = "=3.0.0-rc.2", optional = true } +wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "=3.0.2", optional = true } +wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "=3.0.2", optional = true } +wasmer-compiler-llvm = { path = "../compiler-llvm", version = "=3.0.2", optional = true } wasm-bindgen = { version = "0.2.74", optional = true } js-sys = { version = "0.3.51", optional = true } @@ -57,16 +56,16 @@ winapi = "0.3" wat = "1.0" tempfile = "3.1" anyhow = "1.0" -macro-wasmer-universal-test = { version = "3.0.0-rc.2", path = "./macro-wasmer-universal-test" } +macro-wasmer-universal-test = { version = "3.0.2", path = "./macro-wasmer-universal-test" } # Dependencies and Develoment Dependencies for `js`. [target.'cfg(target_arch = "wasm32")'.dependencies] # - Mandatory dependencies for `js`. -wasmer-types = { path = "../types", version = "=3.0.0-rc.2", default-features = false, features = ["std"] } +wasmer-types = { path = "../types", version = "=3.0.2", default-features = false, features = ["std"] } wasm-bindgen = "0.2.74" js-sys = "0.3.51" #web-sys = { version = "0.3.51", features = [ "console" ] } -wasmer-derive = { path = "../derive", version = "=3.0.0-rc.2" } +wasmer-derive = { path = "../derive", version = "=3.0.2" } # - Optional dependencies for `js`. wasmparser = { version = "0.83", default-features = false, optional = true } hashbrown = { version = "0.11", optional = true } @@ -78,7 +77,7 @@ serde = { version = "1.0", features = ["derive"] } wat = "1.0" anyhow = "1.0" wasm-bindgen-test = "0.3.0" -macro-wasmer-universal-test = { version = "3.0.0-rc.2", path = "./macro-wasmer-universal-test" } +macro-wasmer-universal-test = { version = "3.0.2", path = "./macro-wasmer-universal-test" } # Specific to `js`. # @@ -98,14 +97,13 @@ core = ["hashbrown"] # Features for `sys`. sys = [ - "compiler", "wasmer-compiler/translator", "wasmer-compiler/compiler", ] sys-default = ["sys", "wat", "cranelift"] # - Compilers. compiler = [ - "wasmer-compiler" + "sys", ] singlepass = ["compiler", "wasmer-compiler-singlepass"] cranelift = ["compiler", "wasmer-compiler-cranelift"] @@ -129,10 +127,6 @@ enable-serde = [ "wasmer-compiler/enable-serde", "wasmer-types/enable-serde", ] -enable-rkyv = [ - "wasmer-types/enable-rkyv", - "wasmer-compiler/enable-rkyv", -] wasmer-artifact-load = ["wasmer-compiler/wasmer-artifact-load"] wasmer-artifact-create = ["wasmer-compiler/wasmer-artifact-create"] diff --git a/lib/api/macro-wasmer-universal-test/Cargo.toml b/lib/api/macro-wasmer-universal-test/Cargo.toml index b09c61d87..c87166daf 100644 --- a/lib/api/macro-wasmer-universal-test/Cargo.toml +++ b/lib/api/macro-wasmer-universal-test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "macro-wasmer-universal-test" -version = "3.0.0-rc.2" +version = "3.0.2" edition = "2021" license = "MIT" description = "Universal test macro for wasmer-test" diff --git a/lib/api/src/js/imports.rs b/lib/api/src/js/imports.rs index 11e486909..80235e2cc 100644 --- a/lib/api/src/js/imports.rs +++ b/lib/api/src/js/imports.rs @@ -132,7 +132,11 @@ impl Imports { /// Resolve and return a vector of imports in the order they are defined in the `module`'s source code. /// /// This means the returned `Vec` might be a subset of the imports contained in `self`. - pub fn imports_for_module(&self, module: &Module) -> Result, LinkError> { + pub fn imports_for_module( + &self, + module: &Module, + _store: &mut impl AsStoreMut, + ) -> Result, LinkError> { let mut ret = vec![]; for import in module.imports() { if let Some(imp) = self diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 186892a06..1404b6fff 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -54,7 +54,7 @@ pub use crate::js::function_env::{FunctionEnv, FunctionEnvMut}; pub use crate::js::imports::Imports; pub use crate::js::instance::Instance; pub use crate::js::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; -pub use crate::js::module::{Module, ModuleTypeHints}; +pub use crate::js::module::{IoCompileError, Module, ModuleTypeHints}; pub use crate::js::native::TypedFunction; pub use crate::js::native_type::NativeWasmTypeInto; pub use crate::js::ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64}; @@ -73,7 +73,6 @@ pub use crate::js::value::Value as Val; pub mod vm { //! The `vm` module re-exports wasmer-vm types. - pub use crate::js::export::VMMemory; } diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 44f4c7b6f..6d003caba 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -26,6 +26,7 @@ use wasmer_types::{ Pages, TableType, Type, }; +/// IO Error on a Module Compilation #[derive(Debug)] #[cfg_attr(feature = "std", derive(Error))] pub enum IoCompileError { diff --git a/lib/api/src/sys/imports.rs b/lib/api/src/sys/imports.rs index 6f7ee931c..f2ceba1ba 100644 --- a/lib/api/src/sys/imports.rs +++ b/lib/api/src/sys/imports.rs @@ -58,16 +58,26 @@ impl Imports { /// import_object.get_export("module", "name"); /// ``` pub fn get_export(&self, module: &str, name: &str) -> Option { - if self - .map - .contains_key(&(module.to_string(), name.to_string())) - { + if self.exists(module, name) { let ext = &self.map[&(module.to_string(), name.to_string())]; return Some(ext.clone()); } None } + /// Returns if an export exist for a given module and name. + /// + /// # Usage + /// ```no_run + /// # use wasmer::Imports; + /// let mut import_object = Imports::new(); + /// import_object.exists("module", "name"); + /// ``` + pub fn exists(&self, module: &str, name: &str) -> bool { + self.map + .contains_key(&(module.to_string(), name.to_string())) + } + /// Returns true if the Imports contains namespace with the provided name. pub fn contains_namespace(&self, name: &str) -> bool { self.map.keys().any(|(k, _)| (k == name)) diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index c810bf817..f81f0be44 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -23,7 +23,7 @@ pub use crate::sys::function_env::{FunctionEnv, FunctionEnvMut}; pub use crate::sys::imports::Imports; pub use crate::sys::instance::{Instance, InstantiationError}; pub use crate::sys::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; -pub use crate::sys::module::Module; +pub use crate::sys::module::{IoCompileError, Module}; pub use crate::sys::native::TypedFunction; pub use crate::sys::native_type::NativeWasmTypeInto; pub use crate::sys::store::{AsStoreMut, AsStoreRef, StoreMut, StoreRef}; @@ -74,9 +74,9 @@ pub use wasmer_compiler_cranelift::{Cranelift, CraneliftOptLevel}; #[cfg(feature = "llvm")] pub use wasmer_compiler_llvm::{LLVMOptLevel, LLVM}; -pub use wasmer_compiler::Engine; #[cfg(feature = "compiler")] pub use wasmer_compiler::{Artifact, EngineBuilder}; +pub use wasmer_compiler::{AsEngineRef, Engine, EngineRef}; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index a63cd1e9d..394f3a1f3 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -1,14 +1,16 @@ use std::fmt; use std::io; -#[cfg(feature = "compiler")] use std::path::Path; use std::sync::Arc; use thiserror::Error; -#[cfg(feature = "compiler")] +use wasmer_compiler::Artifact; use wasmer_compiler::ArtifactCreate; +use wasmer_compiler::AsEngineRef; #[cfg(feature = "wat")] use wasmer_types::WasmError; -use wasmer_types::{CompileError, ExportsIterator, ImportsIterator, ModuleInfo}; +use wasmer_types::{ + CompileError, DeserializeError, ExportsIterator, ImportsIterator, ModuleInfo, SerializeError, +}; use wasmer_types::{ExportType, ImportType}; #[cfg(feature = "compiler")] @@ -16,6 +18,7 @@ use crate::{sys::InstantiationError, AsStoreMut, AsStoreRef, IntoBytes}; #[cfg(feature = "compiler")] use wasmer_vm::InstanceHandle; +/// IO Error on a Module Compilation #[derive(Error, Debug)] pub enum IoCompileError { /// An IO error @@ -50,8 +53,7 @@ pub struct Module { // // In the future, this code should be refactored to properly describe the // ownership of the code and its metadata. - #[cfg(feature = "compiler")] - artifact: Arc, + artifact: Arc, module_info: Arc, } @@ -116,33 +118,38 @@ impl Module { /// # Ok(()) /// # } /// ``` + /// # Example of loading a module using just an `Engine` and no `Store` + /// + /// ``` + /// # use wasmer::*; + /// # + /// # let compiler = Cranelift::default(); + /// # let engine = EngineBuilder::new(compiler).engine(); + /// + /// let module = Module::from_file(&engine, "path/to/foo.wasm"); + /// ``` #[allow(unreachable_code)] - pub fn new(store: &impl AsStoreRef, bytes: impl IntoBytes) -> Result { - #[allow(unused_mut)] - let mut bytes = bytes.into_bytes(); + pub fn new(engine: &impl AsEngineRef, bytes: impl AsRef<[u8]>) -> Result { #[cfg(feature = "wat")] - if bytes.starts_with(b"\0asm") == false { - let parsed_bytes = wat::parse_bytes(&bytes[..]).map_err(|e| { - CompileError::Wasm(WasmError::Generic(format!( - "Error when converting wat: {}", - e - ))) - })?; - bytes = bytes::Bytes::from(parsed_bytes.to_vec()); - } - Self::from_binary(store, bytes.as_ref()) + let bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| { + CompileError::Wasm(WasmError::Generic(format!( + "Error when converting wat: {}", + e + ))) + })?; + Self::from_binary(engine, bytes.as_ref()) } #[cfg(feature = "compiler")] /// Creates a new WebAssembly module from a file path. pub fn from_file( - store: &impl AsStoreRef, + engine: &impl AsEngineRef, file: impl AsRef, ) -> Result { let file_ref = file.as_ref(); let canonical = file_ref.canonicalize()?; let wasm_bytes = std::fs::read(file_ref)?; - let mut module = Self::new(store, &wasm_bytes)?; + let mut module = Self::new(engine, &wasm_bytes)?; // Set the module name to the absolute path of the filename. // This is useful for debugging the stack traces. let filename = canonical.as_path().to_str().unwrap(); @@ -156,9 +163,9 @@ impl Module { /// Opposed to [`Module::new`], this function is not compatible with /// the WebAssembly text format (if the "wat" feature is enabled for /// this crate). - pub fn from_binary(store: &impl AsStoreRef, binary: &[u8]) -> Result { - Self::validate(store, binary)?; - unsafe { Self::from_binary_unchecked(store, binary) } + pub fn from_binary(engine: &impl AsEngineRef, binary: &[u8]) -> Result { + Self::validate(engine, binary)?; + unsafe { Self::from_binary_unchecked(engine, binary) } } #[cfg(feature = "compiler")] @@ -170,11 +177,10 @@ impl Module { /// in environments where the WebAssembly modules are trusted and validated /// beforehand. pub unsafe fn from_binary_unchecked( - store: &impl AsStoreRef, - binary: impl IntoBytes, + engine: &impl AsEngineRef, + binary: &[u8], ) -> Result { - let binary = binary.into_bytes(); - let module = Self::compile(store, binary)?; + let module = Self::compile(engine, binary)?; Ok(module) } @@ -185,24 +191,18 @@ impl Module { /// This validation is normally pretty fast and checks the enabled /// WebAssembly features in the Store Engine to assure deterministic /// validation of the Module. - pub fn validate(store: &impl AsStoreRef, binary: impl IntoBytes) -> Result<(), CompileError> { - let binary = binary.into_bytes(); - store.as_store_ref().engine().validate(&binary[..]) + pub fn validate(engine: &impl AsEngineRef, binary: &[u8]) -> Result<(), CompileError> { + engine.as_engine_ref().engine().validate(binary) } #[cfg(feature = "compiler")] - fn compile(store: &impl AsStoreRef, binary: impl IntoBytes) -> Result { - let binary = binary.into_bytes(); - let artifact = store - .as_store_ref() - .engine() - .compile(&binary[..], store.as_store_ref().tunables())?; + fn compile(engine: &impl AsEngineRef, binary: &[u8]) -> Result { + let artifact = engine.as_engine_ref().engine().compile(binary)?; Ok(Self::from_artifact(artifact)) } /// Serializes a module into a binary representation that the `Engine` /// can later process via - #[cfg(feature = "enable-rkyv")] #[cfg_attr(feature = "compiler", doc = "[`Module::deserialize`].")] #[cfg_attr(not(feature = "compiler"), doc = "`Module::deserialize`.")] /// @@ -217,13 +217,12 @@ impl Module { /// # Ok(()) /// # } /// ``` - pub fn serialize(&self) -> Result { + pub fn serialize(&self) -> Result { self.artifact.serialize().map(|bytes| bytes.into()) } /// Serializes a module into a file that the `Engine` /// can later process via - #[cfg(feature = "enable-rkyv")] #[cfg_attr(feature = "compiler", doc = "[`Module::deserialize_from_file`].")] #[cfg_attr(not(feature = "compiler"), doc = "`Module::deserialize_from_file`.")] /// @@ -238,14 +237,10 @@ impl Module { /// # Ok(()) /// # } /// ``` - pub fn serialize_to_file( - &self, - path: impl AsRef, - ) -> Result<(), wasmer_types::SerializeError> { + pub fn serialize_to_file(&self, path: impl AsRef) -> Result<(), SerializeError> { self.artifact.serialize_to_file(path.as_ref()) } - #[cfg(feature = "enable-rkyv")] #[cfg(feature = "compiler")] /// Deserializes a serialized Module binary into a `Module`. /// > Note: the module has to be serialized before with the `serialize` method. @@ -273,13 +268,12 @@ impl Module { pub unsafe fn deserialize( store: &impl AsStoreRef, bytes: impl IntoBytes, - ) -> Result { - let bytes = bytes.into_bytes().to_vec(); + ) -> Result { + let bytes = bytes.into_bytes(); let artifact = store.as_store_ref().engine().deserialize(&bytes)?; Ok(Self::from_artifact(artifact)) } - #[cfg(feature = "enable-rkyv")] #[cfg(feature = "compiler")] /// Deserializes a a serialized Module located in a `Path` into a `Module`. /// > Note: the module has to be serialized before with the `serialize` method. @@ -301,7 +295,7 @@ impl Module { pub unsafe fn deserialize_from_file( store: &impl AsStoreRef, path: impl AsRef, - ) -> Result { + ) -> Result { let artifact = store .as_store_ref() .engine() @@ -309,8 +303,7 @@ impl Module { Ok(Self::from_artifact(artifact)) } - #[cfg(feature = "compiler")] - fn from_artifact(artifact: Arc) -> Self { + fn from_artifact(artifact: Arc) -> Self { Self { module_info: Arc::new(artifact.create_module_info()), artifact, diff --git a/lib/api/src/sys/store.rs b/lib/api/src/sys/store.rs index 3da344ac2..16fd9ef23 100644 --- a/lib/api/src/sys/store.rs +++ b/lib/api/src/sys/store.rs @@ -1,13 +1,10 @@ -#[cfg(feature = "compiler")] use crate::sys::tunables::BaseTunables; use derivative::Derivative; use std::fmt; #[cfg(feature = "compiler")] -use wasmer_compiler::{Engine, EngineBuilder, Tunables}; +use wasmer_compiler::{AsEngineRef, Engine, EngineBuilder, EngineRef, Tunables}; +use wasmer_vm::{init_traps, StoreId, TrapHandler, TrapHandlerFn}; use wasmer_types::{OnCalledAction, StoreSnapshot}; -#[cfg(feature = "compiler")] -use wasmer_vm::init_traps; -use wasmer_vm::{StoreId, TrapHandler, TrapHandlerFn}; use wasmer_vm::StoreObjects; @@ -22,9 +19,6 @@ pub(crate) struct StoreInner { #[cfg(feature = "compiler")] pub(crate) engine: Engine, #[derivative(Debug = "ignore")] - #[cfg(feature = "compiler")] - pub(crate) tunables: Box, - #[derivative(Debug = "ignore")] pub(crate) trap_handler: Option>>, #[derivative(Debug = "ignore")] pub(crate) on_called: Option< @@ -55,10 +49,7 @@ impl StoreInner { /// have been allocated during the lifetime of the abstract machine. /// /// The `Store` holds the engine (that is —amongst many things— used to compile -/// the Wasm bytes into a valid module artifact), in addition to the -#[cfg_attr(feature = "compiler", doc = "[`Tunables`]")] -#[cfg_attr(not(feature = "compiler"), doc = "`Tunables`")] -/// (that are used to create the memories, tables and globals). +/// the Wasm bytes into a valid module artifact). /// /// Spec: pub struct Store { @@ -72,8 +63,21 @@ impl Store { /// Creates a new `Store` with a specific [`Engine`]. pub fn new(engine: impl Into) -> Self { let engine = engine.into(); - let target = engine.target().clone(); - Self::new_with_tunables(engine, BaseTunables::for_target(&target)) + + // Make sure the signal handlers are installed. + // This is required for handling traps. + init_traps(); + + Self { + inner: Box::new(StoreInner { + objects: Default::default(), + engine: engine.cloned(), + trap_handler: None, + on_called: None, + }), + engine: engine.cloned(), + trap_handler: Arc::new(RwLock::new(None)), + } } #[cfg(feature = "compiler")] @@ -97,28 +101,16 @@ impl Store { engine: impl Into, tunables: impl Tunables + Send + Sync + 'static, ) -> Self { - let engine = engine.into(); + let mut engine = engine.into(); + engine.set_tunables(tunables); - // Make sure the signal handlers are installed. - // This is required for handling traps. - init_traps(); - - Self { - inner: Box::new(StoreInner { - objects: Default::default(), - engine: engine.cloned(), - tunables: Box::new(tunables), - trap_handler: None, - on_called: None, - }), - engine: engine.cloned(), - } + Self::new(engine) } #[cfg(feature = "compiler")] /// Returns the [`Tunables`]. pub fn tunables(&self) -> &dyn Tunables { - self.inner.tunables.as_ref() + self.engine.tunables() } #[cfg(feature = "compiler")] @@ -236,6 +228,34 @@ impl AsStoreMut for Store { } } +#[cfg(feature = "compiler")] +impl AsEngineRef for Store { + fn as_engine_ref(&self) -> EngineRef<'_> { + EngineRef::new(&self.engine) + } +} + +#[cfg(feature = "compiler")] +impl AsEngineRef for &Store { + fn as_engine_ref(&self) -> EngineRef<'_> { + EngineRef::new(&self.engine) + } +} + +#[cfg(feature = "compiler")] +impl AsEngineRef for StoreRef<'_> { + fn as_engine_ref(&self) -> EngineRef<'_> { + EngineRef::new(&self.inner.engine) + } +} + +#[cfg(feature = "compiler")] +impl AsEngineRef for StoreMut<'_> { + fn as_engine_ref(&self) -> EngineRef<'_> { + EngineRef::new(&self.inner.engine) + } +} + impl fmt::Debug for Store { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Store").finish() @@ -255,7 +275,7 @@ impl<'a> StoreRef<'a> { #[cfg(feature = "compiler")] /// Returns the [`Tunables`]. pub fn tunables(&self) -> &dyn Tunables { - self.inner.tunables.as_ref() + self.inner.engine.tunables() } #[cfg(feature = "compiler")] @@ -296,7 +316,7 @@ impl<'a> StoreMut<'a> { /// Returns the [`Tunables`]. #[cfg(feature = "compiler")] pub fn tunables(&self) -> &dyn Tunables { - self.inner.tunables.as_ref() + self.inner.engine.tunables() } /// Returns the [`Engine`]. @@ -325,10 +345,9 @@ impl<'a> StoreMut<'a> { #[cfg(feature = "compiler")] pub(crate) fn tunables_and_objects_mut(&mut self) -> (&dyn Tunables, &mut StoreObjects) { - (self.inner.tunables.as_ref(), &mut self.inner.objects) + (self.inner.engine.tunables(), &mut self.inner.objects) } - #[cfg(feature = "compiler")] pub(crate) fn as_raw(&self) -> *mut StoreInner { self.inner as *const StoreInner as *mut StoreInner } diff --git a/lib/api/src/sys/tunables.rs b/lib/api/src/sys/tunables.rs index b48f2ea6c..e8866abe7 100644 --- a/lib/api/src/sys/tunables.rs +++ b/lib/api/src/sys/tunables.rs @@ -1,140 +1,20 @@ -use crate::sys::{MemoryType, Pages, TableType}; -use std::ptr::NonNull; -use wasmer_compiler::Tunables; -use wasmer_types::{PointerWidth, Target}; -use wasmer_vm::MemoryError; -use wasmer_vm::{ - MemoryStyle, TableStyle, VMMemory, VMMemoryDefinition, VMTable, VMTableDefinition, -}; +pub use wasmer_compiler::BaseTunables; -/// Tunable parameters for WebAssembly compilation. -/// This is the reference implementation of the `Tunables` trait, -/// used by default. -/// -/// You can use this as a template for creating a custom Tunables -/// implementation or use composition to wrap your Tunables around -/// this one. The later approach is demonstrated in the -/// tunables-limit-memory example. -#[derive(Clone)] -pub struct BaseTunables { - /// 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 BaseTunables { - /// 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, - } - } -} - -impl Tunables for BaseTunables { - /// Get a `MemoryStyle` for the provided `MemoryType` - 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`]. - fn table_style(&self, _table: &TableType) -> TableStyle { - TableStyle::CallerChecksSignature - } - - /// Create a memory owned by the host given a [`MemoryType`] and a [`MemoryStyle`]. - fn create_host_memory( - &self, - ty: &MemoryType, - style: &MemoryStyle, - ) -> Result { - VMMemory::new(ty, style) - } - - /// Create a memory owned by the VM given a [`MemoryType`] and a [`MemoryStyle`]. - /// - /// # Safety - /// - `vm_definition_location` must point to a valid, owned `VMMemoryDefinition`, - /// for example in `VMContext`. - unsafe fn create_vm_memory( - &self, - ty: &MemoryType, - style: &MemoryStyle, - vm_definition_location: NonNull, - ) -> Result { - VMMemory::from_definition(ty, style, vm_definition_location) - } - - /// Create a table owned by the host given a [`TableType`] and a [`TableStyle`]. - fn create_host_table(&self, ty: &TableType, style: &TableStyle) -> Result { - VMTable::new(ty, style) - } - - /// Create a table owned by the VM given a [`TableType`] and a [`TableStyle`]. - /// - /// # Safety - /// - `vm_definition_location` must point to a valid, owned `VMTableDefinition`, - /// for example in `VMContext`. - unsafe fn create_vm_table( - &self, - ty: &TableType, - style: &TableStyle, - vm_definition_location: NonNull, - ) -> Result { - VMTable::from_definition(ty, style, vm_definition_location) - } -} +// All BaseTunable definition now is in wasmer_compile crate +// Tests are still here #[cfg(test)] mod tests { use super::*; + use crate::sys::TableType; + use std::cell::UnsafeCell; + use std::ptr::NonNull; + use wasmer_compiler::Tunables; + use wasmer_types::{MemoryType, Pages, WASM_PAGE_SIZE}; + use wasmer_vm::{ + LinearMemory, MemoryError, MemoryStyle, TableStyle, VMMemory, VMMemoryDefinition, VMTable, + VMTableDefinition, + }; #[test] fn memory_style() { @@ -175,11 +55,6 @@ mod tests { } } - use std::cell::UnsafeCell; - use std::ptr::NonNull; - use wasmer_types::{MemoryError, MemoryStyle, MemoryType, Pages, WASM_PAGE_SIZE}; - use wasmer_vm::LinearMemory; - #[derive(Debug)] struct VMTinyMemory { mem: Vec, diff --git a/lib/api/tests/externals.rs b/lib/api/tests/externals.rs index f593c763b..5c17579a4 100644 --- a/lib/api/tests/externals.rs +++ b/lib/api/tests/externals.rs @@ -210,25 +210,28 @@ fn memory_grow() -> Result<(), String> { fn function_new() -> Result<(), String> { let mut store = Store::default(); let function = Function::new_typed(&mut store, || {}); - assert_eq!(function.ty(&mut store), FunctionType::new(vec![], vec![])); + assert_eq!( + function.ty(&mut store).clone(), + FunctionType::new(vec![], vec![]) + ); let function = Function::new_typed(&mut store, |_a: i32| {}); assert_eq!( - function.ty(&mut store), + function.ty(&mut store).clone(), FunctionType::new(vec![Type::I32], vec![]) ); let function = Function::new_typed(&mut store, |_a: i32, _b: i64, _c: f32, _d: f64| {}); assert_eq!( - function.ty(&mut store), + function.ty(&mut store).clone(), FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]) ); let function = Function::new_typed(&mut store, || -> i32 { 1 }); assert_eq!( - function.ty(&mut store), + function.ty(&mut store).clone(), FunctionType::new(vec![], vec![Type::I32]) ); let function = Function::new_typed(&mut store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) }); assert_eq!( - function.ty(&mut store), + function.ty(&mut store).clone(), FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]) ); Ok(()) @@ -243,11 +246,14 @@ fn function_new_env() -> Result<(), String> { let my_env = MyEnv {}; let env = FunctionEnv::new(&mut store, my_env); let function = Function::new_typed_with_env(&mut store, &env, |_env: FunctionEnvMut| {}); - assert_eq!(function.ty(&mut store), FunctionType::new(vec![], vec![])); + assert_eq!( + function.ty(&mut store).clone(), + FunctionType::new(vec![], vec![]) + ); let function = Function::new_typed_with_env(&mut store, &env, |_env: FunctionEnvMut, _a: i32| {}); assert_eq!( - function.ty(&mut store), + function.ty(&mut store).clone(), FunctionType::new(vec![Type::I32], vec![]) ); let function = Function::new_typed_with_env( @@ -256,13 +262,13 @@ fn function_new_env() -> Result<(), String> { |_env: FunctionEnvMut, _a: i32, _b: i64, _c: f32, _d: f64| {}, ); assert_eq!( - function.ty(&mut store), + function.ty(&mut store).clone(), FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]) ); let function = Function::new_typed_with_env(&mut store, &env, |_env: FunctionEnvMut| -> i32 { 1 }); assert_eq!( - function.ty(&mut store), + function.ty(&mut store).clone(), FunctionType::new(vec![], vec![Type::I32]) ); let function = Function::new_typed_with_env( @@ -271,7 +277,7 @@ fn function_new_env() -> Result<(), String> { |_env: FunctionEnvMut| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) }, ); assert_eq!( - function.ty(&mut store), + function.ty(&mut store).clone(), FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]) ); Ok(()) @@ -288,35 +294,35 @@ fn function_new_dynamic() -> Result<(), String> { &function_type, |_values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store), function_type); + assert_eq!(function.ty(&mut store).clone(), function_type); let function_type = FunctionType::new(vec![Type::I32], vec![]); let function = Function::new( &mut store, &function_type, |_values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store), function_type); + assert_eq!(function.ty(&mut store).clone(), function_type); let function_type = FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]); let function = Function::new( &mut store, &function_type, |_values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store), function_type); + assert_eq!(function.ty(&mut store).clone(), function_type); let function_type = FunctionType::new(vec![], vec![Type::I32]); let function = Function::new( &mut store, &function_type, |_values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store), function_type); + assert_eq!(function.ty(&mut store).clone(), function_type); let function_type = FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]); let function = Function::new( &mut store, &function_type, |_values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store), function_type); + assert_eq!(function.ty(&mut store).clone(), function_type); // Using array signature let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]); @@ -350,7 +356,7 @@ fn function_new_dynamic_env() -> Result<(), String> { &function_type, |_env: FunctionEnvMut, _values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store), function_type); + assert_eq!(function.ty(&mut store).clone(), function_type); let function_type = FunctionType::new(vec![Type::I32], vec![]); let function = Function::new_with_env( &mut store, @@ -358,7 +364,7 @@ fn function_new_dynamic_env() -> Result<(), String> { &function_type, |_env: FunctionEnvMut, _values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store), function_type); + assert_eq!(function.ty(&mut store).clone(), function_type); let function_type = FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]); let function = Function::new_with_env( &mut store, @@ -366,7 +372,7 @@ fn function_new_dynamic_env() -> Result<(), String> { &function_type, |_env: FunctionEnvMut, _values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store), function_type); + assert_eq!(function.ty(&mut store).clone(), function_type); let function_type = FunctionType::new(vec![], vec![Type::I32]); let function = Function::new_with_env( &mut store, @@ -374,7 +380,7 @@ fn function_new_dynamic_env() -> Result<(), String> { &function_type, |_env: FunctionEnvMut, _values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store), function_type); + assert_eq!(function.ty(&mut store).clone(), function_type); let function_type = FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]); let function = Function::new_with_env( &mut store, @@ -382,7 +388,7 @@ fn function_new_dynamic_env() -> Result<(), String> { &function_type, |_env: FunctionEnvMut, _values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store), function_type); + assert_eq!(function.ty(&mut store).clone(), function_type); // Using array signature let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]); diff --git a/lib/api/tests/reference_types.rs b/lib/api/tests/reference_types.rs index 46b86da77..7e6a6967b 100644 --- a/lib/api/tests/reference_types.rs +++ b/lib/api/tests/reference_types.rs @@ -364,7 +364,7 @@ pub mod reference_types { let global: &Global = instance.exports.get_global("global")?; { let er = ExternRef::new(&mut store, 3usize); - global.set(&mut store, Value::ExternRef(Some(er)))?; + global.set(&mut store, Value::ExternRef(Some(er.clone())))?; } let get_from_global: TypedFunction<(), Option> = instance .exports @@ -395,7 +395,7 @@ pub mod reference_types { let er = ExternRef::new(&mut store, 3usize); - let result = pass_extern_ref.call(&mut store, Some(er)); + let result = pass_extern_ref.call(&mut store, Some(er.clone())); assert!(result.is_err()); Ok(()) @@ -439,7 +439,7 @@ pub mod reference_types { let result = grow_table_with_ref.call(&mut store, Some(er1.clone()), 10_000)?; assert_eq!(result, -1); - let result = grow_table_with_ref.call(&mut store, Some(er1), 8)?; + let result = grow_table_with_ref.call(&mut store, Some(er1.clone()), 8)?; assert_eq!(result, 2); for i in 2..10 { @@ -451,7 +451,7 @@ pub mod reference_types { } { - fill_table_with_ref.call(&mut store, Some(er2), 0, 2)?; + fill_table_with_ref.call(&mut store, Some(er2.clone()), 0, 2)?; } { @@ -459,7 +459,7 @@ pub mod reference_types { table2.set(&mut store, 1, Value::ExternRef(Some(er3.clone())))?; table2.set(&mut store, 2, Value::ExternRef(Some(er3.clone())))?; table2.set(&mut store, 3, Value::ExternRef(Some(er3.clone())))?; - table2.set(&mut store, 4, Value::ExternRef(Some(er3)))?; + table2.set(&mut store, 4, Value::ExternRef(Some(er3.clone())))?; } { diff --git a/lib/c-api/Cargo.toml b/lib/c-api/Cargo.toml index 947b6283a..a180b5051 100644 --- a/lib/c-api/Cargo.toml +++ b/lib/c-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-c-api" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Wasmer C API library" categories = ["wasm", "api-bindings"] keywords = ["wasm", "webassembly", "runtime"] @@ -22,16 +22,16 @@ crate-type = ["staticlib", "cdylib"] #"cdylib", "rlib", "staticlib"] [dependencies] # We rename `wasmer` to `wasmer-api` to avoid the conflict with this # library name (see `[lib]`). -wasmer-api = { version = "=3.0.0-rc.2", path = "../api", default-features = false, features = ["sys"], package = "wasmer" } -wasmer-compiler-cranelift = { version = "=3.0.0-rc.2", path = "../compiler-cranelift", optional = true } -wasmer-compiler-singlepass = { version = "=3.0.0-rc.2", path = "../compiler-singlepass", optional = true } -wasmer-compiler-llvm = { version = "=3.0.0-rc.2", path = "../compiler-llvm", optional = true } -wasmer-emscripten = { version = "=3.0.0-rc.2", path = "../emscripten", optional = true } -wasmer-compiler = { version = "=3.0.0-rc.2", path = "../compiler" } -wasmer-middlewares = { version = "=3.0.0-rc.2", path = "../middlewares", optional = true } -wasmer-wasi = { version = "=3.0.0-rc.2", path = "../wasi", default-features = false, features = ["host-fs", "sys"], optional = true } -wasmer-types = { version = "=3.0.0-rc.2", path = "../types" } -wasmer-vfs = { version = "=3.0.0-rc.2", path = "../vfs", optional = true, default-features = false, features = ["static-fs"] } +wasmer-api = { version = "=3.0.2", path = "../api", default-features = false, features = ["sys"], package = "wasmer" } +wasmer-compiler-cranelift = { version = "=3.0.2", path = "../compiler-cranelift", optional = true } +wasmer-compiler-singlepass = { version = "=3.0.2", path = "../compiler-singlepass", optional = true } +wasmer-compiler-llvm = { version = "=3.0.2", path = "../compiler-llvm", optional = true } +wasmer-emscripten = { version = "=3.0.2", path = "../emscripten", optional = true } +wasmer-compiler = { version = "=3.0.2", path = "../compiler" } +wasmer-middlewares = { version = "=3.0.2", path = "../middlewares", optional = true } +wasmer-wasi = { version = "=3.0.2", path = "../wasi", default-features = false, features = ["host-fs", "sys"], optional = true } +wasmer-types = { version = "=3.0.2", path = "../types" } +wasmer-vfs = { version = "=3.0.2", path = "../vfs", optional = true, default-features = false, features = ["static-fs"] } webc = { version = "3.0.1", optional = true } enumset = "1.0.2" cfg-if = "1.0" 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 baf65d0f6..d7300cf99 100644 --- a/lib/c-api/examples/wasmer-capi-examples-runner/Cargo.toml +++ b/lib/c-api/examples/wasmer-capi-examples-runner/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-capi-examples-runner" -version = "3.0.0-rc.2" +version = "3.0.2" edition = "2021" license = "MIT" description = "wasmer-capi-examples-runner" 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 780930658..ab1bc28b3 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -11,647 +11,22 @@ use super::{ types::wasm_byte_vec_t, }; use crate::error::update_last_error; -use std::convert::TryInto; +use std::convert::TryFrom; use std::ffi::CStr; use std::os::raw::c_char; use std::slice; -use std::sync::{Arc, Mutex}; -use std::{ - convert::TryFrom, - ffi::c_void, - fmt, - io::{self, SeekFrom}, - sync::MutexGuard, -}; #[cfg(feature = "webc_runner")] use wasmer_api::{AsStoreMut, Imports, Module}; use wasmer_wasi::{ - get_wasi_version, FsError, VirtualFile, WasiBidirectionalPipePair, WasiFile, WasiFunctionEnv, - WasiPipe, WasiState, WasiStateBuilder, WasiVersion, + get_wasi_version, Pipe, WasiFile, WasiFunctionEnv, WasiState, WasiStateBuilder, WasiVersion, }; -/// Function callback that takes: -/// -/// - a *mut to the environment data (passed in on creation), -/// - the length of the environment data -/// - a *const to the bytes to write -/// - the length of the bytes to write -pub type WasiConsoleIoReadCallback = unsafe extern "C" fn(*const c_void, *mut c_char, usize) -> i64; -pub type WasiConsoleIoWriteCallback = - unsafe extern "C" fn(*const c_void, *const c_char, usize, bool) -> i64; -pub type WasiConsoleIoSeekCallback = unsafe extern "C" fn(*const c_void, c_char, i64) -> i64; -pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn(*const c_void) -> i64; - -/// The console override is a custom context consisting of callback pointers -/// (which are activated whenever some console I/O occurs) and a "context", which -/// can be owned or referenced from C. This struct can be used in `wasi_config_overwrite_stdin`, -/// `wasi_config_overwrite_stdout` or `wasi_config_overwrite_stderr` to redirect the output or -/// insert input into the console I/O log. -/// -/// Internally the stdout / stdin is synchronized, so the console is usable across threads -/// (only one thread can read / write / seek from the console I/O) -#[allow(non_camel_case_types)] -#[allow(clippy::box_collection, clippy::redundant_allocation)] -#[repr(C)] -#[derive(Clone)] -pub struct wasi_pipe_t { - read: WasiConsoleIoReadCallback, - write: WasiConsoleIoWriteCallback, - seek: WasiConsoleIoSeekCallback, - data: Option>>>, -} - -#[derive(Debug)] -struct WasiPipeDataWithDestructor { - data: Vec, - // Buffer of already-read data that is being read into, - // then the result is returned - temp_buffer: Vec, - destructor: WasiConsoleIoEnvDestructor, -} - -impl WasiPipeDataWithDestructor { - fn read_buffer( - &mut self, - read_cb: WasiConsoleIoReadCallback, - max_read: Option, - ) -> io::Result { - const BLOCK_SIZE: usize = 1024; - - let mut final_buf = Vec::new(); - - let max_to_read = max_read.unwrap_or(usize::MAX); - let max_read = max_to_read.saturating_sub(self.temp_buffer.len()); - if max_read == 0 { - // there are n bytes being available to read in the temp_buffer - return Ok(max_to_read); - } - let mut cur_read = 0; - - // Read bytes until either EOF is reached or max_read bytes are reached - loop { - if cur_read >= max_read { - break; - } - - let mut temp_buffer = if cur_read + BLOCK_SIZE > max_read { - vec![0; max_read - cur_read] - } else { - vec![0; BLOCK_SIZE] - }; - - let result = unsafe { - let ptr = temp_buffer.as_mut_ptr() as *mut c_char; - (read_cb)( - self.data.as_mut_ptr() as *const c_void, - ptr, - temp_buffer.len(), - ) - }; - - if result < 0 { - return Err(io::Error::new( - io::ErrorKind::Other, - format!("could not read from wasi_pipe_t: {result}"), - )); - } - - let result = result as usize; - if result == 0 || result > temp_buffer.len() { - break; // EOF - } - - cur_read += result; - final_buf.extend_from_slice(&temp_buffer[..result]); - } - - let final_buf_len = final_buf.len(); - - // store the bytes in temp_buffer - self.temp_buffer.extend_from_slice(&final_buf); - - // temp_buffer.len() can be smaller than max_read in case we - // encounter EOF earlier than expected - assert!(self.temp_buffer.len() <= max_read); - - // return how many bytes were just read - // - // caller has to clear temp_buffer to advance actual reading - Ok(final_buf_len) - } -} - -impl Drop for WasiPipeDataWithDestructor { - fn drop(&mut self) { - let error = unsafe { (self.destructor)(self.data.as_mut_ptr() as *const c_void) }; - if error < 0 { - panic!("error dropping wasi_pipe_t: {}", error); - } - } -} - -impl wasi_pipe_t { - fn get_data_mut( - &self, - op_id: &'static str, - ) -> io::Result> { - self.data - .as_ref() - .ok_or_else(|| { - io::Error::new( - io::ErrorKind::Other, - format!("could not lock mutex ({op_id}) on wasi_pipe_t: no mutex"), - ) - })? - .lock() - .map_err(|e| { - io::Error::new( - io::ErrorKind::Other, - format!("could not lock mutex ({op_id}) on wasi_pipe_t: {e}"), - ) - }) - } -} - -impl fmt::Debug for wasi_pipe_t { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "wasi_pipe_t") - } -} - -impl io::Read for wasi_pipe_t { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let self_read = self.read; - let mut data = self.get_data_mut("read")?; - let _ = data.read_buffer(self_read, Some(buf.len()))?; - let bytes_to_read = buf.len().min(data.temp_buffer.len()); - let bytes_read = data.temp_buffer.drain(..bytes_to_read).collect::>(); - buf[..bytes_read.len()].clone_from_slice(&bytes_read); - Ok(bytes_to_read) - } -} - -impl io::Write for wasi_pipe_t { - fn write(&mut self, buf: &[u8]) -> io::Result { - let self_write = self.write; - let mut data = self.get_data_mut("write")?; - let result = unsafe { - (self_write)( - data.data.as_mut_ptr() as *const c_void, - buf.as_ptr() as *const c_char, - buf.len(), - false, - ) - }; - if result >= 0 { - Ok(result.try_into().unwrap_or(0)) - } else { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - format!( - "could not write {} bytes to wasi_pipe_t: {result}", - buf.len() - ), - )) - } - } - fn flush(&mut self) -> io::Result<()> { - let self_write = self.write; - let mut data = self.get_data_mut("flush")?; - let bytes_to_write = &[]; - let result: i64 = unsafe { - (self_write)( - data.data.as_mut_ptr() as *const c_void, - bytes_to_write.as_ptr(), - 0, - true, - ) - }; - if result >= 0 { - Ok(()) - } else { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - format!("could not flush wasi_pipe_t: {result}"), - )) - } - } -} - -impl io::Seek for wasi_pipe_t { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - let self_seek = self.seek; - let mut data = self.get_data_mut("seek")?; - let (id, pos) = match pos { - SeekFrom::Start(s) => (0, s as i64), - SeekFrom::End(s) => (1, s), - SeekFrom::Current(s) => (2, s), - }; - let result = unsafe { (self_seek)(data.data.as_mut_ptr() as *const c_void, id, pos) }; - if result >= 0 { - Ok(result.try_into().unwrap_or(0)) - } else { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - format!("could not seek to {pos:?} wasi_pipe_t: {result}"), - )) - } - } -} - -impl VirtualFile for wasi_pipe_t { - fn last_accessed(&self) -> u64 { - 0 - } - fn last_modified(&self) -> u64 { - 0 - } - fn created_time(&self) -> u64 { - 0 - } - fn size(&self) -> u64 { - 0 - } - fn set_len(&mut self, _: u64) -> Result<(), FsError> { - Ok(()) - } - fn unlink(&mut self) -> Result<(), FsError> { - Ok(()) - } - fn bytes_available(&self) -> Result { - Ok(self.bytes_available_read()?.unwrap_or(0usize) - + self.bytes_available_write()?.unwrap_or(0usize)) - } - fn bytes_available_read(&self) -> Result, FsError> { - let self_read = self.read; - let mut data = self.get_data_mut("bytes_available_read")?; - let _ = data.read_buffer(self_read, None)?; - Ok(Some(data.temp_buffer.len())) - } - fn bytes_available_write(&self) -> Result, FsError> { - Ok(None) - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_pipe_new_internal( - read: WasiConsoleIoReadCallback, - write: WasiConsoleIoWriteCallback, - seek: WasiConsoleIoSeekCallback, - destructor: WasiConsoleIoEnvDestructor, - env_data: *const c_void, - env_data_len: usize, -) -> *mut wasi_pipe_t { - let data_vec: Vec = - std::slice::from_raw_parts(env_data as *const c_char, env_data_len).to_vec(); - - Box::leak(Box::new(wasi_pipe_t { - read, - write, - seek, - data: Some(Box::new(Arc::new(Mutex::new(WasiPipeDataWithDestructor { - data: data_vec, - temp_buffer: Vec::new(), - destructor, - })))), - })) -} - -/// Creates a `wasi_pipe_t` callback object that does nothing -/// and redirects stdout / stderr to /dev/null -#[no_mangle] -pub unsafe extern "C" fn wasi_pipe_new_null() -> *mut wasi_pipe_t { - let mut data = Vec::new(); - wasi_pipe_new_internal( - wasi_pipe_read_null, - wasi_pipe_write_null, - wasi_pipe_seek_null, - wasi_pipe_delete_null, - data.as_mut_ptr(), - data.len(), - ) -} - -extern "C" fn wasi_pipe_read_null(_: *const c_void, _: *mut c_char, _: usize) -> i64 { - 0 -} - -extern "C" fn wasi_pipe_write_null(_: *const c_void, _: *const c_char, _: usize, _: bool) -> i64 { - 0 -} - -extern "C" fn wasi_pipe_seek_null(_: *const c_void, _: c_char, _: i64) -> i64 { - 0 -} - -extern "C" fn wasi_pipe_delete_null(_: *const c_void) -> i64 { - 0 -} - -unsafe extern "C" fn wasi_pipe_read_memory_2( - ptr: *const c_void, /* = *WasiPipe */ - byte_ptr: *mut c_char, /* &[u8] bytes to read */ - max_bytes: usize, /* max bytes to read */ -) -> i64 { - use std::io::Read; - let ptr = ptr as *mut WasiPipe; - let ptr = &mut *ptr; - let slice = std::slice::from_raw_parts_mut(byte_ptr as *mut u8, max_bytes); - match ptr.read(slice) { - Ok(o) => o as i64, - Err(_) => -1, - } -} - -unsafe extern "C" fn wasi_pipe_write_memory_2( - ptr: *const c_void, /* = *WasiPipe */ - byte_ptr: *const c_char, - byte_len: usize, - flush: bool, -) -> i64 { - use std::io::Write; - - let ptr = ptr as *mut WasiPipe; - let ptr = &mut *ptr; - - if flush { - match ptr.flush() { - Ok(()) => 0, - Err(_) => -1, - } - } else { - let slice = std::slice::from_raw_parts(byte_ptr as *const u8, byte_len); - match ptr.write(slice) { - Ok(o) => o as i64, - Err(_) => -1, - } - } -} - -unsafe extern "C" fn wasi_pipe_seek_memory_2( - ptr: *const c_void, /* = *WasiPipe */ - direction: c_char, - seek_to: i64, -) -> i64 { - use std::io::Seek; - - let ptr = ptr as *mut WasiPipe; - let ptr = &mut *ptr; - - let seek_from = match direction { - 0 => std::io::SeekFrom::Start(seek_to.max(0) as u64), - 1 => std::io::SeekFrom::End(seek_to), - 2 => std::io::SeekFrom::Current(seek_to), - _ => { - return -1; - } - }; - - match ptr.seek(seek_from) { - Ok(o) => o as i64, - Err(_) => -1, - } -} - -#[no_mangle] -unsafe extern "C" fn wasi_pipe_delete_memory_2(ptr: *const c_void /* = *WasiPipe */) -> i64 { - let ptr = ptr as *const WasiPipe; - let mut pipe: WasiPipe = std::mem::transmute_copy(&*ptr); // dropped here, destructors run here - pipe.close(); - 0 -} - -/// Creates a new `wasi_pipe_t` which uses a memory buffer -/// for backing stdin / stdout / stderr -#[no_mangle] -pub unsafe extern "C" fn wasi_pipe_new(ptr_user: &mut *mut wasi_pipe_t) -> *mut wasi_pipe_t { - wasi_pipe_new_internal_memory(ptr_user, false) -} - -/// Same as `wasi_pipe_new`, but the pipe will block to wait for stdin input -#[no_mangle] -pub unsafe extern "C" fn wasi_pipe_new_blocking( - ptr_user: &mut *mut wasi_pipe_t, -) -> *mut wasi_pipe_t { - wasi_pipe_new_internal_memory(ptr_user, true) -} - -unsafe fn wasi_pipe_new_internal_memory( - ptr_user: &mut *mut wasi_pipe_t, - blocking: bool, -) -> *mut wasi_pipe_t { - use std::mem::ManuallyDrop; - - let mut pair = WasiBidirectionalPipePair::new(); - pair.send.set_blocking(blocking); - pair.recv.set_blocking(blocking); - - let mut data1 = ManuallyDrop::new(pair.send); - let ptr1: &mut WasiPipe = &mut data1; - - *ptr_user = wasi_pipe_new_internal( - wasi_pipe_read_memory_2, - wasi_pipe_write_memory_2, - wasi_pipe_seek_memory_2, - wasi_pipe_delete_memory_2, - ptr1 as *mut _ as *mut c_void, - std::mem::size_of::(), - ); - - let mut data2 = ManuallyDrop::new(pair.recv); - let ptr2: &mut WasiPipe = &mut data2; - wasi_pipe_new_internal( - wasi_pipe_read_memory_2, - wasi_pipe_write_memory_2, - wasi_pipe_seek_memory_2, - wasi_pipe_delete_memory_2, - ptr2 as *mut _ as *mut c_void, - std::mem::size_of::(), - ) -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_pipe_delete(ptr: *mut wasi_pipe_t) -> bool { - let _ = Box::from_raw(ptr); - true -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_pipe_write_bytes( - ptr: *mut wasi_pipe_t, - buf: *const c_char, - len: usize, -) -> i64 { - use std::io::Write; - let buf = buf as *const u8; - let ptr = &mut *ptr; - let read_slice = std::slice::from_raw_parts(buf, len); - match ptr.write(read_slice) { - Ok(o) => o as i64, - Err(_) => -1, - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_pipe_write_str(ptr: *const wasi_pipe_t, buf: *const c_char) -> i64 { - use std::io::Write; - let c_str = std::ffi::CStr::from_ptr(buf); - let as_bytes_with_nul = c_str.to_bytes(); - let ptr = &mut *(ptr as *mut wasi_pipe_t); - match ptr.write(as_bytes_with_nul) { - Ok(o) => o as i64, - Err(_) => -1, - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_pipe_flush(ptr: *mut wasi_pipe_t) -> i64 { - use std::io::Write; - let ptr = &mut *ptr; - match ptr.flush() { - Ok(_) => 0, - Err(_) => -1, - } -} - -#[test] -fn test_wasi_pipe_with_destructor() { - let mut wasi_pipe_t_ptr = std::ptr::null_mut(); - let second_wasi_pipe_t_ptr = unsafe { wasi_pipe_new(&mut wasi_pipe_t_ptr) }; - let wasi_pipe_t_ptr = unsafe { &mut *wasi_pipe_t_ptr }; - let second_wasi_pipe_t_ptr = unsafe { &mut *second_wasi_pipe_t_ptr }; - - let data = b"hello".iter().map(|v| *v as i8).collect::>(); - let result = unsafe { wasi_pipe_write_bytes(wasi_pipe_t_ptr, data.as_ptr(), data.len()) }; - assert_eq!(result, 5); - - let bytes_avail = wasi_pipe_t_ptr.bytes_available_read(); - assert_eq!(bytes_avail, Ok(Some(0))); - - let bytes_avail2 = second_wasi_pipe_t_ptr.bytes_available_read(); - assert_eq!(bytes_avail2, Ok(Some(5))); - - let mut read_str_ptr = std::ptr::null_mut(); - let result = unsafe { wasi_pipe_read_str(second_wasi_pipe_t_ptr, &mut read_str_ptr) }; - assert_eq!(result, 6); // hello\0 - let buf_slice = unsafe { std::slice::from_raw_parts_mut(read_str_ptr, result as usize) }; - assert_eq!(buf_slice[..5], data); - - unsafe { - wasi_pipe_delete_str(read_str_ptr); - } - unsafe { wasi_pipe_delete(wasi_pipe_t_ptr) }; - unsafe { wasi_pipe_delete(second_wasi_pipe_t_ptr) }; -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_pipe_read_bytes( - ptr: *const wasi_pipe_t, - buf: *const c_char, - read: usize, -) -> i64 { - use std::io::Read; - let ptr = &mut *(ptr as *mut wasi_pipe_t); - let buf = buf as *mut u8; - let slice = std::slice::from_raw_parts_mut(buf, read); - match ptr.read(slice) { - Ok(o) => o as i64, - Err(_) => -1, - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_pipe_delete_str(buf: *mut c_char) { - use std::ffi::CString; - let _ = CString::from_raw(buf); -} - -unsafe fn wasi_pipe_read_bytes_internal(ptr: *const wasi_pipe_t, buf: &mut Vec) -> i64 { - use std::io::Read; - - const BLOCK_SIZE: usize = 1024; - - let ptr = &mut *(ptr as *mut wasi_pipe_t); - let mut target = Vec::new(); - - loop { - let mut v = vec![0; BLOCK_SIZE]; - // read n bytes, maximum of 1024 - match ptr.read(&mut v) { - Ok(0) => { - break; - } - Ok(n) => { - target.extend_from_slice(&v[..n]); - } - Err(_) => { - return -1; - } - } - } - - let len = target.len() as i64; - *buf = target; - len -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_pipe_read_str(ptr: *const wasi_pipe_t, buf: &mut *mut c_char) -> i64 { - use std::ffi::CString; - - let mut target = Vec::new(); - let read_result = wasi_pipe_read_bytes_internal(ptr, &mut target); - if read_result < 0 { - return read_result; - } - - target.push(0); - let len = target.len(); - let c_string = match CString::from_vec_with_nul(target.clone()) { - Ok(o) => o, - Err(_) => { - return -1; - } - }; - - *buf = CString::into_raw(c_string); - len as i64 -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_pipe_seek( - ptr: *mut wasi_pipe_t, - // 0 = from start - // 1 = from end - // 2 = from current position - seek_dir: c_char, - seek: i64, -) -> i64 { - use std::io::Seek; - - let seek_pos = match seek_dir { - 0 => SeekFrom::Start(seek as u64), - 1 => SeekFrom::End(seek), - 2 => SeekFrom::Current(seek), - _ => { - return -1; - } - }; - - let ptr = &mut *ptr; - - ptr.seek(seek_pos) - .ok() - .and_then(|p| p.try_into().ok()) - .unwrap_or(-1) -} - #[derive(Debug)] #[allow(non_camel_case_types)] pub struct wasi_config_t { - stdout: Option>, - stderr: Option>, - stdin: Option>, + inherit_stdout: bool, + inherit_stderr: bool, + inherit_stdin: bool, state_builder: WasiStateBuilder, } @@ -665,16 +40,16 @@ pub unsafe extern "C" fn wasi_config_new( let prog_name = c_try!(name_c_str.to_str()); Some(Box::new(wasi_config_t { - stdout: None, - stderr: None, - stdin: None, + inherit_stdout: true, + inherit_stderr: true, + inherit_stdin: true, state_builder: WasiState::new(prog_name), })) } #[no_mangle] pub unsafe extern "C" fn wasi_config_env( - wasi_config: &mut wasi_config_t, + config: &mut wasi_config_t, key: *const c_char, value: *const c_char, ) { @@ -686,22 +61,22 @@ pub unsafe extern "C" fn wasi_config_env( let value_cstr = CStr::from_ptr(value); let value_bytes = value_cstr.to_bytes(); - wasi_config.state_builder.env(key_bytes, value_bytes); + config.state_builder.env(key_bytes, value_bytes); } #[no_mangle] -pub unsafe extern "C" fn wasi_config_arg(wasi_config: &mut wasi_config_t, arg: *const c_char) { +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_bytes = arg_cstr.to_bytes(); - wasi_config.state_builder.arg(arg_bytes); + config.state_builder.arg(arg_bytes); } #[no_mangle] pub unsafe extern "C" fn wasi_config_preopen_dir( - wasi_config: &mut wasi_config_t, + config: &mut wasi_config_t, dir: *const c_char, ) -> bool { let dir_cstr = CStr::from_ptr(dir); @@ -714,7 +89,7 @@ pub unsafe extern "C" fn wasi_config_preopen_dir( } }; - if let Err(e) = wasi_config.state_builder.preopen_dir(dir_str) { + if let Err(e) = config.state_builder.preopen_dir(dir_str) { update_last_error(e); return false; } @@ -724,7 +99,7 @@ pub unsafe extern "C" fn wasi_config_preopen_dir( #[no_mangle] pub unsafe extern "C" fn wasi_config_mapdir( - wasi_config: &mut wasi_config_t, + config: &mut wasi_config_t, alias: *const c_char, dir: *const c_char, ) -> bool { @@ -748,7 +123,7 @@ pub unsafe extern "C" fn wasi_config_mapdir( } }; - if let Err(e) = wasi_config.state_builder.map_dir(alias_str, dir_str) { + if let Err(e) = config.state_builder.map_dir(alias_str, dir_str) { update_last_error(e); return false; } @@ -757,63 +132,33 @@ pub unsafe extern "C" fn wasi_config_mapdir( } #[no_mangle] -pub extern "C" fn wasi_config_capture_stdout(wasi_config: &mut wasi_config_t) { - wasi_config.stdout = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); +pub extern "C" fn wasi_config_capture_stdout(config: &mut wasi_config_t) { + config.inherit_stdout = false; } #[no_mangle] -pub extern "C" fn wasi_config_inherit_stdout(wasi_config: &mut wasi_config_t) { - wasi_config.stdout = None; +pub extern "C" fn wasi_config_inherit_stdout(config: &mut wasi_config_t) { + config.inherit_stdout = true; } #[no_mangle] -pub extern "C" fn wasi_config_capture_stderr(wasi_config: &mut wasi_config_t) { - wasi_config.stderr = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); +pub extern "C" fn wasi_config_capture_stderr(config: &mut wasi_config_t) { + config.inherit_stderr = false; } #[no_mangle] -pub extern "C" fn wasi_config_inherit_stderr(wasi_config: &mut wasi_config_t) { - wasi_config.stderr = None; +pub extern "C" fn wasi_config_inherit_stderr(config: &mut wasi_config_t) { + config.inherit_stderr = true; } -#[no_mangle] -pub extern "C" fn wasi_config_capture_stdin(wasi_config: &mut wasi_config_t) { - wasi_config.stdin = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); -} +//#[no_mangle] +//pub extern "C" fn wasi_config_capture_stdin(config: &mut wasi_config_t) { +// config.inherit_stdin = false; +//} #[no_mangle] -pub extern "C" fn wasi_config_inherit_stdin(wasi_config: &mut wasi_config_t) { - wasi_config.stdin = None; -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_config_overwrite_stdin( - config_overwrite: &mut wasi_config_t, - stdin_overwrite: *mut wasi_pipe_t, -) { - config_overwrite - .state_builder - .stdin(Box::from_raw(stdin_overwrite)); -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_config_overwrite_stdout( - config_overwrite: &mut wasi_config_t, - stdout_overwrite: *mut wasi_pipe_t, -) { - config_overwrite - .state_builder - .stdout(Box::from_raw(stdout_overwrite)); -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_config_overwrite_stderr( - config_overwrite: &mut wasi_config_t, - stderr_overwrite: *mut wasi_pipe_t, -) { - config_overwrite - .state_builder - .stderr(Box::from_raw(stderr_overwrite)); +pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { + config.inherit_stdin = true; } #[repr(C)] @@ -924,12 +269,12 @@ fn prepare_webc_env( let filesystem = Box::new(StaticFileSystem::init(slice, &package_name)?); let mut wasi_env = config.state_builder; - if let Some(s) = config.stdout { - wasi_env.stdout(s); + if !config.inherit_stdout { + wasi_env.stdout(Box::new(Pipe::new())); } - if let Some(s) = config.stderr { - wasi_env.stderr(s); + if !config.inherit_stderr { + wasi_env.stderr(Box::new(Pipe::new())); } wasi_env.set_fs(filesystem); @@ -957,24 +302,21 @@ pub struct wasi_env_t { #[no_mangle] pub unsafe extern "C" fn wasi_env_new( store: Option<&mut wasm_store_t>, - mut wasi_config: Box, + mut config: Box, ) -> Option> { let store = &mut store?.inner; let mut store_mut = store.store_mut(); - - if let Some(stdout) = wasi_config.stdout { - wasi_config.state_builder.stdout(stdout); + if !config.inherit_stdout { + config.state_builder.stdout(Box::new(Pipe::new())); } - if let Some(stderr) = wasi_config.stderr { - wasi_config.state_builder.stderr(stderr); + if !config.inherit_stderr { + config.state_builder.stderr(Box::new(Pipe::new())); } - if let Some(stdin) = wasi_config.stdin { - wasi_config.state_builder.stdin(stdin); - } + // TODO: impl capturer for stdin - let wasi_state = c_try!(wasi_config.state_builder.finalize(&mut store_mut)); + let wasi_state = c_try!(config.state_builder.finalize(&mut store_mut)); Some(Box::new(wasi_env_t { inner: wasi_state, @@ -1296,218 +638,4 @@ mod tests { }) .success(); } - - #[test] - fn test_wasi_stdin_set() { - (assert_c! { - #include "tests/wasmer.h" - #include "string.h" - #include "stdio.h" - - int main() { - wasi_pipe_t* override_stdout_1 = NULL; - wasi_pipe_t* override_stdout_2 = wasi_pipe_new(&override_stdout_1); - - assert(override_stdout_1); - assert(override_stdout_2); - - // write to override_stdout_1, then close override_stdout_1 - wasi_pipe_write_str(override_stdout_1, "test"); - wasi_pipe_delete(override_stdout_1); - - // read from override_stdout_2, after override_stdout_1 has been closed so it doesn't block - char* out; - wasi_pipe_read_str(override_stdout_2, &out); - assert(strcmp(out, "test") == 0); - wasi_pipe_delete_str(out); - - // cleanup - wasi_pipe_delete(override_stdout_2); - return 0; - } - }) - .success(); - } - - #[test] - fn test_wasi_stdin_set_2() { - (assert_c! { - #include "tests/wasmer.h" - #include "string.h" - #include "stdio.h" - - int main() { - - wasm_engine_t* engine = wasm_engine_new(); - wasm_store_t* store = wasm_store_new(engine); - wasi_config_t* config = wasi_config_new("example_program"); - - wasi_pipe_t* override_stdout_1 = NULL; - wasi_pipe_t* override_stdout_2 = wasi_pipe_new(&override_stdout_1); - assert(override_stdout_1); - assert(override_stdout_2); - - wasi_pipe_t* override_stderr_1 = NULL; - wasi_pipe_t* override_stderr_2 = wasi_pipe_new(&override_stderr_1); - assert(override_stderr_1); - assert(override_stderr_2); - - wasi_pipe_t* override_stdin_1 = NULL; - wasi_pipe_t* override_stdin_2 = wasi_pipe_new(&override_stdin_1); - assert(override_stdin_1); - assert(override_stdin_2); - - // The override_stdin ownership is moved to the config - wasi_config_overwrite_stdin(config, override_stdin_1); - wasi_config_overwrite_stdout(config, override_stdout_1); - wasi_config_overwrite_stderr(config, override_stderr_1); - - // write to stdin, then close all senders in order - // not to block during execution - wasi_pipe_write_str(override_stdin_2, "hello"); - wasi_pipe_delete(override_stdin_2); - - /* - // testrust.wasm: - - use std::io::{self, Write}; - - fn main() -> io::Result<()> { - - let mut input = String::new(); - io::stdin().read_line(&mut input)?; - - io::stdout().write_all(format!("stdout: {input}").as_bytes())?; - io::stderr().write_all(format!("stderr: {input}").as_bytes())?; - - Ok(()) - } - */ - - // Load binary. - FILE* file = fopen("tests/wasm-c-api/example/testrust.wasm", "rb"); - if (!file) { - printf("> Error loading module!\n"); - return 1; - } - - fseek(file, 0L, SEEK_END); - size_t file_size = ftell(file); - fseek(file, 0L, SEEK_SET); - - wasm_byte_vec_t binary; - wasm_byte_vec_new_uninitialized(&binary, file_size); - - if (fread(binary.data, file_size, 1, file) != 1) { - printf("> Error loading module!\n"); - return 1; - } - - fclose(file); - - wasm_module_t* module = wasm_module_new(store, &binary); - if (!module) { - printf("> Error compiling module!\n"); - return 1; - } - - // The env now has ownership of the config (using the custom stdout / stdin channels) - wasi_env_t *wasi_env = wasi_env_new(store, config); - if (!wasi_env) { - printf("> Error building WASI env!\n"); - return 1; - } - - wasm_importtype_vec_t import_types; - wasm_module_imports(module, &import_types); - - wasm_extern_vec_t imports; - wasm_extern_vec_new_uninitialized(&imports, import_types.size); - wasm_importtype_vec_delete(&import_types); - - bool get_imports_result = wasi_get_imports(store, wasi_env, module, &imports); - - if (!get_imports_result) { - printf("Error getting WASI imports!\n"); - return 1; - } - - // The program should wait for a stdin, then print "stdout: $1" to stdout - // and "stderr: $1" to stderr and exit. - - // Instantiate the module - wasm_instance_t *instance = wasm_instance_new(store, module, &imports, NULL); - if (!instance) { - printf("> Error instantiating module!\n"); - return -1; - } - - // Read the exports. - wasm_extern_vec_t exports; - wasm_instance_exports(instance, &exports); - wasm_memory_t* mem = NULL; - for (size_t i = 0; i < exports.size; i++) { - mem = wasm_extern_as_memory(exports.data[i]); - if (mem) { - break; - } - } - - if (!mem) { - printf("Failed to create instance: Could not find memory in exports\n"); - return -1; - } - wasi_env_set_memory(wasi_env, mem); - - // Get the _start function - wasm_func_t* run_func = wasi_get_start_function(instance); - if (run_func == NULL) { - printf("> Error accessing export!\n"); - return 1; - } - - // Run the _start function - // Running the program should trigger the stdin to write "hello" to the stdin - wasm_val_vec_t args = WASM_EMPTY_VEC; - wasm_val_vec_t res = WASM_EMPTY_VEC; - if (wasm_func_call(run_func, &args, &res)) { - printf("> Error calling function!\n"); - return 1; - } - - // Verify that the stdout / stderr worked as expected - char* out; - wasi_pipe_read_str(override_stdout_2, &out); - assert(strcmp(out, "stdout: hello") == 0); - wasi_pipe_delete_str(out); - - char* out2; - wasi_pipe_read_str(override_stdout_2, &out2); - assert(strcmp(out2, "") == 0); - wasi_pipe_delete_str(out2); - - char* out3; - wasi_pipe_read_str(override_stderr_2, &out3); - assert(strcmp(out3, "stderr: hello") == 0); - wasi_pipe_delete_str(out3); - - char* out4; - wasi_pipe_read_str(override_stderr_2, &out4); - assert(strcmp(out4, "") == 0); - wasi_pipe_delete_str(out4); - - wasi_pipe_delete(override_stdout_2); - wasi_pipe_delete(override_stderr_2); - wasm_byte_vec_delete(&binary); - wasm_module_delete(module); - wasm_func_delete(run_func); - wasi_env_delete(wasi_env); - wasm_store_delete(store); - wasm_engine_delete(engine); - - return 0; - } - }) - .success(); - } } diff --git a/lib/c-api/tests/wasm-c-api/example/stdio.wasm b/lib/c-api/tests/wasm-c-api/example/stdio.wasm deleted file mode 100755 index 9ed5b3d47..000000000 Binary files a/lib/c-api/tests/wasm-c-api/example/stdio.wasm and /dev/null differ diff --git a/lib/c-api/tests/wasm-c-api/example/testrust.wasm b/lib/c-api/tests/wasm-c-api/example/testrust.wasm deleted file mode 100755 index 92a691fc6..000000000 Binary files a/lib/c-api/tests/wasm-c-api/example/testrust.wasm and /dev/null differ 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 18b60ceab..2d6fb4a91 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,6 +1,6 @@ [package] name = "wasmer-c-api-test-runner" -version = "3.0.0-rc.2" +version = "3.0.2" edition = "2021" license = "MIT" description = "wasmer-c-api-test-runner" diff --git a/lib/cache/Cargo.toml b/lib/cache/Cargo.toml index adbbecb7e..71eb844b5 100644 --- a/lib/cache/Cargo.toml +++ b/lib/cache/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-cache" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Cache system for Wasmer WebAssembly runtime" categories = ["wasm", "caching"] keywords = ["wasm", "webassembly", "cache"] @@ -11,7 +11,7 @@ readme = "README.md" edition = "2018" [dependencies] -wasmer = { path = "../api", version = "=3.0.0-rc.2", default-features = false, features = ["sys"] } +wasmer = { path = "../api", version = "=3.0.2", default-features = false, features = ["sys"] } hex = "0.4" thiserror = "1" blake3 = "1.0" @@ -20,7 +20,7 @@ blake3 = "1.0" criterion = "0.3" tempfile = "3" rand = "0.8.3" -wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "=3.0.0-rc.2" } +wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "=3.0.2" } [features] default = ["wasmer/js-serializable-module", "wasmer/compiler", "filesystem"] diff --git a/lib/cli-compiler/Cargo.toml b/lib/cli-compiler/Cargo.toml index 109b78ae3..63158131c 100644 --- a/lib/cli-compiler/Cargo.toml +++ b/lib/cli-compiler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-compiler-cli" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Wasmer Compiler CLI" categories = ["wasm", "command-line-interface"] keywords = ["wasm", "webassembly", "cli"] @@ -18,8 +18,8 @@ path = "src/bin/wasmer_compiler.rs" doc = false [dependencies] -wasmer-compiler = { version = "=3.0.0-rc.2", path = "../compiler", features = ["compiler"] } -wasmer-types = { version = "=3.0.0-rc.2", path = "../types" } +wasmer-compiler = { version = "=3.0.2", path = "../compiler", features = ["compiler"] } +wasmer-types = { version = "=3.0.2", path = "../types" } atty = "0.2" colored = "2.0" anyhow = "1.0" @@ -36,12 +36,12 @@ target-lexicon = { version = "0.12", features = ["std"] } tempfile = "3" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -wasmer-compiler-singlepass = { version = "=3.0.0-rc.2", path = "../compiler-singlepass", optional = true } -wasmer-compiler-cranelift = { version = "=3.0.0-rc.2", path = "../compiler-cranelift", optional = true } +wasmer-compiler-singlepass = { version = "=3.0.2", path = "../compiler-singlepass", optional = true } +wasmer-compiler-cranelift = { version = "=3.0.2", path = "../compiler-cranelift", optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] -wasmer-compiler-singlepass = { version = "=3.0.0-rc.2", path = "../compiler-singlepass", optional = true, default-features = false, features = ["wasm"] } -wasmer-compiler-cranelift = { version = "=3.0.0-rc.2", path = "../compiler-cranelift", optional = true, default-features = false, features = ["wasm"] } +wasmer-compiler-singlepass = { version = "=3.0.2", path = "../compiler-singlepass", optional = true, default-features = false, features = ["wasm"] } +wasmer-compiler-cranelift = { version = "=3.0.2", path = "../compiler-cranelift", optional = true, default-features = false, features = ["wasm"] } [target.'cfg(target_os = "linux")'.dependencies] unix_mode = "0.1.3" diff --git a/lib/cli/Cargo.toml b/lib/cli/Cargo.toml index f068b2639..7f2502af0 100644 --- a/lib/cli/Cargo.toml +++ b/lib/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-cli" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Wasmer CLI" categories = ["wasm", "command-line-interface"] keywords = ["wasm", "webassembly", "cli"] @@ -25,26 +25,26 @@ doc = false required-features = ["headless"] [dependencies] -wasmer = { version = "=3.0.0-rc.2", path = "../api", default-features = false } -wasmer-compiler = { version = "=3.0.0-rc.2", path = "../compiler", features = ["compiler", ] } -wasmer-compiler-cranelift = { version = "=3.0.0-rc.2", path = "../compiler-cranelift", optional = true } -wasmer-compiler-singlepass = { version = "=3.0.0-rc.2", path = "../compiler-singlepass", optional = true } -wasmer-compiler-llvm = { version = "=3.0.0-rc.2", path = "../compiler-llvm", optional = true } -wasmer-emscripten = { version = "=3.0.0-rc.2", path = "../emscripten", optional = true } -wasmer-vm = { version = "=3.0.0-rc.2", path = "../vm", features = ["tracing"] } -wasmer-wasi = { version = "=3.0.0-rc.2", path = "../wasi", optional = true, features = [ "host-vnet" ] } -wasmer-wasi-experimental-io-devices = { version = "=3.0.0-rc.2", path = "../wasi-experimental-io-devices", optional = true, features = ["link_external_libs"] } -wasmer-wast = { version = "=3.0.0-rc.2", path = "../../tests/lib/wast", optional = true } -wasmer-cache = { version = "=3.0.0-rc.2", path = "../cache", optional = true } -wasmer-types = { version = "=3.0.0-rc.2", path = "../types" } -wasmer-registry = { version = "=3.0.0-rc.2", path = "../registry" } -wasmer-object = { version = "=3.0.0-rc.2", path = "../object", optional = true } -wasmer-vfs = { version = "=3.0.0-rc.2", path = "../vfs", default-features = false, features = ["host-fs"] } +wasmer = { version = "=3.0.2", path = "../api", default-features = false } +wasmer-compiler = { version = "=3.0.2", path = "../compiler", features = ["compiler", ] } +wasmer-compiler-cranelift = { version = "=3.0.2", path = "../compiler-cranelift", optional = true } +wasmer-compiler-singlepass = { version = "=3.0.2", path = "../compiler-singlepass", optional = true } +wasmer-compiler-llvm = { version = "=3.0.2", path = "../compiler-llvm", optional = true } +wasmer-emscripten = { version = "=3.0.2", path = "../emscripten", optional = true } +wasmer-vm = { version = "=3.0.2", path = "../vm", features = ["tracing"] } +wasmer-wasi = { version = "=3.0.2", path = "../wasi", optional = true, features = ["host-vnet"] } +wasmer-wasi-experimental-io-devices = { version = "=3.0.2", path = "../wasi-experimental-io-devices", optional = true, features = ["link_external_libs"] } +wasmer-wast = { version = "=3.0.2", path = "../../tests/lib/wast", optional = true } +wasmer-cache = { version = "=3.0.2", path = "../cache", optional = true } +wasmer-types = { version = "=3.0.2", path = "../types" } +wasmer-registry = { version = "=3.0.2", path = "../registry" } +wasmer-object = { version = "=3.0.2", path = "../object", optional = true } +wasmer-vfs = { version = "=3.0.2", path = "../vfs", default-features = false, features = ["host-fs"] } atty = "0.2" colored = "2.0" anyhow = "1.0" -spinner = "0.5.0" -clap = { version = "3.2.22", features = ["derive"] } +spinoff = "0.5.4" +clap = { version = "3.2.22", features = ["derive", "env"] } # For the function names autosuggestion distance = "0.4" # For the inspect subcommand @@ -56,7 +56,7 @@ log = { version = "0.4", optional = true } tempfile = "3" tempdir = "0.3.7" http_req = { version="^0.8", default-features = false, features = ["rust-tls"], optional = true } -reqwest = { version = "^0.11", default-features = false, feature = ["rustls-tls", "json"], optional = true } +reqwest = { version = "^0.11", default-features = false, features = ["rustls-tls", "json", "multipart"], optional = true } serde = { version = "1.0.147", features = ["derive"], optional = true } dirs = { version = "4.0", optional = true } serde_json = { version = "1.0", optional = true } @@ -71,6 +71,8 @@ libc = { version = "^0.2", default-features = false } nuke-dir = { version = "0.1.0", optional = true } webc = { version = "3.0.1", optional = true } isatty = "0.1.9" +dialoguer = "0.10.2" +tldextract = "0.6.0" [build-dependencies] chrono = { version = "^0.4", default-features = false, features = [ "std", "clock" ] } @@ -148,7 +150,6 @@ debug = ["fern", "log"] disable-all-logging = ["wasmer-wasi/disable-all-logging"] headless = [] headless-minimal = ["headless", "disable-all-logging", "wasi"] -termios = ["wasmer-wasi/host-termios"] # Optional enable-serde = [ @@ -167,31 +168,32 @@ http = [ "serde", ] +[target.'cfg(target_os = "windows")'.dependencies] +colored = "2.0.0" + [package.metadata.binstall] pkg-fmt = "tgz" [package.metadata.binstall.overrides.aarch64-apple-darwin] -pkg-url = "{ repo }/releases/download/{ version }/wasmer-darwin-arm64.{ archive-format }" -bin-dir = "wasmer-darwin-arm64/bin/{ bin }" - -#https://github.com/wasmerio/wasmer/releases/download/3.0.0-beta/wasmer-darwin-arm64.tar.gz +pkg-url = "{ repo }/releases/download/v{ version }/wasmer-darwin-arm64.{ archive-format }" +bin-dir = "bin/{ bin }" [package.metadata.binstall.overrides.x86_64-apple-darwin] -pkg-url = "{ repo }/releases/download/{ version }/wasmer-darwin-amd64.{ archive-format }" -bin-dir = "wasmer-darwin-amd64/bin/{ bin }" +pkg-url = "{ repo }/releases/download/v{ version }/wasmer-darwin-amd64.{ archive-format }" +bin-dir = "bin/{ bin }" [package.metadata.binstall.overrides.aarch64-unknown-linux-gnu] -pkg-url = "{ repo }/releases/download/{ version }/wasmer-linux-aarch64.{ archive-format }" -bin-dir = "wasmer-linux-aarch64/bin/{ bin }" +pkg-url = "{ repo }/releases/download/v{ version }/wasmer-linux-aarch64.{ archive-format }" +bin-dir = "bin/{ bin }" [package.metadata.binstall.overrides.x86_64-unknown-linux-gnu] -pkg-url = "{ repo }/releases/download/{ version }/wasmer-linux-amd64.{ archive-format }" -bin-dir = "wasmer-linux-amd64/bin/{ bin }" +pkg-url = "{ repo }/releases/download/v{ version }/wasmer-linux-amd64.{ archive-format }" +bin-dir = "bin/{ bin }" [package.metadata.binstall.overrides.x86_64-unknown-linux-musl] -pkg-url = "{ repo }/releases/download/{ version }/wasmer-linux-musl-amd64.{ archive-format }" -bin-dir = "wasmer-linux-musl-amd64/bin/{ bin }" +pkg-url = "{ repo }/releases/download/v{ version }/wasmer-linux-musl-amd64.{ archive-format }" +bin-dir = "bin/{ bin }" [package.metadata.binstall.overrides.x86_64-pc-windows-msvc] -pkg-url = "{ repo }/releases/download/{ version }/wasmer-windows-amd64.{ archive-format }" -bin-dir = "wasmer-windows-amd64/bin/{ bin }.exe" +pkg-url = "{ repo }/releases/download/v{ version }/wasmer-windows-amd64.{ archive-format }" +bin-dir = "bin/{ bin }.exe" diff --git a/lib/cli/src/cli.rs b/lib/cli/src/cli.rs index 6e1603f48..5829fb16c 100644 --- a/lib/cli/src/cli.rs +++ b/lib/cli/src/cli.rs @@ -10,10 +10,12 @@ use crate::commands::CreateExe; use crate::commands::CreateObj; #[cfg(feature = "wast")] use crate::commands::Wast; -use crate::commands::{Cache, Config, Inspect, List, Run, SelfUpdate, Validate}; +use crate::commands::{ + Add, Cache, Config, Inspect, List, Login, Run, SelfUpdate, Validate, Whoami, +}; use crate::error::PrettyError; use clap::{CommandFactory, ErrorKind, Parser}; -use std::fmt; +use std::{fmt, str::FromStr}; #[derive(Parser, Debug)] #[cfg_attr( @@ -37,24 +39,23 @@ use std::fmt; /// The options for the wasmer Command Line Interface enum WasmerCLIOptions { /// List all locally installed packages - #[clap(name = "list")] List(List), /// Run a WebAssembly file. Formats accepted: wasm, wat - #[clap(name = "run")] Run(Run), + /// Login into a wapm.io-like registry + Login(Login), + /// Wasmer cache - #[clap(subcommand, name = "cache")] + #[clap(subcommand)] Cache(Cache), /// Validate a WebAssembly binary - #[clap(name = "validate")] Validate(Validate), /// Compile a WebAssembly binary #[cfg(feature = "compiler")] - #[clap(name = "compile")] Compile(Compile), /// Compile a WebAssembly binary into a native executable @@ -126,7 +127,6 @@ enum WasmerCLIOptions { /// Get various configuration information needed /// to compile programs which use Wasmer - #[clap(name = "config")] Config(Config), /// Update wasmer to the latest version @@ -134,18 +134,21 @@ enum WasmerCLIOptions { SelfUpdate(SelfUpdate), /// Inspect a WebAssembly file - #[clap(name = "inspect")] Inspect(Inspect), /// Run spec testsuite #[cfg(feature = "wast")] - #[clap(name = "wast")] Wast(Wast), /// Unregister and/or register wasmer as binfmt interpreter #[cfg(target_os = "linux")] - #[clap(name = "binfmt")] Binfmt(Binfmt), + + /// Shows the current logged in user for the current active registry + Whoami(Whoami), + + /// Add a WAPM package's bindings to your application. + Add(Add), } impl WasmerCLIOptions { @@ -164,10 +167,13 @@ impl WasmerCLIOptions { Self::Config(config) => config.execute(), Self::Inspect(inspect) => inspect.execute(), Self::List(list) => list.execute(), + Self::Login(login) => login.execute(), #[cfg(feature = "wast")] Self::Wast(wast) => wast.execute(), #[cfg(target_os = "linux")] Self::Binfmt(binfmt) => binfmt.execute(), + Self::Whoami(whoami) => whoami.execute(), + Self::Add(install) => install.execute(), } } } @@ -219,8 +225,10 @@ fn wasmer_main_inner() -> Result<(), anyhow::Error> { WasmerCLIOptions::Run(Run::from_binfmt_args()) } else { match command.unwrap_or(&"".to_string()).as_ref() { - "cache" | "compile" | "config" | "create-exe" | "help" | "inspect" | "run" - | "self-update" | "validate" | "wast" | "binfmt" | "list" => WasmerCLIOptions::parse(), + "add" | "cache" | "compile" | "config" | "create-exe" | "help" | "inspect" | "run" + | "self-update" | "validate" | "wast" | "binfmt" | "list" | "login" => { + WasmerCLIOptions::parse() + } _ => { WasmerCLIOptions::try_parse_from(args.iter()).unwrap_or_else(|e| { match e.kind() { @@ -271,7 +279,7 @@ impl fmt::Display for SplitVersion { #[test] fn test_split_version() { assert_eq!( - SplitVersion::new("registry.wapm.io/graphql/python/python").unwrap(), + SplitVersion::parse("registry.wapm.io/graphql/python/python").unwrap(), SplitVersion { original: "registry.wapm.io/graphql/python/python".to_string(), registry: Some("https://registry.wapm.io/graphql".to_string()), @@ -281,7 +289,7 @@ fn test_split_version() { } ); assert_eq!( - SplitVersion::new("registry.wapm.io/python/python").unwrap(), + SplitVersion::parse("registry.wapm.io/python/python").unwrap(), SplitVersion { original: "registry.wapm.io/python/python".to_string(), registry: Some("https://registry.wapm.io/graphql".to_string()), @@ -291,7 +299,7 @@ fn test_split_version() { } ); assert_eq!( - SplitVersion::new("namespace/name@version:command").unwrap(), + SplitVersion::parse("namespace/name@version:command").unwrap(), SplitVersion { original: "namespace/name@version:command".to_string(), registry: None, @@ -301,7 +309,7 @@ fn test_split_version() { } ); assert_eq!( - SplitVersion::new("namespace/name@version").unwrap(), + SplitVersion::parse("namespace/name@version").unwrap(), SplitVersion { original: "namespace/name@version".to_string(), registry: None, @@ -311,7 +319,7 @@ fn test_split_version() { } ); assert_eq!( - SplitVersion::new("namespace/name").unwrap(), + SplitVersion::parse("namespace/name").unwrap(), SplitVersion { original: "namespace/name".to_string(), registry: None, @@ -321,7 +329,7 @@ fn test_split_version() { } ); assert_eq!( - SplitVersion::new("registry.wapm.io/namespace/name").unwrap(), + SplitVersion::parse("registry.wapm.io/namespace/name").unwrap(), SplitVersion { original: "registry.wapm.io/namespace/name".to_string(), registry: Some("https://registry.wapm.io/graphql".to_string()), @@ -331,13 +339,21 @@ fn test_split_version() { } ); assert_eq!( - format!("{}", SplitVersion::new("namespace").unwrap_err()), + format!("{}", SplitVersion::parse("namespace").unwrap_err()), "Invalid package version: \"namespace\"".to_string(), ); } impl SplitVersion { - pub fn new(s: &str) -> Result { + pub fn parse(s: &str) -> Result { + s.parse() + } +} + +impl FromStr for SplitVersion { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { let command = WasmerCLIOptions::command(); let mut prohibited_package_names = command.get_subcommands().map(|s| s.get_name()); diff --git a/lib/cli/src/commands.rs b/lib/cli/src/commands.rs index ad5dc0135..d59d5c78c 100644 --- a/lib/cli/src/commands.rs +++ b/lib/cli/src/commands.rs @@ -1,4 +1,5 @@ //! The commands available in the Wasmer binary. +mod add; #[cfg(target_os = "linux")] mod binfmt; mod cache; @@ -11,11 +12,13 @@ mod create_exe; mod create_obj; mod inspect; mod list; +mod login; mod run; mod self_update; mod validate; #[cfg(feature = "wast")] mod wast; +mod whoami; #[cfg(target_os = "linux")] pub use binfmt::*; @@ -27,7 +30,10 @@ pub use create_exe::*; pub use create_obj::*; #[cfg(feature = "wast")] pub use wast::*; -pub use {cache::*, config::*, inspect::*, list::*, run::*, self_update::*, validate::*}; +pub use { + add::*, cache::*, config::*, inspect::*, list::*, login::*, run::*, self_update::*, + validate::*, whoami::*, +}; /// The kind of object format to emit. #[derive(Debug, Copy, Clone, clap::Parser)] diff --git a/lib/cli/src/commands/add.rs b/lib/cli/src/commands/add.rs new file mode 100644 index 000000000..f52964936 --- /dev/null +++ b/lib/cli/src/commands/add.rs @@ -0,0 +1,210 @@ +use std::process::{Command, Stdio}; + +use anyhow::{Context, Error}; +use clap::Parser; +use wasmer_registry::{Bindings, PartialWapmConfig, ProgrammingLanguage}; + +use crate::cli::SplitVersion; + +/// Add a WAPM package's bindings to your application. +#[derive(Debug, Parser)] +pub struct Add { + /// The registry to fetch bindings from. + #[clap(long, env = "WAPM_REGISTRY")] + registry: Option, + /// Add the JavaScript bindings using "npm install". + #[clap(long, groups = &["bindings", "js"])] + npm: bool, + /// Add the JavaScript bindings using "yarn add". + #[clap(long, groups = &["bindings", "js"])] + yarn: bool, + /// Add the package as a dev-dependency. + #[clap(long, requires = "js")] + dev: bool, + /// Add the Python bindings using "pip install". + #[clap(long, groups = &["bindings", "py"])] + pip: bool, + /// The packages to add (e.g. "wasmer/wasmer-pack@0.5.0" or "python/python") + #[clap(parse(try_from_str))] + packages: Vec, +} + +impl Add { + /// Execute [`Add`]. + pub fn execute(&self) -> Result<(), Error> { + anyhow::ensure!(!self.packages.is_empty(), "No packages specified"); + + let registry = self + .registry() + .context("Unable to determine which registry to use")?; + + let bindings = self.lookup_bindings(®istry)?; + + let mut cmd = self.target()?.command(&bindings)?; + cmd.stdin(Stdio::null()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()); + + println!("Running: {cmd:?}"); + + let status = cmd.status().with_context(|| { + format!( + "Unable to start \"{:?}\". Is it installed?", + cmd.get_program() + ) + })?; + + anyhow::ensure!(status.success(), "Command failed: {:?}", cmd); + + Ok(()) + } + + fn lookup_bindings(&self, registry: &str) -> Result, Error> { + println!("Querying WAPM for package bindings"); + + let mut bindings_to_add = Vec::new(); + let language = self.target()?.language(); + + for pkg in &self.packages { + let bindings = lookup_bindings_for_package(registry, pkg, &language) + .with_context(|| format!("Unable to find bindings for {pkg}"))?; + bindings_to_add.push(bindings); + } + + Ok(bindings_to_add) + } + + fn registry(&self) -> Result { + match &self.registry { + Some(r) => Ok(r.clone()), + None => { + let cfg = PartialWapmConfig::from_file() + .map_err(Error::msg) + .context("Unable to load WAPM's config file")?; + Ok(cfg.registry.get_current_registry()) + } + } + } + + fn target(&self) -> Result { + match (self.pip, self.npm, self.yarn) { + (false, false, false) => Err(anyhow::anyhow!( + "at least one of --npm, --pip or --yarn has to be specified" + )), + (true, false, false) => Ok(Target::Pip), + (false, true, false) => Ok(Target::Npm { dev: self.dev }), + (false, false, true) => Ok(Target::Yarn { dev: self.dev }), + _ => Err(anyhow::anyhow!( + "only one of --npm, --pip or --yarn has to be specified" + )), + } + } +} + +fn lookup_bindings_for_package( + registry: &str, + pkg: &SplitVersion, + language: &ProgrammingLanguage, +) -> Result { + let all_bindings = + wasmer_registry::list_bindings(registry, &pkg.package, pkg.version.as_deref())?; + + match all_bindings.iter().find(|b| b.language == *language) { + Some(b) => { + #[cfg(feature = "debug")] + { + let Bindings { url, generator, .. } = b; + log::debug!("Found {pkg} bindings generated by {generator} at {url}"); + } + + Ok(b.clone()) + } + None => { + if all_bindings.is_empty() { + anyhow::bail!("The package doesn't contain any bindings"); + } else { + todo!(); + } + } + } +} + +#[derive(Debug, Copy, Clone)] +enum Target { + Pip, + Yarn { dev: bool }, + Npm { dev: bool }, +} + +impl Target { + fn language(self) -> ProgrammingLanguage { + match self { + Target::Pip => ProgrammingLanguage::PYTHON, + Target::Yarn { .. } | Target::Npm { .. } => ProgrammingLanguage::JAVASCRIPT, + } + } + + /// Construct a command which we can run to add packages. + /// + /// This deliberately runs the command using the OS shell instead of + /// invoking the tool directly. That way we can handle when a version + /// manager (e.g. `nvm` or `asdf`) replaces the tool with a script (e.g. + /// `npm.cmd` or `yarn.ps1`). + /// + /// See for more. + fn command(self, packages: &[Bindings]) -> Result { + let command_line = match self { + Target::Pip => { + if Command::new("pip").arg("--version").output().is_ok() { + "pip install" + } else if Command::new("pip3").arg("--version").output().is_ok() { + "pip3 install" + } else if Command::new("python").arg("--version").output().is_ok() { + "python -m pip install" + } else if Command::new("python3").arg("--version").output().is_ok() { + "python3 -m pip install" + } else { + return Err(anyhow::anyhow!( + "neither pip, pip3, python or python3 installed" + )); + } + } + Target::Yarn { dev } => { + if Command::new("yarn").arg("--version").output().is_err() { + return Err(anyhow::anyhow!("yarn not installed")); + } + if dev { + "yarn add --dev" + } else { + "yarn add" + } + } + Target::Npm { dev } => { + if Command::new("npm").arg("--version").output().is_err() { + return Err(anyhow::anyhow!("yarn not installed")); + } + if dev { + "npm install --dev" + } else { + "npm install" + } + } + }; + let mut command_line = command_line.to_string(); + + for pkg in packages { + command_line.push(' '); + command_line.push_str(&pkg.url); + } + + if cfg!(windows) { + let mut cmd = Command::new("cmd"); + cmd.arg("/C").arg(command_line); + Ok(cmd) + } else { + let mut cmd = Command::new("sh"); + cmd.arg("-c").arg(command_line); + Ok(cmd) + } + } +} diff --git a/lib/cli/src/commands/create_exe.rs b/lib/cli/src/commands/create_exe.rs index e2f8d6204..c13a38d11 100644 --- a/lib/cli/src/commands/create_exe.rs +++ b/lib/cli/src/commands/create_exe.rs @@ -4,11 +4,8 @@ use super::ObjectFormat; use crate::store::CompilerOptions; use anyhow::{Context, Result}; use clap::Parser; -#[cfg(feature = "http")] -use serde::{Deserialize, Serialize}; -#[cfg(feature = "http")] -use std::collections::BTreeMap; use std::env; +use std::fmt::Write as _; use std::fs; use std::fs::File; use std::io::prelude::*; @@ -240,8 +237,8 @@ impl CreateExe { if let Some(setup) = cross_compilation.as_ref() { self.compile_zig( output_path, - wasm_module_path, - std::path::Path::new("static_defs.h").into(), + &[wasm_module_path], + &[std::path::Path::new("static_defs.h").into()], setup, &[], None, @@ -311,8 +308,8 @@ impl CreateExe { if let Some(setup) = cross_compilation.as_ref() { self.compile_zig( output_path, - object_file_path, - std::path::Path::new("static_defs.h").into(), + &[object_file_path], + &[std::path::Path::new("static_defs.h").into()], setup, &[], None, @@ -371,7 +368,7 @@ impl CreateExe { )); } - let target = if let Some(target_triple) = target_triple.clone() { + let target = if let Some(target_triple) = target_triple { target_triple } else { return Err(anyhow!( @@ -406,13 +403,7 @@ impl CreateExe { v.canonicalize().unwrap_or(v) } else { { - let libwasmer_path = if target_triple.unwrap_or(Triple::host()).operating_system - == wasmer_types::OperatingSystem::Windows - { - "lib/wasmer.lib" - } else { - "lib/libwasmer.a" - }; + let libwasmer_path = "lib/libwasmer.a"; let tarball_dir; let filename = if let Some(local_tarball) = cross_subc.tarball.as_ref() { let target_file_path = local_tarball @@ -494,6 +485,7 @@ impl CreateExe { run_c_compile(&c_src_path, &c_src_obj, target_triple.clone()) .context("Failed to compile C source code")?; + LinkCode { object_paths: vec![c_src_obj, wasm_object_path], output_path, @@ -511,8 +503,8 @@ impl CreateExe { fn compile_zig( &self, output_path: PathBuf, - object_path: PathBuf, - mut header_code_path: PathBuf, + object_paths: &[PathBuf], + header_code_paths: &[PathBuf], setup: &CrossCompileSetup, pirita_atoms: &[String], pirita_main_atom: Option<&str>, @@ -548,12 +540,16 @@ impl CreateExe { std::fs::write(&c_src_path, WASMER_STATIC_MAIN_C_SOURCE)?; } - if !header_code_path.is_dir() { - header_code_path.pop(); - } + let mut header_code_paths = header_code_paths.to_vec(); - if header_code_path.display().to_string().is_empty() { - header_code_path = std::env::current_dir()?; + for h in header_code_paths.iter_mut() { + if !h.is_dir() { + h.pop(); + } + + if h.display().to_string().is_empty() { + *h = std::env::current_dir()?; + } } /* Compile main function */ @@ -563,28 +559,49 @@ impl CreateExe { include_dir.push("include"); let mut cmd = Command::new(zig_binary_path); - let mut cmd_mut: &mut Command = cmd - .arg("cc") - .arg("-target") - .arg(&zig_triple) - .arg(&format!("-L{}", libwasmer_path.display())) - .arg(&format!("-l:{}", lib_filename)) - .arg(&format!("-I{}", include_dir.display())) - .arg(&format!("-I{}", header_code_path.display())); - if !zig_triple.contains("windows") { - cmd_mut = cmd_mut.arg("-lunwind"); + cmd.arg("build-exe"); + cmd.arg("-target"); + cmd.arg(&zig_triple); + cmd.arg(&format!("-I{}/", include_dir.display())); + for h in header_code_paths { + cmd.arg(&format!("-I{}/", h.display())); } - cmd_mut = cmd_mut.arg(&object_path).arg(&c_src_path); + if zig_triple.contains("windows") { + cmd.arg("-lc++"); + } else { + cmd.arg("-lc"); + } + cmd.arg("-lunwind"); + cmd.arg("-OReleaseSafe"); + cmd.arg("-fstrip"); + cmd.arg("-dead_strip"); + cmd.arg("-dead_strip_dylibs"); + cmd.arg("-fno-compiler-rt"); + cmd.arg(&format!("-femit-bin={}", output_path.display())); + for o in object_paths { + cmd.arg(o); + } + cmd.arg(&c_src_path); + cmd.arg(libwasmer_path.join(&lib_filename)); + if zig_triple.contains("windows") { + let mut libwasmer_parent = libwasmer_path.clone(); + libwasmer_parent.pop(); + let files_winsdk = std::fs::read_dir(libwasmer_parent.join("winsdk")) + .ok() + .map(|res| res.filter_map(|r| Some(r.ok()?.path())).collect::>()) + .unwrap_or_default(); + for f in files_winsdk { + cmd.arg(f); + } + } if let Some(volume_obj) = pirita_volume_path.as_ref() { - cmd_mut = cmd_mut.arg(volume_obj.clone()); + cmd.arg(volume_obj.clone()); } - cmd_mut - .arg("-o") - .arg(&output_path) - .output() - .context("Could not execute `zig`")? + #[cfg(feature = "debug")] + log::debug!("{:?}", cmd); + cmd.output().context("Could not execute `zig`")? }; if !compilation.status.success() { return Err(anyhow::anyhow!(String::from_utf8_lossy( @@ -763,8 +780,6 @@ impl CreateExe { let volume_object_path = Self::write_volume_obj(volume_bytes, target, tempdir_path)?; - link_objects.push(volume_object_path); - #[cfg(not(windows))] let c_src_obj = working_dir.join("wasmer_main.o"); #[cfg(windows)] @@ -784,66 +799,29 @@ impl CreateExe { std::fs::write(&c_src_path, c_code.as_bytes()) .context("Failed to open C source code file")?; + // TODO: this branch is never hit because object format serialized + + // cross compilation doesn't work if let Some(setup) = cross_compilation { - let CrossCompileSetup { - ref target, - ref zig_binary_path, - ref library, - } = setup; + // zig treats .o files the same as .c files + link_objects.push(c_src_path); - let mut libwasmer_path = library.to_path_buf(); - let zig_triple = triple_to_zig_triple(target); - - // Cross compilation is only possible with zig - println!("Library Path: {}", libwasmer_path.display()); - println!("Using zig binary: {}", zig_binary_path.display()); - println!("Using zig target triple: {}", &zig_triple); - - let lib_filename = libwasmer_path - .file_name() - .unwrap() - .to_str() - .unwrap() - .to_string(); - - /* Compile main function */ - let compilation = { - libwasmer_path.pop(); - let mut include_dir = libwasmer_path.clone(); - include_dir.pop(); - include_dir.push("include"); - println!("include dir: {}", include_dir.display()); - let mut cmd = Command::new(zig_binary_path); - let mut cmd_mut: &mut Command = cmd - .arg("cc") - .arg("--verbose") - .arg("-target") - .arg(&zig_triple) - .arg(&format!("-L{}", libwasmer_path.display())) - .arg(&format!("-l:{}", lib_filename)) - .arg(&format!("-I{}", include_dir.display())); - if !zig_triple.contains("windows") { - cmd_mut = cmd_mut.arg("-lunwind"); - } - cmd_mut - .args(link_objects.into_iter()) - .arg(&c_src_path) - .arg("-o") - .arg(&output_path) - .output() - .context("Could not execute `zig`")? - }; - if !compilation.status.success() { - return Err(anyhow::anyhow!(String::from_utf8_lossy( - &compilation.stderr - ) - .to_string())); - } + self.compile_zig( + output_path, + &link_objects, + &[], + &setup, + &atom_names, + Some(&entrypoint), + Some(volume_object_path), + )?; } else { + // compile with cc instead of zig run_c_compile(c_src_path.as_path(), &c_src_obj, self.target_triple.clone()) .context("Failed to compile C source code")?; link_objects.push(c_src_obj); + link_objects.push(volume_object_path); + LinkCode { object_paths: link_objects, output_path, @@ -866,8 +844,8 @@ impl CreateExe { if let Some(setup) = cross_compilation.as_ref() { self.compile_zig( output_path, - object_file_path, - static_defs_file_path, + &[object_file_path], + &[static_defs_file_path], setup, &atom_names, Some(&entrypoint), @@ -912,7 +890,8 @@ impl CreateExe { for atom_name in atom_names.iter() { let atom_name = Self::normalize_atom_name(atom_name); - c_code_to_instantiate.push_str(&format!( + write!( + c_code_to_instantiate, " wasm_module_t *atom_{atom_name} = wasmer_object_module_new(store, \"{atom_name}\"); @@ -923,11 +902,16 @@ impl CreateExe { return -1; }} " - )); - deallocate_module.push_str(&format!("wasm_module_delete(atom_{atom_name});")); + ) + .unwrap(); + write!(deallocate_module, "wasm_module_delete(atom_{atom_name});").unwrap(); } - c_code_to_instantiate.push_str(&format!("wasm_module_t *module = atom_{atom_to_run};")); + write!( + c_code_to_instantiate, + "wasm_module_t *module = atom_{atom_to_run};" + ) + .unwrap(); WASMER_STATIC_MAIN_C_SOURCE .replace("#define WASI", "#define WASI\r\n#define WASI_PIRITA") @@ -1036,8 +1020,6 @@ impl CreateExe { .canonicalize() .context("Failed to find libwasmer")?; - println!("Using libwasmer file: {}", libwasmer_path.display()); - let lib_filename = libwasmer_path .file_name() .unwrap() @@ -1350,19 +1332,24 @@ impl LinkCode { #[cfg(feature = "http")] mod http_fetch { use anyhow::{anyhow, Context, Result}; - use http_req::{ - request::Request, - response::{Response, StatusCode}, - uri::Uri, - }; + use http_req::{request::Request, response::StatusCode, uri::Uri}; use std::convert::TryFrom; + use target_lexicon::OperatingSystem; pub fn get_latest_release() -> Result { let mut writer = Vec::new(); let uri = Uri::try_from("https://api.github.com/repos/wasmerio/wasmer/releases").unwrap(); - let response = Request::new(&uri) - .header("User-Agent", "wasmer") + // Increases rate-limiting in GitHub CI + let auth = std::env::var("GITHUB_TOKEN"); + let mut response = Request::new(&uri); + + if let Ok(token) = auth { + response.header("Authorization", &format!("Bearer {token}")); + } + + let response = response + .header("User-Agent", "wasmerio") .header("Accept", "application/vnd.github.v3+json") .timeout(Some(std::time::Duration::new(30, 0))) .send(&mut writer) @@ -1370,10 +1357,12 @@ mod http_fetch { .context("Could not lookup wasmer repository on Github.")?; if response.status_code() != StatusCode::new(200) { - return Err(anyhow!( - "Github API replied with non-200 status code: {}", - response.status_code() - )); + #[cfg(feature = "debug")] + log::warn!( + "Warning: Github API replied with non-200 status code: {}. Response: {}", + response.status_code(), + String::from_utf8_lossy(&writer), + ); } let v: std::result::Result = serde_json::from_reader(&*writer); @@ -1436,31 +1425,64 @@ mod http_fetch { } }; + // Test if file has been already downloaded if let Ok(mut cache_path) = super::get_libwasmer_cache_path() { - match std::fs::read_dir(&cache_path).and_then(|r| { + let paths = std::fs::read_dir(&cache_path).and_then(|r| { r.map(|res| res.map(|e| e.path())) .collect::, std::io::Error>>() - }) { - Ok(mut entries) => { + }); + + if let Ok(mut entries) = paths { + entries.retain(|p| p.to_str().map(|p| p.ends_with(".tar.gz")).unwrap_or(false)); + + // create-exe on Windows is special: we use the windows-gnu64.tar.gz (GNU ABI) + // to link, not the windows-amd64.tar.gz (MSVC ABI) + if target_triple.operating_system == OperatingSystem::Windows { + entries.retain(|p| { + p.to_str() + .map(|p| p.contains("windows") && p.contains("gnu64")) + .unwrap_or(false) + }); + } else { entries.retain(|p| p.to_str().map(|p| check_arch(p)).unwrap_or(true)); entries.retain(|p| p.to_str().map(|p| check_vendor(p)).unwrap_or(true)); entries.retain(|p| p.to_str().map(|p| check_os(p)).unwrap_or(true)); entries.retain(|p| p.to_str().map(|p| check_env(p)).unwrap_or(true)); - if entries.len() == 1 { - cache_path.push(&entries[0]); - if cache_path.exists() { - eprintln!( - "Using cached tarball to cache path `{}`.", - cache_path.display() - ); - return Ok(cache_path); - } + } + + if !entries.is_empty() { + cache_path.push(&entries[0]); + if cache_path.exists() { + eprintln!( + "Using cached tarball to cache path `{}`.", + cache_path.display() + ); + return Ok(cache_path); } } - Err(_ioerr) => {} } } - if let Some(assets) = release["assets"].as_array_mut() { + + let assets = match release["assets"].as_array_mut() { + Some(s) => s, + None => { + return Err(anyhow!( + "GitHub API: no [assets] array in JSON response for latest releases" + )); + } + }; + + // create-exe on Windows is special: we use the windows-gnu64.tar.gz (GNU ABI) + // to link, not the windows-amd64.tar.gz (MSVC ABI) + if target_triple.operating_system == OperatingSystem::Windows { + assets.retain(|a| { + if let Some(name) = a["name"].as_str() { + name.contains("windows") && name.contains("gnu64") + } else { + false + } + }); + } else { assets.retain(|a| { if let Some(name) = a["name"].as_str() { check_arch(name) @@ -1475,6 +1497,7 @@ mod http_fetch { false } }); + assets.retain(|a| { if let Some(name) = a["name"].as_str() { check_os(name) @@ -1482,6 +1505,7 @@ mod http_fetch { false } }); + assets.retain(|a| { if let Some(name) = a["name"].as_str() { check_env(name) @@ -1489,128 +1513,105 @@ mod http_fetch { false } }); + } - if assets.len() == 1 { - let browser_download_url = - if let Some(url) = assets[0]["browser_download_url"].as_str() { - url.to_string() - } else { - return Err(anyhow!( - "Could not get download url from Github API response." - )); - }; - let filename = browser_download_url - .split('/') - .last() - .unwrap_or("output") - .to_string(); - let mut file = std::fs::File::create(&filename)?; - println!("Downloading {} to {}", browser_download_url, &filename); - let download_thread: std::thread::JoinHandle> = - std::thread::spawn(move || { - let uri = Uri::try_from(browser_download_url.as_str())?; - let mut response = Request::new(&uri) - .header("User-Agent", "wasmer") - .send(&mut file) - .map_err(anyhow::Error::new) - .context("Could not lookup wasmer artifact on Github.")?; - if response.status_code() == StatusCode::new(302) { - let redirect_uri = - Uri::try_from(response.headers().get("Location").unwrap().as_str()) - .unwrap(); - response = Request::new(&redirect_uri) - .header("User-Agent", "wasmer") - .send(&mut file) - .map_err(anyhow::Error::new) - .context("Could not lookup wasmer artifact on Github.")?; - } - Ok(response) - }); - match super::get_libwasmer_cache_path() { - Ok(mut cache_path) => { - cache_path.push(&filename); - if !cache_path.exists() { - if let Err(err) = std::fs::copy(&filename, &cache_path) { - eprintln!( - "Could not store tarball to cache path `{}`: {}", - cache_path.display(), - err - ); - } else { - eprintln!( - "Cached tarball to cache path `{}`.", - cache_path.display() - ); - } - } - } - Err(err) => { - eprintln!( - "Could not determine cache path for downloaded binaries.: {}", - err - ); - } + if assets.len() != 1 { + return Err(anyhow!( + "GitHub API: more that one release selected for target {target_triple}: {assets:?}" + )); + } + + let browser_download_url = if let Some(url) = assets[0]["browser_download_url"].as_str() { + url.to_string() + } else { + return Err(anyhow!( + "Could not get download url from Github API response." + )); + }; + + let filename = browser_download_url + .split('/') + .last() + .unwrap_or("output") + .to_string(); + + let download_tempdir = tempdir::TempDir::new("wasmer-download")?; + let download_path = download_tempdir.path().join(&filename); + + let mut file = std::fs::File::create(&download_path)?; + #[cfg(feature = "debug")] + log::debug!( + "Downloading {} to {}", + browser_download_url, + download_path.display() + ); + + let mut response = reqwest::blocking::Client::builder() + .redirect(reqwest::redirect::Policy::limited(10)) + .timeout(std::time::Duration::from_secs(10)) + .build() + .map_err(anyhow::Error::new) + .context("Could not lookup wasmer artifact on Github.")? + .get(browser_download_url.as_str()) + .send() + .map_err(anyhow::Error::new) + .context("Could not lookup wasmer artifact on Github.")?; + + response + .copy_to(&mut file) + .map_err(|e| anyhow::anyhow!("{e}"))?; + + match super::get_libwasmer_cache_path() { + Ok(mut cache_path) => { + cache_path.push(&filename); + if let Err(err) = std::fs::copy(&download_path, &cache_path) { + eprintln!( + "Could not store tarball to cache path `{}`: {}", + cache_path.display(), + err + ); + Err(anyhow!( + "Could not copy from {} to {}", + download_path.display(), + cache_path.display() + )) + } else { + eprintln!("Cached tarball to cache path `{}`.", cache_path.display()); + Ok(cache_path) } - let _response = download_thread - .join() - .expect("Could not join downloading thread"); - match super::get_libwasmer_cache_path() { - Ok(mut cache_path) => { - cache_path.push(&filename); - if !cache_path.exists() { - if let Err(err) = std::fs::copy(&filename, &cache_path) { - eprintln!( - "Could not store tarball to cache path `{}`: {}", - cache_path.display(), - err - ); - } else { - eprintln!( - "Cached tarball to cache path `{}`.", - cache_path.display() - ); - } - } - } - Err(err) => { - eprintln!( - "Could not determine cache path for downloaded binaries.: {}", - err - ); - } - } - return Ok(filename.into()); + } + Err(err) => { + eprintln!( + "Could not determine cache path for downloaded binaries.: {}", + err + ); + Err(anyhow!("Could not determine libwasmer cache path")) } } - Err(anyhow!("Could not get release artifact.")) } } fn untar(tarball: std::path::PathBuf, target: std::path::PathBuf) -> Result> { - let files = std::process::Command::new("tar") - .arg("-tf") - .arg(&tarball) - .output() - .expect("failed to execute process") - .stdout; + use walkdir::WalkDir; - let files_s = String::from_utf8(files)?; + wasmer_registry::try_unpack_targz(&tarball, &target, false)?; - let files = files_s - .lines() - .filter(|p| !p.ends_with('/')) - .map(|s| s.to_string()) - .collect::>(); + Ok(WalkDir::new(&target) + .into_iter() + .filter_map(|e| e.ok()) + .map(|entry| format!("{}", entry.path().display())) + .collect()) +} - let _ = std::fs::create_dir_all(&target); - let _output = std::process::Command::new("tar") - .arg("-xf") - .arg(&tarball) - .arg("-C") - .arg(&target) - .output() - .expect("failed to execute process"); - Ok(files) +fn get_zig_exe_str() -> &'static str { + #[cfg(target_os = "windows")] + { + "zig.exe" + } + #[cfg(not(target_os = "windows"))] + { + "zig" + } } fn find_zig_binary(path: Option) -> Result { @@ -1643,24 +1644,13 @@ fn find_zig_binary(path: Option) -> Result { OsStr::new("") }, )) { - p.push("zig"); + p.push(get_zig_exe_str()); if p.exists() { retval = Some(p); break; } } - retval - .or_else(|| { - #[cfg(feature = "http")] - { - try_autoinstall_zig().map(|p| p.join("zig")) - } - #[cfg(not(feature = "http"))] - { - None - } - }) - .ok_or_else(|| anyhow!("Could not find `zig` binary in PATH."))? + retval.ok_or_else(|| anyhow!("Could not find `zig` binary in PATH."))? }; let version = std::process::Command::new(&retval) @@ -1688,126 +1678,3 @@ fn find_zig_binary(path: Option) -> Result { Ok(retval) } } - -/// Tries to auto-install zig into ~/.wasmer/utils/zig/{version} -#[cfg(feature = "http")] -fn try_autoinstall_zig() -> Option { - let zig_dir = wasmer_registry::get_wasmer_root_dir()? - .join("utils") - .join("zig"); - let mut existing_version = None; - - if !zig_dir.exists() { - return install_zig(&zig_dir); - } - - if let Ok(mut rd) = std::fs::read_dir(&zig_dir) { - existing_version = rd.next().and_then(|entry| { - let string = entry.ok()?.file_name().to_str()?.to_string(); - if zig_dir.join(&string).join("zig").exists() { - Some(string) - } else { - None - } - }) - } - - if let Some(exist) = existing_version { - return Some(zig_dir.join(exist)); - } - - install_zig(&zig_dir) -} - -#[cfg(feature = "http")] -fn install_zig(target_targz_path: &Path) -> Option { - let resp = reqwest::blocking::get("https://ziglang.org/download/index.json"); - let resp = resp.ok()?; - let resp = resp.json::(); - let resp = resp.ok()?; - - let default_key = "master".to_string(); - let (latest_version, latest_version_json) = resp - .versions - .get(&default_key) - .map(|v| (&default_key, v)) - .or_else(|| resp.versions.iter().next())?; - - let latest_version = match latest_version_json.version.as_ref() { - Some(s) => s, - None => latest_version, - }; - - let install_dir = target_targz_path.join(latest_version); - if install_dir.join("zig").exists() { - return Some(install_dir); - } - - let native_host_url = latest_version_json.get_native_host_url()?; - let _ = std::fs::create_dir_all(&install_dir); - wasmer_registry::download_and_unpack_targz(&native_host_url, &install_dir, true).ok() -} - -#[cfg(feature = "http")] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -struct ZiglangOrgJson { - #[serde(flatten)] - versions: BTreeMap, -} - -#[cfg(feature = "http")] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -struct ZiglangOrgJsonTarget { - version: Option, - date: String, - src: ZiglangOrgJsonBuildTarget, - #[serde(rename = "x86_64-freebsd")] - x86_64_freebsd: Option, - #[serde(rename = "x86_64-macos")] - x86_64_macos: Option, - #[serde(rename = "aarch64-macos")] - aarch64_macos: Option, - #[serde(rename = "x86_64-windows")] - x86_64_windows: Option, - #[serde(rename = "x86_64-linux")] - x86_64_linux: Option, - #[serde(rename = "aarch64-linux")] - aarch64_linux: Option, -} - -impl ZiglangOrgJsonTarget { - pub fn get_native_host_url(&self) -> Option { - let native_host = format!("{}", target_lexicon::HOST); - if native_host.starts_with("x86_64") { - if native_host.contains("freebsd") { - Some(self.x86_64_freebsd.as_ref()?.tarball.clone()) - } else if native_host.contains("darwin") || native_host.contains("macos") { - Some(self.x86_64_macos.as_ref()?.tarball.clone()) - } else if native_host.contains("windows") { - Some(self.x86_64_windows.as_ref()?.tarball.clone()) - } else if native_host.contains("linux") { - Some(self.x86_64_linux.as_ref()?.tarball.clone()) - } else { - None - } - } else if native_host.starts_with("aarch64") { - if native_host.contains("darwin") || native_host.contains("macos") { - Some(self.aarch64_macos.as_ref()?.tarball.clone()) - } else if native_host.contains("linux") { - Some(self.aarch64_linux.as_ref()?.tarball.clone()) - } else { - None - } - } else { - None - } - } -} - -#[cfg(feature = "http")] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -struct ZiglangOrgJsonBuildTarget { - tarball: String, - shasum: String, - size: String, -} diff --git a/lib/cli/src/commands/list.rs b/lib/cli/src/commands/list.rs index 332129b39..0851d9947 100644 --- a/lib/cli/src/commands/list.rs +++ b/lib/cli/src/commands/list.rs @@ -36,7 +36,7 @@ impl List { if empty_table { table.add_empty_row(); } - let _ = table.printstd(); + table.printstd(); Ok(()) } diff --git a/lib/cli/src/commands/login.rs b/lib/cli/src/commands/login.rs new file mode 100644 index 000000000..96f412bac --- /dev/null +++ b/lib/cli/src/commands/login.rs @@ -0,0 +1,83 @@ +use clap::Parser; +#[cfg(not(test))] +use dialoguer::Input; + +/// Subcommand for listing packages +#[derive(Debug, Clone, Parser)] +pub struct Login { + /// Registry to log into (default: wapm.io) + #[clap(long, default_value = "wapm.io")] + pub registry: String, + /// Login token + #[clap(name = "TOKEN")] + pub token: Option, +} + +impl Login { + fn get_token_or_ask_user(&self) -> Result { + match self.token.as_ref() { + Some(s) => Ok(s.clone()), + None => { + let registry_host = wasmer_registry::format_graphql(&self.registry); + let registry_tld = tldextract::TldExtractor::new(tldextract::TldOption::default()) + .extract(®istry_host) + .map_err(|e| { + std::io::Error::new( + std::io::ErrorKind::Other, + format!("Invalid registry for login {}: {e}", self.registry), + ) + })?; + let login_prompt = match ( + registry_tld.domain.as_deref(), + registry_tld.suffix.as_deref(), + ) { + (Some(d), Some(s)) => { + format!("Please paste the login token for https://{d}.{s}/me") + } + _ => "Please paste the login token".to_string(), + }; + #[cfg(test)] + { + Ok(login_prompt) + } + #[cfg(not(test))] + { + Input::new().with_prompt(&login_prompt).interact_text() + } + } + } + } + + /// execute [List] + pub fn execute(&self) -> Result<(), anyhow::Error> { + let token = self.get_token_or_ask_user()?; + match wasmer_registry::login::login_and_save_token(&self.registry, &token)? { + Some(s) => println!("Login for WAPM user {:?} saved", s), + None => println!( + "Error: no user found on registry {:?} with token {:?}. Token saved regardless.", + self.registry, token + ), + } + Ok(()) + } +} + +#[test] +fn test_login_2() { + let login = Login { + registry: "wapm.dev".to_string(), + token: None, + }; + + assert_eq!( + login.get_token_or_ask_user().unwrap(), + "Please paste the login token for https://wapm.dev/me" + ); + + let login = Login { + registry: "wapm.dev".to_string(), + token: Some("abc".to_string()), + }; + + assert_eq!(login.get_token_or_ask_user().unwrap(), "abc"); +} diff --git a/lib/cli/src/commands/run.rs b/lib/cli/src/commands/run.rs index 778f65020..e5d329108 100644 --- a/lib/cli/src/commands/run.rs +++ b/lib/cli/src/commands/run.rs @@ -11,6 +11,7 @@ use std::collections::HashMap; use std::ops::Deref; use std::path::PathBuf; use std::str::FromStr; +use url::Url; use wasmer::FunctionEnv; use wasmer::*; #[cfg(feature = "cache")] @@ -647,17 +648,20 @@ impl Run { } } -fn start_spinner(msg: String) -> Option { +fn start_spinner(msg: String) -> Option { if !isatty::stdout_isatty() { return None; } - Some( - spinner::SpinnerBuilder::new(msg) - .spinner(vec![ - "⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷", " ", "⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈", - ]) - .start(), - ) + #[cfg(target_os = "windows")] + { + use colored::control; + let _ = control::set_virtual_terminal(true); + } + Some(spinoff::Spinner::new( + spinoff::Spinners::Dots, + msg, + spinoff::Color::White, + )) } /// Before looking up a command from the registry, try to see if we have @@ -708,8 +712,7 @@ pub(crate) fn try_autoinstall_package( force_install, ); if let Some(sp) = sp.take() { - sp.close(); - print!("\r"); + sp.clear(); } let _ = std::io::stdout().flush(); let (_, package_dir) = match result { @@ -767,8 +770,8 @@ fn try_lookup_command(sv: &mut SplitVersion) -> Result Result {} + Err(ExecuteLocalPackageError::DuringExec(e)) => return Err(e), + Ok(o) => return Ok(o), + } + } + } + let package = format!("{}", r.path.display()); let mut is_fake_sv = false; - let mut sv = match SplitVersion::new(&package) { + let mut sv = match SplitVersion::parse(&package) { Ok(o) => o, Err(_) => { let mut fake_sv = SplitVersion { @@ -911,3 +925,41 @@ pub(crate) fn try_run_package_or_file( // else: local package not found - try to download and install package try_autoinstall_package(args, &sv, package_download_info, r.force_install) } + +fn try_run_url( + url: &Url, + _args: &[String], + r: &Run, + _debug: bool, +) -> Result<(), ExecuteLocalPackageError> { + let checksum = wasmer_registry::get_remote_webc_checksum(url).map_err(|e| { + ExecuteLocalPackageError::BeforeExec(anyhow::anyhow!("error fetching {url}: {e}")) + })?; + + let packages = wasmer_registry::get_all_installed_webc_packages(); + + if !packages.iter().any(|p| p.checksum == checksum) { + let sp = start_spinner(format!("Installing {}", url)); + + let result = wasmer_registry::install_webc_package(url, &checksum); + + result.map_err(|e| { + ExecuteLocalPackageError::BeforeExec(anyhow::anyhow!("error fetching {url}: {e}")) + })?; + + if let Some(sp) = sp { + sp.clear(); + } + } + + let webc_dir = wasmer_registry::get_webc_dir(); + + let webc_install_path = webc_dir + .context("Error installing package: no webc dir") + .map_err(ExecuteLocalPackageError::BeforeExec)? + .join(checksum); + + let mut r = r.clone(); + r.path = webc_install_path; + r.execute().map_err(ExecuteLocalPackageError::DuringExec) +} diff --git a/lib/cli/src/commands/whoami.rs b/lib/cli/src/commands/whoami.rs new file mode 100644 index 000000000..275467fc5 --- /dev/null +++ b/lib/cli/src/commands/whoami.rs @@ -0,0 +1,18 @@ +use clap::Parser; + +#[derive(Debug, Parser)] +/// The options for the `wasmer whoami` subcommand +pub struct Whoami { + /// Which registry to check the logged in username for + #[clap(long, name = "registry")] + pub registry: Option, +} + +impl Whoami { + /// Execute `wasmer whoami` + pub fn execute(&self) -> Result<(), anyhow::Error> { + let (registry, username) = wasmer_registry::whoami(self.registry.as_deref())?; + println!("logged into registry {registry:?} as user {username:?}"); + Ok(()) + } +} diff --git a/lib/compiler-cranelift/Cargo.toml b/lib/compiler-cranelift/Cargo.toml index f762b180c..2968e65e0 100644 --- a/lib/compiler-cranelift/Cargo.toml +++ b/lib/compiler-cranelift/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-compiler-cranelift" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Cranelift compiler for Wasmer WebAssembly runtime" categories = ["wasm"] keywords = ["wasm", "webassembly", "compiler", "cranelift"] @@ -12,8 +12,8 @@ readme = "README.md" edition = "2018" [dependencies] -wasmer-compiler = { path = "../compiler", version = "=3.0.0-rc.2", features = ["translator", "compiler"], default-features = false } -wasmer-types = { path = "../types", version = "=3.0.0-rc.2", default-features = false, features = ["std"] } +wasmer-compiler = { path = "../compiler", version = "=3.0.2", features = ["translator", "compiler"], default-features = false } +wasmer-types = { path = "../types", version = "=3.0.2", default-features = false, features = ["std"] } cranelift-entity = { version = "0.86.1", default-features = false } cranelift-codegen = { version = "0.86.1", default-features = false, features = ["x86", "arm64"] } cranelift-frontend = { version = "0.86.1", default-features = false } diff --git a/lib/compiler-cranelift/src/compiler.rs b/lib/compiler-cranelift/src/compiler.rs index 0a1a189f3..9f2481bb0 100644 --- a/lib/compiler-cranelift/src/compiler.rs +++ b/lib/compiler-cranelift/src/compiler.rs @@ -384,13 +384,13 @@ impl Compiler for CraneliftCompiler { .into_iter() .collect::>(); - Ok(Compilation::new( - functions.into_iter().collect(), + Ok(Compilation { + functions: functions.into_iter().collect(), custom_sections, function_call_trampolines, dynamic_function_trampolines, - dwarf, - )) + debug: dwarf, + }) } } @@ -434,7 +434,7 @@ fn translate_ir_trapcode(trap: ir::TrapCode) -> TrapCode { match trap { ir::TrapCode::StackOverflow => TrapCode::StackOverflow, ir::TrapCode::HeapOutOfBounds => TrapCode::HeapAccessOutOfBounds, - ir::TrapCode::HeapMisaligned => TrapCode::HeapMisaligned, + ir::TrapCode::HeapMisaligned => TrapCode::UnalignedAtomic, ir::TrapCode::TableOutOfBounds => TrapCode::TableAccessOutOfBounds, ir::TrapCode::IndirectCallToNull => TrapCode::IndirectCallToNull, ir::TrapCode::BadSignature => TrapCode::BadSignature, diff --git a/lib/compiler-cranelift/src/func_environ.rs b/lib/compiler-cranelift/src/func_environ.rs index afb6010d4..0608b7add 100644 --- a/lib/compiler-cranelift/src/func_environ.rs +++ b/lib/compiler-cranelift/src/func_environ.rs @@ -104,6 +104,15 @@ pub struct FuncEnvironment<'module_environment> { /// The external function signature for implementing wasm's `table.fill`. table_fill_sig: Option, + /// The external function signature for implementing wasm's `memory32.atomic.wait32`. + memory32_atomic_wait32_sig: Option, + + /// The external function signature for implementing wasm's `memory32.atomic.wait64`. + memory32_atomic_wait64_sig: Option, + + /// The external function signature for implementing wasm's `memory32.atomic.notify`. + memory32_atomic_notify_sig: Option, + /// Offsets to struct fields accessed by JIT code. offsets: VMOffsets, @@ -143,6 +152,9 @@ impl<'module_environment> FuncEnvironment<'module_environment> { data_drop_sig: None, func_ref_sig: None, table_fill_sig: None, + memory32_atomic_wait32_sig: None, + memory32_atomic_wait64_sig: None, + memory32_atomic_notify_sig: None, offsets: VMOffsets::new(target_config.pointer_bytes(), module), memory_styles, table_styles, @@ -684,6 +696,139 @@ impl<'module_environment> FuncEnvironment<'module_environment> { (sig, VMBuiltinFunctionIndex::get_data_drop_index()) } + fn get_memory32_atomic_wait32_sig(&mut self, func: &mut Function) -> ir::SigRef { + let sig = self.memory32_atomic_wait32_sig.unwrap_or_else(|| { + func.import_signature(Signature { + params: vec![ + AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext), + // Memory Index + AbiParam::new(I32), + // Dst + AbiParam::new(I32), + // Val + AbiParam::new(I32), + // Timeout + AbiParam::new(I64), + ], + returns: vec![AbiParam::new(I32)], + call_conv: self.target_config.default_call_conv, + }) + }); + self.memory32_atomic_wait32_sig = Some(sig); + sig + } + + /// Return the memory.atomic.wait32 function signature to call for the given index, + /// along with the translated index value to pass to it + /// and its index in `VMBuiltinFunctionsArray`. + fn get_memory_atomic_wait32_func( + &mut self, + func: &mut Function, + index: MemoryIndex, + ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) { + if self.module.is_imported_memory(index) { + ( + self.get_memory32_atomic_wait32_sig(func), + index.index(), + VMBuiltinFunctionIndex::get_imported_memory_atomic_wait32_index(), + ) + } else { + ( + self.get_memory32_atomic_wait32_sig(func), + self.module.local_memory_index(index).unwrap().index(), + VMBuiltinFunctionIndex::get_memory_atomic_wait32_index(), + ) + } + } + + fn get_memory32_atomic_wait64_sig(&mut self, func: &mut Function) -> ir::SigRef { + let sig = self.memory32_atomic_wait64_sig.unwrap_or_else(|| { + func.import_signature(Signature { + params: vec![ + AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext), + // Memory Index + AbiParam::new(I32), + // Dst + AbiParam::new(I32), + // Val + AbiParam::new(I64), + // Timeout + AbiParam::new(I64), + ], + returns: vec![AbiParam::new(I32)], + call_conv: self.target_config.default_call_conv, + }) + }); + self.memory32_atomic_wait64_sig = Some(sig); + sig + } + + /// Return the memory.atomic.wait64 function signature to call for the given index, + /// along with the translated index value to pass to it + /// and its index in `VMBuiltinFunctionsArray`. + fn get_memory_atomic_wait64_func( + &mut self, + func: &mut Function, + index: MemoryIndex, + ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) { + if self.module.is_imported_memory(index) { + ( + self.get_memory32_atomic_wait64_sig(func), + index.index(), + VMBuiltinFunctionIndex::get_imported_memory_atomic_wait64_index(), + ) + } else { + ( + self.get_memory32_atomic_wait64_sig(func), + self.module.local_memory_index(index).unwrap().index(), + VMBuiltinFunctionIndex::get_memory_atomic_wait64_index(), + ) + } + } + + fn get_memory32_atomic_notify_sig(&mut self, func: &mut Function) -> ir::SigRef { + let sig = self.memory32_atomic_notify_sig.unwrap_or_else(|| { + func.import_signature(Signature { + params: vec![ + AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext), + // Memory Index + AbiParam::new(I32), + // Dst + AbiParam::new(I32), + // Count + AbiParam::new(I32), + ], + returns: vec![AbiParam::new(I32)], + call_conv: self.target_config.default_call_conv, + }) + }); + self.memory32_atomic_notify_sig = Some(sig); + sig + } + + /// Return the memory.atomic.notify function signature to call for the given index, + /// along with the translated index value to pass to it + /// and its index in `VMBuiltinFunctionsArray`. + fn get_memory_atomic_notify_func( + &mut self, + func: &mut Function, + index: MemoryIndex, + ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) { + if self.module.is_imported_memory(index) { + ( + self.get_memory32_atomic_notify_sig(func), + index.index(), + VMBuiltinFunctionIndex::get_imported_memory_atomic_notify_index(), + ) + } else { + ( + self.get_memory32_atomic_notify_sig(func), + self.module.local_memory_index(index).unwrap().index(), + VMBuiltinFunctionIndex::get_memory_atomic_notify_index(), + ) + } + } + /// Translates load of builtin function and returns a pair of values `vmctx` /// and address of the loaded function. fn translate_load_builtin_function_address( @@ -1389,29 +1534,43 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro fn translate_atomic_wait( &mut self, - _pos: FuncCursor, - _index: MemoryIndex, + mut pos: FuncCursor, + index: MemoryIndex, _heap: ir::Heap, - _addr: ir::Value, - _expected: ir::Value, - _timeout: ir::Value, + addr: ir::Value, + expected: ir::Value, + timeout: ir::Value, ) -> WasmResult { - Err(WasmError::Unsupported( - "wasm atomics (fn translate_atomic_wait)".to_string(), - )) + let (func_sig, index_arg, func_idx) = if pos.func.dfg.value_type(expected) == I64 { + self.get_memory_atomic_wait64_func(pos.func, index) + } else { + self.get_memory_atomic_wait32_func(pos.func, index) + }; + let memory_index = pos.ins().iconst(I32, index_arg as i64); + let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx); + let call_inst = pos.ins().call_indirect( + func_sig, + func_addr, + &[vmctx, memory_index, addr, expected, timeout], + ); + Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap()) } fn translate_atomic_notify( &mut self, - _pos: FuncCursor, - _index: MemoryIndex, + mut pos: FuncCursor, + index: MemoryIndex, _heap: ir::Heap, - _addr: ir::Value, - _count: ir::Value, + addr: ir::Value, + count: ir::Value, ) -> WasmResult { - Err(WasmError::Unsupported( - "wasm atomics (fn translate_atomic_notify)".to_string(), - )) + let (func_sig, index_arg, func_idx) = self.get_memory_atomic_notify_func(pos.func, index); + let memory_index = pos.ins().iconst(I32, index_arg as i64); + let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx); + let call_inst = + pos.ins() + .call_indirect(func_sig, func_addr, &[vmctx, memory_index, addr, count]); + Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap()) } fn get_global_type(&self, global_index: GlobalIndex) -> Option { diff --git a/lib/compiler-cranelift/src/translator/code_translator.rs b/lib/compiler-cranelift/src/translator/code_translator.rs index e38640fb3..6b42a8e6c 100644 --- a/lib/compiler-cranelift/src/translator/code_translator.rs +++ b/lib/compiler-cranelift/src/translator/code_translator.rs @@ -2408,11 +2408,24 @@ fn finalise_atomic_mem_addr( state: &mut FuncTranslationState, environ: &mut FE, ) -> WasmResult { - // Check the alignment of `linear_mem_addr`. let access_ty_bytes = access_ty.bytes(); - let final_lma = builder - .ins() - .iadd_imm(linear_mem_addr, memarg.offset as i64); + let final_lma = if memarg.offset > 0 { + assert!(builder.func.dfg.value_type(linear_mem_addr) == I32); + let linear_mem_addr = builder.ins().uextend(I64, linear_mem_addr); + let a = builder + .ins() + .iadd_imm(linear_mem_addr, memarg.offset as i64); + let cflags = builder.ins().ifcmp_imm(a, 0x1_0000_0000i64); + builder.ins().trapif( + IntCC::UnsignedGreaterThanOrEqual, + cflags, + ir::TrapCode::HeapOutOfBounds, + ); + builder.ins().ireduce(I32, a) + } else { + linear_mem_addr + }; + // Check the alignment of `linear_mem_addr`. if access_ty_bytes != 1 { assert!(access_ty_bytes == 2 || access_ty_bytes == 4 || access_ty_bytes == 8); let final_lma_misalignment = builder diff --git a/lib/compiler-cranelift/src/translator/func_state.rs b/lib/compiler-cranelift/src/translator/func_state.rs index fafa6fe0d..773ec7810 100644 --- a/lib/compiler-cranelift/src/translator/func_state.rs +++ b/lib/compiler-cranelift/src/translator/func_state.rs @@ -189,7 +189,7 @@ impl ControlStackFrame { /// Pop values from the value stack so that it is left at the /// input-parameters to an else-block. pub fn truncate_value_stack_to_else_params(&self, stack: &mut Vec) { - debug_assert!(matches!(self, &ControlStackFrame::If { .. })); + debug_assert!(matches!(self, &Self::If { .. })); stack.truncate(self.original_stack_size()); } @@ -202,7 +202,7 @@ impl ControlStackFrame { // block can see the same number of parameters as the consequent block. As a matter of // fact, we need to substract an extra number of parameter values for if blocks. let num_duplicated_params = match self { - &ControlStackFrame::If { + &Self::If { num_param_values, .. } => { debug_assert!(num_param_values <= self.original_stack_size()); diff --git a/lib/compiler-llvm/Cargo.toml b/lib/compiler-llvm/Cargo.toml index 4510f06cd..87a827559 100644 --- a/lib/compiler-llvm/Cargo.toml +++ b/lib/compiler-llvm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-compiler-llvm" -version = "3.0.0-rc.2" +version = "3.0.2" description = "LLVM compiler for Wasmer WebAssembly runtime" categories = ["wasm"] keywords = ["wasm", "webassembly", "compiler", "llvm"] @@ -12,11 +12,11 @@ readme = "README.md" edition = "2018" [dependencies] -wasmer-compiler = { path = "../compiler", version = "=3.0.0-rc.2", features = [ +wasmer-compiler = { path = "../compiler", version = "=3.0.2", features = [ "translator", "compiler" ] } -wasmer-vm = { path = "../vm", version = "=3.0.0-rc.2" } -wasmer-types = { path = "../types", version = "=3.0.0-rc.2" } +wasmer-vm = { path = "../vm", version = "=3.0.2" } +wasmer-types = { path = "../types", version = "=3.0.2" } target-lexicon = { version = "0.12.2", default-features = false } smallvec = "1.6" object = { version = "0.28.3", default-features = false, features = ["read"] } @@ -27,7 +27,7 @@ rayon = "1.5" [dependencies.inkwell] package = "inkwell" -version = "0.1.0-beta.4" +version = "=0.1.0-beta.4" default-features = false features = ["llvm12-0", "target-x86", "target-aarch64"] diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index ac9ea5508..fd7a86d00 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -364,12 +364,12 @@ impl Compiler for LLVMCompiler { .into_iter() .collect::>(); - Ok(Compilation::new( + Ok(Compilation { functions, - module_custom_sections, + custom_sections: module_custom_sections, function_call_trampolines, dynamic_function_trampolines, - dwarf, - )) + debug: dwarf, + }) } } diff --git a/lib/compiler-llvm/src/object_file.rs b/lib/compiler-llvm/src/object_file.rs index 2807c3633..5e5734e97 100644 --- a/lib/compiler-llvm/src/object_file.rs +++ b/lib/compiler-llvm/src/object_file.rs @@ -96,6 +96,30 @@ where libcalls.insert("wasmer_vm_memory32_init".to_string(), LibCall::Memory32Init); libcalls.insert("wasmer_vm_data_drop".to_string(), LibCall::DataDrop); libcalls.insert("wasmer_vm_raise_trap".to_string(), LibCall::RaiseTrap); + libcalls.insert( + "wasmer_vm_memory32_atomic_wait32".to_string(), + LibCall::Memory32AtomicWait32, + ); + libcalls.insert( + "wasmer_vm_imported_memory32_atomic_wait32".to_string(), + LibCall::ImportedMemory32AtomicWait32, + ); + libcalls.insert( + "wasmer_vm_memory32_atomic_wait64".to_string(), + LibCall::Memory32AtomicWait64, + ); + libcalls.insert( + "wasmer_vm_imported_memory32_atomic_wait64".to_string(), + LibCall::ImportedMemory32AtomicWait64, + ); + libcalls.insert( + "wasmer_vm_memory32_atomic_notify".to_string(), + LibCall::Memory32AtomicNotify, + ); + libcalls.insert( + "wasmer_vm_imported_memory32_atomic_notify".to_string(), + LibCall::ImportedMemory32AtomicNotify, + ); let elf = object::File::parse(contents).map_err(map_object_err)?; diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index 0d372e95e..8bdd06553 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -1174,8 +1174,10 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { .into_pointer_value()) } - fn trap_if_misaligned(&self, memarg: &MemoryImmediate, ptr: PointerValue<'ctx>) { - let align = memarg.align; + fn trap_if_misaligned(&self, _memarg: &MemoryImmediate, ptr: PointerValue<'ctx>, align: u8) { + if align <= 1 { + return; + } let value = self .builder .build_ptr_to_int(ptr, self.intrinsics.i64_ty, ""); @@ -8962,7 +8964,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let result = self.builder.build_load(effective_address, ""); let load = result.as_instruction_value().unwrap(); self.annotate_user_memaccess(memory_index, memarg, 4, load)?; @@ -8980,7 +8982,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 8, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 8); let result = self.builder.build_load(effective_address, ""); let load = result.as_instruction_value().unwrap(); self.annotate_user_memaccess(memory_index, memarg, 8, load)?; @@ -8998,7 +9000,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_result = self .builder .build_load(effective_address, "") @@ -9022,7 +9024,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_result = self .builder .build_load(effective_address, "") @@ -9046,7 +9048,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_result = self .builder .build_load(effective_address, "") @@ -9070,7 +9072,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_result = self .builder .build_load(effective_address, "") @@ -9094,7 +9096,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let narrow_result = self .builder .build_load(effective_address, "") @@ -9119,7 +9121,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let store = self.builder.build_store(effective_address, value); self.annotate_user_memaccess(memory_index, memarg, 4, store)?; store @@ -9137,7 +9139,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 8, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 8); let store = self.builder.build_store(effective_address, value); self.annotate_user_memaccess(memory_index, memarg, 8, store)?; store @@ -9155,7 +9157,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i8_ty, ""); @@ -9177,7 +9179,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i16_ty, ""); @@ -9198,7 +9200,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i32_ty, ""); @@ -9219,7 +9221,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i8_ty, ""); @@ -9254,7 +9256,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i16_ty, ""); @@ -9289,7 +9291,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let old = self .builder .build_atomicrmw( @@ -9318,7 +9320,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i8_ty, ""); @@ -9353,7 +9355,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i16_ty, ""); @@ -9388,7 +9390,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i32_ty, ""); @@ -9423,7 +9425,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 8, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 8); let old = self .builder .build_atomicrmw( @@ -9452,7 +9454,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i8_ty, ""); @@ -9487,7 +9489,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i16_ty, ""); @@ -9522,7 +9524,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let old = self .builder .build_atomicrmw( @@ -9551,7 +9553,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i8_ty, ""); @@ -9586,7 +9588,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i16_ty, ""); @@ -9621,7 +9623,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i32_ty, ""); @@ -9656,7 +9658,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 8, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 8); let old = self .builder .build_atomicrmw( @@ -9685,7 +9687,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i8_ty, ""); @@ -9720,7 +9722,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i16_ty, ""); @@ -9755,7 +9757,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let old = self .builder .build_atomicrmw( @@ -9784,7 +9786,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i8_ty, ""); @@ -9819,7 +9821,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i16_ty, ""); @@ -9854,7 +9856,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i32_ty, ""); @@ -9889,7 +9891,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 8, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 8); let old = self .builder .build_atomicrmw( @@ -9918,7 +9920,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i8_ty, ""); @@ -9953,7 +9955,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i16_ty, ""); @@ -9988,7 +9990,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let old = self .builder .build_atomicrmw( @@ -10020,7 +10022,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i8_ty, ""); @@ -10055,7 +10057,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i16_ty, ""); @@ -10090,7 +10092,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i32_ty, ""); @@ -10125,7 +10127,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 8, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 8); let old = self .builder .build_atomicrmw( @@ -10154,7 +10156,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i8_ty, ""); @@ -10189,7 +10191,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i16_ty, ""); @@ -10224,7 +10226,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let old = self .builder .build_atomicrmw( @@ -10253,7 +10255,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i8_ty, ""); @@ -10288,7 +10290,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i16_ty, ""); @@ -10323,7 +10325,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i32_ty, ""); @@ -10358,7 +10360,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 8, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 8); let old = self .builder .build_atomicrmw( @@ -10387,7 +10389,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i8_ty, ""); @@ -10422,7 +10424,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i16_ty, ""); @@ -10457,7 +10459,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let old = self .builder .build_atomicrmw( @@ -10486,7 +10488,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i8_ty, ""); @@ -10521,7 +10523,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i16_ty, ""); @@ -10556,7 +10558,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let narrow_value = self.builder .build_int_truncate(value, self.intrinsics.i32_ty, ""); @@ -10591,7 +10593,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 8, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 8); let old = self .builder .build_atomicrmw( @@ -10623,7 +10625,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_cmp = self .builder .build_int_truncate(cmp, self.intrinsics.i8_ty, ""); @@ -10670,7 +10672,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_cmp = self .builder .build_int_truncate(cmp, self.intrinsics.i16_ty, ""); @@ -10717,7 +10719,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let old = self .builder .build_cmpxchg( @@ -10751,7 +10753,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 1, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 1); let narrow_cmp = self .builder .build_int_truncate(cmp, self.intrinsics.i8_ty, ""); @@ -10798,7 +10800,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 2, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 2); let narrow_cmp = self .builder .build_int_truncate(cmp, self.intrinsics.i16_ty, ""); @@ -10845,7 +10847,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 4, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 4); let narrow_cmp = self .builder .build_int_truncate(cmp, self.intrinsics.i32_ty, ""); @@ -10892,7 +10894,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { offset, 8, )?; - self.trap_if_misaligned(memarg, effective_address); + self.trap_if_misaligned(memarg, effective_address, 8); let old = self .builder .build_cmpxchg( @@ -11231,6 +11233,71 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { .unwrap(); 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 callable_func = + inkwell::values::CallableValue::try_from(wait32_fn_ptr).unwrap(); + let ret = self.builder.build_call( + callable_func, + &[ + 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()); + } + 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 callable_func = + inkwell::values::CallableValue::try_from(wait64_fn_ptr).unwrap(); + let ret = self.builder.build_call( + callable_func, + &[ + 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()); + } + 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 callable_func = + inkwell::values::CallableValue::try_from(notify_fn_ptr).unwrap(); + let cnt = self.builder.build_call( + callable_func, + &[ + 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()); + } _ => { return Err(CompileError::Codegen(format!( "Operator {:?} unimplemented", diff --git a/lib/compiler-llvm/src/translator/intrinsics.rs b/lib/compiler-llvm/src/translator/intrinsics.rs index 7a1d1ebb9..028b0a37a 100644 --- a/lib/compiler-llvm/src/translator/intrinsics.rs +++ b/lib/compiler-llvm/src/translator/intrinsics.rs @@ -240,6 +240,12 @@ pub struct Intrinsics<'ctx> { pub imported_memory_copy: FunctionValue<'ctx>, pub memory_fill: FunctionValue<'ctx>, pub imported_memory_fill: FunctionValue<'ctx>, + pub memory_wait32: FunctionValue<'ctx>, + pub imported_memory_wait32: FunctionValue<'ctx>, + pub memory_wait64: FunctionValue<'ctx>, + pub imported_memory_wait64: FunctionValue<'ctx>, + pub memory_notify: FunctionValue<'ctx>, + pub imported_memory_notify: FunctionValue<'ctx>, pub throw_trap: FunctionValue<'ctx>, @@ -256,6 +262,12 @@ pub struct Intrinsics<'ctx> { pub imported_memory32_grow_ptr_ty: PointerType<'ctx>, pub memory32_size_ptr_ty: PointerType<'ctx>, pub imported_memory32_size_ptr_ty: PointerType<'ctx>, + pub memory32_wait32_ptr_ty: PointerType<'ctx>, + pub imported_memory32_wait32_ptr_ty: PointerType<'ctx>, + pub memory32_wait64_ptr_ty: PointerType<'ctx>, + pub imported_memory32_wait64_ptr_ty: PointerType<'ctx>, + pub memory32_notify_ptr_ty: PointerType<'ctx>, + pub imported_memory32_notify_ptr_ty: PointerType<'ctx>, // Pointer to the VM. pub ctx_ptr_ty: PointerType<'ctx>, @@ -1007,6 +1019,78 @@ impl<'ctx> Intrinsics<'ctx> { void_ty.fn_type(&[i32_ty_basic_md], false), None, ), + memory_wait32: module.add_function( + "wasmer_vm_memory32_atomic_wait32", + i32_ty.fn_type( + &[ + ctx_ptr_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + i64_ty_basic_md, + ], + false, + ), + None, + ), + imported_memory_wait32: module.add_function( + "wasmer_vm_imported_memory32_atomic_wait32", + i32_ty.fn_type( + &[ + ctx_ptr_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + i64_ty_basic_md, + ], + false, + ), + None, + ), + memory_wait64: module.add_function( + "wasmer_vm_memory32_atomic_wait64", + i32_ty.fn_type( + &[ + ctx_ptr_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + i64_ty_basic_md, + i64_ty_basic_md, + ], + false, + ), + None, + ), + imported_memory_wait64: module.add_function( + "wasmer_vm_imported_memory32_atomic_wait64", + i32_ty.fn_type( + &[ + ctx_ptr_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + i64_ty_basic_md, + i64_ty_basic_md, + ], + false, + ), + None, + ), + memory_notify: module.add_function( + "wasmer_vm_memory32_atomic_notify", + i32_ty.fn_type( + &[ctx_ptr_ty_basic_md, i32_ty_basic_md, i32_ty_basic_md], + false, + ), + None, + ), + imported_memory_notify: module.add_function( + "wasmer_vm_imported_memory32_atomic_notify", + i32_ty.fn_type( + &[ctx_ptr_ty_basic_md, i32_ty_basic_md, i32_ty_basic_md], + false, + ), + None, + ), vmfunction_import_ptr_ty: context .struct_type(&[i8_ptr_ty_basic, i8_ptr_ty_basic], false) @@ -1038,6 +1122,76 @@ impl<'ctx> Intrinsics<'ctx> { imported_memory32_size_ptr_ty: i32_ty .fn_type(&[ctx_ptr_ty_basic_md, i32_ty_basic_md], false) .ptr_type(AddressSpace::Generic), + memory32_wait32_ptr_ty: i32_ty + .fn_type( + &[ + ctx_ptr_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + i64_ty_basic_md, + ], + false, + ) + .ptr_type(AddressSpace::Generic), + imported_memory32_wait32_ptr_ty: i32_ty + .fn_type( + &[ + ctx_ptr_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + i64_ty_basic_md, + ], + false, + ) + .ptr_type(AddressSpace::Generic), + memory32_wait64_ptr_ty: i32_ty + .fn_type( + &[ + ctx_ptr_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + i64_ty_basic_md, + i64_ty_basic_md, + ], + false, + ) + .ptr_type(AddressSpace::Generic), + imported_memory32_wait64_ptr_ty: i32_ty + .fn_type( + &[ + ctx_ptr_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + i64_ty_basic_md, + i64_ty_basic_md, + ], + false, + ) + .ptr_type(AddressSpace::Generic), + memory32_notify_ptr_ty: i32_ty + .fn_type( + &[ + ctx_ptr_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + ], + false, + ) + .ptr_type(AddressSpace::Generic), + imported_memory32_notify_ptr_ty: i32_ty + .fn_type( + &[ + ctx_ptr_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + i32_ty_basic_md, + ], + false, + ) + .ptr_type(AddressSpace::Generic), ctx_ptr_ty, }; @@ -1658,6 +1812,132 @@ impl<'ctx, 'a> CtxType<'ctx, 'a> { }) } + pub fn memory_wait32( + &mut self, + memory_index: MemoryIndex, + intrinsics: &Intrinsics<'ctx>, + ) -> PointerValue<'ctx> { + let (cached_memory_size, wasm_module, offsets, cache_builder, ctx_ptr_value) = ( + &mut self.cached_memory_size, + &self.wasm_module, + &self.offsets, + &self.cache_builder, + &self.ctx_ptr_value, + ); + *cached_memory_size.entry(memory_index).or_insert_with(|| { + let (size_fn, size_fn_ty) = if wasm_module.local_memory_index(memory_index).is_some() { + ( + VMBuiltinFunctionIndex::get_memory_atomic_wait32_index(), + intrinsics.memory32_wait32_ptr_ty, + ) + } else { + ( + VMBuiltinFunctionIndex::get_imported_memory_atomic_wait32_index(), + intrinsics.imported_memory32_wait32_ptr_ty, + ) + }; + let offset = offsets.vmctx_builtin_function(size_fn); + let offset = intrinsics.i32_ty.const_int(offset.into(), false); + let size_fn_ptr_ptr = unsafe { cache_builder.build_gep(*ctx_ptr_value, &[offset], "") }; + + let size_fn_ptr_ptr = cache_builder + .build_bitcast( + size_fn_ptr_ptr, + size_fn_ty.ptr_type(AddressSpace::Generic), + "", + ) + .into_pointer_value(); + + cache_builder + .build_load(size_fn_ptr_ptr, "") + .into_pointer_value() + }) + } + + pub fn memory_wait64( + &mut self, + memory_index: MemoryIndex, + intrinsics: &Intrinsics<'ctx>, + ) -> PointerValue<'ctx> { + let (cached_memory_size, wasm_module, offsets, cache_builder, ctx_ptr_value) = ( + &mut self.cached_memory_size, + &self.wasm_module, + &self.offsets, + &self.cache_builder, + &self.ctx_ptr_value, + ); + *cached_memory_size.entry(memory_index).or_insert_with(|| { + let (size_fn, size_fn_ty) = if wasm_module.local_memory_index(memory_index).is_some() { + ( + VMBuiltinFunctionIndex::get_memory_atomic_wait64_index(), + intrinsics.memory32_wait64_ptr_ty, + ) + } else { + ( + VMBuiltinFunctionIndex::get_imported_memory_atomic_wait64_index(), + intrinsics.imported_memory32_wait64_ptr_ty, + ) + }; + let offset = offsets.vmctx_builtin_function(size_fn); + let offset = intrinsics.i32_ty.const_int(offset.into(), false); + let size_fn_ptr_ptr = unsafe { cache_builder.build_gep(*ctx_ptr_value, &[offset], "") }; + + let size_fn_ptr_ptr = cache_builder + .build_bitcast( + size_fn_ptr_ptr, + size_fn_ty.ptr_type(AddressSpace::Generic), + "", + ) + .into_pointer_value(); + + cache_builder + .build_load(size_fn_ptr_ptr, "") + .into_pointer_value() + }) + } + + pub fn memory_notify( + &mut self, + memory_index: MemoryIndex, + intrinsics: &Intrinsics<'ctx>, + ) -> PointerValue<'ctx> { + let (cached_memory_size, wasm_module, offsets, cache_builder, ctx_ptr_value) = ( + &mut self.cached_memory_size, + &self.wasm_module, + &self.offsets, + &self.cache_builder, + &self.ctx_ptr_value, + ); + *cached_memory_size.entry(memory_index).or_insert_with(|| { + let (size_fn, size_fn_ty) = if wasm_module.local_memory_index(memory_index).is_some() { + ( + VMBuiltinFunctionIndex::get_memory_atomic_notify_index(), + intrinsics.memory32_notify_ptr_ty, + ) + } else { + ( + VMBuiltinFunctionIndex::get_imported_memory_atomic_notify_index(), + intrinsics.imported_memory32_notify_ptr_ty, + ) + }; + let offset = offsets.vmctx_builtin_function(size_fn); + let offset = intrinsics.i32_ty.const_int(offset.into(), false); + let size_fn_ptr_ptr = unsafe { cache_builder.build_gep(*ctx_ptr_value, &[offset], "") }; + + let size_fn_ptr_ptr = cache_builder + .build_bitcast( + size_fn_ptr_ptr, + size_fn_ty.ptr_type(AddressSpace::Generic), + "", + ) + .into_pointer_value(); + + cache_builder + .build_load(size_fn_ptr_ptr, "") + .into_pointer_value() + }) + } + pub fn get_offsets(&self) -> &VMOffsets { &self.offsets } diff --git a/lib/compiler-singlepass/Cargo.toml b/lib/compiler-singlepass/Cargo.toml index 0da4ca211..9362235ca 100644 --- a/lib/compiler-singlepass/Cargo.toml +++ b/lib/compiler-singlepass/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-compiler-singlepass" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Singlepass compiler for Wasmer WebAssembly runtime" categories = ["wasm"] keywords = ["wasm", "webassembly", "compiler", "singlepass"] @@ -12,10 +12,11 @@ readme = "README.md" edition = "2018" [dependencies] -wasmer-compiler = { path = "../compiler", version = "=3.0.0-rc.2", features = ["translator", "compiler"], default-features = false } -wasmer-types = { path = "../types", version = "=3.0.0-rc.2", default-features = false, features = ["std"] } +wasmer-compiler = { path = "../compiler", version = "=3.0.2", features = ["translator", "compiler"], default-features = false } +wasmer-types = { path = "../types", version = "=3.0.2", default-features = false, features = ["std"] } hashbrown = { version = "0.11", optional = true } gimli = { version = "0.26", optional = true } +enumset = "1.0.2" more-asserts = "0.2" dynasm = "1.2.3" dynasmrt = "1.2.3" diff --git a/lib/compiler-singlepass/src/codegen.rs b/lib/compiler-singlepass/src/codegen.rs index 575f69611..9b24e3be6 100644 --- a/lib/compiler-singlepass/src/codegen.rs +++ b/lib/compiler-singlepass/src/codegen.rs @@ -3,7 +3,7 @@ use crate::codegen_error; #[cfg(feature = "unwind")] use crate::dwarf::WriterRelocate; use crate::location::{Location, Reg}; -use crate::machine::{CodegenError, Label, Machine, MachineStackOffset, NATIVE_PAGE_SIZE}; +use crate::machine::{Label, Machine, MachineStackOffset, NATIVE_PAGE_SIZE}; use crate::unwind::UnwindFrame; use crate::{common_decl::*, config::Singlepass}; #[cfg(feature = "unwind")] @@ -17,7 +17,7 @@ use wasmer_compiler::FunctionBodyData; use wasmer_types::CompiledFunctionUnwindInfo; use wasmer_types::{ entity::{EntityRef, PrimaryMap}, - CallingConvention, FunctionIndex, FunctionType, GlobalIndex, LocalFunctionIndex, + CallingConvention, CompileError, FunctionIndex, FunctionType, GlobalIndex, LocalFunctionIndex, LocalMemoryIndex, MemoryIndex, MemoryStyle, ModuleInfo, Relocation, RelocationTarget, SectionIndex, SignatureIndex, TableIndex, TableStyle, TrapCode, Type, VMBuiltinFunctionIndex, VMOffsets, @@ -94,6 +94,7 @@ struct SpecialLabelSet { table_access_oob: Label, indirect_call_null: Label, bad_signature: Label, + unaligned_atomic: Label, } /// Metadata about a floating-point value. @@ -128,7 +129,7 @@ impl FloatValue { } } - fn promote(self, depth: usize) -> Result { + fn promote(self, depth: usize) -> Result { let ret = FloatValue { canonicalization: match self.canonicalization { Some(CanonicalizeType::F32) => Some(CanonicalizeType::F64), @@ -140,7 +141,7 @@ impl FloatValue { Ok(ret) } - fn demote(self, depth: usize) -> Result { + fn demote(self, depth: usize) -> Result { let ret = FloatValue { canonicalization: match self.canonicalization { Some(CanonicalizeType::F64) => Some(CanonicalizeType::F32), @@ -171,27 +172,25 @@ impl CanonicalizeType { } trait PopMany { - fn peek1(&self) -> Result<&T, CodegenError>; - fn pop1(&mut self) -> Result; - fn pop2(&mut self) -> Result<(T, T), CodegenError>; + 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, CodegenError> { - self.last().ok_or_else(|| CodegenError { - message: "peek1() expects at least 1 element".into(), - }) + 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(|| CodegenError { - message: "pop1() expects at least 1 element".into(), - }) + 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), CodegenError> { + fn pop2(&mut self) -> Result<(T, T), CompileError> { if self.len() < 2 { - return Err(CodegenError { - message: "pop2() expects at least 2 elements".into(), - }); + return Err(CompileError::Codegen( + "pop2() expects at least 2 elements".to_owned(), + )); } let right = self.pop().unwrap(); @@ -263,7 +262,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { &mut self, tys: &[(WpType, MachineValue)], zeroed: bool, - ) -> Result; 1]>, CodegenError> { + ) -> Result; 1]>, CompileError> { let mut ret = smallvec![]; let mut delta_stack_offset: usize = 0; @@ -311,7 +310,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { fn release_locations( &mut self, locs: &[Location], - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut delta_stack_offset: usize = 0; for loc in locs.iter().rev() { @@ -341,16 +340,18 @@ impl<'a, M: Machine> FuncGen<'a, M> { } self.stack_offset.0 -= 8; delta_stack_offset += 8; - self.state.stack_values.pop().ok_or(CodegenError { - message: "Empty stack_value".to_string(), - })?; + self.state + .stack_values + .pop() + .ok_or_else(|| CompileError::Codegen("Empty stack_value".to_owned()))?; } } _ => {} } - self.state.wasm_stack.pop().ok_or(CodegenError { - message: "Pop with wasm stack empty".to_string(), - })?; + 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 { @@ -359,7 +360,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { Ok(()) } /// Releases locations used for stack value. - fn release_locations_value(&mut self, stack_depth: usize) -> Result<(), CodegenError> { + 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..]; @@ -390,16 +391,17 @@ impl<'a, M: Machine> FuncGen<'a, M> { } self.stack_offset.0 -= 8; delta_stack_offset += 8; - self.state.stack_values.pop().ok_or(CodegenError { - message: "Pop with values stack empty".to_string(), + self.state.stack_values.pop().ok_or_else(|| { + CompileError::Codegen("Pop with values stack empty".to_owned()) })?; } } _ => {} } - self.state.wasm_stack.pop().ok_or(CodegenError { - message: "Pop with wasm stack empty".to_string(), - })?; + 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); @@ -412,7 +414,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { fn release_locations_only_regs( &mut self, locs: &[Location], - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { for loc in locs.iter().rev() { match *loc { Location::GPR(ref x) => { @@ -435,7 +437,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { fn release_locations_only_stack( &mut self, locs: &[Location], - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut delta_stack_offset: usize = 0; for loc in locs.iter().rev() { @@ -450,8 +452,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { } self.stack_offset.0 -= 8; delta_stack_offset += 8; - self.state.stack_values.pop().ok_or(CodegenError { - message: "Pop on empty value stack".to_string(), + self.state.stack_values.pop().ok_or_else(|| { + CompileError::Codegen("Pop on empty value stack".to_owned()) })?; } } @@ -465,7 +467,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { Ok(()) } - fn release_locations_only_osr_state(&mut self, n: usize) -> Result<(), CodegenError> { + fn release_locations_only_osr_state(&mut self, n: usize) -> Result<(), CompileError> { let new_length = self .state .wasm_stack @@ -476,7 +478,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { Ok(()) } - fn release_locations_keep_state(&mut self, stack_depth: usize) -> Result<(), CodegenError> { + 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..]; @@ -510,7 +512,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { n: usize, sig: FunctionType, calling_convention: CallingConvention, - ) -> Result>, CodegenError> { + ) -> Result>, CompileError> { // 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)) @@ -665,7 +667,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { fn finalize_locals( &mut self, calling_convention: CallingConvention, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { // Unwind stack to the "save area". self.machine .restore_saved_area(self.save_area_offset.as_ref().unwrap().0 as i32)?; @@ -696,20 +698,20 @@ impl<'a, M: Machine> FuncGen<'a, M> { fn get_location_released( &mut self, loc: Location, - ) -> Result, CodegenError> { + ) -> Result, CompileError> { self.release_locations(&[loc])?; Ok(loc) } - fn pop_value_released(&mut self) -> Result, CodegenError> { - let loc = self.value_stack.pop().ok_or(CodegenError { - message: "pop_value_released: value stack is empty".to_string(), + 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) } /// Prepare data for binary operator with 2 inputs and 1 output. - fn i2o1_prepare(&mut self, ty: WpType) -> Result, CodegenError> { + 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( @@ -759,13 +761,13 @@ impl<'a, M: Machine> FuncGen<'a, M> { fn emit_call_native< I: Iterator>, J: Iterator, - F: FnOnce(&mut Self) -> Result<(), CodegenError>, + F: FnOnce(&mut Self) -> Result<(), CompileError>, >( &mut self, cb: F, params: I, params_type: J, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { // Values pushed in this function are above the shadow region. self.state.stack_values.push(MachineValue::ExplicitShadow); @@ -784,9 +786,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { 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(CodegenError { - message: "emit_call_native: Undefined used_gprs content".to_string(), - }); + return Err(CompileError::Codegen( + "emit_call_native: Undefined used_gprs content".to_owned(), + )); } self.state.stack_values.push(content); } @@ -800,9 +802,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { let content = self.state.register_values[self.machine.index_from_simd(*r).0].clone(); if content == MachineValue::Undefined { - return Err(CodegenError { - message: "emit_call_native: Undefined used_simds content".to_string(), - }); + return Err(CompileError::Codegen( + "emit_call_native: Undefined used_simds content".to_owned(), + )); } self.state.stack_values.push(content); } @@ -871,10 +873,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { } Location::Memory(reg, offset) => { if reg != self.machine.local_pointer() { - return Err(CodegenError { - message: "emit_call_native loc param: unreachable code" - .to_string(), - }); + return Err(CompileError::Codegen( + "emit_call_native loc param: unreachable code".to_owned(), + )); } self.state .stack_values @@ -889,9 +890,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { .move_location_for_native(params_size[i], *param, loc)?; } _ => { - return Err(CodegenError { - message: "emit_call_native loc: unreachable code".to_string(), - }) + return Err(CompileError::Codegen( + "emit_call_native loc: unreachable code".to_owned(), + )) } } } @@ -947,14 +948,15 @@ impl<'a, M: Machine> FuncGen<'a, M> { .round_stack_adjust(stack_offset + stack_padding) as u32, )?; if (stack_offset % 8) != 0 { - return Err(CodegenError { - message: "emit_call_native: Bad restoring stack alignement".to_string(), - }); + 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(CodegenError { - message: "Pop an empty value stack".to_string(), - })?; + self.state + .stack_values + .pop() + .ok_or_else(|| CompileError::Codegen("Pop an empty value stack".to_owned()))?; } } @@ -962,27 +964,32 @@ impl<'a, M: Machine> FuncGen<'a, M> { 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(CodegenError { - message: "Pop an empty value stack".to_string(), - })?; + 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(CodegenError { - message: "Pop an empty value stack".to_string(), - })?; + 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(CodegenError { - message: "Pop an empty value stack".to_string(), - })? != MachineValue::ExplicitShadow + if self + .state + .stack_values + .pop() + .ok_or_else(|| CompileError::Codegen("Pop an empty value stack".to_owned()))? + != MachineValue::ExplicitShadow { - return Err(CodegenError { - message: "emit_call_native: Popped value is not ExplicitShadow".to_string(), - }); + return Err(CompileError::Codegen( + "emit_call_native: Popped value is not ExplicitShadow".to_owned(), + )); } Ok(()) } @@ -996,7 +1003,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { label: Label, params: I, params_type: J, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_call_native( |this| this.machine.emit_call_label(label), params, @@ -1006,10 +1013,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { } /// Emits a memory operation. - fn op_memory Result<(), CodegenError>>( + fn op_memory< + F: FnOnce(&mut Self, bool, bool, i32, Label, Label) -> Result<(), CompileError>, + >( &mut self, cb: F, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let need_check = match self.memory_styles[MemoryIndex::new(0)] { MemoryStyle::Static { .. } => false, MemoryStyle::Dynamic { .. } => true, @@ -1028,6 +1037,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { self.module.num_imported_memories != 0, offset as i32, self.special_labels.heap_access_oob, + self.special_labels.unaligned_atomic, ) } @@ -1045,7 +1055,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { id } - fn emit_head(&mut self) -> Result<(), CodegenError> { + fn emit_head(&mut self) -> Result<(), CompileError> { self.machine.emit_function_prolog()?; // Initialize locals. @@ -1090,9 +1100,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { self.machine.insert_stackoverflow(); if self.state.wasm_inst_offset != std::usize::MAX { - return Err(CodegenError { - message: "emit_head: wasm_inst_offset not std::usize::MAX".to_string(), - }); + return Err(CompileError::Codegen( + "emit_head: wasm_inst_offset not std::usize::MAX".to_owned(), + )); } Ok(()) } @@ -1108,7 +1118,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { local_types_excluding_arguments: &[WpType], machine: M, calling_convention: CallingConvention, - ) -> Result, CodegenError> { + ) -> Result, CompileError> { let func_index = module.func_index(local_func_index); let sig_index = module.functions[func_index]; let signature = module.signatures[sig_index].clone(); @@ -1128,6 +1138,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { table_access_oob: machine.get_label(), indirect_call_null: machine.get_label(), bad_signature: machine.get_label(), + unaligned_atomic: machine.get_label(), }; let fsm = FunctionStateMap::new( @@ -1170,7 +1181,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { !self.control_stack.is_empty() } - pub fn feed_operator(&mut self, op: Operator) -> Result<(), CodegenError> { + pub fn feed_operator(&mut self, op: Operator) -> Result<(), CompileError> { assert!(self.fp_stack.len() <= self.value_stack.len()); self.state.wasm_inst_offset = self.state.wasm_inst_offset.wrapping_add(1); @@ -2939,9 +2950,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { WpTypeOrFuncType::Type(WpType::EmptyBlockType) => smallvec![], WpTypeOrFuncType::Type(inner_ty) => smallvec![inner_ty], _ => { - return Err(CodegenError { - message: "If: multi-value returns not yet implemented".to_string(), - }) + return Err(CompileError::Codegen( + "If: multi-value returns not yet implemented".to_owned(), + )) } }, value_stack_depth: self.value_stack.len(), @@ -2987,9 +2998,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { frame.if_else = IfElseState::Else; } _ => { - return Err(CodegenError { - message: "Else: frame.if_else unreachable code".to_string(), - }) + return Err(CompileError::Codegen( + "Else: frame.if_else unreachable code".to_owned(), + )) } } } @@ -3062,10 +3073,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { WpTypeOrFuncType::Type(WpType::EmptyBlockType) => smallvec![], WpTypeOrFuncType::Type(inner_ty) => smallvec![inner_ty], _ => { - return Err(CodegenError { - message: "Block: multi-value returns not yet implemented" - .to_string(), - }) + return Err(CompileError::Codegen( + "Block: multi-value returns not yet implemented".to_owned(), + )) } }, value_stack_depth: self.value_stack.len(), @@ -3089,10 +3099,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { WpTypeOrFuncType::Type(WpType::EmptyBlockType) => smallvec![], WpTypeOrFuncType::Type(inner_ty) => smallvec![inner_ty], _ => { - return Err(CodegenError { - message: "Loop: multi-value returns not yet implemented" - .to_string(), - }) + return Err(CompileError::Codegen( + "Loop: multi-value returns not yet implemented".to_owned(), + )) } }, value_stack_depth: self.value_stack.len(), @@ -3366,7 +3375,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_load( target, memarg, @@ -3375,6 +3389,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3389,7 +3404,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { self.fp_stack .push(FloatValue::new(self.value_stack.len() - 1)); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.f32_load( target, memarg, @@ -3398,6 +3418,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3410,7 +3431,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_load_8u( target, memarg, @@ -3419,6 +3445,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3431,7 +3458,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_load_8s( target, memarg, @@ -3440,6 +3472,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3452,7 +3485,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_load_16u( target, memarg, @@ -3461,6 +3499,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3473,7 +3512,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_load_16s( target, memarg, @@ -3482,6 +3526,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3490,7 +3535,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let target_value = self.pop_value_released()?; let target_addr = self.pop_value_released()?; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_save( target_value, memarg, @@ -3499,6 +3549,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3509,7 +3560,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let fp = self.fp_stack.pop1()?; let config_nan_canonicalization = self.config.enable_nan_canonicalization; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.f32_save( target_value, memarg, @@ -3519,6 +3575,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3527,7 +3584,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let target_value = self.pop_value_released()?; let target_addr = self.pop_value_released()?; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_save_8( target_value, memarg, @@ -3536,6 +3598,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3544,7 +3607,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let target_value = self.pop_value_released()?; let target_addr = self.pop_value_released()?; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_save_16( target_value, memarg, @@ -3553,6 +3621,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3565,7 +3634,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_load( target, memarg, @@ -3574,6 +3648,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3588,7 +3663,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { self.fp_stack .push(FloatValue::new(self.value_stack.len() - 1)); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.f64_load( target, memarg, @@ -3597,6 +3677,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3609,7 +3690,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_load_8u( target, memarg, @@ -3618,6 +3704,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3630,7 +3717,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_load_8s( target, memarg, @@ -3639,6 +3731,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3651,7 +3744,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_load_16u( target, memarg, @@ -3660,6 +3758,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3672,7 +3771,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_load_16s( target, memarg, @@ -3681,6 +3785,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3693,7 +3798,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_load_32u( target, memarg, @@ -3702,6 +3812,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3714,7 +3825,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_load_32s( target, memarg, @@ -3723,6 +3839,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3732,7 +3849,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let target_addr = self.pop_value_released()?; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_save( target_value, memarg, @@ -3741,6 +3863,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3751,7 +3874,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let fp = self.fp_stack.pop1()?; let config_nan_canonicalization = self.config.enable_nan_canonicalization; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.f64_save( target_value, memarg, @@ -3761,6 +3889,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3769,7 +3898,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let target_value = self.pop_value_released()?; let target_addr = self.pop_value_released()?; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_save_8( target_value, memarg, @@ -3778,6 +3912,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3786,7 +3921,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let target_value = self.pop_value_released()?; let target_addr = self.pop_value_released()?; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_save_16( target_value, memarg, @@ -3795,6 +3935,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3803,7 +3944,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let target_value = self.pop_value_released()?; let target_addr = self.pop_value_released()?; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_save_32( target_value, memarg, @@ -3812,6 +3958,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -3826,9 +3973,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { let frame = &self.control_stack[0]; if !frame.returns.is_empty() { if frame.returns.len() != 1 { - return Err(CodegenError { - message: "Return: incorrect frame.returns".to_string(), - }); + return Err(CompileError::Codegen( + "Return: incorrect frame.returns".to_owned(), + )); } let first_return = frame.returns[0]; let loc = *self.value_stack.last().unwrap(); @@ -3855,9 +4002,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { &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(CodegenError { - message: "Br: incorrect frame.returns".to_string(), - }); + return Err(CompileError::Codegen( + "Br: incorrect frame.returns".to_owned(), + )); } let first_return = frame.returns[0]; let loc = *self.value_stack.last().unwrap(); @@ -3892,9 +4039,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { &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(CodegenError { - message: "BrIf: incorrect frame.returns".to_string(), - }); + return Err(CompileError::Codegen( + "BrIf: incorrect frame.returns".to_owned(), + )); } let first_return = frame.returns[0]; @@ -3923,9 +4070,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { let targets = table .targets() .collect::, _>>() - .map_err(|e| CodegenError { - message: format!("BrTable read_table: {:?}", e), - })?; + .map_err(|e| CompileError::Codegen(format!("BrTable read_table: {:?}", e)))?; let default_target = table.default(); let cond = self.pop_value_released()?; let table_label = self.machine.get_label(); @@ -3948,12 +4093,10 @@ impl<'a, M: Machine> FuncGen<'a, M> { &self.control_stack[self.control_stack.len() - 1 - (*target as usize)]; if !frame.loop_like && !frame.returns.is_empty() { if frame.returns.len() != 1 { - return Err(CodegenError { - message: format!( - "BrTable: incorrect frame.returns for {:?}", - target - ), - }); + return Err(CompileError::Codegen(format!( + "BrTable: incorrect frame.returns for {:?}", + target + ))); } let first_return = frame.returns[0]; @@ -3983,9 +4126,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { [self.control_stack.len() - 1 - (default_target as usize)]; if !frame.loop_like && !frame.returns.is_empty() { if frame.returns.len() != 1 { - return Err(CodegenError { - message: "BrTable: incorrect frame.returns".to_string(), - }); + return Err(CompileError::Codegen( + "BrTable: incorrect frame.returns".to_owned(), + )); } let first_return = frame.returns[0]; @@ -4069,9 +4212,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { if !frame.returns.is_empty() { if frame.returns.len() != 1 { - return Err(CodegenError { - message: "End: incorrect frame.returns".to_string(), - }); + return Err(CompileError::Codegen( + "End: incorrect frame.returns".to_owned(), + )); } let loc = self.acquire_locations( &[( @@ -4112,7 +4255,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_load( target, memarg, @@ -4121,6 +4269,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4133,7 +4282,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_load_8u( target, memarg, @@ -4142,6 +4296,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4154,7 +4309,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_load_16u( target, memarg, @@ -4163,6 +4323,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4171,7 +4332,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let target_value = self.pop_value_released()?; let target_addr = self.pop_value_released()?; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_save( target_value, memarg, @@ -4180,6 +4346,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4188,7 +4355,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let target_value = self.pop_value_released()?; let target_addr = self.pop_value_released()?; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_save_8( target_value, memarg, @@ -4197,6 +4369,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4205,7 +4378,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let target_value = self.pop_value_released()?; let target_addr = self.pop_value_released()?; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_save_16( target_value, memarg, @@ -4214,6 +4392,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4226,7 +4405,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_load( target, memarg, @@ -4235,6 +4419,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4247,7 +4432,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_load_8u( target, memarg, @@ -4256,6 +4446,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4268,7 +4459,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_load_16u( target, memarg, @@ -4277,6 +4473,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4289,7 +4486,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_load_32u( target, memarg, @@ -4298,6 +4500,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4306,7 +4509,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let target_value = self.pop_value_released()?; let target_addr = self.pop_value_released()?; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_save( target_value, memarg, @@ -4315,6 +4523,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4323,7 +4532,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let target_value = self.pop_value_released()?; let target_addr = self.pop_value_released()?; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_save_8( target_value, memarg, @@ -4332,6 +4546,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4340,7 +4555,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let target_value = self.pop_value_released()?; let target_addr = self.pop_value_released()?; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_save_16( target_value, memarg, @@ -4349,6 +4569,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4357,7 +4578,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { let target_value = self.pop_value_released()?; let target_addr = self.pop_value_released()?; self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_save_32( target_value, memarg, @@ -4366,6 +4592,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4379,7 +4606,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_add( loc, target, @@ -4389,6 +4621,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4402,7 +4635,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_add( loc, target, @@ -4412,6 +4650,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4425,7 +4664,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_add_8u( loc, target, @@ -4435,6 +4679,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4448,7 +4693,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_add_16u( loc, target, @@ -4458,6 +4708,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4471,7 +4722,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_add_8u( loc, target, @@ -4481,6 +4737,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4494,7 +4751,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_add_16u( loc, target, @@ -4504,6 +4766,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4517,7 +4780,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_add_32u( loc, target, @@ -4527,6 +4795,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4540,7 +4809,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_sub( loc, target, @@ -4550,6 +4824,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4563,7 +4838,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_sub( loc, target, @@ -4573,6 +4853,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4586,7 +4867,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_sub_8u( loc, target, @@ -4596,6 +4882,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4609,7 +4896,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_sub_16u( loc, target, @@ -4619,6 +4911,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4632,7 +4925,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_sub_8u( loc, target, @@ -4642,6 +4940,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4655,7 +4954,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_sub_16u( loc, target, @@ -4665,6 +4969,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4678,7 +4983,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_sub_32u( loc, target, @@ -4688,6 +4998,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4701,7 +5012,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_and( loc, target, @@ -4711,6 +5027,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4724,7 +5041,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_and( loc, target, @@ -4734,6 +5056,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4747,7 +5070,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_and_8u( loc, target, @@ -4757,6 +5085,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4770,7 +5099,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_and_16u( loc, target, @@ -4780,6 +5114,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4793,7 +5128,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_and_8u( loc, target, @@ -4803,6 +5143,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4816,7 +5157,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_and_16u( loc, target, @@ -4826,6 +5172,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4839,7 +5186,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_and_32u( loc, target, @@ -4849,6 +5201,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4862,7 +5215,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_or( loc, target, @@ -4872,6 +5230,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4885,7 +5244,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_or( loc, target, @@ -4895,6 +5259,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4908,7 +5273,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_or_8u( loc, target, @@ -4918,6 +5288,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4931,7 +5302,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_or_16u( loc, target, @@ -4941,6 +5317,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4954,7 +5331,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_or_8u( loc, target, @@ -4964,6 +5346,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -4977,7 +5360,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_or_16u( loc, target, @@ -4987,6 +5375,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5000,7 +5389,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_or_32u( loc, target, @@ -5010,6 +5404,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5023,7 +5418,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_xor( loc, target, @@ -5033,6 +5433,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5046,7 +5447,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_xor( loc, target, @@ -5056,6 +5462,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5069,7 +5476,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_xor_8u( loc, target, @@ -5079,6 +5491,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5092,7 +5505,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_xor_16u( loc, target, @@ -5102,6 +5520,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5115,7 +5534,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_xor_8u( loc, target, @@ -5125,6 +5549,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5138,7 +5563,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_xor_16u( loc, target, @@ -5148,6 +5578,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5161,7 +5592,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_xor_32u( loc, target, @@ -5171,6 +5607,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5184,7 +5621,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_xchg( loc, target, @@ -5194,6 +5636,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5207,7 +5650,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_xchg( loc, target, @@ -5217,6 +5665,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5230,7 +5679,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_xchg_8u( loc, target, @@ -5240,6 +5694,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5253,7 +5708,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_xchg_16u( loc, target, @@ -5263,6 +5723,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5276,7 +5737,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_xchg_8u( loc, target, @@ -5286,6 +5752,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5299,7 +5766,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_xchg_16u( loc, target, @@ -5309,6 +5781,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5322,7 +5795,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_xchg_32u( loc, target, @@ -5332,6 +5810,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5346,7 +5825,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_cmpxchg( new, cmp, @@ -5357,6 +5841,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5371,7 +5856,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_cmpxchg( new, cmp, @@ -5382,6 +5872,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5396,7 +5887,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_cmpxchg_8u( new, cmp, @@ -5407,6 +5903,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5421,7 +5918,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i32_atomic_cmpxchg_16u( new, cmp, @@ -5432,6 +5934,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5446,7 +5949,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_cmpxchg_8u( new, cmp, @@ -5457,6 +5965,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5471,7 +5980,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_cmpxchg_16u( new, cmp, @@ -5482,6 +5996,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5496,7 +6011,12 @@ impl<'a, M: Machine> FuncGen<'a, M> { )?[0]; self.value_stack.push(ret); self.op_memory( - |this, need_check, imported_memories, offset, heap_access_oob| { + |this, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic| { this.machine.i64_atomic_cmpxchg_32u( new, cmp, @@ -5507,6 +6027,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { imported_memories, offset, heap_access_oob, + unaligned_atomic, ) }, )?; @@ -5896,10 +6417,189 @@ impl<'a, M: Machine> FuncGen<'a, M> { [WpType::I32].iter().cloned(), )?; } + Operator::MemoryAtomicWait32 { ref memarg } => { + let timeout = self.value_stack.pop().unwrap(); + let val = self.value_stack.pop().unwrap(); + let dst = self.value_stack.pop().unwrap(); + self.release_locations_only_regs(&[timeout, val, dst])?; + + let memory_index = MemoryIndex::new(memarg.memory as usize); + let (memory_atomic_wait32, memory_index) = + if self.module.local_memory_index(memory_index).is_some() { + ( + VMBuiltinFunctionIndex::get_memory_atomic_wait32_index(), + memory_index, + ) + } else { + ( + VMBuiltinFunctionIndex::get_imported_memory_atomic_wait32_index(), + memory_index, + ) + }; + + self.machine.move_location( + Size::S64, + Location::Memory( + self.machine.get_vmctx_reg(), + self.vmoffsets.vmctx_builtin_function(memory_atomic_wait32) as i32, + ), + Location::GPR(self.machine.get_grp_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()) + }, + // [vmctx, memory_index, dst, src, timeout] + [ + Location::Imm32(memory_index.index() as u32), + dst, + val, + timeout, + ] + .iter() + .cloned(), + [WpType::I32, WpType::I32, WpType::I32, WpType::I64] + .iter() + .cloned(), + )?; + self.release_locations_only_stack(&[dst, val, timeout])?; + let ret = self.acquire_locations( + &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], + false, + )?[0]; + self.value_stack.push(ret); + self.machine.move_location( + Size::S32, + Location::GPR(self.machine.get_gpr_for_ret()), + ret, + )?; + } + Operator::MemoryAtomicWait64 { ref memarg } => { + let timeout = self.value_stack.pop().unwrap(); + let val = self.value_stack.pop().unwrap(); + let dst = self.value_stack.pop().unwrap(); + self.release_locations_only_regs(&[timeout, val, dst])?; + + let memory_index = MemoryIndex::new(memarg.memory as usize); + let (memory_atomic_wait64, memory_index) = + if self.module.local_memory_index(memory_index).is_some() { + ( + VMBuiltinFunctionIndex::get_memory_atomic_wait64_index(), + memory_index, + ) + } else { + ( + VMBuiltinFunctionIndex::get_imported_memory_atomic_wait64_index(), + memory_index, + ) + }; + + self.machine.move_location( + Size::S64, + Location::Memory( + self.machine.get_vmctx_reg(), + self.vmoffsets.vmctx_builtin_function(memory_atomic_wait64) as i32, + ), + Location::GPR(self.machine.get_grp_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()) + }, + // [vmctx, memory_index, dst, src, timeout] + [ + Location::Imm32(memory_index.index() as u32), + dst, + val, + timeout, + ] + .iter() + .cloned(), + [WpType::I32, WpType::I32, WpType::I64, WpType::I64] + .iter() + .cloned(), + )?; + self.release_locations_only_stack(&[dst, val, timeout])?; + let ret = self.acquire_locations( + &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], + false, + )?[0]; + self.value_stack.push(ret); + self.machine.move_location( + Size::S32, + Location::GPR(self.machine.get_gpr_for_ret()), + ret, + )?; + } + Operator::MemoryAtomicNotify { ref memarg } => { + let cnt = self.value_stack.pop().unwrap(); + let dst = self.value_stack.pop().unwrap(); + self.release_locations_only_regs(&[cnt, dst])?; + + let memory_index = MemoryIndex::new(memarg.memory as usize); + let (memory_atomic_notify, memory_index) = + if self.module.local_memory_index(memory_index).is_some() { + ( + VMBuiltinFunctionIndex::get_memory_atomic_notify_index(), + memory_index, + ) + } else { + ( + VMBuiltinFunctionIndex::get_imported_memory_atomic_notify_index(), + memory_index, + ) + }; + + self.machine.move_location( + Size::S64, + Location::Memory( + self.machine.get_vmctx_reg(), + self.vmoffsets.vmctx_builtin_function(memory_atomic_notify) as i32, + ), + Location::GPR(self.machine.get_grp_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()) + }, + // [vmctx, memory_index, dst, src, timeout] + [Location::Imm32(memory_index.index() as u32), dst] + .iter() + .cloned(), + [WpType::I32, WpType::I32].iter().cloned(), + )?; + self.release_locations_only_stack(&[dst, cnt])?; + let ret = self.acquire_locations( + &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], + false, + )?[0]; + self.value_stack.push(ret); + self.machine.move_location( + Size::S32, + Location::GPR(self.machine.get_gpr_for_ret()), + ret, + )?; + } _ => { - return Err(CodegenError { - message: format!("not yet implemented: {:?}", op), - }); + return Err(CompileError::Codegen(format!( + "not yet implemented: {:?}", + op + ))); } } @@ -5909,7 +6609,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { pub fn finalize( mut self, data: &FunctionBodyData, - ) -> Result<(CompiledFunction, Option), CodegenError> { + ) -> Result<(CompiledFunction, Option), CompileError> { // Generate actual code for special labels. self.machine .emit_label(self.special_labels.integer_division_by_zero)?; @@ -5937,6 +6637,10 @@ impl<'a, M: Machine> FuncGen<'a, M> { self.machine.emit_label(self.special_labels.bad_signature)?; self.machine.emit_illegal_op(TrapCode::BadSignature)?; + self.machine + .emit_label(self.special_labels.unaligned_atomic)?; + self.machine.emit_illegal_op(TrapCode::UnalignedAtomic)?; + // Notify the assembler backend to generate necessary code at end of function. self.machine.finalize_function()?; @@ -5968,7 +6672,8 @@ impl<'a, M: Machine> FuncGen<'a, M> { let address_map = get_function_address_map(self.machine.instructions_address_map(), data, body_len); let traps = self.machine.collect_trap_information(); - let body = self.machine.assembler_finalize(); + let mut body = self.machine.assembler_finalize(); + body.shrink_to_fit(); Ok(( CompiledFunction { diff --git a/lib/compiler-singlepass/src/compiler.rs b/lib/compiler-singlepass/src/compiler.rs index bd014f70f..5cee5d4ec 100644 --- a/lib/compiler-singlepass/src/compiler.rs +++ b/lib/compiler-singlepass/src/compiler.rs @@ -8,12 +8,13 @@ use crate::config::Singlepass; use crate::dwarf::WriterRelocate; use crate::machine::Machine; use crate::machine::{ - gen_import_call_trampoline, gen_std_dynamic_import_trampoline, gen_std_trampoline, CodegenError, + gen_import_call_trampoline, gen_std_dynamic_import_trampoline, gen_std_trampoline, }; use crate::machine_arm64::MachineARM64; use crate::machine_x64::MachineX86_64; #[cfg(feature = "unwind")] use crate::unwind::{create_systemv_cie, UnwindFrame}; +use enumset::EnumSet; #[cfg(feature = "unwind")] use gimli::write::{EhFrame, FrameTable}; #[cfg(feature = "rayon")] @@ -31,12 +32,6 @@ use wasmer_types::{ TrapCode, TrapInformation, VMOffsets, }; -impl From for CompileError { - fn from(err: CodegenError) -> Self { - Self::Codegen(err.message) - } -} - /// A compiler that compiles a WebAssembly module with Singlepass. /// It does the compilation in one pass pub struct SinglepassCompiler { @@ -84,20 +79,6 @@ impl Compiler for SinglepassCompiler { } } - let simd_arch = match target.triple().architecture { - Architecture::X86_64 => { - if target.cpu_features().contains(CpuFeature::AVX) { - Some(CpuFeature::AVX) - } else if target.cpu_features().contains(CpuFeature::SSE42) { - Some(CpuFeature::SSE42) - } else { - return Err(CompileError::UnsupportedTarget( - "x86_64 without AVX or SSE 4.2".to_string(), - )); - } - } - _ => None, - }; let calling_convention = match target.triple().default_calling_convention() { Ok(CallingConvention::WindowsFastcall) => CallingConvention::WindowsFastcall, Ok(CallingConvention::SystemV) => CallingConvention::SystemV, @@ -148,6 +129,7 @@ impl Compiler for SinglepassCompiler { target, calling_convention, ) + .unwrap() }) .collect::>() .into_iter() @@ -177,7 +159,7 @@ impl Compiler for SinglepassCompiler { match target.triple().architecture { Architecture::X86_64 => { - let machine = MachineX86_64::new(simd_arch); + let machine = MachineX86_64::new(Some(target.clone()))?; let mut generator = FuncGen::new( module, &self.config, @@ -188,15 +170,14 @@ impl Compiler for SinglepassCompiler { &locals, machine, calling_convention, - ) - .map_err(to_compile_error)?; + )?; while generator.has_control_frames() { generator.set_srcloc(reader.original_position() as u32); let op = reader.read_operator()?; - generator.feed_operator(op).map_err(to_compile_error)?; + generator.feed_operator(op)?; } - generator.finalize(input).map_err(to_compile_error) + generator.finalize(input) } Architecture::Aarch64(_) => { let machine = MachineARM64::new(); @@ -210,15 +191,14 @@ impl Compiler for SinglepassCompiler { &locals, machine, calling_convention, - ) - .map_err(to_compile_error)?; + )?; while generator.has_control_frames() { generator.set_srcloc(reader.original_position() as u32); let op = reader.read_operator()?; - generator.feed_operator(op).map_err(to_compile_error)?; + generator.feed_operator(op)?; } - generator.finalize(input).map_err(to_compile_error) + generator.finalize(input) } _ => unimplemented!(), } @@ -232,7 +212,7 @@ impl Compiler for SinglepassCompiler { .values() .collect::>() .into_par_iter_if_rayon() - .map(|func_type| gen_std_trampoline(func_type, target, calling_convention)) + .map(|func_type| gen_std_trampoline(func_type, target, calling_convention).unwrap()) .collect::>() .into_iter() .collect::>(); @@ -248,6 +228,7 @@ impl Compiler for SinglepassCompiler { target, calling_convention, ) + .unwrap() }) .collect::>() .into_iter() @@ -272,30 +253,21 @@ impl Compiler for SinglepassCompiler { #[cfg(not(feature = "unwind"))] let dwarf = None; - Ok(Compilation::new( - functions.into_iter().collect(), + Ok(Compilation { + functions: functions.into_iter().collect(), custom_sections, function_call_trampolines, dynamic_function_trampolines, - dwarf, - )) + debug: dwarf, + }) } -} -trait ToCompileError { - fn to_compile_error(self) -> CompileError; -} - -impl ToCompileError for CodegenError { - fn to_compile_error(self) -> CompileError { - CompileError::Codegen(self.message) + fn get_cpu_features_used(&self, cpu_features: &EnumSet) -> EnumSet { + let used = CpuFeature::AVX | CpuFeature::SSE42 | CpuFeature::LZCNT | CpuFeature::BMI1; + cpu_features.intersection(used) } } -fn to_compile_error(x: T) -> CompileError { - x.to_compile_error() -} - trait IntoParIterIfRayon { type Output; fn into_par_iter_if_rayon(self) -> Self::Output; @@ -361,4 +333,24 @@ mod tests { error => panic!("Unexpected error: {:?}", error), }; } + + #[test] + fn errors_for_unsuported_cpufeatures() { + let compiler = SinglepassCompiler::new(Singlepass::default()); + let mut features = + CpuFeature::AVX | CpuFeature::SSE42 | CpuFeature::LZCNT | CpuFeature::BMI1; + // simple test + assert!(compiler + .get_cpu_features_used(&features) + .is_subset(CpuFeature::AVX | CpuFeature::SSE42 | CpuFeature::LZCNT | CpuFeature::BMI1)); + // check that an AVX build don't work on SSE4.2 only host + assert!(!compiler + .get_cpu_features_used(&features) + .is_subset(CpuFeature::SSE42 | CpuFeature::LZCNT | CpuFeature::BMI1)); + // check that having a host with AVX512 doesn't change anything + features.insert_all(CpuFeature::AVX512DQ | CpuFeature::AVX512F); + assert!(compiler + .get_cpu_features_used(&features) + .is_subset(CpuFeature::AVX | CpuFeature::SSE42 | CpuFeature::LZCNT | CpuFeature::BMI1)); + } } diff --git a/lib/compiler-singlepass/src/emitter_arm64.rs b/lib/compiler-singlepass/src/emitter_arm64.rs index 23ca12c45..074ae0acd 100644 --- a/lib/compiler-singlepass/src/emitter_arm64.rs +++ b/lib/compiler-singlepass/src/emitter_arm64.rs @@ -3,7 +3,6 @@ use crate::codegen_error; use crate::common_decl::Size; use crate::location::Location as AbstractLocation; pub use crate::location::{Multiplier, Reg}; -use crate::machine::CodegenError; pub use crate::machine::{Label, Offset}; use dynasm::dynasm; pub use dynasmrt::aarch64::{encode_logical_immediate_32bit, encode_logical_immediate_64bit}; @@ -12,8 +11,8 @@ use dynasmrt::{ VecAssembler, }; use wasmer_types::{ - CallingConvention, CustomSection, CustomSectionProtection, FunctionBody, FunctionIndex, - FunctionType, SectionBody, Type, VMOffsets, + CallingConvention, CompileError, CustomSection, CustomSectionProtection, FunctionBody, + FunctionIndex, FunctionType, SectionBody, Type, VMOffsets, }; type Assembler = VecAssembler; @@ -92,43 +91,43 @@ pub trait EmitterARM64 { fn finalize_function(&mut self); - fn emit_str(&mut self, sz: Size, reg: Location, addr: Location) -> Result<(), CodegenError>; - fn emit_ldr(&mut self, sz: Size, reg: Location, addr: Location) -> Result<(), CodegenError>; + fn emit_str(&mut self, sz: Size, reg: Location, addr: Location) -> Result<(), CompileError>; + fn emit_ldr(&mut self, sz: Size, reg: Location, addr: Location) -> Result<(), CompileError>; fn emit_stur( &mut self, sz: Size, reg: Location, addr: GPR, offset: i32, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_ldur( &mut self, sz: Size, reg: Location, addr: GPR, offset: i32, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_strdb( &mut self, sz: Size, reg: Location, addr: GPR, offset: u32, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_stria( &mut self, sz: Size, reg: Location, addr: GPR, offset: u32, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_ldria( &mut self, sz: Size, reg: Location, addr: GPR, offset: u32, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_stpdb( &mut self, sz: Size, @@ -136,7 +135,7 @@ pub trait EmitterARM64 { reg2: Location, addr: GPR, offset: u32, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_ldpia( &mut self, sz: Size, @@ -144,23 +143,48 @@ pub trait EmitterARM64 { reg2: Location, addr: GPR, offset: u32, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; - fn emit_ldrb(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_ldrh(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_ldrsb(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_ldrsh(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_ldrsw(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_strb(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_strh(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CodegenError>; + fn emit_ldrb(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CompileError>; + fn emit_ldrh(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CompileError>; + fn emit_ldrsb(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CompileError>; + fn emit_ldrsh(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CompileError>; + fn emit_ldrsw(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CompileError>; + fn emit_strb(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CompileError>; + fn emit_strh(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CompileError>; - fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; + fn emit_ldaxr(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CompileError>; + fn emit_ldaxrb(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CompileError>; + fn emit_ldaxrh(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CompileError>; + fn emit_stlxr( + &mut self, + sz: Size, + status: Location, + reg: Location, + dst: Location, + ) -> Result<(), CompileError>; + fn emit_stlxrb( + &mut self, + sz: Size, + status: Location, + reg: Location, + dst: Location, + ) -> Result<(), CompileError>; + fn emit_stlxrh( + &mut self, + sz: Size, + status: Location, + reg: Location, + dst: Location, + ) -> Result<(), CompileError>; - fn emit_movn(&mut self, sz: Size, reg: Location, val: u32) -> Result<(), CodegenError>; - fn emit_movz(&mut self, reg: Location, val: u32) -> Result<(), CodegenError>; - fn emit_movk(&mut self, reg: Location, val: u32, shift: u32) -> Result<(), CodegenError>; + fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; - fn emit_mov_imm(&mut self, dst: Location, val: u64) -> Result<(), CodegenError>; + fn emit_movn(&mut self, sz: Size, reg: Location, val: u32) -> Result<(), CompileError>; + fn emit_movz(&mut self, reg: Location, val: u32) -> Result<(), CompileError>; + fn emit_movk(&mut self, reg: Location, val: u32, shift: u32) -> Result<(), CompileError>; + + fn emit_mov_imm(&mut self, dst: Location, val: u64) -> Result<(), CompileError>; fn emit_add( &mut self, @@ -168,35 +192,35 @@ pub trait EmitterARM64 { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_sub( &mut self, sz: Size, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_mul( &mut self, sz: Size, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_adds( &mut self, sz: Size, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_subs( &mut self, sz: Size, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_add_lsl( &mut self, @@ -205,10 +229,10 @@ pub trait EmitterARM64 { src2: Location, lsl: u32, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; - fn emit_cmp(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_tst(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; + fn emit_cmp(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_tst(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; fn emit_lsl( &mut self, @@ -216,28 +240,28 @@ pub trait EmitterARM64 { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_lsr( &mut self, sz: Size, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_asr( &mut self, sz: Size, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_ror( &mut self, sz: Size, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_or( &mut self, @@ -245,21 +269,21 @@ pub trait EmitterARM64 { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_and( &mut self, sz: Size, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_eor( &mut self, sz: Size, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_bfc( &mut self, @@ -267,7 +291,7 @@ pub trait EmitterARM64 { lsb: u32, width: u32, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_bfi( &mut self, se: Size, @@ -275,7 +299,7 @@ pub trait EmitterARM64 { lsb: u32, width: u32, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_udiv( &mut self, @@ -283,14 +307,14 @@ pub trait EmitterARM64 { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_sdiv( &mut self, sz: Size, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// msub : c - a*b -> dst fn emit_msub( &mut self, @@ -299,69 +323,69 @@ pub trait EmitterARM64 { b: Location, c: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; - fn emit_sxtb(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_sxth(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_sxtw(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_uxtb(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_uxth(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; + fn emit_sxtb(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_sxth(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_sxtw(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_uxtb(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_uxth(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; - fn emit_cset(&mut self, sz: Size, dst: Location, cond: Condition) -> Result<(), CodegenError>; - fn emit_csetm(&mut self, sz: Size, dst: Location, cond: Condition) -> Result<(), CodegenError>; + fn emit_cset(&mut self, sz: Size, dst: Location, cond: Condition) -> Result<(), CompileError>; + fn emit_csetm(&mut self, sz: Size, dst: Location, cond: Condition) -> Result<(), CompileError>; fn emit_cinc( &mut self, sz: Size, src: Location, dst: Location, cond: Condition, - ) -> Result<(), CodegenError>; - fn emit_clz(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_rbit(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; + fn emit_clz(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_rbit(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; - fn emit_label(&mut self, label: Label) -> Result<(), CodegenError>; - fn emit_load_label(&mut self, reg: GPR, label: Label) -> Result<(), CodegenError>; - fn emit_b_label(&mut self, label: Label) -> Result<(), CodegenError>; + fn emit_label(&mut self, label: Label) -> Result<(), CompileError>; + fn emit_load_label(&mut self, reg: GPR, label: Label) -> Result<(), CompileError>; + fn emit_b_label(&mut self, label: Label) -> Result<(), CompileError>; fn emit_cbz_label(&mut self, sz: Size, reg: Location, label: Label) - -> Result<(), CodegenError>; + -> Result<(), CompileError>; fn emit_cbnz_label( &mut self, sz: Size, reg: Location, label: Label, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_tbz_label( &mut self, sz: Size, reg: Location, n: u32, label: Label, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_tbnz_label( &mut self, sz: Size, reg: Location, n: u32, label: Label, - ) -> Result<(), CodegenError>; - fn emit_bcond_label(&mut self, condition: Condition, label: Label) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; + fn emit_bcond_label(&mut self, condition: Condition, label: Label) -> Result<(), CompileError>; fn emit_bcond_label_far( &mut self, condition: Condition, label: Label, - ) -> Result<(), CodegenError>; - fn emit_b_register(&mut self, reg: GPR) -> Result<(), CodegenError>; - fn emit_call_label(&mut self, label: Label) -> Result<(), CodegenError>; - fn emit_call_register(&mut self, reg: GPR) -> Result<(), CodegenError>; - fn emit_ret(&mut self) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; + fn emit_b_register(&mut self, reg: GPR) -> Result<(), CompileError>; + fn emit_call_label(&mut self, label: Label) -> Result<(), CompileError>; + fn emit_call_register(&mut self, reg: GPR) -> Result<(), CompileError>; + fn emit_ret(&mut self) -> Result<(), CompileError>; - fn emit_udf(&mut self, payload: u16) -> Result<(), CodegenError>; - fn emit_dmb(&mut self) -> Result<(), CodegenError>; - fn emit_brk(&mut self) -> Result<(), CodegenError>; + fn emit_udf(&mut self, payload: u16) -> Result<(), CompileError>; + fn emit_dmb(&mut self) -> Result<(), CompileError>; + fn emit_brk(&mut self) -> Result<(), CompileError>; - fn emit_fcmp(&mut self, sz: Size, src1: Location, src2: Location) -> Result<(), CodegenError>; - fn emit_fneg(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_fsqrt(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; + fn emit_fcmp(&mut self, sz: Size, src1: Location, src2: Location) -> Result<(), CompileError>; + fn emit_fneg(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_fsqrt(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; fn emit_fadd( &mut self, @@ -369,28 +393,28 @@ pub trait EmitterARM64 { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_fsub( &mut self, sz: Size, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_fmul( &mut self, sz: Size, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_fdiv( &mut self, sz: Size, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_fmin( &mut self, @@ -398,19 +422,19 @@ pub trait EmitterARM64 { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_fmax( &mut self, sz: Size, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; - fn emit_frintz(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_frintn(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_frintm(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_frintp(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; + fn emit_frintz(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_frintn(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_frintm(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_frintp(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; fn emit_scvtf( &mut self, @@ -418,34 +442,34 @@ pub trait EmitterARM64 { src: Location, sz_out: Size, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_ucvtf( &mut self, sz_in: Size, src: Location, sz_out: Size, dst: Location, - ) -> Result<(), CodegenError>; - fn emit_fcvt(&mut self, sz_in: Size, src: Location, dst: Location) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; + fn emit_fcvt(&mut self, sz_in: Size, src: Location, dst: Location) -> Result<(), CompileError>; fn emit_fcvtzs( &mut self, sz_in: Size, src: Location, sz_out: Size, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_fcvtzu( &mut self, sz_in: Size, src: Location, sz_out: Size, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; - fn emit_read_fpcr(&mut self, reg: GPR) -> Result<(), CodegenError>; - fn emit_write_fpcr(&mut self, reg: GPR) -> Result<(), CodegenError>; - fn emit_read_fpsr(&mut self, reg: GPR) -> Result<(), CodegenError>; - fn emit_write_fpsr(&mut self, reg: GPR) -> Result<(), CodegenError>; + fn emit_read_fpcr(&mut self, reg: GPR) -> Result<(), CompileError>; + fn emit_write_fpcr(&mut self, reg: GPR) -> Result<(), CompileError>; + fn emit_read_fpsr(&mut self, reg: GPR) -> Result<(), CompileError>; + fn emit_write_fpsr(&mut self, reg: GPR) -> Result<(), CompileError>; fn arch_supports_canonicalize_nan(&self) -> bool { true @@ -458,7 +482,7 @@ pub trait EmitterARM64 { fn arch_emit_indirect_call_with_trampoline( &mut self, _loc: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { codegen_error!("singlepass arch_emit_indirect_call_with_trampoline unimplemented") } } @@ -488,7 +512,7 @@ impl EmitterARM64 for Assembler { ); } - fn emit_str(&mut self, sz: Size, reg: Location, addr: Location) -> Result<(), CodegenError> { + fn emit_str(&mut self, sz: Size, reg: Location, addr: Location) -> Result<(), CompileError> { match (sz, reg, addr) { (Size::S64, Location::GPR(reg), Location::Memory(addr, disp)) => { let reg = reg.into_index() as u32; @@ -560,7 +584,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_ldr(&mut self, sz: Size, reg: Location, addr: Location) -> Result<(), CodegenError> { + fn emit_ldr(&mut self, sz: Size, reg: Location, addr: Location) -> Result<(), CompileError> { match (sz, reg, addr) { (Size::S64, Location::GPR(reg), Location::Memory(addr, disp)) => { let reg = reg.into_index() as u32; @@ -662,7 +686,7 @@ impl EmitterARM64 for Assembler { reg: Location, addr: GPR, offset: i32, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { assert!((-255..=255).contains(&offset)); match (sz, reg) { (Size::S64, Location::GPR(reg)) => { @@ -701,7 +725,7 @@ impl EmitterARM64 for Assembler { reg: Location, addr: GPR, offset: i32, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { assert!((-255..=255).contains(&offset)); match (sz, reg) { (Size::S64, Location::GPR(reg)) => { @@ -741,7 +765,7 @@ impl EmitterARM64 for Assembler { reg: Location, addr: GPR, offset: u32, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { assert!(offset <= 255); match (sz, reg) { (Size::S64, Location::GPR(reg)) => { @@ -764,7 +788,7 @@ impl EmitterARM64 for Assembler { reg: Location, addr: GPR, offset: u32, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { assert!(offset <= 255); match (sz, reg) { (Size::S64, Location::GPR(reg)) => { @@ -787,7 +811,7 @@ impl EmitterARM64 for Assembler { reg: Location, addr: GPR, offset: u32, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { assert!(offset <= 255); match (sz, reg) { (Size::S64, Location::GPR(reg)) => { @@ -812,7 +836,7 @@ impl EmitterARM64 for Assembler { reg2: Location, addr: GPR, offset: u32, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { assert!(offset <= 255); match (sz, reg1, reg2) { (Size::S64, Location::GPR(reg1), Location::GPR(reg2)) => { @@ -832,7 +856,7 @@ impl EmitterARM64 for Assembler { reg2: Location, addr: GPR, offset: u32, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { assert!(offset <= 255); match (sz, reg1, reg2) { (Size::S64, Location::GPR(reg1), Location::GPR(reg2)) => { @@ -846,7 +870,7 @@ impl EmitterARM64 for Assembler { Ok(()) } - fn emit_ldrb(&mut self, _sz: Size, reg: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_ldrb(&mut self, _sz: Size, reg: Location, dst: Location) -> Result<(), CompileError> { match (reg, dst) { (Location::GPR(reg), Location::Memory(addr, offset)) => { let reg = reg.into_index() as u32; @@ -871,7 +895,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_ldrh(&mut self, _sz: Size, reg: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_ldrh(&mut self, _sz: Size, reg: Location, dst: Location) -> Result<(), CompileError> { match (reg, dst) { (Location::GPR(reg), Location::Memory(addr, offset)) => { let reg = reg.into_index() as u32; @@ -896,7 +920,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_ldrsb(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_ldrsb(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CompileError> { match (sz, reg, dst) { (Size::S64, Location::GPR(reg), Location::Memory(addr, offset)) => { let reg = reg.into_index() as u32; @@ -940,7 +964,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_ldrsh(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_ldrsh(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CompileError> { match (sz, reg, dst) { (Size::S64, Location::GPR(reg), Location::Memory(addr, offset)) => { let reg = reg.into_index() as u32; @@ -984,7 +1008,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_ldrsw(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_ldrsw(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CompileError> { match (sz, reg, dst) { (Size::S64, Location::GPR(reg), Location::Memory(addr, offset)) => { let reg = reg.into_index() as u32; @@ -1009,7 +1033,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_strb(&mut self, _sz: Size, reg: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_strb(&mut self, _sz: Size, reg: Location, dst: Location) -> Result<(), CompileError> { match (reg, dst) { (Location::GPR(reg), Location::Memory(addr, offset)) => { let reg = reg.into_index() as u32; @@ -1034,7 +1058,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_strh(&mut self, _sz: Size, reg: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_strh(&mut self, _sz: Size, reg: Location, dst: Location) -> Result<(), CompileError> { match (reg, dst) { (Location::GPR(reg), Location::Memory(addr, offset)) => { let reg = reg.into_index() as u32; @@ -1060,7 +1084,106 @@ impl EmitterARM64 for Assembler { Ok(()) } - fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_ldaxr(&mut self, sz: Size, reg: Location, dst: Location) -> Result<(), CompileError> { + match (sz, reg, dst) { + (Size::S32, Location::GPR(reg), Location::GPR(dst)) => { + let reg = reg.into_index() as u32; + let dst = dst.into_index() as u32; + dynasm!(self ; ldaxr W(reg), [X(dst)]); + } + (Size::S64, Location::GPR(reg), Location::GPR(dst)) => { + let reg = reg.into_index() as u32; + let dst = dst.into_index() as u32; + dynasm!(self ; ldaxr X(reg), [X(dst)]); + } + _ => codegen_error!("singlepass can't emit LDAXR {:?}, {:?}", reg, dst), + } + Ok(()) + } + fn emit_ldaxrb(&mut self, _sz: Size, reg: Location, dst: Location) -> Result<(), CompileError> { + match (reg, dst) { + (Location::GPR(reg), Location::GPR(dst)) => { + let reg = reg.into_index() as u32; + let dst = dst.into_index() as u32; + dynasm!(self ; ldaxrb W(reg), [X(dst)]); + } + _ => codegen_error!("singlepass can't emit LDAXRB {:?}, {:?}", reg, dst), + } + Ok(()) + } + fn emit_ldaxrh(&mut self, _sz: Size, reg: Location, dst: Location) -> Result<(), CompileError> { + match (reg, dst) { + (Location::GPR(reg), Location::GPR(dst)) => { + let reg = reg.into_index() as u32; + let dst = dst.into_index() as u32; + dynasm!(self ; ldaxrh W(reg), [X(dst)]); + } + _ => codegen_error!("singlepass can't emit LDAXRH {:?}, {:?}", reg, dst), + } + Ok(()) + } + fn emit_stlxr( + &mut self, + sz: Size, + status: Location, + reg: Location, + dst: Location, + ) -> Result<(), CompileError> { + match (sz, status, reg, dst) { + (Size::S32, Location::GPR(status), Location::GPR(reg), Location::GPR(dst)) => { + let reg = reg.into_index() as u32; + let dst = dst.into_index() as u32; + let status = status.into_index() as u32; + dynasm!(self ; stlxr W(status), W(reg), [X(dst)]); + } + (Size::S64, Location::GPR(status), Location::GPR(reg), Location::GPR(dst)) => { + let reg = reg.into_index() as u32; + let dst = dst.into_index() as u32; + let status = status.into_index() as u32; + dynasm!(self ; stlxr W(status), X(reg), [X(dst)]); + } + _ => codegen_error!("singlepass can't emit STLXR {:?}, {:?}", reg, dst), + } + Ok(()) + } + fn emit_stlxrb( + &mut self, + _sz: Size, + status: Location, + reg: Location, + dst: Location, + ) -> Result<(), CompileError> { + match (status, reg, dst) { + (Location::GPR(status), Location::GPR(reg), Location::GPR(dst)) => { + let reg = reg.into_index() as u32; + let dst = dst.into_index() as u32; + let status = status.into_index() as u32; + dynasm!(self ; stlxrb W(status), W(reg), [X(dst)]); + } + _ => codegen_error!("singlepass can't emit STLXRB {:?}, {:?}", reg, dst), + } + Ok(()) + } + fn emit_stlxrh( + &mut self, + _sz: Size, + status: Location, + reg: Location, + dst: Location, + ) -> Result<(), CompileError> { + match (status, reg, dst) { + (Location::GPR(status), Location::GPR(reg), Location::GPR(dst)) => { + let reg = reg.into_index() as u32; + let dst = dst.into_index() as u32; + let status = status.into_index() as u32; + dynasm!(self ; stlxrh W(status), W(reg), [X(dst)]); + } + _ => codegen_error!("singlepass can't emit STLXRH {:?}, {:?}", reg, dst), + } + Ok(()) + } + + fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S64, Location::GPR(src), Location::GPR(dst)) => { let src = src.into_index() as u32; @@ -1137,7 +1260,7 @@ impl EmitterARM64 for Assembler { Ok(()) } - fn emit_movn(&mut self, sz: Size, reg: Location, val: u32) -> Result<(), CodegenError> { + fn emit_movn(&mut self, sz: Size, reg: Location, val: u32) -> Result<(), CompileError> { match (sz, reg) { (Size::S32, Location::GPR(reg)) => { let reg = reg.into_index() as u32; @@ -1151,7 +1274,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_movz(&mut self, reg: Location, val: u32) -> Result<(), CodegenError> { + fn emit_movz(&mut self, reg: Location, val: u32) -> Result<(), CompileError> { match reg { Location::GPR(reg) => { let reg = reg.into_index() as u32; @@ -1161,7 +1284,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_movk(&mut self, reg: Location, val: u32, shift: u32) -> Result<(), CodegenError> { + fn emit_movk(&mut self, reg: Location, val: u32, shift: u32) -> Result<(), CompileError> { match reg { Location::GPR(reg) => { let reg = reg.into_index() as u32; @@ -1172,7 +1295,7 @@ impl EmitterARM64 for Assembler { Ok(()) } - fn emit_mov_imm(&mut self, dst: Location, val: u64) -> Result<(), CodegenError> { + fn emit_mov_imm(&mut self, dst: Location, val: u64) -> Result<(), CompileError> { match dst { Location::GPR(dst) => { let dst = dst.into_index() as u32; @@ -1207,7 +1330,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -1277,7 +1400,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -1341,7 +1464,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -1371,7 +1494,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -1431,7 +1554,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -1472,7 +1595,7 @@ impl EmitterARM64 for Assembler { src2: Location, lsl: u32, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -1492,7 +1615,7 @@ impl EmitterARM64 for Assembler { Ok(()) } - fn emit_cmp(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_cmp(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S64, Location::GPR(src), Location::GPR(dst)) => { let src = src.into_index() as u32; @@ -1538,7 +1661,7 @@ impl EmitterARM64 for Assembler { Ok(()) } - fn emit_tst(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_tst(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S64, Location::GPR(src), Location::GPR(dst)) => { let src = src.into_index() as u32; @@ -1582,7 +1705,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -1657,7 +1780,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -1732,7 +1855,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -1807,7 +1930,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -1875,7 +1998,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -1923,7 +2046,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -1971,7 +2094,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -2020,7 +2143,7 @@ impl EmitterARM64 for Assembler { lsb: u32, width: u32, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, dst) { (Size::S32, Location::GPR(dst)) => { dynasm!(self ; bfc W(dst as u32), lsb, width); @@ -2039,7 +2162,7 @@ impl EmitterARM64 for Assembler { lsb: u32, width: u32, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S32, Location::GPR(src), Location::GPR(dst)) => { dynasm!(self ; bfi W(dst as u32), W(src as u32), lsb, width); @@ -2058,7 +2181,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -2088,7 +2211,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => { let src1 = src1.into_index() as u32; @@ -2121,7 +2244,7 @@ impl EmitterARM64 for Assembler { b: Location, c: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, a, b, c, dst) { ( Size::S32, @@ -2161,7 +2284,7 @@ impl EmitterARM64 for Assembler { Ok(()) } - fn emit_sxtb(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_sxtb(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S32, Location::GPR(src), Location::GPR(dst)) => { let src = src.into_index() as u32; @@ -2177,7 +2300,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_sxth(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_sxth(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S32, Location::GPR(src), Location::GPR(dst)) => { let src = src.into_index() as u32; @@ -2193,7 +2316,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_sxtw(&mut self, _sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_sxtw(&mut self, _sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (src, dst) { (Location::GPR(src), Location::GPR(dst)) => { let src = src.into_index() as u32; @@ -2204,7 +2327,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_uxtb(&mut self, _sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_uxtb(&mut self, _sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (src, dst) { (Location::GPR(src), Location::GPR(dst)) => { let src = src.into_index() as u32; @@ -2215,7 +2338,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_uxth(&mut self, _sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_uxth(&mut self, _sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (src, dst) { (Location::GPR(src), Location::GPR(dst)) => { let src = src.into_index() as u32; @@ -2227,7 +2350,7 @@ impl EmitterARM64 for Assembler { Ok(()) } - fn emit_cset(&mut self, sz: Size, dst: Location, cond: Condition) -> Result<(), CodegenError> { + fn emit_cset(&mut self, sz: Size, dst: Location, cond: Condition) -> Result<(), CompileError> { match (sz, dst) { (Size::S32, Location::GPR(reg)) => { let reg = reg as u32; @@ -2273,7 +2396,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_csetm(&mut self, sz: Size, dst: Location, cond: Condition) -> Result<(), CodegenError> { + fn emit_csetm(&mut self, sz: Size, dst: Location, cond: Condition) -> Result<(), CompileError> { match (sz, dst) { (Size::S32, Location::GPR(reg)) => { let reg = reg as u32; @@ -2325,7 +2448,7 @@ impl EmitterARM64 for Assembler { src: Location, dst: Location, cond: Condition, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S32, Location::GPR(src), Location::GPR(dst)) => { let src = src.into_index() as u32; @@ -2374,7 +2497,7 @@ impl EmitterARM64 for Assembler { Ok(()) } - fn emit_clz(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_clz(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S64, Location::GPR(src), Location::GPR(dst)) => { let src = src.into_index() as u32; @@ -2390,7 +2513,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_rbit(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_rbit(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S64, Location::GPR(src), Location::GPR(dst)) => { let src = src.into_index() as u32; @@ -2407,17 +2530,17 @@ impl EmitterARM64 for Assembler { Ok(()) } - fn emit_label(&mut self, label: Label) -> Result<(), CodegenError> { + fn emit_label(&mut self, label: Label) -> Result<(), CompileError> { dynasm!(self ; => label); Ok(()) } - fn emit_load_label(&mut self, reg: GPR, label: Label) -> Result<(), CodegenError> { + fn emit_load_label(&mut self, reg: GPR, label: Label) -> Result<(), CompileError> { let reg = reg.into_index() as u32; dynasm!(self ; adr X(reg), =>label); Ok(()) } - fn emit_b_label(&mut self, label: Label) -> Result<(), CodegenError> { + fn emit_b_label(&mut self, label: Label) -> Result<(), CompileError> { dynasm!(self ; b =>label); Ok(()) } @@ -2426,7 +2549,7 @@ impl EmitterARM64 for Assembler { sz: Size, reg: Location, label: Label, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, reg) { (Size::S32, Location::GPR(reg)) => { let reg = reg.into_index() as u32; @@ -2445,7 +2568,7 @@ impl EmitterARM64 for Assembler { sz: Size, reg: Location, label: Label, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, reg) { (Size::S32, Location::GPR(reg)) => { let reg = reg.into_index() as u32; @@ -2465,7 +2588,7 @@ impl EmitterARM64 for Assembler { reg: Location, n: u32, label: Label, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, reg) { (Size::S32, Location::GPR(reg)) => { let reg = reg.into_index() as u32; @@ -2491,7 +2614,7 @@ impl EmitterARM64 for Assembler { reg: Location, n: u32, label: Label, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, reg) { (Size::S32, Location::GPR(reg)) => { let reg = reg.into_index() as u32; @@ -2511,7 +2634,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_bcond_label(&mut self, condition: Condition, label: Label) -> Result<(), CodegenError> { + fn emit_bcond_label(&mut self, condition: Condition, label: Label) -> Result<(), CompileError> { match condition { Condition::Eq => dynasm!(self ; b.eq => label), Condition::Ne => dynasm!(self ; b.ne => label), @@ -2535,7 +2658,7 @@ impl EmitterARM64 for Assembler { &mut self, condition: Condition, label: Label, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let cont: Label = self.get_label(); match condition { // if not condition than continue @@ -2559,37 +2682,37 @@ impl EmitterARM64 for Assembler { self.emit_label(cont)?; Ok(()) } - fn emit_b_register(&mut self, reg: GPR) -> Result<(), CodegenError> { + fn emit_b_register(&mut self, reg: GPR) -> Result<(), CompileError> { dynasm!(self ; br X(reg.into_index() as u32)); Ok(()) } - fn emit_call_label(&mut self, label: Label) -> Result<(), CodegenError> { + fn emit_call_label(&mut self, label: Label) -> Result<(), CompileError> { dynasm!(self ; bl =>label); Ok(()) } - fn emit_call_register(&mut self, reg: GPR) -> Result<(), CodegenError> { + fn emit_call_register(&mut self, reg: GPR) -> Result<(), CompileError> { dynasm!(self ; blr X(reg.into_index() as u32)); Ok(()) } - fn emit_ret(&mut self) -> Result<(), CodegenError> { + fn emit_ret(&mut self) -> Result<(), CompileError> { dynasm!(self ; ret); Ok(()) } - fn emit_udf(&mut self, payload: u16) -> Result<(), CodegenError> { + fn emit_udf(&mut self, payload: u16) -> Result<(), CompileError> { dynasm!(self ; udf (payload as u32)); Ok(()) } - fn emit_dmb(&mut self) -> Result<(), CodegenError> { + fn emit_dmb(&mut self) -> Result<(), CompileError> { dynasm!(self ; dmb ish); Ok(()) } - fn emit_brk(&mut self) -> Result<(), CodegenError> { + fn emit_brk(&mut self) -> Result<(), CompileError> { dynasm!(self ; brk 0); Ok(()) } - fn emit_fcmp(&mut self, sz: Size, src1: Location, src2: Location) -> Result<(), CodegenError> { + fn emit_fcmp(&mut self, sz: Size, src1: Location, src2: Location) -> Result<(), CompileError> { match (sz, src1, src2) { (Size::S32, Location::SIMD(src1), Location::SIMD(src2)) => { let src1 = src1.into_index() as u32; @@ -2606,7 +2729,7 @@ impl EmitterARM64 for Assembler { Ok(()) } - fn emit_fneg(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_fneg(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S32, Location::SIMD(src), Location::SIMD(dst)) => { let src = src.into_index() as u32; @@ -2622,7 +2745,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_fsqrt(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_fsqrt(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S32, Location::SIMD(src), Location::SIMD(dst)) => { let src = src.into_index() as u32; @@ -2645,7 +2768,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => { let src1 = src1.into_index() as u32; @@ -2675,7 +2798,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => { let src1 = src1.into_index() as u32; @@ -2705,7 +2828,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => { let src1 = src1.into_index() as u32; @@ -2735,7 +2858,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => { let src1 = src1.into_index() as u32; @@ -2766,7 +2889,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => { let src1 = src1.into_index() as u32; @@ -2796,7 +2919,7 @@ impl EmitterARM64 for Assembler { src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src1, src2, dst) { (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => { let src1 = src1.into_index() as u32; @@ -2821,7 +2944,7 @@ impl EmitterARM64 for Assembler { Ok(()) } - fn emit_frintz(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_frintz(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S32, Location::SIMD(src), Location::SIMD(dst)) => { let src = src.into_index() as u32; @@ -2837,7 +2960,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_frintn(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_frintn(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S32, Location::SIMD(src), Location::SIMD(dst)) => { let src = src.into_index() as u32; @@ -2853,7 +2976,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_frintm(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_frintm(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S32, Location::SIMD(src), Location::SIMD(dst)) => { let src = src.into_index() as u32; @@ -2869,7 +2992,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_frintp(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_frintp(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S32, Location::SIMD(src), Location::SIMD(dst)) => { let src = src.into_index() as u32; @@ -2892,7 +3015,7 @@ impl EmitterARM64 for Assembler { src: Location, sz_out: Size, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz_in, src, sz_out, dst) { (Size::S32, Location::GPR(src), Size::S32, Location::SIMD(dst)) => { let src = src.into_index() as u32; @@ -2930,7 +3053,7 @@ impl EmitterARM64 for Assembler { src: Location, sz_out: Size, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz_in, src, sz_out, dst) { (Size::S32, Location::GPR(src), Size::S32, Location::SIMD(dst)) => { let src = src.into_index() as u32; @@ -2962,7 +3085,7 @@ impl EmitterARM64 for Assembler { } Ok(()) } - fn emit_fcvt(&mut self, sz_in: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_fcvt(&mut self, sz_in: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz_in, src, dst) { (Size::S32, Location::SIMD(src), Location::SIMD(dst)) => { let src = src.into_index() as u32; @@ -2989,7 +3112,7 @@ impl EmitterARM64 for Assembler { src: Location, sz_out: Size, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz_in, src, sz_out, dst) { (Size::S32, Location::SIMD(src), Size::S32, Location::GPR(dst)) => { let src = src.into_index() as u32; @@ -3027,7 +3150,7 @@ impl EmitterARM64 for Assembler { src: Location, sz_out: Size, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz_in, src, sz_out, dst) { (Size::S32, Location::SIMD(src), Size::S32, Location::GPR(dst)) => { let src = src.into_index() as u32; @@ -3061,20 +3184,20 @@ impl EmitterARM64 for Assembler { } // 1 011 0100 0100 000 => fpcr - fn emit_read_fpcr(&mut self, reg: GPR) -> Result<(), CodegenError> { + fn emit_read_fpcr(&mut self, reg: GPR) -> Result<(), CompileError> { dynasm!(self ; mrs X(reg as u32), 0b1_011_0100_0100_000); Ok(()) } - fn emit_write_fpcr(&mut self, reg: GPR) -> Result<(), CodegenError> { + fn emit_write_fpcr(&mut self, reg: GPR) -> Result<(), CompileError> { dynasm!(self ; msr 0b1_011_0100_0100_000, X(reg as u32)); Ok(()) } // 1 011 0100 0100 001 => fpsr - fn emit_read_fpsr(&mut self, reg: GPR) -> Result<(), CodegenError> { + fn emit_read_fpsr(&mut self, reg: GPR) -> Result<(), CompileError> { dynasm!(self ; mrs X(reg as u32), 0b1_011_0100_0100_001); Ok(()) } - fn emit_write_fpsr(&mut self, reg: GPR) -> Result<(), CodegenError> { + fn emit_write_fpsr(&mut self, reg: GPR) -> Result<(), CompileError> { dynasm!(self ; msr 0b1_011_0100_0100_001, X(reg as u32)); Ok(()) } @@ -3083,7 +3206,7 @@ impl EmitterARM64 for Assembler { pub fn gen_std_trampoline_arm64( sig: &FunctionType, calling_convention: CallingConvention, -) -> Result { +) -> Result { let mut a = Assembler::new(0); let fptr = GPR::X27; @@ -3210,7 +3333,7 @@ pub fn gen_std_dynamic_import_trampoline_arm64( vmoffsets: &VMOffsets, sig: &FunctionType, calling_convention: CallingConvention, -) -> Result { +) -> Result { let mut a = Assembler::new(0); // Allocate argument array. let stack_offset: usize = 16 * std::cmp::max(sig.params().len(), sig.results().len()); @@ -3368,7 +3491,7 @@ pub fn gen_import_call_trampoline_arm64( index: FunctionIndex, sig: &FunctionType, calling_convention: CallingConvention, -) -> Result { +) -> Result { let mut a = Assembler::new(0); // Singlepass internally treats all arguments as integers diff --git a/lib/compiler-singlepass/src/emitter_x64.rs b/lib/compiler-singlepass/src/emitter_x64.rs index 635635e9d..7bea71664 100644 --- a/lib/compiler-singlepass/src/emitter_x64.rs +++ b/lib/compiler-singlepass/src/emitter_x64.rs @@ -2,13 +2,12 @@ use crate::codegen_error; use crate::common_decl::Size; use crate::location::Location as AbstractLocation; pub use crate::location::Multiplier; -use crate::machine::CodegenError; pub use crate::machine::{Label, Offset}; use crate::machine_x64::AssemblerX64; pub use crate::x64_decl::{GPR, XMM}; use dynasm::dynasm; use dynasmrt::{AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; -use wasmer_types::CpuFeature; +use wasmer_types::{CompileError, CpuFeature}; /// Force `dynasm!` to use the correct arch (x64) when cross-compiling. /// `dynasm!` proc-macro tries to auto-detect it by default by looking at the @@ -68,265 +67,265 @@ pub trait EmitterX64 { fn get_offset(&self) -> Offset; fn get_jmp_instr_size(&self) -> u8; - fn finalize_function(&mut self) -> Result<(), CodegenError> { + fn finalize_function(&mut self) -> Result<(), CompileError> { Ok(()) } - fn emit_u64(&mut self, x: u64) -> Result<(), CodegenError>; - fn emit_bytes(&mut self, bytes: &[u8]) -> Result<(), CodegenError>; + fn emit_u64(&mut self, x: u64) -> Result<(), CompileError>; + fn emit_bytes(&mut self, bytes: &[u8]) -> Result<(), CompileError>; - fn emit_label(&mut self, label: Label) -> Result<(), CodegenError>; + fn emit_label(&mut self, label: Label) -> Result<(), CompileError>; - fn emit_nop(&mut self) -> Result<(), CodegenError>; + fn emit_nop(&mut self) -> Result<(), CompileError>; /// A high-level assembler method. Emits an instruction sequence of length `n` that is functionally /// equivalent to a `nop` instruction, without guarantee about the underlying implementation. - fn emit_nop_n(&mut self, n: usize) -> Result<(), CodegenError>; + fn emit_nop_n(&mut self, n: usize) -> Result<(), CompileError>; - fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_lea(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_lea_label(&mut self, label: Label, dst: Location) -> Result<(), CodegenError>; - fn emit_cdq(&mut self) -> Result<(), CodegenError>; - fn emit_cqo(&mut self) -> Result<(), CodegenError>; - fn emit_xor(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_jmp(&mut self, condition: Condition, label: Label) -> Result<(), CodegenError>; - fn emit_jmp_location(&mut self, loc: Location) -> Result<(), CodegenError>; - fn emit_set(&mut self, condition: Condition, dst: GPR) -> Result<(), CodegenError>; - fn emit_push(&mut self, sz: Size, src: Location) -> Result<(), CodegenError>; - fn emit_pop(&mut self, sz: Size, dst: Location) -> Result<(), CodegenError>; - fn emit_cmp(&mut self, sz: Size, left: Location, right: Location) -> Result<(), CodegenError>; - fn emit_add(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_sub(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_neg(&mut self, sz: Size, value: Location) -> Result<(), CodegenError>; - fn emit_imul(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_imul_imm32_gpr64(&mut self, src: u32, dst: GPR) -> Result<(), CodegenError>; - fn emit_div(&mut self, sz: Size, divisor: Location) -> Result<(), CodegenError>; - fn emit_idiv(&mut self, sz: Size, divisor: Location) -> Result<(), CodegenError>; - fn emit_shl(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_shr(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_sar(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_rol(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_ror(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_and(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_test(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_or(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_bsf(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; - fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; + fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_lea(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_lea_label(&mut self, label: Label, dst: Location) -> Result<(), CompileError>; + fn emit_cdq(&mut self) -> Result<(), CompileError>; + fn emit_cqo(&mut self) -> Result<(), CompileError>; + fn emit_xor(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_jmp(&mut self, condition: Condition, label: Label) -> Result<(), CompileError>; + fn emit_jmp_location(&mut self, loc: Location) -> Result<(), CompileError>; + fn emit_set(&mut self, condition: Condition, dst: GPR) -> Result<(), CompileError>; + fn emit_push(&mut self, sz: Size, src: Location) -> Result<(), CompileError>; + fn emit_pop(&mut self, sz: Size, dst: Location) -> Result<(), CompileError>; + fn emit_cmp(&mut self, sz: Size, left: Location, right: Location) -> Result<(), CompileError>; + fn emit_add(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_sub(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_neg(&mut self, sz: Size, value: Location) -> Result<(), CompileError>; + fn emit_imul(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_imul_imm32_gpr64(&mut self, src: u32, dst: GPR) -> Result<(), CompileError>; + fn emit_div(&mut self, sz: Size, divisor: Location) -> Result<(), CompileError>; + fn emit_idiv(&mut self, sz: Size, divisor: Location) -> Result<(), CompileError>; + fn emit_shl(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_shr(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_sar(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_rol(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_ror(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_and(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_test(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_or(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_bsf(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; + fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; fn emit_movzx( &mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_movsx( &mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location, - ) -> Result<(), CodegenError>; - fn emit_xchg(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; + fn emit_xchg(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>; fn emit_lock_xadd( &mut self, sz: Size, src: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_lock_cmpxchg( &mut self, sz: Size, src: Location, dst: Location, - ) -> Result<(), CodegenError>; - fn emit_rep_stosq(&mut self) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; + fn emit_rep_stosq(&mut self) -> Result<(), CompileError>; - fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) -> Result<(), CodegenError>; - fn emit_btc_gpr_imm8_64(&mut self, src: u8, dst: GPR) -> Result<(), CodegenError>; + fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) -> Result<(), CompileError>; + fn emit_btc_gpr_imm8_64(&mut self, src: u8, dst: GPR) -> Result<(), CompileError>; - fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR) -> Result<(), CodegenError>; - fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR) -> Result<(), CodegenError>; + fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR) -> Result<(), CompileError>; + fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR) -> Result<(), CompileError>; - fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory) -> Result<(), CodegenError>; - fn emit_vmovapd(&mut self, src: XMMOrMemory, dst: XMMOrMemory) -> Result<(), CodegenError>; - fn emit_vxorps(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; - fn emit_vxorpd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; + fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory) -> Result<(), CompileError>; + fn emit_vmovapd(&mut self, src: XMMOrMemory, dst: XMMOrMemory) -> Result<(), CompileError>; + fn emit_vxorps(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; + fn emit_vxorpd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; - fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; - fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; - fn emit_vsubss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; - fn emit_vsubsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; - fn emit_vmulss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; - fn emit_vmulsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; - fn emit_vdivss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; - fn emit_vdivsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; - fn emit_vmaxss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; - fn emit_vmaxsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; - fn emit_vminss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; - fn emit_vminsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; + fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; + fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; + fn emit_vsubss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; + fn emit_vsubsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; + fn emit_vmulss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; + fn emit_vmulsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; + fn emit_vdivss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; + fn emit_vdivsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; + fn emit_vmaxss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; + fn emit_vmaxsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; + fn emit_vminss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; + fn emit_vminsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; fn emit_vcmpeqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) - -> Result<(), CodegenError>; + -> Result<(), CompileError>; fn emit_vcmpeqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) - -> Result<(), CodegenError>; + -> Result<(), CompileError>; fn emit_vcmpneqss( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vcmpneqsd( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vcmpltss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) - -> Result<(), CodegenError>; + -> Result<(), CompileError>; fn emit_vcmpltsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) - -> Result<(), CodegenError>; + -> Result<(), CompileError>; fn emit_vcmpless(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) - -> Result<(), CodegenError>; + -> Result<(), CompileError>; fn emit_vcmplesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) - -> Result<(), CodegenError>; + -> Result<(), CompileError>; fn emit_vcmpgtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) - -> Result<(), CodegenError>; + -> Result<(), CompileError>; fn emit_vcmpgtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) - -> Result<(), CodegenError>; + -> Result<(), CompileError>; fn emit_vcmpgess(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) - -> Result<(), CodegenError>; + -> Result<(), CompileError>; fn emit_vcmpgesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) - -> Result<(), CodegenError>; + -> Result<(), CompileError>; fn emit_vcmpunordss( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vcmpunordsd( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vcmpordss( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vcmpordsd( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; - fn emit_vsqrtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; - fn emit_vsqrtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; + fn emit_vsqrtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; + fn emit_vsqrtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; fn emit_vroundss_nearest( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vroundss_floor( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vroundss_ceil( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vroundss_trunc( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vroundsd_nearest( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vroundsd_floor( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vroundsd_ceil( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vroundsd_trunc( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vcvtss2sd( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vcvtsd2ss( &mut self, src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; - fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; - fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) -> Result<(), CodegenError>; + fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; + fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) -> Result<(), CompileError>; - fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CodegenError>; - fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CodegenError>; - fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CodegenError>; - fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CodegenError>; + fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CompileError>; + fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CompileError>; + fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CompileError>; + fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CompileError>; fn emit_vcvtsi2ss_32( &mut self, src1: XMM, src2: GPROrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vcvtsi2ss_64( &mut self, src1: XMM, src2: GPROrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vcvtsi2sd_32( &mut self, src1: XMM, src2: GPROrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vcvtsi2sd_64( &mut self, src1: XMM, src2: GPROrMemory, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vblendvps( &mut self, @@ -334,92 +333,92 @@ pub trait EmitterX64 { src2: XMMOrMemory, mask: XMM, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; fn emit_vblendvpd( &mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; - fn emit_test_gpr_64(&mut self, reg: GPR) -> Result<(), CodegenError>; + fn emit_test_gpr_64(&mut self, reg: GPR) -> Result<(), CompileError>; - fn emit_ud2(&mut self) -> Result<(), CodegenError>; - fn emit_ud1_payload(&mut self, payload: u8) -> Result<(), CodegenError>; - fn emit_ret(&mut self) -> Result<(), CodegenError>; - fn emit_call_label(&mut self, label: Label) -> Result<(), CodegenError>; - fn emit_call_location(&mut self, loc: Location) -> Result<(), CodegenError>; + fn emit_ud2(&mut self) -> Result<(), CompileError>; + fn emit_ud1_payload(&mut self, payload: u8) -> Result<(), CompileError>; + fn emit_ret(&mut self) -> Result<(), CompileError>; + fn emit_call_label(&mut self, label: Label) -> Result<(), CompileError>; + fn emit_call_location(&mut self, loc: Location) -> Result<(), CompileError>; - fn emit_call_register(&mut self, reg: GPR) -> Result<(), CodegenError>; + fn emit_call_register(&mut self, reg: GPR) -> Result<(), CompileError>; - fn emit_bkpt(&mut self) -> Result<(), CodegenError>; + fn emit_bkpt(&mut self) -> Result<(), CompileError>; - fn emit_host_redirection(&mut self, target: GPR) -> Result<(), CodegenError>; + fn emit_host_redirection(&mut self, target: GPR) -> Result<(), CompileError>; fn arch_has_itruncf(&self) -> bool { false } - fn arch_emit_i32_trunc_sf32(&mut self, _src: XMM, _dst: GPR) -> Result<(), CodegenError> { + fn arch_emit_i32_trunc_sf32(&mut self, _src: XMM, _dst: GPR) -> Result<(), CompileError> { codegen_error!("singplepass arch_emit_i32_trunc_sf32 unimplemented") } - fn arch_emit_i32_trunc_sf64(&mut self, _src: XMM, _dst: GPR) -> Result<(), CodegenError> { + fn arch_emit_i32_trunc_sf64(&mut self, _src: XMM, _dst: GPR) -> Result<(), CompileError> { codegen_error!("singplepass arch_emit_i32_trunc_sf64 unimplemented") } - fn arch_emit_i32_trunc_uf32(&mut self, _src: XMM, _dst: GPR) -> Result<(), CodegenError> { + fn arch_emit_i32_trunc_uf32(&mut self, _src: XMM, _dst: GPR) -> Result<(), CompileError> { codegen_error!("singplepass arch_emit_i32_trunc_uf32 unimplemented") } - fn arch_emit_i32_trunc_uf64(&mut self, _src: XMM, _dst: GPR) -> Result<(), CodegenError> { + fn arch_emit_i32_trunc_uf64(&mut self, _src: XMM, _dst: GPR) -> Result<(), CompileError> { codegen_error!("singplepass arch_emit_i32_trunc_uf64 unimplemented") } - fn arch_emit_i64_trunc_sf32(&mut self, _src: XMM, _dst: GPR) -> Result<(), CodegenError> { + fn arch_emit_i64_trunc_sf32(&mut self, _src: XMM, _dst: GPR) -> Result<(), CompileError> { codegen_error!("singplepass arch_emit_i64_trunc_sf32 unimplemented") } - fn arch_emit_i64_trunc_sf64(&mut self, _src: XMM, _dst: GPR) -> Result<(), CodegenError> { + fn arch_emit_i64_trunc_sf64(&mut self, _src: XMM, _dst: GPR) -> Result<(), CompileError> { codegen_error!("singplepass arch_emit_i64_trunc_sf64 unimplemented") } - fn arch_emit_i64_trunc_uf32(&mut self, _src: XMM, _dst: GPR) -> Result<(), CodegenError> { + fn arch_emit_i64_trunc_uf32(&mut self, _src: XMM, _dst: GPR) -> Result<(), CompileError> { codegen_error!("singplepass arch_emit_i64_trunc_uf32 unimplemented") } - fn arch_emit_i64_trunc_uf64(&mut self, _src: XMM, _dst: GPR) -> Result<(), CodegenError> { + fn arch_emit_i64_trunc_uf64(&mut self, _src: XMM, _dst: GPR) -> Result<(), CompileError> { codegen_error!("singplepass arch_emit_i64_trunc_uf64 unimplemented") } fn arch_has_fconverti(&self) -> bool { false } - fn arch_emit_f32_convert_si32(&mut self, _src: GPR, _dst: XMM) -> Result<(), CodegenError> { + fn arch_emit_f32_convert_si32(&mut self, _src: GPR, _dst: XMM) -> Result<(), CompileError> { codegen_error!("singlepass arch_emit_f32_convert_si32 unimplemented") } - fn arch_emit_f32_convert_si64(&mut self, _src: GPR, _dst: XMM) -> Result<(), CodegenError> { + fn arch_emit_f32_convert_si64(&mut self, _src: GPR, _dst: XMM) -> Result<(), CompileError> { codegen_error!("singlepass arch_emit_f32_convert_si64 unimplemented") } - fn arch_emit_f32_convert_ui32(&mut self, _src: GPR, _dst: XMM) -> Result<(), CodegenError> { + fn arch_emit_f32_convert_ui32(&mut self, _src: GPR, _dst: XMM) -> Result<(), CompileError> { codegen_error!("singlepass arch_emit_f32_convert_ui32 unimplemented") } - fn arch_emit_f32_convert_ui64(&mut self, _src: GPR, _dst: XMM) -> Result<(), CodegenError> { + fn arch_emit_f32_convert_ui64(&mut self, _src: GPR, _dst: XMM) -> Result<(), CompileError> { codegen_error!("singlepass arch_emit_f32_convert_ui64 unimplemented") } - fn arch_emit_f64_convert_si32(&mut self, _src: GPR, _dst: XMM) -> Result<(), CodegenError> { + fn arch_emit_f64_convert_si32(&mut self, _src: GPR, _dst: XMM) -> Result<(), CompileError> { codegen_error!("singlepass arch_emit_f64_convert_si32 unimplemented") } - fn arch_emit_f64_convert_si64(&mut self, _src: GPR, _dst: XMM) -> Result<(), CodegenError> { + fn arch_emit_f64_convert_si64(&mut self, _src: GPR, _dst: XMM) -> Result<(), CompileError> { codegen_error!("singlepass arch_emit_f64_convert_si64 unimplemented") } - fn arch_emit_f64_convert_ui32(&mut self, _src: GPR, _dst: XMM) -> Result<(), CodegenError> { + fn arch_emit_f64_convert_ui32(&mut self, _src: GPR, _dst: XMM) -> Result<(), CompileError> { codegen_error!("singlepass arch_emit_f64_convert_ui32 unimplemented") } - fn arch_emit_f64_convert_ui64(&mut self, _src: GPR, _dst: XMM) -> Result<(), CodegenError> { + fn arch_emit_f64_convert_ui64(&mut self, _src: GPR, _dst: XMM) -> Result<(), CompileError> { codegen_error!("singlepass arch_emit_f64_convert_ui64 unimplemented") } fn arch_has_fneg(&self) -> bool { false } - fn arch_emit_f32_neg(&mut self, _src: XMM, _dst: XMM) -> Result<(), CodegenError> { + fn arch_emit_f32_neg(&mut self, _src: XMM, _dst: XMM) -> Result<(), CompileError> { codegen_error!("singlepass arch_emit_f32_neg unimplemented") } - fn arch_emit_f64_neg(&mut self, _src: XMM, _dst: XMM) -> Result<(), CodegenError> { + fn arch_emit_f64_neg(&mut self, _src: XMM, _dst: XMM) -> Result<(), CompileError> { codegen_error!("singlepass arch_emit_f64_neg unimplemented") } @@ -431,7 +430,7 @@ pub trait EmitterX64 { _sz: Size, _src: Location, _dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { codegen_error!("singlepass arch_emit_lzcnt unimplemented") } fn arch_emit_tzcnt( @@ -439,7 +438,7 @@ pub trait EmitterX64 { _sz: Size, _src: Location, _dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { codegen_error!("singlepass arch_emit_tzcnt unimplemented") } @@ -454,18 +453,18 @@ pub trait EmitterX64 { fn arch_emit_indirect_call_with_trampoline( &mut self, _loc: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { codegen_error!("singlepass arch_emit_indirect_call_with_trampoline unimplemented") } // Emits entry trampoline just before the real function. - fn arch_emit_entry_trampoline(&mut self) -> Result<(), CodegenError> { + fn arch_emit_entry_trampoline(&mut self) -> Result<(), CompileError> { Ok(()) } // Byte offset from the beginning of a `mov Imm64, GPR` instruction to the imm64 value. // Required to support emulation on Aarch64. - fn arch_mov64_imm_offset(&self) -> Result { + fn arch_mov64_imm_offset(&self) -> Result { codegen_error!("singlepass arch_mov64_imm_offset unimplemented") } } @@ -934,7 +933,7 @@ impl EmitterX64 for AssemblerX64 { 5 } - fn finalize_function(&mut self) -> Result<(), CodegenError> { + fn finalize_function(&mut self) -> Result<(), CompileError> { dynasm!( self ; const_neg_one_32: @@ -947,29 +946,67 @@ impl EmitterX64 for AssemblerX64 { Ok(()) } - fn emit_u64(&mut self, x: u64) -> Result<(), CodegenError> { + fn arch_has_xzcnt(&self) -> bool { + match &self.target { + Some(target) => { + target.cpu_features().contains(CpuFeature::LZCNT) + && target.cpu_features().contains(CpuFeature::BMI1) + } + None => false, + } + } + + fn arch_emit_lzcnt( + &mut self, + sz: Size, + src: Location, + dst: Location, + ) -> Result<(), CompileError> { + binop_gpr_gpr!(lzcnt, self, sz, src, dst, { + binop_mem_gpr!(lzcnt, self, sz, src, dst, { + codegen_error!("singlepass cannot emit lzcnt") + }) + }); + Ok(()) + } + + fn arch_emit_tzcnt( + &mut self, + sz: Size, + src: Location, + dst: Location, + ) -> Result<(), CompileError> { + binop_gpr_gpr!(tzcnt, self, sz, src, dst, { + binop_mem_gpr!(tzcnt, self, sz, src, dst, { + codegen_error!("singlepass cannot emit tzcnt") + }) + }); + Ok(()) + } + + fn emit_u64(&mut self, x: u64) -> Result<(), CompileError> { self.push_u64(x); Ok(()) } - fn emit_bytes(&mut self, bytes: &[u8]) -> Result<(), CodegenError> { + fn emit_bytes(&mut self, bytes: &[u8]) -> Result<(), CompileError> { for &b in bytes { self.push(b); } Ok(()) } - fn emit_label(&mut self, label: Label) -> Result<(), CodegenError> { + fn emit_label(&mut self, label: Label) -> Result<(), CompileError> { dynasm!(self ; => label); Ok(()) } - fn emit_nop(&mut self) -> Result<(), CodegenError> { + fn emit_nop(&mut self) -> Result<(), CompileError> { dynasm!(self ; nop); Ok(()) } - fn emit_nop_n(&mut self, mut n: usize) -> Result<(), CodegenError> { + fn emit_nop_n(&mut self, mut n: usize) -> Result<(), CompileError> { /* 1 90H NOP 2 66 90H 66 NOP @@ -1001,7 +1038,7 @@ impl EmitterX64 for AssemblerX64 { self.emit_bytes(seq) } - fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { // fast path if let (Location::Imm32(0), Location::GPR(x)) = (src, dst) { dynasm!(self ; xor Rd(x as u8), Rd(x as u8)); @@ -1088,7 +1125,7 @@ impl EmitterX64 for AssemblerX64 { }); Ok(()) } - fn emit_lea(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_lea(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S32, Location::Memory(src, disp), Location::GPR(dst)) => { dynasm!(self ; lea Rd(dst as u8), [Rq(src as u8) + disp]); @@ -1134,7 +1171,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_lea_label(&mut self, label: Label, dst: Location) -> Result<(), CodegenError> { + fn emit_lea_label(&mut self, label: Label, dst: Location) -> Result<(), CompileError> { match dst { Location::GPR(x) => { dynasm!(self ; lea Rq(x as u8), [=>label]); @@ -1143,21 +1180,21 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_cdq(&mut self) -> Result<(), CodegenError> { + fn emit_cdq(&mut self) -> Result<(), CompileError> { dynasm!(self ; cdq); Ok(()) } - fn emit_cqo(&mut self) -> Result<(), CodegenError> { + fn emit_cqo(&mut self) -> Result<(), CompileError> { dynasm!(self ; cqo); Ok(()) } - fn emit_xor(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_xor(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { binop_all_nofp!(xor, self, sz, src, dst, { codegen_error!("singlepass can't emit XOR {:?} {:?} {:?}", sz, src, dst) }); Ok(()) } - fn emit_jmp(&mut self, condition: Condition, label: Label) -> Result<(), CodegenError> { + fn emit_jmp(&mut self, condition: Condition, label: Label) -> Result<(), CompileError> { match condition { Condition::None => jmp_op!(jmp, self, label), Condition::Above => jmp_op!(ja, self, label), @@ -1175,7 +1212,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_jmp_location(&mut self, loc: Location) -> Result<(), CodegenError> { + fn emit_jmp_location(&mut self, loc: Location) -> Result<(), CompileError> { match loc { Location::GPR(x) => dynasm!(self ; jmp Rq(x as u8)), Location::Memory(base, disp) => dynasm!(self ; jmp QWORD [Rq(base as u8) + disp]), @@ -1183,7 +1220,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_set(&mut self, condition: Condition, dst: GPR) -> Result<(), CodegenError> { + fn emit_set(&mut self, condition: Condition, dst: GPR) -> Result<(), CompileError> { match condition { Condition::Above => dynasm!(self ; seta Rb(dst as u8)), Condition::AboveEqual => dynasm!(self ; setae Rb(dst as u8)), @@ -1201,7 +1238,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_push(&mut self, sz: Size, src: Location) -> Result<(), CodegenError> { + fn emit_push(&mut self, sz: Size, src: Location) -> Result<(), CompileError> { match (sz, src) { (Size::S64, Location::Imm32(src)) => dynasm!(self ; push src as i32), (Size::S64, Location::GPR(src)) => dynasm!(self ; push Rq(src as u8)), @@ -1212,7 +1249,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_pop(&mut self, sz: Size, dst: Location) -> Result<(), CodegenError> { + fn emit_pop(&mut self, sz: Size, dst: Location) -> Result<(), CompileError> { match (sz, dst) { (Size::S64, Location::GPR(dst)) => dynasm!(self ; pop Rq(dst as u8)), (Size::S64, Location::Memory(dst, disp)) => { @@ -1222,7 +1259,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_cmp(&mut self, sz: Size, left: Location, right: Location) -> Result<(), CodegenError> { + fn emit_cmp(&mut self, sz: Size, left: Location, right: Location) -> Result<(), CompileError> { // Constant elimination for comparison between consts. // // Only needed for `emit_cmp`, since other binary operators actually write to `right` and `right` must @@ -1247,7 +1284,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_add(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_add(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { // Fast path if let Location::Imm32(0) = src { return Ok(()); @@ -1257,7 +1294,7 @@ impl EmitterX64 for AssemblerX64 { }); Ok(()) } - fn emit_sub(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_sub(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { // Fast path if let Location::Imm32(0) = src { return Ok(()); @@ -1267,7 +1304,7 @@ impl EmitterX64 for AssemblerX64 { }); Ok(()) } - fn emit_neg(&mut self, sz: Size, value: Location) -> Result<(), CodegenError> { + fn emit_neg(&mut self, sz: Size, value: Location) -> Result<(), CompileError> { match (sz, value) { (Size::S8, Location::GPR(value)) => dynasm!(self ; neg Rb(value as u8)), (Size::S8, Location::Memory(value, disp)) => { @@ -1289,7 +1326,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_imul(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_imul(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { binop_gpr_gpr!(imul, self, sz, src, dst, { binop_mem_gpr!(imul, self, sz, src, dst, { codegen_error!("singlepass can't emit IMUL {:?} {:?} {:?}", sz, src, dst) @@ -1297,71 +1334,71 @@ impl EmitterX64 for AssemblerX64 { }); Ok(()) } - fn emit_imul_imm32_gpr64(&mut self, src: u32, dst: GPR) -> Result<(), CodegenError> { + fn emit_imul_imm32_gpr64(&mut self, src: u32, dst: GPR) -> Result<(), CompileError> { dynasm!(self ; imul Rq(dst as u8), Rq(dst as u8), src as i32); Ok(()) } - fn emit_div(&mut self, sz: Size, divisor: Location) -> Result<(), CodegenError> { + fn emit_div(&mut self, sz: Size, divisor: Location) -> Result<(), CompileError> { unop_gpr_or_mem!(div, self, sz, divisor, { codegen_error!("singlepass can't emit DIV {:?} {:?}", sz, divisor) }); Ok(()) } - fn emit_idiv(&mut self, sz: Size, divisor: Location) -> Result<(), CodegenError> { + fn emit_idiv(&mut self, sz: Size, divisor: Location) -> Result<(), CompileError> { unop_gpr_or_mem!(idiv, self, sz, divisor, { codegen_error!("singlepass can't emit IDIV {:?} {:?}", sz, divisor) }); Ok(()) } - fn emit_shl(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_shl(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { binop_shift!(shl, self, sz, src, dst, { codegen_error!("singlepass can't emit SHL {:?} {:?} {:?}", sz, src, dst) }); Ok(()) } - fn emit_shr(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_shr(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { binop_shift!(shr, self, sz, src, dst, { codegen_error!("singlepass can't emit SHR {:?} {:?} {:?}", sz, src, dst) }); Ok(()) } - fn emit_sar(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_sar(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { binop_shift!(sar, self, sz, src, dst, { codegen_error!("singlepass can't emit SAR {:?} {:?} {:?}", sz, src, dst) }); Ok(()) } - fn emit_rol(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_rol(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { binop_shift!(rol, self, sz, src, dst, { codegen_error!("singlepass can't emit ROL {:?} {:?} {:?}", sz, src, dst) }); Ok(()) } - fn emit_ror(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_ror(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { binop_shift!(ror, self, sz, src, dst, { codegen_error!("singlepass can't emit ROR {:?} {:?} {:?}", sz, src, dst) }); Ok(()) } - fn emit_and(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_and(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { binop_all_nofp!(and, self, sz, src, dst, { codegen_error!("singlepass can't emit AND {:?} {:?} {:?}", sz, src, dst) }); Ok(()) } - fn emit_test(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_test(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { binop_all_nofp!(test, self, sz, src, dst, { codegen_error!("singlepass can't emit TEST {:?} {:?} {:?}", sz, src, dst) }); Ok(()) } - fn emit_or(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_or(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { binop_all_nofp!(or, self, sz, src, dst, { codegen_error!("singlepass can't emit OR {:?} {:?} {:?}", sz, src, dst) }); Ok(()) } - fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { binop_gpr_gpr!(bsr, self, sz, src, dst, { binop_mem_gpr!(bsr, self, sz, src, dst, { codegen_error!("singlepass can't emit BSR {:?} {:?} {:?}", sz, src, dst) @@ -1369,7 +1406,7 @@ impl EmitterX64 for AssemblerX64 { }); Ok(()) } - fn emit_bsf(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_bsf(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { binop_gpr_gpr!(bsf, self, sz, src, dst, { binop_mem_gpr!(bsf, self, sz, src, dst, { codegen_error!("singlepass can't emit BSF {:?} {:?} {:?}", sz, src, dst) @@ -1377,7 +1414,7 @@ impl EmitterX64 for AssemblerX64 { }); Ok(()) } - fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { binop_gpr_gpr!(popcnt, self, sz, src, dst, { binop_mem_gpr!(popcnt, self, sz, src, dst, { codegen_error!("singlepass can't emit POPCNT {:?} {:?} {:?}", sz, src, dst) @@ -1391,7 +1428,7 @@ impl EmitterX64 for AssemblerX64 { src: Location, sz_dst: Size, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz_src, src, sz_dst, dst) { (Size::S8, Location::GPR(src), Size::S32, Location::GPR(dst)) => { dynasm!(self ; movzx Rd(dst as u8), Rb(src as u8)); @@ -1405,6 +1442,9 @@ impl EmitterX64 for AssemblerX64 { (Size::S16, Location::Memory(src, disp), Size::S32, Location::GPR(dst)) => { dynasm!(self ; movzx Rd(dst as u8), WORD [Rq(src as u8) + disp]); } + (Size::S16, Location::Imm32(imm), Size::S32, Location::GPR(dst)) => { + dynasm!(self ; mov Rd(dst as u8), imm as i32); + } (Size::S8, Location::GPR(src), Size::S64, Location::GPR(dst)) => { dynasm!(self ; movzx Rq(dst as u8), Rb(src as u8)); } @@ -1417,6 +1457,20 @@ impl EmitterX64 for AssemblerX64 { (Size::S16, Location::Memory(src, disp), Size::S64, Location::GPR(dst)) => { dynasm!(self ; movzx Rq(dst as u8), WORD [Rq(src as u8) + disp]); } + (Size::S32, Location::GPR(src), Size::S64, Location::GPR(dst)) => { + if src != dst { + dynasm!(self ; mov Rd(dst as u8), Rd(src as u8)); + } + } + (Size::S32, Location::Memory(src, disp), Size::S64, Location::GPR(dst)) => { + dynasm!(self ; mov Rd(dst as u8), DWORD [Rq(src as u8) + disp]); + } + (Size::S32, Location::Imm64(imm), Size::S64, Location::GPR(dst)) => { + dynasm!(self ; mov Rq(dst as u8), imm as i32); + } + (Size::S16, Location::Imm64(imm), Size::S64, Location::GPR(dst)) => { + dynasm!(self ; mov Rq(dst as u8), imm as i32); + } _ => { codegen_error!( "singlepass can't emit MOVZX {:?} {:?} {:?} {:?}", @@ -1435,7 +1489,7 @@ impl EmitterX64 for AssemblerX64 { src: Location, sz_dst: Size, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz_src, src, sz_dst, dst) { (Size::S8, Location::GPR(src), Size::S32, Location::GPR(dst)) => { dynasm!(self ; movsx Rd(dst as u8), Rb(src as u8)); @@ -1480,7 +1534,7 @@ impl EmitterX64 for AssemblerX64 { Ok(()) } - fn emit_xchg(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CodegenError> { + fn emit_xchg(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S8, Location::GPR(src), Location::GPR(dst)) => { dynasm!(self ; xchg Rb(dst as u8), Rb(src as u8)); @@ -1528,7 +1582,7 @@ impl EmitterX64 for AssemblerX64 { sz: Size, src: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S8, Location::GPR(src), Location::Memory(dst, disp)) => { dynasm!(self ; lock xadd [Rq(dst as u8) + disp], Rb(src as u8)); @@ -1557,7 +1611,7 @@ impl EmitterX64 for AssemblerX64 { sz: Size, src: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (sz, src, dst) { (Size::S8, Location::GPR(src), Location::Memory(dst, disp)) => { dynasm!(self ; lock cmpxchg [Rq(dst as u8) + disp], Rb(src as u8)); @@ -1581,31 +1635,31 @@ impl EmitterX64 for AssemblerX64 { Ok(()) } - fn emit_rep_stosq(&mut self) -> Result<(), CodegenError> { + fn emit_rep_stosq(&mut self) -> Result<(), CompileError> { dynasm!(self ; rep stosq); Ok(()) } - fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) -> Result<(), CodegenError> { + fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) -> Result<(), CompileError> { dynasm!(self ; btc Rd(dst as u8), BYTE src as i8); Ok(()) } - fn emit_btc_gpr_imm8_64(&mut self, src: u8, dst: GPR) -> Result<(), CodegenError> { + fn emit_btc_gpr_imm8_64(&mut self, src: u8, dst: GPR) -> Result<(), CompileError> { dynasm!(self ; btc Rq(dst as u8), BYTE src as i8); Ok(()) } - fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR) -> Result<(), CodegenError> { + fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR) -> Result<(), CompileError> { dynasm!(self ; cmovae Rd(dst as u8), Rd(src as u8)); Ok(()) } - fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR) -> Result<(), CodegenError> { + fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR) -> Result<(), CompileError> { dynasm!(self ; cmovae Rq(dst as u8), Rq(src as u8)); Ok(()) } - fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory) -> Result<(), CodegenError> { + fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory) -> Result<(), CompileError> { match (src, dst) { (XMMOrMemory::XMM(src), XMMOrMemory::XMM(dst)) => { dynasm!(self ; movaps Rx(dst as u8), Rx(src as u8)) @@ -1621,7 +1675,7 @@ impl EmitterX64 for AssemblerX64 { Ok(()) } - fn emit_vmovapd(&mut self, src: XMMOrMemory, dst: XMMOrMemory) -> Result<(), CodegenError> { + fn emit_vmovapd(&mut self, src: XMMOrMemory, dst: XMMOrMemory) -> Result<(), CompileError> { match (src, dst) { (XMMOrMemory::XMM(src), XMMOrMemory::XMM(dst)) => { dynasm!(self ; movapd Rx(dst as u8), Rx(src as u8)) @@ -1636,7 +1690,7 @@ impl EmitterX64 for AssemblerX64 { }; Ok(()) } - fn emit_vxorps(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vxorps(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vxorps)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(xorps)(self, Precision::Single, src1, src2, dst), @@ -1644,7 +1698,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vxorpd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vxorpd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vxorpd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(xorpd)(self, Precision::Double, src1, src2, dst), @@ -1652,7 +1706,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vaddss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(addss)(self, Precision::Single, src1, src2, dst), @@ -1660,7 +1714,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vaddsd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(addsd)(self, Precision::Double, src1, src2, dst), @@ -1668,7 +1722,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vsubss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vsubss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vsubss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(subss)(self, Precision::Single, src1, src2, dst), @@ -1676,7 +1730,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vsubsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vsubsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vsubsd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(subsd)(self, Precision::Double, src1, src2, dst), @@ -1684,7 +1738,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vmulss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vmulss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vmulss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(mulss)(self, Precision::Single, src1, src2, dst), @@ -1692,7 +1746,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vmulsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vmulsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vmulsd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(mulsd)(self, Precision::Double, src1, src2, dst), @@ -1700,7 +1754,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vdivss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vdivss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vdivss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(divss)(self, Precision::Single, src1, src2, dst), @@ -1708,7 +1762,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vdivsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vdivsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vdivsd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(divsd)(self, Precision::Double, src1, src2, dst), @@ -1716,7 +1770,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vmaxss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vmaxss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vmaxss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(maxss)(self, Precision::Single, src1, src2, dst), @@ -1724,7 +1778,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vmaxsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vmaxsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vmaxsd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(maxsd)(self, Precision::Double, src1, src2, dst), @@ -1732,7 +1786,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vminss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vminss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vminss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(minss)(self, Precision::Single, src1, src2, dst), @@ -1740,7 +1794,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vminsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vminsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vminsd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(minsd)(self, Precision::Double, src1, src2, dst), @@ -1753,7 +1807,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpeqss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpss, 0)(self, Precision::Single, src1, src2, dst), @@ -1766,7 +1820,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpeqsd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpsd, 0)(self, Precision::Double, src1, src2, dst), @@ -1779,7 +1833,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpneqss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpss, 4)(self, Precision::Single, src1, src2, dst), @@ -1792,7 +1846,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpneqsd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpsd, 4)(self, Precision::Double, src1, src2, dst), @@ -1805,7 +1859,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpltss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpss, 1)(self, Precision::Single, src1, src2, dst), @@ -1818,7 +1872,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpltsd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpsd, 1)(self, Precision::Double, src1, src2, dst), @@ -1831,7 +1885,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpless)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpss, 2)(self, Precision::Single, src1, src2, dst), @@ -1844,7 +1898,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmplesd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpsd, 2)(self, Precision::Double, src1, src2, dst), @@ -1857,7 +1911,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpgtss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpss, 6)(self, Precision::Single, src1, src2, dst), @@ -1870,7 +1924,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpgtsd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpsd, 6)(self, Precision::Double, src1, src2, dst), @@ -1883,7 +1937,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpgess)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpss, 5)(self, Precision::Single, src1, src2, dst), @@ -1896,7 +1950,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpgesd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpsd, 5)(self, Precision::Double, src1, src2, dst), @@ -1909,7 +1963,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpunordss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpss, 3)(self, Precision::Single, src1, src2, dst), @@ -1922,7 +1976,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpunordsd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpsd, 3)(self, Precision::Double, src1, src2, dst), @@ -1935,7 +1989,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpordss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpss, 7)(self, Precision::Single, src1, src2, dst), @@ -1948,7 +2002,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcmpordsd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cmpsd, 7)(self, Precision::Double, src1, src2, dst), @@ -1956,7 +2010,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vsqrtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vsqrtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vsqrtss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(sqrtss)(self, Precision::Single, src1, src2, dst), @@ -1964,7 +2018,7 @@ impl EmitterX64 for AssemblerX64 { } Ok(()) } - fn emit_vsqrtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_vsqrtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vsqrtsd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(sqrtsd)(self, Precision::Double, src1, src2, dst), @@ -1977,7 +2031,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcvtss2sd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cvtss2sd)(self, Precision::Single, src1, src2, dst), @@ -1990,7 +2044,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_fn!(vcvtsd2ss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => sse_fn!(cvtsd2ss)(self, Precision::Double, src1, src2, dst), @@ -2003,7 +2057,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_round_fn!(vroundss, 0)(self, src1, src2, dst), Some(CpuFeature::SSE42) => { @@ -2018,7 +2072,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_round_fn!(vroundsd, 0)(self, src1, src2, dst), Some(CpuFeature::SSE42) => { @@ -2033,7 +2087,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_round_fn!(vroundss, 1)(self, src1, src2, dst), Some(CpuFeature::SSE42) => { @@ -2048,7 +2102,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_round_fn!(vroundsd, 1)(self, src1, src2, dst), Some(CpuFeature::SSE42) => { @@ -2063,7 +2117,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_round_fn!(vroundss, 2)(self, src1, src2, dst), Some(CpuFeature::SSE42) => { @@ -2078,7 +2132,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_round_fn!(vroundsd, 2)(self, src1, src2, dst), Some(CpuFeature::SSE42) => { @@ -2093,7 +2147,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_round_fn!(vroundss, 3)(self, src1, src2, dst), Some(CpuFeature::SSE42) => { @@ -2108,7 +2162,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: XMMOrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_round_fn!(vroundsd, 3)(self, src1, src2, dst), Some(CpuFeature::SSE42) => { @@ -2123,7 +2177,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: GPROrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_i2f_32_fn!(vcvtsi2ss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => { @@ -2138,7 +2192,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: GPROrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_i2f_32_fn!(vcvtsi2sd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => { @@ -2153,7 +2207,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: GPROrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_i2f_64_fn!(vcvtsi2ss)(self, src1, src2, dst), Some(CpuFeature::SSE42) => { @@ -2168,7 +2222,7 @@ impl EmitterX64 for AssemblerX64 { src1: XMM, src2: GPROrMemory, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match self.get_simd_arch() { Some(CpuFeature::AVX) => avx_i2f_64_fn!(vcvtsi2sd)(self, src1, src2, dst), Some(CpuFeature::SSE42) => { @@ -2185,7 +2239,7 @@ impl EmitterX64 for AssemblerX64 { src2: XMMOrMemory, mask: XMM, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { // this implementation works only for sse 4.1 and greater match self.get_simd_arch() { Some(CpuFeature::AVX) => match src2 { @@ -2218,7 +2272,7 @@ impl EmitterX64 for AssemblerX64 { src2: XMMOrMemory, mask: XMM, dst: XMM, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { // this implementation works only for sse 4.1 and greater match self.get_simd_arch() { Some(CpuFeature::AVX) => match src2 { @@ -2245,7 +2299,7 @@ impl EmitterX64 for AssemblerX64 { Ok(()) } - fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match src { XMMOrMemory::XMM(x) => dynasm!(self ; ucomiss Rx(dst as u8), Rx(x as u8)), XMMOrMemory::Memory(base, disp) => { @@ -2255,7 +2309,7 @@ impl EmitterX64 for AssemblerX64 { Ok(()) } - fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) -> Result<(), CodegenError> { + fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) -> Result<(), CompileError> { match src { XMMOrMemory::XMM(x) => dynasm!(self ; ucomisd Rx(dst as u8), Rx(x as u8)), XMMOrMemory::Memory(base, disp) => { @@ -2265,7 +2319,7 @@ impl EmitterX64 for AssemblerX64 { Ok(()) } - fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CodegenError> { + fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CompileError> { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttss2si Rd(dst as u8), Rx(x as u8)), XMMOrMemory::Memory(base, disp) => { @@ -2275,7 +2329,7 @@ impl EmitterX64 for AssemblerX64 { Ok(()) } - fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CodegenError> { + fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CompileError> { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttss2si Rq(dst as u8), Rx(x as u8)), XMMOrMemory::Memory(base, disp) => { @@ -2285,7 +2339,7 @@ impl EmitterX64 for AssemblerX64 { Ok(()) } - fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CodegenError> { + fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CompileError> { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttsd2si Rd(dst as u8), Rx(x as u8)), XMMOrMemory::Memory(base, disp) => { @@ -2295,7 +2349,7 @@ impl EmitterX64 for AssemblerX64 { Ok(()) } - fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CodegenError> { + fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) -> Result<(), CompileError> { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttsd2si Rq(dst as u8), Rx(x as u8)), XMMOrMemory::Memory(base, disp) => { @@ -2305,30 +2359,30 @@ impl EmitterX64 for AssemblerX64 { Ok(()) } - fn emit_test_gpr_64(&mut self, reg: GPR) -> Result<(), CodegenError> { + fn emit_test_gpr_64(&mut self, reg: GPR) -> Result<(), CompileError> { dynasm!(self ; test Rq(reg as u8), Rq(reg as u8)); Ok(()) } - fn emit_ud2(&mut self) -> Result<(), CodegenError> { + fn emit_ud2(&mut self) -> Result<(), CompileError> { dynasm!(self ; ud2); Ok(()) } - fn emit_ud1_payload(&mut self, payload: u8) -> Result<(), CodegenError> { + fn emit_ud1_payload(&mut self, payload: u8) -> Result<(), CompileError> { assert!(payload & 0xf0 == 0); dynasm!(self ; ud1 Rd((payload>>3)&1), Rd(payload&7)); Ok(()) } - fn emit_ret(&mut self) -> Result<(), CodegenError> { + fn emit_ret(&mut self) -> Result<(), CompileError> { dynasm!(self ; ret); Ok(()) } - fn emit_call_label(&mut self, label: Label) -> Result<(), CodegenError> { + fn emit_call_label(&mut self, label: Label) -> Result<(), CompileError> { dynasm!(self ; call =>label); Ok(()) } - fn emit_call_location(&mut self, loc: Location) -> Result<(), CodegenError> { + fn emit_call_location(&mut self, loc: Location) -> Result<(), CompileError> { match loc { Location::GPR(x) => dynasm!(self ; call Rq(x as u8)), Location::Memory(base, disp) => dynasm!(self ; call QWORD [Rq(base as u8) + disp]), @@ -2337,21 +2391,21 @@ impl EmitterX64 for AssemblerX64 { Ok(()) } - fn emit_call_register(&mut self, reg: GPR) -> Result<(), CodegenError> { + fn emit_call_register(&mut self, reg: GPR) -> Result<(), CompileError> { dynasm!(self ; call Rq(reg as u8)); Ok(()) } - fn emit_bkpt(&mut self) -> Result<(), CodegenError> { + fn emit_bkpt(&mut self) -> Result<(), CompileError> { dynasm!(self ; int3); Ok(()) } - fn emit_host_redirection(&mut self, target: GPR) -> Result<(), CodegenError> { + fn emit_host_redirection(&mut self, target: GPR) -> Result<(), CompileError> { self.emit_jmp_location(Location::GPR(target)) } - fn arch_mov64_imm_offset(&self) -> Result { + fn arch_mov64_imm_offset(&self) -> Result { Ok(2) } } diff --git a/lib/compiler-singlepass/src/machine.rs b/lib/compiler-singlepass/src/machine.rs index 31f007e2e..7f8239fbc 100644 --- a/lib/compiler-singlepass/src/machine.rs +++ b/lib/compiler-singlepass/src/machine.rs @@ -9,7 +9,7 @@ use std::fmt::Debug; pub use wasmer_compiler::wasmparser::MemoryImmediate; use wasmer_compiler::wasmparser::Type as WpType; use wasmer_types::{ - Architecture, CallingConvention, CpuFeature, CustomSection, FunctionBody, FunctionIndex, + Architecture, CallingConvention, CompileError, CustomSection, FunctionBody, FunctionIndex, FunctionType, InstructionAddressMap, Relocation, RelocationTarget, Target, TrapCode, TrapInformation, VMOffsets, }; @@ -27,14 +27,9 @@ pub enum Value { F64(f64), } -#[derive(Debug)] -pub struct CodegenError { - pub message: String, -} - #[macro_export] macro_rules! codegen_error { - ($($arg:tt)*) => {return Err(CodegenError{message : format!($($arg)*)})} + ($($arg:tt)*) => {return Err(CompileError::Codegen(format!($($arg)*)))} } pub trait MaybeImmediate { @@ -88,9 +83,9 @@ pub trait Machine { /// reserve a GPR fn reserve_gpr(&mut self, gpr: Self::GPR); /// Push used gpr to the stack. Return the bytes taken on the stack - fn push_used_gpr(&mut self, grps: &[Self::GPR]) -> Result; + fn push_used_gpr(&mut self, grps: &[Self::GPR]) -> Result; /// Pop used gpr to the stack - fn pop_used_gpr(&mut self, grps: &[Self::GPR]) -> Result<(), CodegenError>; + fn pop_used_gpr(&mut self, grps: &[Self::GPR]) -> Result<(), CompileError>; /// Picks an unused SIMD register. /// /// This method does not mark the register as used @@ -106,9 +101,9 @@ pub trait Machine { /// Releases a temporary XMM register. fn release_simd(&mut self, simd: Self::SIMD); /// Push used simd regs to the stack. Return bytes taken on the stack - fn push_used_simd(&mut self, simds: &[Self::SIMD]) -> Result; + fn push_used_simd(&mut self, simds: &[Self::SIMD]) -> Result; /// Pop used simd regs to the stack - fn pop_used_simd(&mut self, simds: &[Self::SIMD]) -> Result<(), CodegenError>; + fn pop_used_simd(&mut self, simds: &[Self::SIMD]) -> Result<(), CompileError>; /// Return a rounded stack adjustement value (must be multiple of 16bytes on ARM64 for example) fn round_stack_adjust(&self, value: usize) -> usize; /// Set the source location of the Wasm to the given offset. @@ -133,19 +128,19 @@ pub trait Machine { fn local_on_stack(&mut self, stack_offset: i32) -> Location; /// Adjust stack for locals /// Like assembler.emit_sub(Size::S64, Location::Imm32(delta_stack_offset as u32), Location::GPR(GPR::RSP)) - fn adjust_stack(&mut self, delta_stack_offset: u32) -> Result<(), CodegenError>; + fn adjust_stack(&mut self, delta_stack_offset: u32) -> Result<(), CompileError>; /// restore stack /// Like assembler.emit_add(Size::S64, Location::Imm32(delta_stack_offset as u32), Location::GPR(GPR::RSP)) - fn restore_stack(&mut self, delta_stack_offset: u32) -> Result<(), CodegenError>; + fn restore_stack(&mut self, delta_stack_offset: u32) -> Result<(), CompileError>; /// Pop stack of locals /// Like assembler.emit_add(Size::S64, Location::Imm32(delta_stack_offset as u32), Location::GPR(GPR::RSP)) - fn pop_stack_locals(&mut self, delta_stack_offset: u32) -> Result<(), CodegenError>; + fn pop_stack_locals(&mut self, delta_stack_offset: u32) -> Result<(), CompileError>; /// Zero a location taht is 32bits fn zero_location( &mut self, size: Size, location: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// GPR Reg used for local pointer on the stack fn local_pointer(&self) -> Self::GPR; /// push a value on the stack for a native call @@ -154,7 +149,7 @@ pub trait Machine { size: Size, loc: Location, dest: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Determine whether a local should be allocated on the stack. fn is_local_on_stack(&self, idx: usize) -> bool; /// Determine a local's location. @@ -169,7 +164,7 @@ pub trait Machine { &mut self, stack_offset: i32, location: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// List of register to save, depending on the CallingConvention fn list_to_save( &self, @@ -203,7 +198,7 @@ pub trait Machine { size: Size, source: Location, dest: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// move a location to another, with zero or sign extension fn move_location_extend( &mut self, @@ -212,7 +207,7 @@ pub trait Machine { source: Location, size_op: Size, dest: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Load a memory value to a register, zero extending to 64bits. /// Panic if gpr is not a Location::GPR or if mem is not a Memory(2) fn load_address( @@ -220,20 +215,20 @@ pub trait Machine { size: Size, gpr: Location, mem: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Init the stack loc counter fn init_stack_loc( &mut self, init_stack_loc_cnt: u64, last_stack_loc: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Restore save_area - fn restore_saved_area(&mut self, saved_area_offset: i32) -> Result<(), CodegenError>; + fn restore_saved_area(&mut self, saved_area_offset: i32) -> Result<(), CompileError>; /// Pop a location fn pop_location( &mut self, location: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Create a new `MachineState` with default values. fn new_machine_state(&self) -> MachineState; @@ -244,21 +239,21 @@ pub trait Machine { fn get_offset(&self) -> Offset; /// finalize a function - fn finalize_function(&mut self) -> Result<(), CodegenError>; + fn finalize_function(&mut self) -> Result<(), CompileError>; /// emit native function prolog (depending on the calling Convention, like "PUSH RBP / MOV RSP, RBP") - fn emit_function_prolog(&mut self) -> Result<(), CodegenError>; + fn emit_function_prolog(&mut self) -> Result<(), CompileError>; /// emit native function epilog (depending on the calling Convention, like "MOV RBP, RSP / POP RBP") - fn emit_function_epilog(&mut self) -> Result<(), CodegenError>; + fn emit_function_epilog(&mut self) -> Result<(), CompileError>; /// handle return value, with optionnal cannonicalization if wanted fn emit_function_return_value( &mut self, ty: WpType, cannonicalize: bool, loc: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Handle copy to SIMD register from ret value (if needed by the arch/calling convention) - fn emit_function_return_float(&mut self) -> Result<(), CodegenError>; + fn emit_function_return_float(&mut self) -> Result<(), CompileError>; /// Is NaN canonicalization supported fn arch_supports_canonicalize_nan(&self) -> bool; /// Cannonicalize a NaN (or panic if not supported) @@ -267,40 +262,40 @@ pub trait Machine { sz: Size, input: Location, output: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// emit an Illegal Opcode, associated with a trapcode - fn emit_illegal_op(&mut self, trp: TrapCode) -> Result<(), CodegenError>; + fn emit_illegal_op(&mut self, trp: TrapCode) -> Result<(), CompileError>; /// create a new label fn get_label(&mut self) -> Label; /// emit a label - fn emit_label(&mut self, label: Label) -> Result<(), CodegenError>; + fn emit_label(&mut self, label: Label) -> Result<(), CompileError>; /// get the gpr use for call. like RAX on x86_64 fn get_grp_for_call(&self) -> Self::GPR; /// Emit a call using the value in register - fn emit_call_register(&mut self, register: Self::GPR) -> Result<(), CodegenError>; + fn emit_call_register(&mut self, register: Self::GPR) -> Result<(), CompileError>; /// Emit a call to a label - fn emit_call_label(&mut self, label: Label) -> Result<(), CodegenError>; + fn emit_call_label(&mut self, label: Label) -> Result<(), CompileError>; /// Does an trampoline is neededfor indirect call fn arch_requires_indirect_call_trampoline(&self) -> bool; /// indirect call with trampoline fn arch_emit_indirect_call_with_trampoline( &mut self, location: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// emit a call to a location fn emit_call_location( &mut self, location: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// get the gpr for the return of generic values fn get_gpr_for_ret(&self) -> Self::GPR; /// get the simd for the return of float/double values fn get_simd_for_ret(&self) -> Self::SIMD; /// Emit a debug breakpoint - fn emit_debug_breakpoint(&mut self) -> Result<(), CodegenError>; + fn emit_debug_breakpoint(&mut self) -> Result<(), CompileError>; /// load the address of a memory location (will panic if src is not a memory) /// like LEA opcode on x86_64 @@ -309,7 +304,7 @@ pub trait Machine { size: Size, source: Location, dest: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// And src & dst -> dst (with or without flags) fn location_and( @@ -318,7 +313,7 @@ pub trait Machine { source: Location, dest: Location, flags: bool, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Xor src & dst -> dst (with or without flags) fn location_xor( &mut self, @@ -326,7 +321,7 @@ pub trait Machine { source: Location, dest: Location, flags: bool, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Or src & dst -> dst (with or without flags) fn location_or( &mut self, @@ -334,7 +329,7 @@ pub trait Machine { source: Location, dest: Location, flags: bool, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Add src+dst -> dst (with or without flags) fn location_add( @@ -343,7 +338,7 @@ pub trait Machine { source: Location, dest: Location, flags: bool, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Sub dst-src -> dst (with or without flags) fn location_sub( &mut self, @@ -351,7 +346,7 @@ pub trait Machine { source: Location, dest: Location, flags: bool, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// -src -> dst fn location_neg( &mut self, @@ -360,7 +355,7 @@ pub trait Machine { source: Location, size_op: Size, dest: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Cmp src - dst and set flags fn location_cmp( @@ -368,77 +363,77 @@ pub trait Machine { size: Size, source: Location, dest: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Test src & dst and set flags fn location_test( &mut self, size: Size, source: Location, dest: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// jmp without condidtion - fn jmp_unconditionnal(&mut self, label: Label) -> Result<(), CodegenError>; + fn jmp_unconditionnal(&mut self, label: Label) -> Result<(), CompileError>; /// jmp on equal (src==dst) /// like Equal set on x86_64 - fn jmp_on_equal(&mut self, label: Label) -> Result<(), CodegenError>; + fn jmp_on_equal(&mut self, label: Label) -> Result<(), CompileError>; /// jmp on different (src!=dst) /// like NotEqual set on x86_64 - fn jmp_on_different(&mut self, label: Label) -> Result<(), CodegenError>; + fn jmp_on_different(&mut self, label: Label) -> Result<(), CompileError>; /// jmp on above (src>dst) /// like Above set on x86_64 - fn jmp_on_above(&mut self, label: Label) -> Result<(), CodegenError>; + fn jmp_on_above(&mut self, label: Label) -> Result<(), CompileError>; /// jmp on above (src>=dst) /// like Above or Equal set on x86_64 - fn jmp_on_aboveequal(&mut self, label: Label) -> Result<(), CodegenError>; + fn jmp_on_aboveequal(&mut self, label: Label) -> Result<(), CompileError>; /// jmp on above (src<=dst) /// like Below or Equal set on x86_64 - fn jmp_on_belowequal(&mut self, label: Label) -> Result<(), CodegenError>; + fn jmp_on_belowequal(&mut self, label: Label) -> Result<(), CompileError>; /// jmp on overflow /// like Carry set on x86_64 - fn jmp_on_overflow(&mut self, label: Label) -> Result<(), CodegenError>; + fn jmp_on_overflow(&mut self, label: Label) -> Result<(), CompileError>; /// jmp using a jump table at lable with cond as the indice fn emit_jmp_to_jumptable( &mut self, label: Label, cond: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Align for Loop (may do nothing, depending on the arch) - fn align_for_loop(&mut self) -> Result<(), CodegenError>; + fn align_for_loop(&mut self) -> Result<(), CompileError>; /// ret (from a Call) - fn emit_ret(&mut self) -> Result<(), CodegenError>; + fn emit_ret(&mut self) -> Result<(), CompileError>; /// Stack push of a location fn emit_push( &mut self, size: Size, loc: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Stack pop of a location fn emit_pop( &mut self, size: Size, loc: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// relaxed mov: move from anywhere to anywhere fn emit_relaxed_mov( &mut self, sz: Size, src: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// relaxed cmp: compare from anywhere and anywhere fn emit_relaxed_cmp( &mut self, sz: Size, src: Location, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Emit a memory fence. Can be nothing for x86_64 or a DMB on ARM64 for example - fn emit_memory_fence(&mut self) -> Result<(), CodegenError>; + fn emit_memory_fence(&mut self) -> Result<(), CompileError>; /// relaxed move with zero extension fn emit_relaxed_zero_extension( &mut self, @@ -446,7 +441,7 @@ pub trait Machine { src: Location, sz_dst: Size, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// relaxed move with sign extension fn emit_relaxed_sign_extension( &mut self, @@ -454,35 +449,35 @@ pub trait Machine { src: Location, sz_dst: Size, dst: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Multiply location with immediate fn emit_imul_imm32( &mut self, size: Size, imm32: u32, gpr: Self::GPR, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Add with location directly from the stack fn emit_binop_add32( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Sub with location directly from the stack fn emit_binop_sub32( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Multiply with location directly from the stack fn emit_binop_mul32( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Unsigned Division with location directly from the stack. return the offset of the DIV opcode, to mark as trappable. fn emit_binop_udiv32( &mut self, @@ -491,7 +486,7 @@ pub trait Machine { ret: Location, integer_division_by_zero: Label, integer_overflow: Label, - ) -> Result; + ) -> Result; /// Signed Division with location directly from the stack. return the offset of the DIV opcode, to mark as trappable. fn emit_binop_sdiv32( &mut self, @@ -500,7 +495,7 @@ pub trait Machine { ret: Location, integer_division_by_zero: Label, integer_overflow: Label, - ) -> Result; + ) -> Result; /// Unsigned Reminder (of a division) with location directly from the stack. return the offset of the DIV opcode, to mark as trappable. fn emit_binop_urem32( &mut self, @@ -509,7 +504,7 @@ pub trait Machine { ret: Location, integer_division_by_zero: Label, integer_overflow: Label, - ) -> Result; + ) -> Result; /// Signed Reminder (of a Division) with location directly from the stack. return the offset of the DIV opcode, to mark as trappable. fn emit_binop_srem32( &mut self, @@ -518,151 +513,151 @@ pub trait Machine { ret: Location, integer_division_by_zero: Label, integer_overflow: Label, - ) -> Result; + ) -> Result; /// And with location directly from the stack fn emit_binop_and32( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Or with location directly from the stack fn emit_binop_or32( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Xor with location directly from the stack fn emit_binop_xor32( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Signed Greater of Equal Compare 2 i32, result in a GPR fn i32_cmp_ge_s( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Signed Greater Than Compare 2 i32, result in a GPR fn i32_cmp_gt_s( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Signed Less of Equal Compare 2 i32, result in a GPR fn i32_cmp_le_s( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Signed Less Than Compare 2 i32, result in a GPR fn i32_cmp_lt_s( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Unsigned Greater of Equal Compare 2 i32, result in a GPR fn i32_cmp_ge_u( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Unsigned Greater Than Compare 2 i32, result in a GPR fn i32_cmp_gt_u( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Unsigned Less of Equal Compare 2 i32, result in a GPR fn i32_cmp_le_u( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Unsigned Less Than Compare 2 i32, result in a GPR fn i32_cmp_lt_u( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Not Equal Compare 2 i32, result in a GPR fn i32_cmp_ne( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Equal Compare 2 i32, result in a GPR fn i32_cmp_eq( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Count Leading 0 bit of an i32 fn i32_clz( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Count Trailling 0 bit of an i32 fn i32_ctz( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Count the number of 1 bit of an i32 fn i32_popcnt( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// i32 Logical Shift Left fn i32_shl( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// i32 Logical Shift Right fn i32_shr( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// i32 Arithmetic Shift Right fn i32_sar( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// i32 Roll Left fn i32_rol( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// i32 Roll Right fn i32_ror( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// i32 load #[allow(clippy::too_many_arguments)] fn i32_load( @@ -674,7 +669,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 load of an unsigned 8bits #[allow(clippy::too_many_arguments)] fn i32_load_8u( @@ -686,7 +682,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 load of an signed 8bits #[allow(clippy::too_many_arguments)] fn i32_load_8s( @@ -698,7 +695,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 load of an unsigned 16bits #[allow(clippy::too_many_arguments)] fn i32_load_16u( @@ -710,7 +708,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 load of an signed 16bits #[allow(clippy::too_many_arguments)] fn i32_load_16s( @@ -722,7 +721,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic load #[allow(clippy::too_many_arguments)] fn i32_atomic_load( @@ -734,7 +734,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic load of an unsigned 8bits #[allow(clippy::too_many_arguments)] fn i32_atomic_load_8u( @@ -746,7 +747,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic load of an unsigned 16bits #[allow(clippy::too_many_arguments)] fn i32_atomic_load_16u( @@ -758,7 +760,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 save #[allow(clippy::too_many_arguments)] fn i32_save( @@ -770,7 +773,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 save of the lower 8bits #[allow(clippy::too_many_arguments)] fn i32_save_8( @@ -782,7 +786,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 save of the lower 16bits #[allow(clippy::too_many_arguments)] fn i32_save_16( @@ -794,7 +799,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic save #[allow(clippy::too_many_arguments)] fn i32_atomic_save( @@ -806,7 +812,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic save of a the lower 8bits #[allow(clippy::too_many_arguments)] fn i32_atomic_save_8( @@ -818,7 +825,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic save of a the lower 16bits #[allow(clippy::too_many_arguments)] fn i32_atomic_save_16( @@ -830,7 +838,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Add with i32 #[allow(clippy::too_many_arguments)] fn i32_atomic_add( @@ -843,7 +852,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Add with unsigned 8bits #[allow(clippy::too_many_arguments)] fn i32_atomic_add_8u( @@ -856,7 +866,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Add with unsigned 16bits #[allow(clippy::too_many_arguments)] fn i32_atomic_add_16u( @@ -869,7 +880,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Sub with i32 #[allow(clippy::too_many_arguments)] fn i32_atomic_sub( @@ -882,7 +894,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Sub with unsigned 8bits #[allow(clippy::too_many_arguments)] fn i32_atomic_sub_8u( @@ -895,7 +908,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Sub with unsigned 16bits #[allow(clippy::too_many_arguments)] fn i32_atomic_sub_16u( @@ -908,7 +922,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic And with i32 #[allow(clippy::too_many_arguments)] fn i32_atomic_and( @@ -921,7 +936,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic And with unsigned 8bits #[allow(clippy::too_many_arguments)] fn i32_atomic_and_8u( @@ -934,7 +950,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic And with unsigned 16bits #[allow(clippy::too_many_arguments)] fn i32_atomic_and_16u( @@ -947,7 +964,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Or with i32 #[allow(clippy::too_many_arguments)] fn i32_atomic_or( @@ -960,7 +978,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Or with unsigned 8bits #[allow(clippy::too_many_arguments)] fn i32_atomic_or_8u( @@ -973,7 +992,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Or with unsigned 16bits #[allow(clippy::too_many_arguments)] fn i32_atomic_or_16u( @@ -986,7 +1006,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Xor with i32 #[allow(clippy::too_many_arguments)] fn i32_atomic_xor( @@ -999,7 +1020,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Xor with unsigned 8bits #[allow(clippy::too_many_arguments)] fn i32_atomic_xor_8u( @@ -1012,7 +1034,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Xor with unsigned 16bits #[allow(clippy::too_many_arguments)] fn i32_atomic_xor_16u( @@ -1025,7 +1048,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Exchange with i32 #[allow(clippy::too_many_arguments)] fn i32_atomic_xchg( @@ -1038,7 +1062,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Exchange with u8 #[allow(clippy::too_many_arguments)] fn i32_atomic_xchg_8u( @@ -1051,7 +1076,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Exchange with u16 #[allow(clippy::too_many_arguments)] fn i32_atomic_xchg_16u( @@ -1064,7 +1090,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Compare and Exchange with i32 #[allow(clippy::too_many_arguments)] fn i32_atomic_cmpxchg( @@ -1078,7 +1105,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Compare and Exchange with u8 #[allow(clippy::too_many_arguments)] fn i32_atomic_cmpxchg_8u( @@ -1092,7 +1120,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i32 atomic Compare and Exchange with u16 #[allow(clippy::too_many_arguments)] fn i32_atomic_cmpxchg_16u( @@ -1106,35 +1135,36 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// emit a move function address to GPR ready for call, using appropriate relocation fn emit_call_with_reloc( &mut self, calling_convention: CallingConvention, reloc_target: RelocationTarget, - ) -> Result, CodegenError>; + ) -> Result, CompileError>; /// Add with location directly from the stack fn emit_binop_add64( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Sub with location directly from the stack fn emit_binop_sub64( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Multiply with location directly from the stack fn emit_binop_mul64( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Unsigned Division with location directly from the stack. return the offset of the DIV opcode, to mark as trappable. fn emit_binop_udiv64( &mut self, @@ -1143,7 +1173,7 @@ pub trait Machine { ret: Location, integer_division_by_zero: Label, integer_overflow: Label, - ) -> Result; + ) -> Result; /// Signed Division with location directly from the stack. return the offset of the DIV opcode, to mark as trappable. fn emit_binop_sdiv64( &mut self, @@ -1152,7 +1182,7 @@ pub trait Machine { ret: Location, integer_division_by_zero: Label, integer_overflow: Label, - ) -> Result; + ) -> Result; /// Unsigned Reminder (of a division) with location directly from the stack. return the offset of the DIV opcode, to mark as trappable. fn emit_binop_urem64( &mut self, @@ -1161,7 +1191,7 @@ pub trait Machine { ret: Location, integer_division_by_zero: Label, integer_overflow: Label, - ) -> Result; + ) -> Result; /// Signed Reminder (of a Division) with location directly from the stack. return the offset of the DIV opcode, to mark as trappable. fn emit_binop_srem64( &mut self, @@ -1170,151 +1200,151 @@ pub trait Machine { ret: Location, integer_division_by_zero: Label, integer_overflow: Label, - ) -> Result; + ) -> Result; /// And with location directly from the stack fn emit_binop_and64( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Or with location directly from the stack fn emit_binop_or64( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Xor with location directly from the stack fn emit_binop_xor64( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Signed Greater of Equal Compare 2 i64, result in a GPR fn i64_cmp_ge_s( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Signed Greater Than Compare 2 i64, result in a GPR fn i64_cmp_gt_s( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Signed Less of Equal Compare 2 i64, result in a GPR fn i64_cmp_le_s( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Signed Less Than Compare 2 i64, result in a GPR fn i64_cmp_lt_s( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Unsigned Greater of Equal Compare 2 i64, result in a GPR fn i64_cmp_ge_u( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Unsigned Greater Than Compare 2 i64, result in a GPR fn i64_cmp_gt_u( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Unsigned Less of Equal Compare 2 i64, result in a GPR fn i64_cmp_le_u( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Unsigned Less Than Compare 2 i64, result in a GPR fn i64_cmp_lt_u( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Not Equal Compare 2 i64, result in a GPR fn i64_cmp_ne( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Equal Compare 2 i64, result in a GPR fn i64_cmp_eq( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Count Leading 0 bit of an i64 fn i64_clz( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Count Trailling 0 bit of an i64 fn i64_ctz( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Count the number of 1 bit of an i64 fn i64_popcnt( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// i64 Logical Shift Left fn i64_shl( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// i64 Logical Shift Right fn i64_shr( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// i64 Arithmetic Shift Right fn i64_sar( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// i64 Roll Left fn i64_rol( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// i64 Roll Right fn i64_ror( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// i64 load #[allow(clippy::too_many_arguments)] fn i64_load( @@ -1326,7 +1356,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 load of an unsigned 8bits #[allow(clippy::too_many_arguments)] fn i64_load_8u( @@ -1338,7 +1369,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 load of an signed 8bits #[allow(clippy::too_many_arguments)] fn i64_load_8s( @@ -1350,7 +1382,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 load of an unsigned 32bits #[allow(clippy::too_many_arguments)] fn i64_load_32u( @@ -1362,7 +1395,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 load of an signed 32bits #[allow(clippy::too_many_arguments)] fn i64_load_32s( @@ -1374,7 +1408,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 load of an signed 16bits #[allow(clippy::too_many_arguments)] fn i64_load_16u( @@ -1386,7 +1421,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 load of an signed 16bits #[allow(clippy::too_many_arguments)] fn i64_load_16s( @@ -1398,7 +1434,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic load #[allow(clippy::too_many_arguments)] fn i64_atomic_load( @@ -1410,7 +1447,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic load from unsigned 8bits #[allow(clippy::too_many_arguments)] fn i64_atomic_load_8u( @@ -1422,7 +1460,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic load from unsigned 16bits #[allow(clippy::too_many_arguments)] fn i64_atomic_load_16u( @@ -1434,7 +1473,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic load from unsigned 32bits #[allow(clippy::too_many_arguments)] fn i64_atomic_load_32u( @@ -1446,7 +1486,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 save #[allow(clippy::too_many_arguments)] fn i64_save( @@ -1458,7 +1499,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 save of the lower 8bits #[allow(clippy::too_many_arguments)] fn i64_save_8( @@ -1470,7 +1512,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 save of the lower 16bits #[allow(clippy::too_many_arguments)] fn i64_save_16( @@ -1482,7 +1525,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 save of the lower 32bits #[allow(clippy::too_many_arguments)] fn i64_save_32( @@ -1494,7 +1538,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic save #[allow(clippy::too_many_arguments)] fn i64_atomic_save( @@ -1506,7 +1551,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic save of a the lower 8bits #[allow(clippy::too_many_arguments)] fn i64_atomic_save_8( @@ -1518,7 +1564,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic save of a the lower 16bits #[allow(clippy::too_many_arguments)] fn i64_atomic_save_16( @@ -1530,7 +1577,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic save of a the lower 32bits #[allow(clippy::too_many_arguments)] fn i64_atomic_save_32( @@ -1542,7 +1590,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Add with i64 #[allow(clippy::too_many_arguments)] fn i64_atomic_add( @@ -1555,7 +1604,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Add with unsigned 8bits #[allow(clippy::too_many_arguments)] fn i64_atomic_add_8u( @@ -1568,7 +1618,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Add with unsigned 16bits #[allow(clippy::too_many_arguments)] fn i64_atomic_add_16u( @@ -1581,7 +1632,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Add with unsigned 32bits #[allow(clippy::too_many_arguments)] fn i64_atomic_add_32u( @@ -1594,7 +1646,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Sub with i64 #[allow(clippy::too_many_arguments)] fn i64_atomic_sub( @@ -1607,7 +1660,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Sub with unsigned 8bits #[allow(clippy::too_many_arguments)] fn i64_atomic_sub_8u( @@ -1620,7 +1674,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Sub with unsigned 16bits #[allow(clippy::too_many_arguments)] fn i64_atomic_sub_16u( @@ -1633,7 +1688,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Sub with unsigned 32bits #[allow(clippy::too_many_arguments)] fn i64_atomic_sub_32u( @@ -1646,7 +1702,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic And with i64 #[allow(clippy::too_many_arguments)] fn i64_atomic_and( @@ -1659,7 +1716,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic And with unsigned 8bits #[allow(clippy::too_many_arguments)] fn i64_atomic_and_8u( @@ -1672,7 +1730,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic And with unsigned 16bits #[allow(clippy::too_many_arguments)] fn i64_atomic_and_16u( @@ -1685,7 +1744,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic And with unsigned 32bits #[allow(clippy::too_many_arguments)] fn i64_atomic_and_32u( @@ -1698,7 +1758,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Or with i64 #[allow(clippy::too_many_arguments)] fn i64_atomic_or( @@ -1711,7 +1772,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Or with unsigned 8bits #[allow(clippy::too_many_arguments)] fn i64_atomic_or_8u( @@ -1724,7 +1786,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Or with unsigned 16bits #[allow(clippy::too_many_arguments)] fn i64_atomic_or_16u( @@ -1737,7 +1800,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Or with unsigned 32bits #[allow(clippy::too_many_arguments)] fn i64_atomic_or_32u( @@ -1750,7 +1814,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Xor with i64 #[allow(clippy::too_many_arguments)] fn i64_atomic_xor( @@ -1763,7 +1828,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Xor with unsigned 8bits #[allow(clippy::too_many_arguments)] fn i64_atomic_xor_8u( @@ -1776,7 +1842,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Xor with unsigned 16bits #[allow(clippy::too_many_arguments)] fn i64_atomic_xor_16u( @@ -1789,7 +1856,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Xor with unsigned 32bits #[allow(clippy::too_many_arguments)] fn i64_atomic_xor_32u( @@ -1802,7 +1870,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Exchange with i64 #[allow(clippy::too_many_arguments)] fn i64_atomic_xchg( @@ -1815,7 +1884,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Exchange with u8 #[allow(clippy::too_many_arguments)] fn i64_atomic_xchg_8u( @@ -1828,7 +1898,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Exchange with u16 #[allow(clippy::too_many_arguments)] fn i64_atomic_xchg_16u( @@ -1841,7 +1912,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Exchange with u32 #[allow(clippy::too_many_arguments)] fn i64_atomic_xchg_32u( @@ -1854,7 +1926,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Compare and Exchange with i32 #[allow(clippy::too_many_arguments)] fn i64_atomic_cmpxchg( @@ -1868,7 +1941,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Compare and Exchange with u8 #[allow(clippy::too_many_arguments)] fn i64_atomic_cmpxchg_8u( @@ -1882,7 +1956,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Compare and Exchange with u16 #[allow(clippy::too_many_arguments)] fn i64_atomic_cmpxchg_16u( @@ -1896,7 +1971,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// i64 atomic Compare and Exchange with u32 #[allow(clippy::too_many_arguments)] fn i64_atomic_cmpxchg_32u( @@ -1910,7 +1986,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// load an F32 #[allow(clippy::too_many_arguments)] @@ -1923,7 +2000,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// f32 save #[allow(clippy::too_many_arguments)] fn f32_save( @@ -1936,7 +2014,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// load an F64 #[allow(clippy::too_many_arguments)] fn f64_load( @@ -1948,7 +2027,8 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// f64 save #[allow(clippy::too_many_arguments)] fn f64_save( @@ -1961,35 +2041,36 @@ pub trait Machine { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError>; + unaligned_atomic: Label, + ) -> Result<(), CompileError>; /// Convert a F64 from I64, signed or unsigned fn convert_f64_i64( &mut self, loc: Location, signed: bool, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Convert a F64 from I32, signed or unsigned fn convert_f64_i32( &mut self, loc: Location, signed: bool, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Convert a F32 from I64, signed or unsigned fn convert_f32_i64( &mut self, loc: Location, signed: bool, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Convert a F32 from I32, signed or unsigned fn convert_f32_i32( &mut self, loc: Location, signed: bool, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Convert a F64 to I64, signed or unsigned, without or without saturation fn convert_i64_f64( &mut self, @@ -1997,7 +2078,7 @@ pub trait Machine { ret: Location, signed: bool, sat: bool, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Convert a F64 to I32, signed or unsigned, without or without saturation fn convert_i32_f64( &mut self, @@ -2005,7 +2086,7 @@ pub trait Machine { ret: Location, signed: bool, sat: bool, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Convert a F32 to I64, signed or unsigned, without or without saturation fn convert_i64_f32( &mut self, @@ -2013,7 +2094,7 @@ pub trait Machine { ret: Location, signed: bool, sat: bool, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Convert a F32 to I32, signed or unsigned, without or without saturation fn convert_i32_f32( &mut self, @@ -2021,289 +2102,289 @@ pub trait Machine { ret: Location, signed: bool, sat: bool, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Convert a F32 to F64 fn convert_f64_f32( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Convert a F64 to F32 fn convert_f32_f64( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Negate an F64 fn f64_neg( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Get the Absolute Value of an F64 fn f64_abs( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Copy sign from tmp1 Self::GPR to tmp2 Self::GPR - fn emit_i64_copysign(&mut self, tmp1: Self::GPR, tmp2: Self::GPR) -> Result<(), CodegenError>; + fn emit_i64_copysign(&mut self, tmp1: Self::GPR, tmp2: Self::GPR) -> Result<(), CompileError>; /// Get the Square Root of an F64 fn f64_sqrt( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Trunc of an F64 fn f64_trunc( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Ceil of an F64 fn f64_ceil( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Floor of an F64 fn f64_floor( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Round at nearest int of an F64 fn f64_nearest( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Greater of Equal Compare 2 F64, result in a GPR fn f64_cmp_ge( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Greater Than Compare 2 F64, result in a GPR fn f64_cmp_gt( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Less of Equal Compare 2 F64, result in a GPR fn f64_cmp_le( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Less Than Compare 2 F64, result in a GPR fn f64_cmp_lt( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Not Equal Compare 2 F64, result in a GPR fn f64_cmp_ne( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Equal Compare 2 F64, result in a GPR fn f64_cmp_eq( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// get Min for 2 F64 values fn f64_min( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// get Max for 2 F64 values fn f64_max( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Add 2 F64 values fn f64_add( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Sub 2 F64 values fn f64_sub( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Multiply 2 F64 values fn f64_mul( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Divide 2 F64 values fn f64_div( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Negate an F32 fn f32_neg( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Get the Absolute Value of an F32 fn f32_abs( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Copy sign from tmp1 Self::GPR to tmp2 Self::GPR - fn emit_i32_copysign(&mut self, tmp1: Self::GPR, tmp2: Self::GPR) -> Result<(), CodegenError>; + fn emit_i32_copysign(&mut self, tmp1: Self::GPR, tmp2: Self::GPR) -> Result<(), CompileError>; /// Get the Square Root of an F32 fn f32_sqrt( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Trunc of an F32 fn f32_trunc( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Ceil of an F32 fn f32_ceil( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Floor of an F32 fn f32_floor( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Round at nearest int of an F32 fn f32_nearest( &mut self, loc: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Greater of Equal Compare 2 F32, result in a GPR fn f32_cmp_ge( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Greater Than Compare 2 F32, result in a GPR fn f32_cmp_gt( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Less of Equal Compare 2 F32, result in a GPR fn f32_cmp_le( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Less Than Compare 2 F32, result in a GPR fn f32_cmp_lt( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Not Equal Compare 2 F32, result in a GPR fn f32_cmp_ne( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Equal Compare 2 F32, result in a GPR fn f32_cmp_eq( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// get Min for 2 F32 values fn f32_min( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// get Max for 2 F32 values fn f32_max( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Add 2 F32 values fn f32_add( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Sub 2 F32 values fn f32_sub( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Multiply 2 F32 values fn f32_mul( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Divide 2 F32 values fn f32_div( &mut self, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError>; + ) -> Result<(), CompileError>; /// Standard function Trampoline generation fn gen_std_trampoline( &self, sig: &FunctionType, calling_convention: CallingConvention, - ) -> Result; + ) -> Result; /// Generates dynamic import function call trampoline for a function type. fn gen_std_dynamic_import_trampoline( &self, vmoffsets: &VMOffsets, sig: &FunctionType, calling_convention: CallingConvention, - ) -> Result; + ) -> Result; /// Singlepass calls import functions through a trampoline. fn gen_import_call_trampoline( &self, @@ -2311,7 +2392,7 @@ pub trait Machine { index: FunctionIndex, sig: &FunctionType, calling_convention: CallingConvention, - ) -> Result; + ) -> Result; /// generate eh_frame instruction (or None if not possible / supported) fn gen_dwarf_unwind_info(&mut self, code_len: usize) -> Option; /// generate Windows unwind instructions (or None if not possible / supported) @@ -2323,23 +2404,19 @@ pub fn gen_std_trampoline( sig: &FunctionType, target: &Target, calling_convention: CallingConvention, -) -> FunctionBody { +) -> Result { match target.triple().architecture { Architecture::X86_64 => { - let machine = if target.cpu_features().contains(CpuFeature::AVX) { - MachineX86_64::new(Some(CpuFeature::AVX)) - } else if target.cpu_features().contains(CpuFeature::SSE42) { - MachineX86_64::new(Some(CpuFeature::SSE42)) - } else { - panic!("singlepass unimplement X86_64 variant for gen_std_trampoline") - }; - machine.gen_std_trampoline(sig, calling_convention).unwrap() + let machine = MachineX86_64::new(Some(target.clone()))?; + machine.gen_std_trampoline(sig, calling_convention) } Architecture::Aarch64(_) => { let machine = MachineARM64::new(); - machine.gen_std_trampoline(sig, calling_convention).unwrap() + machine.gen_std_trampoline(sig, calling_convention) } - _ => panic!("singlepass unimplemented arch for gen_std_trampoline"), + _ => Err(CompileError::UnsupportedTarget( + "singlepass unimplemented arch for gen_std_trampoline".to_owned(), + )), } } @@ -2349,29 +2426,19 @@ pub fn gen_std_dynamic_import_trampoline( sig: &FunctionType, target: &Target, calling_convention: CallingConvention, -) -> FunctionBody { +) -> Result { match target.triple().architecture { Architecture::X86_64 => { - let machine = if target.cpu_features().contains(CpuFeature::AVX) { - MachineX86_64::new(Some(CpuFeature::AVX)) - } else if target.cpu_features().contains(CpuFeature::SSE42) { - MachineX86_64::new(Some(CpuFeature::SSE42)) - } else { - panic!( - "singlepass unimplement X86_64 variant for gen_std_dynamic_import_trampoline" - ) - }; - machine - .gen_std_dynamic_import_trampoline(vmoffsets, sig, calling_convention) - .unwrap() + let machine = MachineX86_64::new(Some(target.clone()))?; + machine.gen_std_dynamic_import_trampoline(vmoffsets, sig, calling_convention) } Architecture::Aarch64(_) => { let machine = MachineARM64::new(); - machine - .gen_std_dynamic_import_trampoline(vmoffsets, sig, calling_convention) - .unwrap() + machine.gen_std_dynamic_import_trampoline(vmoffsets, sig, calling_convention) } - _ => panic!("singlepass unimplemented arch for gen_std_dynamic_import_trampoline"), + _ => Err(CompileError::UnsupportedTarget( + "singlepass unimplemented arch for gen_std_dynamic_import_trampoline".to_owned(), + )), } } /// Singlepass calls import functions through a trampoline. @@ -2381,27 +2448,19 @@ pub fn gen_import_call_trampoline( sig: &FunctionType, target: &Target, calling_convention: CallingConvention, -) -> CustomSection { +) -> Result { match target.triple().architecture { Architecture::X86_64 => { - let machine = if target.cpu_features().contains(CpuFeature::AVX) { - MachineX86_64::new(Some(CpuFeature::AVX)) - } else if target.cpu_features().contains(CpuFeature::SSE42) { - MachineX86_64::new(Some(CpuFeature::SSE42)) - } else { - panic!("singlepass unimplement X86_64 variant for gen_import_call_trampoline") - }; - machine - .gen_import_call_trampoline(vmoffsets, index, sig, calling_convention) - .unwrap() + let machine = MachineX86_64::new(Some(target.clone()))?; + machine.gen_import_call_trampoline(vmoffsets, index, sig, calling_convention) } Architecture::Aarch64(_) => { let machine = MachineARM64::new(); - machine - .gen_import_call_trampoline(vmoffsets, index, sig, calling_convention) - .unwrap() + machine.gen_import_call_trampoline(vmoffsets, index, sig, calling_convention) } - _ => panic!("singlepass unimplemented arch for gen_import_call_trampoline"), + _ => Err(CompileError::UnsupportedTarget( + "singlepass unimplemented arch for gen_import_call_trampoline".to_owned(), + )), } } diff --git a/lib/compiler-singlepass/src/machine_arm64.rs b/lib/compiler-singlepass/src/machine_arm64.rs index e7aadbbfd..1f0c5b95f 100644 --- a/lib/compiler-singlepass/src/machine_arm64.rs +++ b/lib/compiler-singlepass/src/machine_arm64.rs @@ -12,7 +12,7 @@ use dynasmrt::{aarch64::Aarch64Relocation, VecAssembler}; use gimli::{write::CallFrameInstruction, AArch64}; use wasmer_compiler::wasmparser::Type as WpType; use wasmer_types::{ - CallingConvention, CustomSection, FunctionBody, FunctionIndex, FunctionType, + CallingConvention, CompileError, CustomSection, FunctionBody, FunctionIndex, FunctionType, InstructionAddressMap, Relocation, RelocationKind, RelocationTarget, SourceLoc, TrapCode, TrapInformation, VMOffsets, }; @@ -176,7 +176,7 @@ impl MachineARM64 { allow_imm: ImmType, read_val: bool, wanted: Option, - ) -> Result { + ) -> Result { match src { Location::GPR(_) | Location::SIMD(_) => Ok(src), Location::Imm8(val) => { @@ -188,8 +188,8 @@ impl MachineARM64 { let tmp = if let Some(wanted) = wanted { wanted } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(tmp); tmp @@ -208,8 +208,8 @@ impl MachineARM64 { let tmp = if let Some(wanted) = wanted { wanted } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(tmp); tmp @@ -228,8 +228,8 @@ impl MachineARM64 { let tmp = if let Some(wanted) = wanted { wanted } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(tmp); tmp @@ -243,8 +243,8 @@ impl MachineARM64 { let tmp = if let Some(wanted) = wanted { wanted } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(tmp); tmp @@ -327,12 +327,12 @@ impl MachineARM64 { temps: &mut Vec, allow_imm: ImmType, read_val: bool, - ) -> Result { + ) -> Result { match src { Location::SIMD(_) => Ok(src), Location::GPR(_) => { - let tmp = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; temps.push(tmp); if read_val { @@ -344,11 +344,11 @@ impl MachineARM64 { if self.compatible_imm(val as i64, allow_imm) { Ok(src) } else { - let gpr = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let gpr = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; temps.push(tmp); self.assembler @@ -363,11 +363,11 @@ impl MachineARM64 { if self.compatible_imm(val as i64, allow_imm) { Ok(src) } else { - let gpr = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let gpr = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; temps.push(tmp); self.assembler @@ -382,11 +382,11 @@ impl MachineARM64 { if self.compatible_imm(val as i64, allow_imm) { Ok(src) } else { - let gpr = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let gpr = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; temps.push(tmp); self.assembler @@ -398,8 +398,8 @@ impl MachineARM64 { } } Location::Memory(reg, val) => { - let tmp = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; temps.push(tmp); if read_val { @@ -418,8 +418,8 @@ impl MachineARM64 { self.assembler .emit_ldur(sz, Location::SIMD(tmp), reg, val)?; } else { - let gpr = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let gpr = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(gpr), (val as i64) as u64)?; @@ -439,12 +439,12 @@ impl MachineARM64 { fn emit_relaxed_binop( &mut self, - op: fn(&mut Assembler, Size, Location, Location) -> Result<(), CodegenError>, + op: fn(&mut Assembler, Size, Location, Location) -> Result<(), CompileError>, sz: Size, src: Location, dst: Location, putback: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let src_imm = if putback { ImmType::None @@ -464,12 +464,12 @@ impl MachineARM64 { } fn emit_relaxed_binop_neon( &mut self, - op: fn(&mut Assembler, Size, Location, Location) -> Result<(), CodegenError>, + op: fn(&mut Assembler, Size, Location, Location) -> Result<(), CompileError>, sz: Size, src: Location, dst: Location, putback: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let src = self.location_to_neon(sz, src, &mut temps, ImmType::None, true)?; let dest = self.location_to_neon(sz, dst, &mut temps, ImmType::None, !putback)?; @@ -484,13 +484,13 @@ impl MachineARM64 { } fn emit_relaxed_binop3( &mut self, - op: fn(&mut Assembler, Size, Location, Location, Location) -> Result<(), CodegenError>, + op: fn(&mut Assembler, Size, Location, Location, Location) -> Result<(), CompileError>, sz: Size, src1: Location, src2: Location, dst: Location, allow_imm: ImmType, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let src1 = self.location_to_reg(sz, src1, &mut temps, ImmType::None, true, None)?; let src2 = self.location_to_reg(sz, src2, &mut temps, allow_imm, true, None)?; @@ -506,13 +506,13 @@ impl MachineARM64 { } fn emit_relaxed_binop3_neon( &mut self, - op: fn(&mut Assembler, Size, Location, Location, Location) -> Result<(), CodegenError>, + op: fn(&mut Assembler, Size, Location, Location, Location) -> Result<(), CompileError>, sz: Size, src1: Location, src2: Location, dst: Location, allow_imm: ImmType, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let src1 = self.location_to_neon(sz, src1, &mut temps, ImmType::None, true)?; let src2 = self.location_to_neon(sz, src2, &mut temps, allow_imm, true)?; @@ -531,7 +531,7 @@ impl MachineARM64 { sz: Size, dst: Location, src: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(sz, dst, &mut temps, ImmType::None, false, None)?; match src { @@ -541,8 +541,8 @@ impl MachineARM64 { } else if self.compatible_imm(offset as i64, ImmType::UnscaledOffset) { self.assembler.emit_ldur(Size::S64, dest, addr, offset)?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), (offset as i64) as u64)?; @@ -569,7 +569,7 @@ impl MachineARM64 { sz: Size, dst: Location, src: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(sz, dst, &mut temps, ImmType::None, false, None)?; match src { @@ -579,8 +579,8 @@ impl MachineARM64 { } else if self.compatible_imm(offset as i64, ImmType::UnscaledOffset) { self.assembler.emit_ldur(Size::S32, dest, addr, offset)?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), (offset as i64) as u64)?; @@ -607,7 +607,7 @@ impl MachineARM64 { sz: Size, dst: Location, src: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(sz, dst, &mut temps, ImmType::None, false, None)?; match src { @@ -615,8 +615,8 @@ impl MachineARM64 { if self.compatible_imm(offset as i64, ImmType::OffsetWord) { self.assembler.emit_ldrsw(Size::S64, dest, src)?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), (offset as i64) as u64)?; @@ -643,7 +643,7 @@ impl MachineARM64 { sz: Size, dst: Location, src: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(sz, dst, &mut temps, ImmType::None, false, None)?; match src { @@ -651,8 +651,8 @@ impl MachineARM64 { if self.compatible_imm(offset as i64, ImmType::OffsetHWord) { self.assembler.emit_ldrh(Size::S32, dest, src)?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), (offset as i64) as u64)?; @@ -679,7 +679,7 @@ impl MachineARM64 { sz: Size, dst: Location, src: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(sz, dst, &mut temps, ImmType::None, false, None)?; match src { @@ -687,8 +687,8 @@ impl MachineARM64 { if self.compatible_imm(offset as i64, ImmType::OffsetHWord) { self.assembler.emit_ldrsh(sz, dest, src)?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), (offset as i64) as u64)?; @@ -715,7 +715,7 @@ impl MachineARM64 { sz: Size, dst: Location, src: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(sz, dst, &mut temps, ImmType::None, false, None)?; match src { @@ -723,8 +723,8 @@ impl MachineARM64 { if self.compatible_imm(offset as i64, ImmType::OffsetByte) { self.assembler.emit_ldrb(Size::S32, dest, src)?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), (offset as i64) as u64)?; @@ -751,7 +751,7 @@ impl MachineARM64 { sz: Size, dst: Location, src: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(sz, dst, &mut temps, ImmType::None, false, None)?; match src { @@ -759,8 +759,8 @@ impl MachineARM64 { if self.compatible_imm(offset as i64, ImmType::OffsetByte) { self.assembler.emit_ldrsb(sz, dest, src)?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), (offset as i64) as u64)?; @@ -782,7 +782,7 @@ impl MachineARM64 { } Ok(()) } - fn emit_relaxed_str64(&mut self, dst: Location, src: Location) -> Result<(), CodegenError> { + fn emit_relaxed_str64(&mut self, dst: Location, src: Location) -> Result<(), CompileError> { let mut temps = vec![]; let dst = self.location_to_reg(Size::S64, dst, &mut temps, ImmType::NoneXzr, true, None)?; match src { @@ -792,8 +792,8 @@ impl MachineARM64 { } else if self.compatible_imm(offset as i64, ImmType::UnscaledOffset) { self.assembler.emit_stur(Size::S64, dst, addr, offset)?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), (offset as i64) as u64)?; @@ -812,7 +812,7 @@ impl MachineARM64 { } Ok(()) } - fn emit_relaxed_str32(&mut self, dst: Location, src: Location) -> Result<(), CodegenError> { + fn emit_relaxed_str32(&mut self, dst: Location, src: Location) -> Result<(), CompileError> { let mut temps = vec![]; let dst = self.location_to_reg(Size::S64, dst, &mut temps, ImmType::NoneXzr, true, None)?; match src { @@ -822,8 +822,8 @@ impl MachineARM64 { } else if self.compatible_imm(offset as i64, ImmType::UnscaledOffset) { self.assembler.emit_stur(Size::S32, dst, addr, offset)?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), (offset as i64) as u64)?; @@ -842,7 +842,7 @@ impl MachineARM64 { } Ok(()) } - fn emit_relaxed_str16(&mut self, dst: Location, src: Location) -> Result<(), CodegenError> { + fn emit_relaxed_str16(&mut self, dst: Location, src: Location) -> Result<(), CompileError> { let mut temps = vec![]; let dst = self.location_to_reg(Size::S64, dst, &mut temps, ImmType::NoneXzr, true, None)?; match src { @@ -850,8 +850,8 @@ impl MachineARM64 { if self.compatible_imm(offset as i64, ImmType::OffsetHWord) { self.assembler.emit_strh(Size::S32, dst, src)?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), (offset as i64) as u64)?; @@ -870,7 +870,7 @@ impl MachineARM64 { } Ok(()) } - fn emit_relaxed_str8(&mut self, dst: Location, src: Location) -> Result<(), CodegenError> { + fn emit_relaxed_str8(&mut self, dst: Location, src: Location) -> Result<(), CompileError> { let mut temps = vec![]; let dst = self.location_to_reg(Size::S64, dst, &mut temps, ImmType::NoneXzr, true, None)?; match src { @@ -879,8 +879,8 @@ impl MachineARM64 { self.assembler .emit_strb(Size::S32, dst, Location::Memory(addr, offset))?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), (offset as i64) as u64)?; @@ -906,15 +906,15 @@ impl MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match ret { Location::GPR(_) => { self.emit_relaxed_cmp(Size::S64, loc_b, loc_a)?; self.assembler.emit_cset(Size::S32, ret, c)?; } Location::Memory(_, _) => { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.emit_relaxed_cmp(Size::S64, loc_b, loc_a)?; self.assembler.emit_cset(Size::S32, Location::GPR(tmp), c)?; @@ -934,15 +934,15 @@ impl MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match ret { Location::GPR(_) => { self.emit_relaxed_cmp(Size::S32, loc_b, loc_a)?; self.assembler.emit_cset(Size::S32, ret, c)?; } Location::Memory(_, _) => { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.emit_relaxed_cmp(Size::S32, loc_b, loc_a)?; self.assembler.emit_cset(Size::S32, Location::GPR(tmp), c)?; @@ -957,7 +957,7 @@ impl MachineARM64 { } #[allow(clippy::too_many_arguments)] - fn memory_op Result<(), CodegenError>>( + fn memory_op Result<(), CompileError>>( &mut self, addr: Location, memarg: &MemoryImmediate, @@ -967,10 +967,11 @@ impl MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, + unaligned_atomic: Label, cb: F, - ) -> Result<(), CodegenError> { - let tmp_addr = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + ) -> Result<(), CompileError> { + let tmp_addr = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; // Reusing `tmp_addr` for temporary indirection here, since it's not used before the last reference to `{base,bound}_loc`. @@ -991,11 +992,11 @@ impl MachineARM64 { ) }; - let tmp_base = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_base = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_bound = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_bound = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; // Load base into temporary register. @@ -1022,8 +1023,8 @@ impl MachineARM64 { Location::GPR(tmp_bound), )?; } else { - let tmp2 = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp2 = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp2), value_size as u64)?; @@ -1052,8 +1053,8 @@ impl MachineARM64 { Location::GPR(tmp_addr), )?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), memarg.offset as _)?; @@ -1095,15 +1096,15 @@ impl MachineARM64 { self.release_gpr(tmp_bound); self.release_gpr(tmp_base); - let align = memarg.align; + let align = value_size as u32; if check_alignment && align != 1 { self.assembler.emit_tst( Size::S64, - Location::Imm32((align - 1).into()), + Location::Imm32(align - 1), Location::GPR(tmp_addr), )?; self.assembler - .emit_bcond_label_far(Condition::Ne, heap_access_oob)?; + .emit_bcond_label_far(Condition::Ne, unaligned_atomic)?; } let begin = self.assembler.get_offset().0; cb(self, tmp_addr)?; @@ -1127,6 +1128,7 @@ impl MachineARM64 { _imported_memories: bool, _offset: i32, _heap_access_oob: Label, + _unaligned_atomic: Label, _cb: F, ) { unimplemented!(); @@ -1151,7 +1153,7 @@ impl MachineARM64 { true } - fn emit_push(&mut self, sz: Size, src: Location) -> Result<(), CodegenError> { + fn emit_push(&mut self, sz: Size, src: Location) -> Result<(), CompileError> { match (sz, src) { (Size::S64, Location::GPR(_)) | (Size::S64, Location::SIMD(_)) => { let offset = if self.pushed { @@ -1199,7 +1201,7 @@ impl MachineARM64 { sz: Size, src1: Location, src2: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { if !self.pushed { match (sz, src1, src2) { (Size::S64, Location::GPR(_), Location::GPR(_)) => { @@ -1217,7 +1219,7 @@ impl MachineARM64 { } Ok(()) } - fn emit_pop(&mut self, sz: Size, dst: Location) -> Result<(), CodegenError> { + fn emit_pop(&mut self, sz: Size, dst: Location) -> Result<(), CompileError> { match (sz, dst) { (Size::S64, Location::GPR(_)) | (Size::S64, Location::SIMD(_)) => { let offset = if self.pushed { 8 } else { 0 }; @@ -1242,7 +1244,7 @@ impl MachineARM64 { sz: Size, dst1: Location, dst2: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { if !self.pushed { match (sz, dst1, dst2) { (Size::S64, Location::GPR(_), Location::GPR(_)) => { @@ -1261,19 +1263,19 @@ impl MachineARM64 { Ok(()) } - fn set_default_nan(&mut self, temps: &mut Vec) -> Result { + fn set_default_nan(&mut self, temps: &mut Vec) -> Result { // temporarly set FPCR to DefaultNan - let old_fpcr = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let old_fpcr = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(old_fpcr); self.assembler.emit_read_fpcr(old_fpcr)?; - let new_fpcr = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let new_fpcr = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(new_fpcr); - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(tmp); self.assembler @@ -1291,15 +1293,15 @@ impl MachineARM64 { self.assembler.emit_write_fpcr(new_fpcr)?; Ok(old_fpcr) } - fn set_trap_enabled(&mut self, temps: &mut Vec) -> Result { + fn set_trap_enabled(&mut self, temps: &mut Vec) -> Result { // temporarly set FPCR to DefaultNan - let old_fpcr = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let old_fpcr = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(old_fpcr); self.assembler.emit_read_fpcr(old_fpcr)?; - let new_fpcr = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let new_fpcr = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(new_fpcr); self.assembler @@ -1310,14 +1312,14 @@ impl MachineARM64 { self.assembler.emit_write_fpcr(new_fpcr)?; Ok(old_fpcr) } - fn restore_fpcr(&mut self, old_fpcr: GPR) -> Result<(), CodegenError> { + fn restore_fpcr(&mut self, old_fpcr: GPR) -> Result<(), CompileError> { self.assembler.emit_write_fpcr(old_fpcr) } - fn reset_exception_fpsr(&mut self) -> Result<(), CodegenError> { + fn reset_exception_fpsr(&mut self) -> Result<(), CompileError> { // reset exception count in FPSR - let fpsr = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let fpsr = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler.emit_read_fpsr(fpsr)?; // IOC is 0 @@ -1327,9 +1329,9 @@ impl MachineARM64 { self.release_gpr(fpsr); Ok(()) } - fn read_fpsr(&mut self) -> Result { - let fpsr = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn read_fpsr(&mut self) -> Result { + let fpsr = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler.emit_read_fpsr(fpsr)?; Ok(fpsr) @@ -1341,7 +1343,7 @@ impl MachineARM64 { sz: Size, f: Location, temps: &mut Vec, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let trap_badconv = self.assembler.get_label(); let end = self.assembler.get_label(); @@ -1392,7 +1394,7 @@ impl MachineARM64 { fn emit_unwind_op(&mut self, op: UnwindOps) { self.unwind_ops.push((self.get_offset().0, op)); } - fn emit_illegal_op_internal(&mut self, trap: TrapCode) -> Result<(), CodegenError> { + fn emit_illegal_op_internal(&mut self, trap: TrapCode) -> Result<(), CompileError> { self.assembler.emit_udf(0xc0 | (trap as u8) as u16) } } @@ -1473,7 +1475,7 @@ impl Machine for MachineARM64 { self.used_gprs_insert(gpr); } - fn push_used_gpr(&mut self, used_gprs: &[GPR]) -> Result { + fn push_used_gpr(&mut self, used_gprs: &[GPR]) -> Result { if used_gprs.len() % 2 == 1 { self.emit_push(Size::S64, Location::GPR(GPR::XzrSp))?; } @@ -1482,7 +1484,7 @@ impl Machine for MachineARM64 { } Ok(((used_gprs.len() + 1) / 2) * 16) } - fn pop_used_gpr(&mut self, used_gprs: &[GPR]) -> Result<(), CodegenError> { + fn pop_used_gpr(&mut self, used_gprs: &[GPR]) -> Result<(), CompileError> { for r in used_gprs.iter().rev() { self.emit_pop(Size::S64, Location::GPR(*r))?; } @@ -1534,7 +1536,7 @@ impl Machine for MachineARM64 { assert!(self.used_simd_remove(&simd)); } - fn push_used_simd(&mut self, used_neons: &[NEON]) -> Result { + fn push_used_simd(&mut self, used_neons: &[NEON]) -> Result { let stack_adjust = if used_neons.len() & 1 == 1 { (used_neons.len() * 8) as u32 + 8 } else { @@ -1551,7 +1553,7 @@ impl Machine for MachineARM64 { } Ok(stack_adjust as usize) } - fn pop_used_simd(&mut self, used_neons: &[NEON]) -> Result<(), CodegenError> { + fn pop_used_simd(&mut self, used_neons: &[NEON]) -> Result<(), CompileError> { for (i, r) in used_neons.iter().enumerate() { self.assembler.emit_ldr( Size::S64, @@ -1647,7 +1649,7 @@ impl Machine for MachineARM64 { } // Adjust stack for locals - fn adjust_stack(&mut self, delta_stack_offset: u32) -> Result<(), CodegenError> { + fn adjust_stack(&mut self, delta_stack_offset: u32) -> Result<(), CompileError> { let delta = if self.compatible_imm(delta_stack_offset as _, ImmType::Bits12) { Location::Imm32(delta_stack_offset as _) } else { @@ -1664,7 +1666,7 @@ impl Machine for MachineARM64 { ) } // restore stack - fn restore_stack(&mut self, delta_stack_offset: u32) -> Result<(), CodegenError> { + fn restore_stack(&mut self, delta_stack_offset: u32) -> Result<(), CompileError> { let delta = if self.compatible_imm(delta_stack_offset as _, ImmType::Bits12) { Location::Imm32(delta_stack_offset as _) } else { @@ -1680,7 +1682,7 @@ impl Machine for MachineARM64 { Location::GPR(GPR::XzrSp), ) } - fn pop_stack_locals(&mut self, delta_stack_offset: u32) -> Result<(), CodegenError> { + fn pop_stack_locals(&mut self, delta_stack_offset: u32) -> Result<(), CompileError> { let real_delta = if delta_stack_offset & 15 != 0 { delta_stack_offset + 8 } else { @@ -1707,7 +1709,7 @@ impl Machine for MachineARM64 { size: Size, loc: Location, dest: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match loc { Location::Imm64(_) | Location::Imm32(_) @@ -1722,7 +1724,7 @@ impl Machine for MachineARM64 { } // Zero a location that is 32bits - fn zero_location(&mut self, size: Size, location: Location) -> Result<(), CodegenError> { + fn zero_location(&mut self, size: Size, location: Location) -> Result<(), CompileError> { self.move_location(size, Location::GPR(GPR::XzrSp), location) } @@ -1752,7 +1754,7 @@ impl Machine for MachineARM64 { } } // Move a local to the stack - fn move_local(&mut self, stack_offset: i32, location: Location) -> Result<(), CodegenError> { + fn move_local(&mut self, stack_offset: i32, location: Location) -> Result<(), CompileError> { if stack_offset < 256 { self.assembler .emit_stur(Size::S64, location, GPR::X29, -stack_offset)?; @@ -1917,7 +1919,7 @@ impl Machine for MachineARM64 { size: Size, source: Location, dest: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match source { Location::GPR(_) | Location::SIMD(_) => match dest { Location::GPR(_) | Location::SIMD(_) => self.assembler.emit_mov(size, source, dest), @@ -2061,7 +2063,7 @@ impl Machine for MachineARM64 { source: Location, size_op: Size, dest: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { if size_op != Size::S64 { codegen_error!("singlepass move_location_extend unreachable"); } @@ -2110,7 +2112,7 @@ impl Machine for MachineARM64 { _size: Size, _reg: Location, _mem: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { codegen_error!("singlepass load_address unimplemented"); } // Init the stack loc counter @@ -2118,11 +2120,11 @@ impl Machine for MachineARM64 { &mut self, init_stack_loc_cnt: u64, last_stack_loc: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let label = self.assembler.get_label(); let mut temps = vec![]; - let dest = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let dest = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(dest); let cnt = self.location_to_reg( @@ -2147,8 +2149,8 @@ impl Machine for MachineARM64 { Location::GPR(dest), )?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), (offset as i64) as u64)?; @@ -2171,8 +2173,8 @@ impl Machine for MachineARM64 { Location::GPR(dest), )?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), (offset as i64) as u64)?; @@ -2201,7 +2203,7 @@ impl Machine for MachineARM64 { Ok(()) } // Restore save_area - fn restore_saved_area(&mut self, saved_area_offset: i32) -> Result<(), CodegenError> { + fn restore_saved_area(&mut self, saved_area_offset: i32) -> Result<(), CompileError> { let real_delta = if saved_area_offset & 15 != 0 { self.pushed = true; saved_area_offset + 8 @@ -2217,8 +2219,8 @@ impl Machine for MachineARM64 { Location::GPR(GPR::XzrSp), )?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), real_delta as u64)?; @@ -2233,7 +2235,7 @@ impl Machine for MachineARM64 { Ok(()) } // Pop a location - fn pop_location(&mut self, location: Location) -> Result<(), CodegenError> { + fn pop_location(&mut self, location: Location) -> Result<(), CompileError> { self.emit_pop(Size::S64, location) } // Create a new `MachineState` with default values. @@ -2250,12 +2252,12 @@ impl Machine for MachineARM64 { self.assembler.get_offset() } - fn finalize_function(&mut self) -> Result<(), CodegenError> { + fn finalize_function(&mut self) -> Result<(), CompileError> { self.assembler.finalize_function(); Ok(()) } - fn emit_function_prolog(&mut self) -> Result<(), CodegenError> { + fn emit_function_prolog(&mut self) -> Result<(), CompileError> { self.emit_double_push(Size::S64, Location::GPR(GPR::X29), Location::GPR(GPR::X30))?; // save LR too self.emit_unwind_op(UnwindOps::Push2Regs { reg1: GPR::X29.to_dwarf(), @@ -2279,7 +2281,7 @@ impl Machine for MachineARM64 { Ok(()) } - fn emit_function_epilog(&mut self) -> Result<(), CodegenError> { + fn emit_function_epilog(&mut self) -> Result<(), CompileError> { // cannot use mov, because XSP is XZR there. Need to use ADD with #0 self.assembler.emit_add( Size::S64, @@ -2298,7 +2300,7 @@ impl Machine for MachineARM64 { ty: WpType, canonicalize: bool, loc: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { if canonicalize { self.canonicalize_nan( match ty { @@ -2315,7 +2317,7 @@ impl Machine for MachineARM64 { Ok(()) } - fn emit_function_return_float(&mut self) -> Result<(), CodegenError> { + fn emit_function_return_float(&mut self) -> Result<(), CompileError> { self.assembler .emit_mov(Size::S64, Location::GPR(GPR::X0), Location::SIMD(NEON::V0)) } @@ -2328,7 +2330,7 @@ impl Machine for MachineARM64 { sz: Size, input: Location, output: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut tempn = vec![]; let mut temps = vec![]; let old_fpcr = self.set_default_nan(&mut temps)?; @@ -2371,7 +2373,7 @@ impl Machine for MachineARM64 { Ok(()) } - fn emit_illegal_op(&mut self, trap: TrapCode) -> Result<(), CodegenError> { + fn emit_illegal_op(&mut self, trap: TrapCode) -> Result<(), CompileError> { let offset = self.assembler.get_offset().0; self.assembler.emit_udf(0xc0 | (trap as u8) as u16)?; self.mark_instruction_address_end(offset); @@ -2380,16 +2382,16 @@ impl Machine for MachineARM64 { fn get_label(&mut self) -> Label { self.assembler.new_dynamic_label() } - fn emit_label(&mut self, label: Label) -> Result<(), CodegenError> { + fn emit_label(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_label(label) } fn get_grp_for_call(&self) -> GPR { GPR::X27 } - fn emit_call_register(&mut self, reg: GPR) -> Result<(), CodegenError> { + fn emit_call_register(&mut self, reg: GPR) -> Result<(), CompileError> { self.assembler.emit_call_register(reg) } - fn emit_call_label(&mut self, label: Label) -> Result<(), CodegenError> { + fn emit_call_label(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_call_label(label) } fn get_gpr_for_ret(&self) -> GPR { @@ -2406,16 +2408,16 @@ impl Machine for MachineARM64 { fn arch_emit_indirect_call_with_trampoline( &mut self, location: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.assembler .arch_emit_indirect_call_with_trampoline(location) } - fn emit_debug_breakpoint(&mut self) -> Result<(), CodegenError> { + fn emit_debug_breakpoint(&mut self) -> Result<(), CompileError> { self.assembler.emit_brk() } - fn emit_call_location(&mut self, location: Location) -> Result<(), CodegenError> { + fn emit_call_location(&mut self, location: Location) -> Result<(), CompileError> { let mut temps = vec![]; let loc = self.location_to_reg( Size::S64, @@ -2440,7 +2442,7 @@ impl Machine for MachineARM64 { _size: Size, _source: Location, _dest: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { codegen_error!("singlepass location_address not implemented") } // logic @@ -2450,7 +2452,7 @@ impl Machine for MachineARM64 { _source: Location, _dest: Location, _flags: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { codegen_error!("singlepass location_and not implemented") } fn location_xor( @@ -2459,7 +2461,7 @@ impl Machine for MachineARM64 { _source: Location, _dest: Location, _flags: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { codegen_error!("singlepass location_xor not implemented") } fn location_or( @@ -2468,7 +2470,7 @@ impl Machine for MachineARM64 { _source: Location, _dest: Location, _flags: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { codegen_error!("singlepass location_or not implemented") } fn location_test( @@ -2476,7 +2478,7 @@ impl Machine for MachineARM64 { _size: Size, _source: Location, _dest: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { codegen_error!("singlepass location_test not implemented") } // math @@ -2486,7 +2488,7 @@ impl Machine for MachineARM64 { source: Location, dest: Location, flags: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let src = self.location_to_reg(size, source, &mut temps, ImmType::Bits12, true, None)?; let dst = self.location_to_reg(size, dest, &mut temps, ImmType::None, true, None)?; @@ -2509,7 +2511,7 @@ impl Machine for MachineARM64 { source: Location, dest: Location, flags: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let src = self.location_to_reg(size, source, &mut temps, ImmType::Bits12, true, None)?; let dst = self.location_to_reg(size, dest, &mut temps, ImmType::None, true, None)?; @@ -2531,38 +2533,38 @@ impl Machine for MachineARM64 { size: Size, source: Location, dest: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop(Assembler::emit_cmp, size, source, dest, false) } - fn jmp_unconditionnal(&mut self, label: Label) -> Result<(), CodegenError> { + fn jmp_unconditionnal(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_b_label(label) } - fn jmp_on_equal(&mut self, label: Label) -> Result<(), CodegenError> { + fn jmp_on_equal(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_bcond_label_far(Condition::Eq, label) } - fn jmp_on_different(&mut self, label: Label) -> Result<(), CodegenError> { + fn jmp_on_different(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_bcond_label_far(Condition::Ne, label) } - fn jmp_on_above(&mut self, label: Label) -> Result<(), CodegenError> { + fn jmp_on_above(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_bcond_label_far(Condition::Hi, label) } - fn jmp_on_aboveequal(&mut self, label: Label) -> Result<(), CodegenError> { + fn jmp_on_aboveequal(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_bcond_label_far(Condition::Cs, label) } - fn jmp_on_belowequal(&mut self, label: Label) -> Result<(), CodegenError> { + fn jmp_on_belowequal(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_bcond_label_far(Condition::Ls, label) } - fn jmp_on_overflow(&mut self, label: Label) -> Result<(), CodegenError> { + fn jmp_on_overflow(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_bcond_label_far(Condition::Cs, label) } // jmp table - fn emit_jmp_to_jumptable(&mut self, label: Label, cond: Location) -> Result<(), CodegenError> { - let tmp1 = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn emit_jmp_to_jumptable(&mut self, label: Label, cond: Location) -> Result<(), CompileError> { + let tmp1 = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp2 = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp2 = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler.emit_load_label(tmp1, label)?; @@ -2581,23 +2583,23 @@ impl Machine for MachineARM64 { Ok(()) } - fn align_for_loop(&mut self) -> Result<(), CodegenError> { + fn align_for_loop(&mut self) -> Result<(), CompileError> { // noting to do on ARM64 Ok(()) } - fn emit_ret(&mut self) -> Result<(), CodegenError> { + fn emit_ret(&mut self) -> Result<(), CompileError> { self.assembler.emit_ret() } - fn emit_push(&mut self, size: Size, loc: Location) -> Result<(), CodegenError> { + fn emit_push(&mut self, size: Size, loc: Location) -> Result<(), CompileError> { self.emit_push(size, loc) } - fn emit_pop(&mut self, size: Size, loc: Location) -> Result<(), CodegenError> { + fn emit_pop(&mut self, size: Size, loc: Location) -> Result<(), CompileError> { self.emit_pop(size, loc) } - fn emit_memory_fence(&mut self) -> Result<(), CodegenError> { + fn emit_memory_fence(&mut self) -> Result<(), CompileError> { self.assembler.emit_dmb() } @@ -2608,13 +2610,13 @@ impl Machine for MachineARM64 { _source: Location, _size_op: Size, _dest: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { codegen_error!("singlepass location_neg unimplemented"); } - fn emit_imul_imm32(&mut self, size: Size, imm32: u32, gpr: GPR) -> Result<(), CodegenError> { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn emit_imul_imm32(&mut self, size: Size, imm32: u32, gpr: GPR) -> Result<(), CompileError> { + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov_imm(Location::GPR(tmp), imm32 as u64)?; @@ -2634,7 +2636,7 @@ impl Machine for MachineARM64 { sz: Size, src: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop(Assembler::emit_mov, sz, src, dst, true) } fn emit_relaxed_cmp( @@ -2642,7 +2644,7 @@ impl Machine for MachineARM64 { sz: Size, src: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop(Assembler::emit_cmp, sz, src, dst, false) } fn emit_relaxed_zero_extension( @@ -2651,7 +2653,7 @@ impl Machine for MachineARM64 { _src: Location, _sz_dst: Size, _dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { codegen_error!("singlepass emit_relaxed_zero_extension unimplemented"); } fn emit_relaxed_sign_extension( @@ -2660,7 +2662,7 @@ impl Machine for MachineARM64 { src: Location, sz_dst: Size, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (src, dst) { (Location::Memory(_, _), Location::GPR(_)) => match sz_src { Size::S8 => self.emit_relaxed_ldr8s(sz_dst, dst, src), @@ -2696,7 +2698,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_add, Size::S32, @@ -2711,7 +2713,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_sub, Size::S32, @@ -2726,7 +2728,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_mul, Size::S32, @@ -2743,7 +2745,7 @@ impl Machine for MachineARM64 { ret: Location, integer_division_by_zero: Label, _integer_overflow: Label, - ) -> Result { + ) -> Result { let mut temps = vec![]; let src1 = self.location_to_reg(Size::S32, loc_a, &mut temps, ImmType::None, true, None)?; let src2 = self.location_to_reg(Size::S32, loc_b, &mut temps, ImmType::None, true, None)?; @@ -2768,7 +2770,7 @@ impl Machine for MachineARM64 { ret: Location, integer_division_by_zero: Label, integer_overflow: Label, - ) -> Result { + ) -> Result { let mut temps = vec![]; let src1 = self.location_to_reg(Size::S32, loc_a, &mut temps, ImmType::None, true, None)?; let src2 = self.location_to_reg(Size::S32, loc_b, &mut temps, ImmType::None, true, None)?; @@ -2810,14 +2812,14 @@ impl Machine for MachineARM64 { ret: Location, integer_division_by_zero: Label, _integer_overflow: Label, - ) -> Result { + ) -> Result { let mut temps = vec![]; let src1 = self.location_to_reg(Size::S32, loc_a, &mut temps, ImmType::None, true, None)?; let src2 = self.location_to_reg(Size::S32, loc_b, &mut temps, ImmType::None, true, None)?; let dest = self.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; let dest = if dest == src1 || dest == src2 { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(tmp); self.assembler @@ -2848,14 +2850,14 @@ impl Machine for MachineARM64 { ret: Location, integer_division_by_zero: Label, _integer_overflow: Label, - ) -> Result { + ) -> Result { let mut temps = vec![]; let src1 = self.location_to_reg(Size::S32, loc_a, &mut temps, ImmType::None, true, None)?; let src2 = self.location_to_reg(Size::S32, loc_b, &mut temps, ImmType::None, true, None)?; let dest = self.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; let dest = if dest == src1 || dest == src2 { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(tmp); self.assembler @@ -2884,7 +2886,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_and, Size::S32, @@ -2899,7 +2901,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_or, Size::S32, @@ -2914,7 +2916,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_eor, Size::S32, @@ -2929,7 +2931,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Ge, loc_a, loc_b, ret) } fn i32_cmp_gt_s( @@ -2937,7 +2939,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Gt, loc_a, loc_b, ret) } fn i32_cmp_le_s( @@ -2945,7 +2947,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Le, loc_a, loc_b, ret) } fn i32_cmp_lt_s( @@ -2953,7 +2955,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Lt, loc_a, loc_b, ret) } fn i32_cmp_ge_u( @@ -2961,7 +2963,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Cs, loc_a, loc_b, ret) } fn i32_cmp_gt_u( @@ -2969,7 +2971,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Hi, loc_a, loc_b, ret) } fn i32_cmp_le_u( @@ -2977,7 +2979,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Ls, loc_a, loc_b, ret) } fn i32_cmp_lt_u( @@ -2985,7 +2987,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Cc, loc_a, loc_b, ret) } fn i32_cmp_ne( @@ -2993,7 +2995,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Ne, loc_a, loc_b, ret) } fn i32_cmp_eq( @@ -3001,13 +3003,13 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Eq, loc_a, loc_b, ret) } - fn i32_clz(&mut self, src: Location, dst: Location) -> Result<(), CodegenError> { + fn i32_clz(&mut self, src: Location, dst: Location) -> Result<(), CompileError> { self.emit_relaxed_binop(Assembler::emit_clz, Size::S32, src, dst, true) } - fn i32_ctz(&mut self, src: Location, dst: Location) -> Result<(), CodegenError> { + fn i32_ctz(&mut self, src: Location, dst: Location) -> Result<(), CompileError> { let mut temps = vec![]; let src = self.location_to_reg(Size::S32, src, &mut temps, ImmType::None, true, None)?; let dest = self.location_to_reg(Size::S32, dst, &mut temps, ImmType::None, false, None)?; @@ -3021,15 +3023,15 @@ impl Machine for MachineARM64 { } Ok(()) } - fn i32_popcnt(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn i32_popcnt(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { // no opcode for that. // 2 solutions: using NEON CNT, that count bits per Byte, or using clz with some shift and loop let mut temps = vec![]; let src = self.location_to_reg(Size::S32, loc, &mut temps, ImmType::None, true, None)?; let dest = self.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; let src = if src == loc { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(tmp); self.assembler @@ -3039,8 +3041,8 @@ impl Machine for MachineARM64 { src }; let tmp = { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(tmp); Location::GPR(tmp) @@ -3072,7 +3074,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_lsl, Size::S32, @@ -3087,7 +3089,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_lsr, Size::S32, @@ -3102,7 +3104,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_asr, Size::S32, @@ -3117,7 +3119,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let src2 = match loc_b { Location::Imm8(imm) => Location::Imm8(32 - (imm & 31)), @@ -3156,7 +3158,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_ror, Size::S32, @@ -3175,7 +3177,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -3185,6 +3188,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_ldr32(Size::S32, ret, Location::Memory(addr, 0)), ) } @@ -3197,7 +3201,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -3207,6 +3212,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_ldr8(Size::S32, ret, Location::Memory(addr, 0)), ) } @@ -3219,7 +3225,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -3229,6 +3236,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_ldr8s(Size::S32, ret, Location::Memory(addr, 0)), ) } @@ -3241,7 +3249,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -3251,6 +3260,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_ldr16(Size::S32, ret, Location::Memory(addr, 0)), ) } @@ -3263,7 +3273,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -3273,44 +3284,81 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_ldr16s(Size::S32, ret, Location::Memory(addr, 0)), ) } fn i32_atomic_load( &mut self, - _addr: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_load unimplemented"); + addr: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + addr, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| this.emit_relaxed_ldr32(Size::S32, ret, Location::Memory(addr, 0)), + ) } fn i32_atomic_load_8u( &mut self, - _addr: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_load_8u unimplemented"); + addr: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + addr, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| this.emit_relaxed_ldr8(Size::S32, ret, Location::Memory(addr, 0)), + ) } fn i32_atomic_load_16u( &mut self, - _addr: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_load_16u unimplemented"); + addr: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + addr, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| this.emit_relaxed_ldr16(Size::S32, ret, Location::Memory(addr, 0)), + ) } fn i32_save( &mut self, @@ -3321,7 +3369,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -3331,6 +3380,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_str32(target_value, Location::Memory(addr, 0)), ) } @@ -3343,7 +3393,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -3353,6 +3404,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_str8(target_value, Location::Memory(addr, 0)), ) } @@ -3365,7 +3417,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -3375,348 +3428,1333 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_str16(target_value, Location::Memory(addr, 0)), ) } fn i32_atomic_save( &mut self, - _value: Location, - _memarg: &MemoryImmediate, - _target_addr: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_save unimplemented"); + target_value: Location, + memarg: &MemoryImmediate, + target_addr: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target_addr, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| this.emit_relaxed_str32(target_value, Location::Memory(addr, 0)), + )?; + self.assembler.emit_dmb() } fn i32_atomic_save_8( &mut self, - _value: Location, - _memarg: &MemoryImmediate, - _target_addr: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_save_8 unimplemented"); + target_value: Location, + memarg: &MemoryImmediate, + target_addr: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target_addr, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| this.emit_relaxed_str8(target_value, Location::Memory(addr, 0)), + )?; + self.assembler.emit_dmb() } fn i32_atomic_save_16( &mut self, - _value: Location, - _memarg: &MemoryImmediate, - _target_addr: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_save_16 unimplemented"); + target_value: Location, + memarg: &MemoryImmediate, + target_addr: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target_addr, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| this.emit_relaxed_str16(target_value, Location::Memory(addr, 0)), + )?; + self.assembler.emit_dmb() } // i32 atomic Add with i32 fn i32_atomic_add( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_add unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_add32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Add with u8 fn i32_atomic_add_8u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_add_8u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrb(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_add32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrb( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Add with u16 fn i32_atomic_add_16u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_add_16u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrh(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_add32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrh( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Sub with i32 fn i32_atomic_sub( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_sub unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_sub32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Sub with u8 fn i32_atomic_sub_8u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_sub_8u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrb(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_sub32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrb( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Sub with u16 fn i32_atomic_sub_16u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_sub_16u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrh(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_sub32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrh( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic And with i32 fn i32_atomic_and( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_and unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_and32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic And with u8 fn i32_atomic_and_8u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_and_8u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrb(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_and32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrb( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic And with u16 fn i32_atomic_and_16u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_and_16u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrh(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_and32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrh( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Or with i32 fn i32_atomic_or( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_or unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_or32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Or with u8 fn i32_atomic_or_8u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_or_8u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrb(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_or32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrb( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Or with u16 fn i32_atomic_or_16u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_or_16u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrh(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_or32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrh( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Xor with i32 fn i32_atomic_xor( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_xor unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_xor32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Xor with u8 fn i32_atomic_xor_8u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_xor_8u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrb(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_xor32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrb( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Xor with u16 fn i32_atomic_xor_16u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_xor_16u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrh(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_xor32(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrh( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Exchange with i32 fn i32_atomic_xchg( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_xchg unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let org = + this.location_to_reg(Size::S32, loc, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S32, dst, Location::GPR(addr))?; + this.assembler.emit_stlxr( + Size::S32, + Location::GPR(tmp), + org, + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Exchange with u8 fn i32_atomic_xchg_8u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_xchg_8u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let org = + this.location_to_reg(Size::S32, loc, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrb(Size::S32, dst, Location::GPR(addr))?; + this.assembler.emit_stlxrb( + Size::S32, + Location::GPR(tmp), + org, + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Exchange with u16 fn i32_atomic_xchg_16u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_xchg_16u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let org = + this.location_to_reg(Size::S32, loc, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrh(Size::S32, dst, Location::GPR(addr))?; + this.assembler.emit_stlxrh( + Size::S32, + Location::GPR(tmp), + org, + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Exchange with i32 fn i32_atomic_cmpxchg( &mut self, - _new: Location, - _cmp: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_cmpxchg unimplemented"); + new: Location, + cmp: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let org = + this.location_to_reg(Size::S32, new, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + let nosame = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S32, dst, Location::GPR(addr))?; + this.emit_relaxed_cmp(Size::S32, dst, cmp)?; + this.assembler.emit_bcond_label(Condition::Ne, nosame)?; + this.assembler.emit_stlxr( + Size::S32, + Location::GPR(tmp), + org, + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp), reread)?; + this.assembler.emit_dmb()?; + + this.emit_label(nosame)?; + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Exchange with u8 fn i32_atomic_cmpxchg_8u( &mut self, - _new: Location, - _cmp: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_cmpxchg_8u unimplemented"); + new: Location, + cmp: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let org = + this.location_to_reg(Size::S32, new, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + let nosame = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrb(Size::S32, dst, Location::GPR(addr))?; + this.emit_relaxed_cmp(Size::S32, dst, cmp)?; + this.assembler.emit_bcond_label(Condition::Ne, nosame)?; + this.assembler.emit_stlxrb( + Size::S32, + Location::GPR(tmp), + org, + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp), reread)?; + this.assembler.emit_dmb()?; + + this.emit_label(nosame)?; + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i32 atomic Exchange with u16 fn i32_atomic_cmpxchg_16u( &mut self, - _new: Location, - _cmp: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i32_atomic_cmpxchg_16u unimplemented"); + new: Location, + cmp: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; + let org = + this.location_to_reg(Size::S32, new, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + let nosame = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrh(Size::S32, dst, Location::GPR(addr))?; + this.emit_relaxed_cmp(Size::S32, dst, cmp)?; + this.assembler.emit_bcond_label(Condition::Ne, nosame)?; + this.assembler.emit_stlxrh( + Size::S32, + Location::GPR(tmp), + org, + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp), reread)?; + this.assembler.emit_dmb()?; + + this.emit_label(nosame)?; + if dst != ret { + this.move_location(Size::S32, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } fn emit_call_with_reloc( &mut self, _calling_convention: CallingConvention, reloc_target: RelocationTarget, - ) -> Result, CodegenError> { + ) -> Result, CompileError> { let mut relocations = vec![]; let next = self.get_label(); let reloc_at = self.assembler.get_offset().0; @@ -3736,7 +4774,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_add, Size::S64, @@ -3751,7 +4789,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_sub, Size::S64, @@ -3766,7 +4804,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_mul, Size::S64, @@ -3783,7 +4821,7 @@ impl Machine for MachineARM64 { ret: Location, integer_division_by_zero: Label, _integer_overflow: Label, - ) -> Result { + ) -> Result { let mut temps = vec![]; let src1 = self.location_to_reg(Size::S64, loc_a, &mut temps, ImmType::None, true, None)?; let src2 = self.location_to_reg(Size::S64, loc_b, &mut temps, ImmType::None, true, None)?; @@ -3808,7 +4846,7 @@ impl Machine for MachineARM64 { ret: Location, integer_division_by_zero: Label, integer_overflow: Label, - ) -> Result { + ) -> Result { let mut temps = vec![]; let src1 = self.location_to_reg(Size::S64, loc_a, &mut temps, ImmType::None, true, None)?; let src2 = self.location_to_reg(Size::S64, loc_b, &mut temps, ImmType::None, true, None)?; @@ -3850,14 +4888,14 @@ impl Machine for MachineARM64 { ret: Location, integer_division_by_zero: Label, _integer_overflow: Label, - ) -> Result { + ) -> Result { let mut temps = vec![]; let src1 = self.location_to_reg(Size::S64, loc_a, &mut temps, ImmType::None, true, None)?; let src2 = self.location_to_reg(Size::S64, loc_b, &mut temps, ImmType::None, true, None)?; let dest = self.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; let dest = if dest == src1 || dest == src2 { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(tmp); self.assembler @@ -3888,14 +4926,14 @@ impl Machine for MachineARM64 { ret: Location, integer_division_by_zero: Label, _integer_overflow: Label, - ) -> Result { + ) -> Result { let mut temps = vec![]; let src1 = self.location_to_reg(Size::S64, loc_a, &mut temps, ImmType::None, true, None)?; let src2 = self.location_to_reg(Size::S64, loc_b, &mut temps, ImmType::None, true, None)?; let dest = self.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; let dest = if dest == src1 || dest == src2 { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(tmp); self.assembler @@ -3924,7 +4962,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_and, Size::S64, @@ -3939,7 +4977,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_or, Size::S64, @@ -3954,7 +4992,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_eor, Size::S64, @@ -3969,7 +5007,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Ge, loc_a, loc_b, ret) } fn i64_cmp_gt_s( @@ -3977,7 +5015,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Gt, loc_a, loc_b, ret) } fn i64_cmp_le_s( @@ -3985,7 +5023,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Le, loc_a, loc_b, ret) } fn i64_cmp_lt_s( @@ -3993,7 +5031,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Lt, loc_a, loc_b, ret) } fn i64_cmp_ge_u( @@ -4001,7 +5039,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Cs, loc_a, loc_b, ret) } fn i64_cmp_gt_u( @@ -4009,7 +5047,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Hi, loc_a, loc_b, ret) } fn i64_cmp_le_u( @@ -4017,7 +5055,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Ls, loc_a, loc_b, ret) } fn i64_cmp_lt_u( @@ -4025,7 +5063,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Cc, loc_a, loc_b, ret) } fn i64_cmp_ne( @@ -4033,7 +5071,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Ne, loc_a, loc_b, ret) } fn i64_cmp_eq( @@ -4041,13 +5079,13 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Eq, loc_a, loc_b, ret) } - fn i64_clz(&mut self, src: Location, dst: Location) -> Result<(), CodegenError> { + fn i64_clz(&mut self, src: Location, dst: Location) -> Result<(), CompileError> { self.emit_relaxed_binop(Assembler::emit_clz, Size::S64, src, dst, true) } - fn i64_ctz(&mut self, src: Location, dst: Location) -> Result<(), CodegenError> { + fn i64_ctz(&mut self, src: Location, dst: Location) -> Result<(), CompileError> { let mut temps = vec![]; let src = self.location_to_reg(Size::S64, src, &mut temps, ImmType::None, true, None)?; let dest = self.location_to_reg(Size::S64, dst, &mut temps, ImmType::None, false, None)?; @@ -4061,13 +5099,13 @@ impl Machine for MachineARM64 { } Ok(()) } - fn i64_popcnt(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn i64_popcnt(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { let mut temps = vec![]; let src = self.location_to_reg(Size::S64, loc, &mut temps, ImmType::None, true, None)?; let dest = self.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; let src = if src == loc { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(tmp); self.assembler @@ -4077,8 +5115,8 @@ impl Machine for MachineARM64 { src }; let tmp = { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; temps.push(tmp); Location::GPR(tmp) @@ -4110,7 +5148,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_lsl, Size::S64, @@ -4125,7 +5163,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_lsr, Size::S64, @@ -4140,7 +5178,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_asr, Size::S64, @@ -4155,7 +5193,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { // there is no ROL on ARM64. We use ROR with 64-value instead let mut temps = vec![]; let src2 = match loc_b { @@ -4195,7 +5233,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3( Assembler::emit_ror, Size::S64, @@ -4214,7 +5252,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -4224,6 +5263,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_ldr64(Size::S64, ret, Location::Memory(addr, 0)), ) } @@ -4236,7 +5276,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -4246,6 +5287,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_ldr8(Size::S64, ret, Location::Memory(addr, 0)), ) } @@ -4258,7 +5300,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -4268,6 +5311,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_ldr8s(Size::S64, ret, Location::Memory(addr, 0)), ) } @@ -4280,7 +5324,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -4290,6 +5335,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_ldr16(Size::S64, ret, Location::Memory(addr, 0)), ) } @@ -4302,7 +5348,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -4312,6 +5359,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_ldr16s(Size::S64, ret, Location::Memory(addr, 0)), ) } @@ -4324,7 +5372,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -4334,6 +5383,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_ldr32(Size::S64, ret, Location::Memory(addr, 0)), ) } @@ -4346,7 +5396,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -4356,56 +5407,105 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_ldr32s(Size::S64, ret, Location::Memory(addr, 0)), ) } fn i64_atomic_load( &mut self, - _addr: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_load unimplemented"); + addr: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + addr, + memarg, + true, + 8, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| this.emit_relaxed_ldr64(Size::S64, ret, Location::Memory(addr, 0)), + ) } fn i64_atomic_load_8u( &mut self, - _addr: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_load_8u unimplemented"); + addr: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + addr, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| this.emit_relaxed_ldr8(Size::S64, ret, Location::Memory(addr, 0)), + ) } fn i64_atomic_load_16u( &mut self, - _addr: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_load_16u unimplemented"); + addr: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + addr, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| this.emit_relaxed_ldr16(Size::S64, ret, Location::Memory(addr, 0)), + ) } fn i64_atomic_load_32u( &mut self, - _addr: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_load_32u unimplemented"); + addr: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + addr, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| this.emit_relaxed_ldr32(Size::S64, ret, Location::Memory(addr, 0)), + ) } fn i64_save( &mut self, @@ -4416,7 +5516,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -4426,6 +5527,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_str64(target_value, Location::Memory(addr, 0)), ) } @@ -4438,7 +5540,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -4448,6 +5551,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_str8(target_value, Location::Memory(addr, 0)), ) } @@ -4460,7 +5564,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -4470,6 +5575,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_str16(target_value, Location::Memory(addr, 0)), ) } @@ -4482,7 +5588,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -4492,452 +5599,1765 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_str32(target_value, Location::Memory(addr, 0)), ) } fn i64_atomic_save( &mut self, - _value: Location, - _memarg: &MemoryImmediate, - _target_addr: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_save unimplemented"); + target_value: Location, + memarg: &MemoryImmediate, + target_addr: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target_addr, + memarg, + true, + 8, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| this.emit_relaxed_str64(target_value, Location::Memory(addr, 0)), + )?; + self.assembler.emit_dmb() } fn i64_atomic_save_8( &mut self, - _value: Location, - _memarg: &MemoryImmediate, - _target_addr: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_save_8 unimplemented"); + target_value: Location, + memarg: &MemoryImmediate, + target_addr: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target_addr, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| this.emit_relaxed_str8(target_value, Location::Memory(addr, 0)), + )?; + self.assembler.emit_dmb() } fn i64_atomic_save_16( &mut self, - _value: Location, - _memarg: &MemoryImmediate, - _target_addr: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_save_16 unimplemented"); + target_value: Location, + memarg: &MemoryImmediate, + target_addr: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target_addr, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| this.emit_relaxed_str16(target_value, Location::Memory(addr, 0)), + )?; + self.assembler.emit_dmb() } fn i64_atomic_save_32( &mut self, - _value: Location, - _memarg: &MemoryImmediate, - _target_addr: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_save_32 unimplemented"); + target_value: Location, + memarg: &MemoryImmediate, + target_addr: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target_addr, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| this.emit_relaxed_str32(target_value, Location::Memory(addr, 0)), + )?; + self.assembler.emit_dmb() } // i64 atomic Add with i64 fn i64_atomic_add( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_add unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 8, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_add64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Add with u8 fn i64_atomic_add_8u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_add_8u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrb(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_add64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrb( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Add with u16 fn i64_atomic_add_16u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_add_16u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrh(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_add64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrh( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Add with u32 fn i64_atomic_add_32u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_add_32u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_add64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Sub with i64 fn i64_atomic_sub( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_sub unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 8, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_sub64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Sub with u8 fn i64_atomic_sub_8u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_sub_8u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrb(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_sub64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrb( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Sub with u16 fn i64_atomic_sub_16u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_sub_16u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrh(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_sub64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrh( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Sub with u32 fn i64_atomic_sub_32u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_sub_32u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_sub64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic And with i64 fn i64_atomic_and( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_and unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 8, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_and64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic And with u8 fn i64_atomic_and_8u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_and_8u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrb(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_and64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrb( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic And with u16 fn i64_atomic_and_16u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_and_16u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrh(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_and64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrh( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic And with u32 fn i64_atomic_and_32u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_and_32u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_and64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Or with i64 fn i64_atomic_or( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_or unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 8, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_or64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Or with u8 fn i64_atomic_or_8u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_or_8u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrb(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_or64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrb( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Or with u16 fn i64_atomic_or_16u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_or_16u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrh(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_or64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrh( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Or with u32 fn i64_atomic_or_32u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_or_32u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_or64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } - // i64 atomic xor with i64 + // i64 atomic Xor with i64 fn i64_atomic_xor( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_xor unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 8, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_xor64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } - // i64 atomic xor with u8 + // i64 atomic Xor with u8 fn i64_atomic_xor_8u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_xor_8u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrb(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_xor64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrb( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } - // i64 atomic xor with u16 + // i64 atomic Xor with u16 fn i64_atomic_xor_16u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_xor_16u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrh(Size::S64, dst, Location::GPR(addr))?; + this.emit_binop_xor64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxrh( + Size::S64, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } - // i64 atomic xor with u32 + // i64 atomic Xor with u32 fn i64_atomic_xor_32u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_xor_32u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp1 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let tmp2 = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S32, dst, Location::GPR(addr))?; + this.emit_binop_xor64(dst, loc, Location::GPR(tmp1))?; + this.assembler.emit_stlxr( + Size::S32, + Location::GPR(tmp2), + Location::GPR(tmp1), + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp2), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Exchange with i64 fn i64_atomic_xchg( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_xchg unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 8, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let org = + this.location_to_reg(Size::S64, loc, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S64, dst, Location::GPR(addr))?; + this.assembler.emit_stlxr( + Size::S64, + Location::GPR(tmp), + org, + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Exchange with u8 fn i64_atomic_xchg_8u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_xchg_8u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let org = + this.location_to_reg(Size::S64, loc, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrb(Size::S64, dst, Location::GPR(addr))?; + this.assembler.emit_stlxrb( + Size::S64, + Location::GPR(tmp), + org, + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Exchange with u16 fn i64_atomic_xchg_16u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_xchg_16u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let org = + this.location_to_reg(Size::S64, loc, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrh(Size::S64, dst, Location::GPR(addr))?; + this.assembler.emit_stlxrh( + Size::S64, + Location::GPR(tmp), + org, + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Exchange with u32 fn i64_atomic_xchg_32u( &mut self, - _loc: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_xchg_32u unimplemented"); + loc: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let org = + this.location_to_reg(Size::S64, loc, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S32, dst, Location::GPR(addr))?; + this.assembler.emit_stlxr( + Size::S32, + Location::GPR(tmp), + org, + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp), reread)?; + this.assembler.emit_dmb()?; + + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Exchange with i64 fn i64_atomic_cmpxchg( &mut self, - _new: Location, - _cmp: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_cmpxchg unimplemented"); + new: Location, + cmp: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 8, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let org = + this.location_to_reg(Size::S64, new, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + let nosame = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S64, dst, Location::GPR(addr))?; + this.emit_relaxed_cmp(Size::S64, dst, cmp)?; + this.assembler.emit_bcond_label(Condition::Ne, nosame)?; + this.assembler.emit_stlxr( + Size::S64, + Location::GPR(tmp), + org, + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp), reread)?; + this.assembler.emit_dmb()?; + + this.emit_label(nosame)?; + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Exchange with u8 fn i64_atomic_cmpxchg_8u( &mut self, - _new: Location, - _cmp: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_cmpxchg_8u unimplemented"); + new: Location, + cmp: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 1, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let org = + this.location_to_reg(Size::S64, new, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + let nosame = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrb(Size::S64, dst, Location::GPR(addr))?; + this.emit_relaxed_cmp(Size::S64, dst, cmp)?; + this.assembler.emit_bcond_label(Condition::Ne, nosame)?; + this.assembler.emit_stlxrb( + Size::S64, + Location::GPR(tmp), + org, + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp), reread)?; + this.assembler.emit_dmb()?; + + this.emit_label(nosame)?; + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Exchange with u16 fn i64_atomic_cmpxchg_16u( &mut self, - _new: Location, - _cmp: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_cmpxchg_16u unimplemented"); + new: Location, + cmp: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 2, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let org = + this.location_to_reg(Size::S64, new, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + let nosame = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxrh(Size::S64, dst, Location::GPR(addr))?; + this.emit_relaxed_cmp(Size::S64, dst, cmp)?; + this.assembler.emit_bcond_label(Condition::Ne, nosame)?; + this.assembler.emit_stlxrh( + Size::S64, + Location::GPR(tmp), + org, + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp), reread)?; + this.assembler.emit_dmb()?; + + this.emit_label(nosame)?; + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } // i64 atomic Exchange with u32 fn i64_atomic_cmpxchg_32u( &mut self, - _new: Location, - _cmp: Location, - _target: Location, - _memarg: &MemoryImmediate, - _ret: Location, - _need_check: bool, - _imported_memories: bool, - _offset: i32, - _heap_access_oob: Label, - ) -> Result<(), CodegenError> { - codegen_error!("singlepass i64_atomic_cmpxchg_32u unimplemented"); + new: Location, + cmp: Location, + target: Location, + memarg: &MemoryImmediate, + ret: Location, + need_check: bool, + imported_memories: bool, + offset: i32, + heap_access_oob: Label, + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + self.memory_op( + target, + memarg, + true, + 4, + need_check, + imported_memories, + offset, + heap_access_oob, + unaligned_atomic, + |this, addr| { + let mut temps = vec![]; + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) + })?; + let dst = + this.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; + let org = + this.location_to_reg(Size::S64, new, &mut temps, ImmType::None, false, None)?; + let reread = this.get_label(); + let nosame = this.get_label(); + + this.emit_label(reread)?; + this.assembler + .emit_ldaxr(Size::S32, dst, Location::GPR(addr))?; + this.emit_relaxed_cmp(Size::S64, dst, cmp)?; + this.assembler.emit_bcond_label(Condition::Ne, nosame)?; + this.assembler.emit_stlxr( + Size::S32, + Location::GPR(tmp), + org, + Location::GPR(addr), + )?; + this.assembler + .emit_cbnz_label(Size::S32, Location::GPR(tmp), reread)?; + this.assembler.emit_dmb()?; + + this.emit_label(nosame)?; + if dst != ret { + this.move_location(Size::S64, ret, dst)?; + } + for r in temps { + this.release_gpr(r); + } + Ok(()) + }, + ) } fn f32_load( @@ -4949,7 +7369,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -4959,6 +7380,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_ldr32(Size::S32, ret, Location::Memory(addr, 0)), ) } @@ -4972,7 +7394,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { let canonicalize = canonicalize && self.arch_supports_canonicalize_nan(); self.memory_op( target_addr, @@ -4983,6 +7406,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { if !canonicalize { this.emit_relaxed_str32(target_value, Location::Memory(addr, 0)) @@ -5001,7 +7425,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -5011,6 +7436,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_ldr64(Size::S64, ret, Location::Memory(addr, 0)), ) } @@ -5024,7 +7450,8 @@ impl Machine for MachineARM64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { let canonicalize = canonicalize && self.arch_supports_canonicalize_nan(); self.memory_op( target_addr, @@ -5035,6 +7462,7 @@ impl Machine for MachineARM64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { if !canonicalize { this.emit_relaxed_str64(target_value, Location::Memory(addr, 0)) @@ -5050,7 +7478,7 @@ impl Machine for MachineARM64 { loc: Location, signed: bool, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut gprs = vec![]; let mut neons = vec![]; let src = self.location_to_reg(Size::S64, loc, &mut gprs, ImmType::NoneXzr, true, None)?; @@ -5076,7 +7504,7 @@ impl Machine for MachineARM64 { loc: Location, signed: bool, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut gprs = vec![]; let mut neons = vec![]; let src = self.location_to_reg(Size::S32, loc, &mut gprs, ImmType::NoneXzr, true, None)?; @@ -5102,7 +7530,7 @@ impl Machine for MachineARM64 { loc: Location, signed: bool, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut gprs = vec![]; let mut neons = vec![]; let src = self.location_to_reg(Size::S64, loc, &mut gprs, ImmType::NoneXzr, true, None)?; @@ -5128,7 +7556,7 @@ impl Machine for MachineARM64 { loc: Location, signed: bool, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut gprs = vec![]; let mut neons = vec![]; let src = self.location_to_reg(Size::S32, loc, &mut gprs, ImmType::NoneXzr, true, None)?; @@ -5155,7 +7583,7 @@ impl Machine for MachineARM64 { ret: Location, signed: bool, sat: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut gprs = vec![]; let mut neons = vec![]; let src = self.location_to_neon(Size::S64, loc, &mut neons, ImmType::None, true)?; @@ -5193,7 +7621,7 @@ impl Machine for MachineARM64 { ret: Location, signed: bool, sat: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut gprs = vec![]; let mut neons = vec![]; let src = self.location_to_neon(Size::S64, loc, &mut neons, ImmType::None, true)?; @@ -5231,7 +7659,7 @@ impl Machine for MachineARM64 { ret: Location, signed: bool, sat: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut gprs = vec![]; let mut neons = vec![]; let src = self.location_to_neon(Size::S32, loc, &mut neons, ImmType::None, true)?; @@ -5269,7 +7697,7 @@ impl Machine for MachineARM64 { ret: Location, signed: bool, sat: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut gprs = vec![]; let mut neons = vec![]; let src = self.location_to_neon(Size::S32, loc, &mut neons, ImmType::None, true)?; @@ -5301,18 +7729,18 @@ impl Machine for MachineARM64 { } Ok(()) } - fn convert_f64_f32(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn convert_f64_f32(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_binop_neon(Assembler::emit_fcvt, Size::S32, loc, ret, true) } - fn convert_f32_f64(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn convert_f32_f64(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_binop_neon(Assembler::emit_fcvt, Size::S64, loc, ret, true) } - fn f64_neg(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f64_neg(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_binop_neon(Assembler::emit_fneg, Size::S64, loc, ret, true) } - fn f64_abs(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn f64_abs(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S64, loc, Location::GPR(tmp))?; @@ -5327,7 +7755,7 @@ impl Machine for MachineARM64 { self.release_gpr(tmp); Ok(()) } - fn emit_i64_copysign(&mut self, tmp1: GPR, tmp2: GPR) -> Result<(), CodegenError> { + fn emit_i64_copysign(&mut self, tmp1: GPR, tmp2: GPR) -> Result<(), CompileError> { self.assembler.emit_and( Size::S64, Location::GPR(tmp1), @@ -5349,19 +7777,19 @@ impl Machine for MachineARM64 { Location::GPR(tmp1), ) } - fn f64_sqrt(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f64_sqrt(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_binop_neon(Assembler::emit_fsqrt, Size::S64, loc, ret, true) } - fn f64_trunc(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f64_trunc(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_binop_neon(Assembler::emit_frintz, Size::S64, loc, ret, true) } - fn f64_ceil(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f64_ceil(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_binop_neon(Assembler::emit_frintp, Size::S64, loc, ret, true) } - fn f64_floor(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f64_floor(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_binop_neon(Assembler::emit_frintm, Size::S64, loc, ret, true) } - fn f64_nearest(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f64_nearest(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_binop_neon(Assembler::emit_frintn, Size::S64, loc, ret, true) } fn f64_cmp_ge( @@ -5369,7 +7797,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; self.emit_relaxed_binop_neon(Assembler::emit_fcmp, Size::S64, loc_b, loc_a, false)?; @@ -5387,7 +7815,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; self.emit_relaxed_binop_neon(Assembler::emit_fcmp, Size::S64, loc_b, loc_a, false)?; @@ -5405,7 +7833,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; self.emit_relaxed_binop_neon(Assembler::emit_fcmp, Size::S64, loc_a, loc_b, false)?; @@ -5423,7 +7851,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; self.emit_relaxed_binop_neon(Assembler::emit_fcmp, Size::S64, loc_a, loc_b, false)?; @@ -5441,7 +7869,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; self.emit_relaxed_binop_neon(Assembler::emit_fcmp, Size::S64, loc_a, loc_b, false)?; @@ -5459,7 +7887,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(Size::S64, ret, &mut temps, ImmType::None, false, None)?; self.emit_relaxed_binop_neon(Assembler::emit_fcmp, Size::S64, loc_a, loc_b, false)?; @@ -5477,7 +7905,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let old_fpcr = self.set_default_nan(&mut temps)?; self.emit_relaxed_binop3_neon( @@ -5499,7 +7927,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let old_fpcr = self.set_default_nan(&mut temps)?; self.emit_relaxed_binop3_neon( @@ -5521,7 +7949,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3_neon( Assembler::emit_fadd, Size::S64, @@ -5536,7 +7964,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3_neon( Assembler::emit_fsub, Size::S64, @@ -5551,7 +7979,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3_neon( Assembler::emit_fmul, Size::S64, @@ -5566,7 +7994,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3_neon( Assembler::emit_fdiv, Size::S64, @@ -5576,12 +8004,12 @@ impl Machine for MachineARM64 { ImmType::None, ) } - fn f32_neg(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f32_neg(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_binop_neon(Assembler::emit_fneg, Size::S32, loc, ret, true) } - fn f32_abs(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn f32_abs(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S32, loc, Location::GPR(tmp))?; self.assembler.emit_and( @@ -5594,7 +8022,7 @@ impl Machine for MachineARM64 { self.release_gpr(tmp); Ok(()) } - fn emit_i32_copysign(&mut self, tmp1: GPR, tmp2: GPR) -> Result<(), CodegenError> { + fn emit_i32_copysign(&mut self, tmp1: GPR, tmp2: GPR) -> Result<(), CompileError> { self.assembler.emit_and( Size::S32, Location::GPR(tmp1), @@ -5614,19 +8042,19 @@ impl Machine for MachineARM64 { Location::GPR(tmp1), ) } - fn f32_sqrt(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f32_sqrt(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_binop_neon(Assembler::emit_fsqrt, Size::S32, loc, ret, true) } - fn f32_trunc(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f32_trunc(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_binop_neon(Assembler::emit_frintz, Size::S32, loc, ret, true) } - fn f32_ceil(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f32_ceil(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_binop_neon(Assembler::emit_frintp, Size::S32, loc, ret, true) } - fn f32_floor(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f32_floor(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_binop_neon(Assembler::emit_frintm, Size::S32, loc, ret, true) } - fn f32_nearest(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f32_nearest(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_binop_neon(Assembler::emit_frintn, Size::S32, loc, ret, true) } fn f32_cmp_ge( @@ -5634,7 +8062,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; self.emit_relaxed_binop_neon(Assembler::emit_fcmp, Size::S32, loc_b, loc_a, false)?; @@ -5652,7 +8080,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; self.emit_relaxed_binop_neon(Assembler::emit_fcmp, Size::S32, loc_b, loc_a, false)?; @@ -5670,7 +8098,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; self.emit_relaxed_binop_neon(Assembler::emit_fcmp, Size::S32, loc_a, loc_b, false)?; @@ -5688,7 +8116,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; self.emit_relaxed_binop_neon(Assembler::emit_fcmp, Size::S32, loc_a, loc_b, false)?; @@ -5706,7 +8134,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; self.emit_relaxed_binop_neon(Assembler::emit_fcmp, Size::S32, loc_a, loc_b, false)?; @@ -5724,7 +8152,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let dest = self.location_to_reg(Size::S32, ret, &mut temps, ImmType::None, false, None)?; self.emit_relaxed_binop_neon(Assembler::emit_fcmp, Size::S32, loc_a, loc_b, false)?; @@ -5742,7 +8170,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let old_fpcr = self.set_default_nan(&mut temps)?; self.emit_relaxed_binop3_neon( @@ -5764,7 +8192,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let mut temps = vec![]; let old_fpcr = self.set_default_nan(&mut temps)?; self.emit_relaxed_binop3_neon( @@ -5786,7 +8214,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3_neon( Assembler::emit_fadd, Size::S32, @@ -5801,7 +8229,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3_neon( Assembler::emit_fsub, Size::S32, @@ -5816,7 +8244,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3_neon( Assembler::emit_fmul, Size::S32, @@ -5831,7 +8259,7 @@ impl Machine for MachineARM64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop3_neon( Assembler::emit_fdiv, Size::S32, @@ -5846,7 +8274,7 @@ impl Machine for MachineARM64 { &self, sig: &FunctionType, calling_convention: CallingConvention, - ) -> Result { + ) -> Result { gen_std_trampoline_arm64(sig, calling_convention) } // Generates dynamic import function call trampoline for a function type. @@ -5855,7 +8283,7 @@ impl Machine for MachineARM64 { vmoffsets: &VMOffsets, sig: &FunctionType, calling_convention: CallingConvention, - ) -> Result { + ) -> Result { gen_std_dynamic_import_trampoline_arm64(vmoffsets, sig, calling_convention) } // Singlepass calls import functions through a trampoline. @@ -5865,7 +8293,7 @@ impl Machine for MachineARM64 { index: FunctionIndex, sig: &FunctionType, calling_convention: CallingConvention, - ) -> Result { + ) -> Result { gen_import_call_trampoline_arm64(vmoffsets, index, sig, calling_convention) } #[cfg(feature = "unwind")] diff --git a/lib/compiler-singlepass/src/machine_x64.rs b/lib/compiler-singlepass/src/machine_x64.rs index 2bfeaa9d6..dad625c69 100644 --- a/lib/compiler-singlepass/src/machine_x64.rs +++ b/lib/compiler-singlepass/src/machine_x64.rs @@ -15,8 +15,8 @@ use gimli::{write::CallFrameInstruction, X86_64}; use std::ops::{Deref, DerefMut}; use wasmer_compiler::wasmparser::Type as WpType; use wasmer_types::{ - CallingConvention, CpuFeature, CustomSection, CustomSectionProtection, Relocation, - RelocationKind, RelocationTarget, SectionBody, + CallingConvention, CompileError, CpuFeature, CustomSection, CustomSectionProtection, + Relocation, RelocationKind, RelocationTarget, SectionBody, Target, }; use wasmer_types::{FunctionBody, InstructionAddressMap, SourceLoc, TrapInformation}; use wasmer_types::{FunctionIndex, FunctionType, TrapCode, Type, VMOffsets}; @@ -29,14 +29,32 @@ pub struct AssemblerX64 { /// the simd instructions set on the target. /// Currently only supports SSE 4.2 and AVX pub simd_arch: Option, + /// Full Target cpu + pub target: Option, } impl AssemblerX64 { - fn new(baseaddr: usize, simd_arch: Option) -> Self { - Self { + fn new(baseaddr: usize, target: Option) -> Result { + let simd_arch = if target.is_none() { + Some(CpuFeature::SSE42) + } else { + let target = target.as_ref().unwrap(); + if target.cpu_features().contains(CpuFeature::AVX) { + Some(CpuFeature::AVX) + } else if target.cpu_features().contains(CpuFeature::SSE42) { + Some(CpuFeature::SSE42) + } else { + return Err(CompileError::UnsupportedTarget( + "x86_64 without AVX or SSE 4.2".to_string(), + )); + } + }; + + Ok(Self { inner: Assembler::new(baseaddr), simd_arch, - } + target, + }) } fn finalize(self) -> Result, DynasmError> { @@ -121,24 +139,25 @@ pub struct MachineX86_64 { } impl MachineX86_64 { - pub fn new(simd_arch: Option) -> Self { - MachineX86_64 { - assembler: AssemblerX64::new(0, simd_arch), + pub fn new(target: Option) -> Result { + let assembler = AssemblerX64::new(0, target)?; + Ok(MachineX86_64 { + assembler, used_gprs: 0, used_simd: 0, trap_table: TrapTable::default(), instructions_address_map: vec![], src_loc: 0, unwind_ops: vec![], - } + }) } pub fn emit_relaxed_binop( &mut self, - op: fn(&mut AssemblerX64, Size, Location, Location) -> Result<(), CodegenError>, + op: fn(&mut AssemblerX64, Size, Location, Location) -> Result<(), CompileError>, sz: Size, src: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { enum RelaxMode { Direct, SrcToGPR, @@ -172,27 +191,27 @@ impl MachineX86_64 { match mode { RelaxMode::SrcToGPR => { - let temp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let temp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(sz, src, Location::GPR(temp))?; op(&mut self.assembler, sz, Location::GPR(temp), dst)?; self.release_gpr(temp); } RelaxMode::DstToGPR => { - let temp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let temp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(sz, dst, Location::GPR(temp))?; op(&mut self.assembler, sz, src, Location::GPR(temp))?; self.release_gpr(temp); } RelaxMode::BothToGPR => { - let temp_src = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let temp_src = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let temp_dst = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let temp_dst = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(sz, src, Location::GPR(temp_src))?; self.move_location(sz, dst, Location::GPR(temp_dst))?; @@ -219,16 +238,16 @@ impl MachineX86_64 { } pub fn emit_relaxed_zx_sx( &mut self, - op: fn(&mut AssemblerX64, Size, Location, Size, Location) -> Result<(), CodegenError>, + op: fn(&mut AssemblerX64, Size, Location, Size, Location) -> Result<(), CompileError>, sz_src: Size, src: Location, sz_dst: Size, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match src { Location::Imm32(_) | Location::Imm64(_) => { - let tmp_src = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_src = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_mov(Size::S64, src, Location::GPR(tmp_src))?; @@ -237,8 +256,8 @@ impl MachineX86_64 { match dst { Location::Imm32(_) | Location::Imm64(_) => unreachable!(), Location::Memory(_, _) => { - let tmp_dst = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_dst = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; op( &mut self.assembler, @@ -265,8 +284,8 @@ impl MachineX86_64 { match dst { Location::Imm32(_) | Location::Imm64(_) => unreachable!(), Location::Memory(_, _) => { - let tmp_dst = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_dst = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; op( &mut self.assembler, @@ -296,14 +315,14 @@ impl MachineX86_64 { /// I32 binary operation with both operands popped from the virtual stack. fn emit_binop_i32( &mut self, - f: fn(&mut AssemblerX64, Size, Location, Location) -> Result<(), CodegenError>, + f: fn(&mut AssemblerX64, Size, Location, Location) -> Result<(), CompileError>, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { if loc_a != ret { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.emit_relaxed_mov(Size::S32, loc_a, Location::GPR(tmp))?; self.emit_relaxed_binop(f, Size::S32, loc_b, Location::GPR(tmp))?; @@ -317,14 +336,14 @@ impl MachineX86_64 { /// I64 binary operation with both operands popped from the virtual stack. fn emit_binop_i64( &mut self, - f: fn(&mut AssemblerX64, Size, Location, Location) -> Result<(), CodegenError>, + f: fn(&mut AssemblerX64, Size, Location, Location) -> Result<(), CompileError>, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { if loc_a != ret { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.emit_relaxed_mov(Size::S64, loc_a, Location::GPR(tmp))?; self.emit_relaxed_binop(f, Size::S64, loc_b, Location::GPR(tmp))?; @@ -342,7 +361,7 @@ impl MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match ret { Location::GPR(x) => { self.emit_relaxed_cmp(Size::S64, loc_b, loc_a)?; @@ -351,8 +370,8 @@ impl MachineX86_64 { .emit_and(Size::S32, Location::Imm32(0xff), Location::GPR(x))?; } Location::Memory(_, _) => { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.emit_relaxed_cmp(Size::S64, loc_b, loc_a)?; self.assembler.emit_set(c, tmp)?; @@ -370,11 +389,11 @@ impl MachineX86_64 { /// I64 shift with both operands popped from the virtual stack. fn emit_shift_i64( &mut self, - f: fn(&mut AssemblerX64, Size, Location, Location) -> Result<(), CodegenError>, + f: fn(&mut AssemblerX64, Size, Location, Location) -> Result<(), CompileError>, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.assembler .emit_mov(Size::S64, loc_b, Location::GPR(GPR::RCX))?; @@ -387,11 +406,11 @@ impl MachineX86_64 { /// Moves `loc` to a valid location for `div`/`idiv`. fn emit_relaxed_xdiv( &mut self, - op: fn(&mut AssemblerX64, Size, Location) -> Result<(), CodegenError>, + op: fn(&mut AssemblerX64, Size, Location) -> Result<(), CompileError>, sz: Size, loc: Location, integer_division_by_zero: Label, - ) -> Result { + ) -> Result { self.assembler.emit_cmp(sz, Location::Imm32(0), loc)?; self.assembler .emit_jmp(Condition::Equal, integer_division_by_zero)?; @@ -419,7 +438,7 @@ impl MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match ret { Location::GPR(x) => { self.emit_relaxed_cmp(Size::S32, loc_b, loc_a)?; @@ -428,8 +447,8 @@ impl MachineX86_64 { .emit_and(Size::S32, Location::Imm32(0xff), Location::GPR(x))?; } Location::Memory(_, _) => { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.emit_relaxed_cmp(Size::S32, loc_b, loc_a)?; self.assembler.emit_set(c, tmp)?; @@ -447,11 +466,11 @@ impl MachineX86_64 { /// I32 shift with both operands popped from the virtual stack. fn emit_shift_i32( &mut self, - f: fn(&mut AssemblerX64, Size, Location, Location) -> Result<(), CodegenError>, + f: fn(&mut AssemblerX64, Size, Location, Location) -> Result<(), CompileError>, loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.assembler .emit_mov(Size::S32, loc_b, Location::GPR(GPR::RCX))?; @@ -463,7 +482,7 @@ impl MachineX86_64 { } #[allow(clippy::too_many_arguments)] - fn memory_op Result<(), CodegenError>>( + fn memory_op Result<(), CompileError>>( &mut self, addr: Location, memarg: &MemoryImmediate, @@ -473,18 +492,19 @@ impl MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, + unaligned_atomic: Label, cb: F, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { // This function as been re-writen to use only 2 temporary register instead of 3 // without compromisong on the perfomances. // The number of memory move should be equivalent to previous 3-temp regs version // Register pressure is high on x86_64, and this is needed to be able to use // instruction that neead RAX, like cmpxchg for example - let tmp_addr = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_addr = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp2 = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp2 = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; // Reusing `tmp_addr` for temporary indirection here, since it's not used before the last reference to `{base,bound}_loc`. @@ -571,10 +591,10 @@ impl MachineX86_64 { self.release_gpr(tmp2); - let align = memarg.align; + let align = value_size as u32; if check_alignment && align != 1 { - let tmp_aligncheck = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_aligncheck = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler.emit_mov( Size::S32, @@ -583,11 +603,11 @@ impl MachineX86_64 { )?; self.assembler.emit_and( Size::S64, - Location::Imm32((align - 1).into()), + Location::Imm32(align - 1), Location::GPR(tmp_aligncheck), )?; self.assembler - .emit_jmp(Condition::NotEqual, heap_access_oob)?; + .emit_jmp(Condition::NotEqual, unaligned_atomic)?; self.release_gpr(tmp_aligncheck); } let begin = self.assembler.get_offset().0; @@ -600,7 +620,7 @@ impl MachineX86_64 { } #[allow(clippy::too_many_arguments)] - fn emit_compare_and_swap Result<(), CodegenError>>( + fn emit_compare_and_swap Result<(), CompileError>>( &mut self, loc: Location, target: Location, @@ -613,8 +633,9 @@ impl MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, + unaligned_atomic: Label, cb: F, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { if memory_sz > stack_sz { codegen_error!("singlepass emit_compare_and_swap unreachable"); } @@ -641,6 +662,7 @@ impl MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.load_address(memory_sz, Location::GPR(compare), Location::Memory(addr, 0))?; this.move_location(stack_sz, Location::GPR(compare), ret)?; @@ -671,15 +693,15 @@ impl MachineX86_64 { overflow_label: Label, nan_label: Label, succeed_label: Label, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let lower_bound = f32::to_bits(lower_bound); let upper_bound = f32::to_bits(upper_bound); - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_x = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_x = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; // Underflow. @@ -725,7 +747,7 @@ impl MachineX86_64 { reg: XMM, lower_bound: f32, upper_bound: f32, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let trap_overflow = self.assembler.get_label(); let trap_badconv = self.assembler.get_label(); let end = self.assembler.get_label(); @@ -753,10 +775,10 @@ impl MachineX86_64 { } #[allow(clippy::too_many_arguments)] fn emit_f32_int_conv_check_sat< - F1: FnOnce(&mut Self) -> Result<(), CodegenError>, - F2: FnOnce(&mut Self) -> Result<(), CodegenError>, - F3: FnOnce(&mut Self) -> Result<(), CodegenError>, - F4: FnOnce(&mut Self) -> Result<(), CodegenError>, + F1: FnOnce(&mut Self) -> Result<(), CompileError>, + F2: FnOnce(&mut Self) -> Result<(), CompileError>, + F3: FnOnce(&mut Self) -> Result<(), CompileError>, + F4: FnOnce(&mut Self) -> Result<(), CompileError>, >( &mut self, reg: XMM, @@ -766,7 +788,7 @@ impl MachineX86_64 { overflow_cb: F2, nan_cb: Option, convert_cb: F4, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { // As an optimization nan_cb is optional, and when set to None we turn // use 'underflow' as the 'nan' label. This is useful for callers who // set the return value to zero for both underflow and nan. @@ -820,15 +842,15 @@ impl MachineX86_64 { overflow_label: Label, nan_label: Label, succeed_label: Label, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let lower_bound = f64::to_bits(lower_bound); let upper_bound = f64::to_bits(upper_bound); - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_x = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_x = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; // Underflow. @@ -873,7 +895,7 @@ impl MachineX86_64 { reg: XMM, lower_bound: f64, upper_bound: f64, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let trap_overflow = self.assembler.get_label(); let trap_badconv = self.assembler.get_label(); let end = self.assembler.get_label(); @@ -898,10 +920,10 @@ impl MachineX86_64 { } #[allow(clippy::too_many_arguments)] fn emit_f64_int_conv_check_sat< - F1: FnOnce(&mut Self) -> Result<(), CodegenError>, - F2: FnOnce(&mut Self) -> Result<(), CodegenError>, - F3: FnOnce(&mut Self) -> Result<(), CodegenError>, - F4: FnOnce(&mut Self) -> Result<(), CodegenError>, + F1: FnOnce(&mut Self) -> Result<(), CompileError>, + F2: FnOnce(&mut Self) -> Result<(), CompileError>, + F3: FnOnce(&mut Self) -> Result<(), CompileError>, + F4: FnOnce(&mut Self) -> Result<(), CompileError>, >( &mut self, reg: XMM, @@ -911,7 +933,7 @@ impl MachineX86_64 { overflow_cb: F2, nan_cb: Option, convert_cb: F4, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { // As an optimization nan_cb is optional, and when set to None we turn // use 'underflow' as the 'nan' label. This is useful for callers who // set the return value to zero for both underflow and nan. @@ -957,11 +979,11 @@ impl MachineX86_64 { /// Moves `src1` and `src2` to valid locations and possibly adds a layer of indirection for `dst` for AVX instructions. fn emit_relaxed_avx( &mut self, - op: fn(&mut AssemblerX64, XMM, XMMOrMemory, XMM) -> Result<(), CodegenError>, + op: fn(&mut AssemblerX64, XMM, XMMOrMemory, XMM) -> Result<(), CompileError>, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx_base( |this, src1, src2, dst| op(&mut this.assembler, src1, src2, dst), src1, @@ -972,25 +994,25 @@ impl MachineX86_64 { /// Moves `src1` and `src2` to valid locations and possibly adds a layer of indirection for `dst` for AVX instructions. fn emit_relaxed_avx_base< - F: FnOnce(&mut Self, XMM, XMMOrMemory, XMM) -> Result<(), CodegenError>, + F: FnOnce(&mut Self, XMM, XMMOrMemory, XMM) -> Result<(), CompileError>, >( &mut self, op: F, src1: Location, src2: Location, dst: Location, - ) -> Result<(), CodegenError> { - let tmp1 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + ) -> Result<(), CompileError> { + let tmp1 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmp2 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp2 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmp3 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp3 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmpg = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmpg = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; let src1 = match src1 { @@ -1063,12 +1085,12 @@ impl MachineX86_64 { Ok(()) } - fn convert_i64_f64_u_s(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn convert_i64_f64_u_s(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S64, loc, Location::SIMD(tmp_in))?; @@ -1087,19 +1109,19 @@ impl MachineX86_64 { Location::GPR(tmp_out), ) }, - None:: Result<(), CodegenError>>, + None:: Result<(), CompileError>>, |this| { if this.assembler.arch_has_itruncf() { this.assembler.arch_emit_i64_trunc_uf64(tmp_in, tmp_out) } else { - let tmp = this.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_x1 = this.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_x1 = this.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmp_x2 = this.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_x2 = this.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; this.assembler.emit_mov( @@ -1151,13 +1173,13 @@ impl MachineX86_64 { self.release_gpr(tmp_out); Ok(()) } - fn convert_i64_f64_u_u(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn convert_i64_f64_u_u(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { if self.assembler.arch_has_itruncf() { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S64, loc, Location::SIMD(tmp_in))?; self.assembler.arch_emit_i64_trunc_uf64(tmp_in, tmp_out)?; @@ -1165,24 +1187,24 @@ impl MachineX86_64 { self.release_simd(tmp_in); self.release_gpr(tmp_out); } else { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; // xmm2 self.emit_relaxed_mov(Size::S64, loc, Location::SIMD(tmp_in))?; self.emit_f64_int_conv_check_trap(tmp_in, GEF64_LT_U64_MIN, LEF64_GT_U64_MAX)?; - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; // r15 - let tmp_x1 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_x1 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; // xmm1 - let tmp_x2 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_x2 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; // xmm3 self.move_location( @@ -1218,12 +1240,12 @@ impl MachineX86_64 { } Ok(()) } - fn convert_i64_f64_s_s(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn convert_i64_f64_s_s(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S64, loc, Location::SIMD(tmp_in))?; @@ -1265,13 +1287,13 @@ impl MachineX86_64 { self.release_gpr(tmp_out); Ok(()) } - fn convert_i64_f64_s_u(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn convert_i64_f64_s_u(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { if self.assembler.arch_has_itruncf() { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S64, loc, Location::SIMD(tmp_in))?; self.assembler.arch_emit_i64_trunc_sf64(tmp_in, tmp_out)?; @@ -1279,11 +1301,11 @@ impl MachineX86_64 { self.release_simd(tmp_in); self.release_gpr(tmp_out); } else { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S64, loc, Location::SIMD(tmp_in))?; @@ -1298,12 +1320,12 @@ impl MachineX86_64 { } Ok(()) } - fn convert_i32_f64_s_s(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn convert_i32_f64_s_s(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; let real_in = match loc { @@ -1357,13 +1379,13 @@ impl MachineX86_64 { self.release_gpr(tmp_out); Ok(()) } - fn convert_i32_f64_s_u(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn convert_i32_f64_s_u(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { if self.assembler.arch_has_itruncf() { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S64, loc, Location::SIMD(tmp_in))?; self.assembler.arch_emit_i32_trunc_sf64(tmp_in, tmp_out)?; @@ -1371,11 +1393,11 @@ impl MachineX86_64 { self.release_simd(tmp_in); self.release_gpr(tmp_out); } else { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; let real_in = match loc { @@ -1402,12 +1424,12 @@ impl MachineX86_64 { } Ok(()) } - fn convert_i32_f64_u_s(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn convert_i32_f64_u_s(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S64, loc, Location::SIMD(tmp_in))?; @@ -1426,7 +1448,7 @@ impl MachineX86_64 { Location::GPR(tmp_out), ) }, - None:: Result<(), CodegenError>>, + None:: Result<(), CompileError>>, |this| { if this.assembler.arch_has_itruncf() { this.assembler.arch_emit_i32_trunc_uf64(tmp_in, tmp_out) @@ -1443,13 +1465,13 @@ impl MachineX86_64 { self.release_gpr(tmp_out); Ok(()) } - fn convert_i32_f64_u_u(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn convert_i32_f64_u_u(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { if self.assembler.arch_has_itruncf() { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S64, loc, Location::SIMD(tmp_in))?; self.assembler.arch_emit_i32_trunc_uf64(tmp_in, tmp_out)?; @@ -1457,11 +1479,11 @@ impl MachineX86_64 { self.release_simd(tmp_in); self.release_gpr(tmp_out); } else { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S64, loc, Location::SIMD(tmp_in))?; @@ -1476,12 +1498,12 @@ impl MachineX86_64 { } Ok(()) } - fn convert_i64_f32_u_s(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn convert_i64_f32_u_s(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S32, loc, Location::SIMD(tmp_in))?; @@ -1500,19 +1522,19 @@ impl MachineX86_64 { Location::GPR(tmp_out), ) }, - None:: Result<(), CodegenError>>, + None:: Result<(), CompileError>>, |this| { if this.assembler.arch_has_itruncf() { this.assembler.arch_emit_i64_trunc_uf32(tmp_in, tmp_out) } else { - let tmp = this.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = this.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_x1 = this.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_x1 = this.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmp_x2 = this.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_x2 = this.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; this.assembler.emit_mov( @@ -1564,13 +1586,13 @@ impl MachineX86_64 { self.release_gpr(tmp_out); Ok(()) } - fn convert_i64_f32_u_u(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn convert_i64_f32_u_u(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { if self.assembler.arch_has_itruncf() { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S32, loc, Location::SIMD(tmp_in))?; self.assembler.arch_emit_i64_trunc_uf32(tmp_in, tmp_out)?; @@ -1578,24 +1600,24 @@ impl MachineX86_64 { self.release_simd(tmp_in); self.release_gpr(tmp_out); } else { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; // xmm2 self.emit_relaxed_mov(Size::S32, loc, Location::SIMD(tmp_in))?; self.emit_f32_int_conv_check_trap(tmp_in, GEF32_LT_U64_MIN, LEF32_GT_U64_MAX)?; - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; // r15 - let tmp_x1 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_x1 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; // xmm1 - let tmp_x2 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_x2 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; // xmm3 self.move_location( @@ -1631,12 +1653,12 @@ impl MachineX86_64 { } Ok(()) } - fn convert_i64_f32_s_s(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn convert_i64_f32_s_s(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S32, loc, Location::SIMD(tmp_in))?; @@ -1678,13 +1700,13 @@ impl MachineX86_64 { self.release_gpr(tmp_out); Ok(()) } - fn convert_i64_f32_s_u(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn convert_i64_f32_s_u(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { if self.assembler.arch_has_itruncf() { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S32, loc, Location::SIMD(tmp_in))?; self.assembler.arch_emit_i64_trunc_sf32(tmp_in, tmp_out)?; @@ -1692,11 +1714,11 @@ impl MachineX86_64 { self.release_simd(tmp_in); self.release_gpr(tmp_out); } else { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S32, loc, Location::SIMD(tmp_in))?; @@ -1710,12 +1732,12 @@ impl MachineX86_64 { } Ok(()) } - fn convert_i32_f32_s_s(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn convert_i32_f32_s_s(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S32, loc, Location::SIMD(tmp_in))?; @@ -1757,13 +1779,13 @@ impl MachineX86_64 { self.release_gpr(tmp_out); Ok(()) } - fn convert_i32_f32_s_u(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn convert_i32_f32_s_u(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { if self.assembler.arch_has_itruncf() { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S32, loc, Location::SIMD(tmp_in))?; self.assembler.arch_emit_i32_trunc_sf32(tmp_in, tmp_out)?; @@ -1771,11 +1793,11 @@ impl MachineX86_64 { self.release_simd(tmp_in); self.release_gpr(tmp_out); } else { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S32, loc, Location::SIMD(tmp_in))?; @@ -1790,12 +1812,12 @@ impl MachineX86_64 { } Ok(()) } - fn convert_i32_f32_u_s(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn convert_i32_f32_u_s(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S32, loc, Location::SIMD(tmp_in))?; self.emit_f32_int_conv_check_sat( @@ -1813,7 +1835,7 @@ impl MachineX86_64 { Location::GPR(tmp_out), ) }, - None:: Result<(), CodegenError>>, + None:: Result<(), CompileError>>, |this| { if this.assembler.arch_has_itruncf() { this.assembler.arch_emit_i32_trunc_uf32(tmp_in, tmp_out) @@ -1830,13 +1852,13 @@ impl MachineX86_64 { self.release_gpr(tmp_out); Ok(()) } - fn convert_i32_f32_u_u(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn convert_i32_f32_u_u(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { if self.assembler.arch_has_itruncf() { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S32, loc, Location::SIMD(tmp_in))?; self.assembler.arch_emit_i32_trunc_uf32(tmp_in, tmp_out)?; @@ -1844,11 +1866,11 @@ impl MachineX86_64 { self.release_simd(tmp_in); self.release_gpr(tmp_out); } else { - let tmp_out = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_out = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmp_in = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp_in = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S32, loc, Location::SIMD(tmp_in))?; self.emit_f32_int_conv_check_trap(tmp_in, GEF32_LT_U32_MIN, LEF32_GT_U32_MAX)?; @@ -1868,7 +1890,7 @@ impl MachineX86_64 { sz: Size, src: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop(AssemblerX64::emit_xchg, sz, src, dst) } @@ -1894,11 +1916,11 @@ impl MachineX86_64 { self.used_simd &= !(1 << r.into_index()); ret } - fn emit_unwind_op(&mut self, op: UnwindOps) -> Result<(), CodegenError> { + fn emit_unwind_op(&mut self, op: UnwindOps) -> Result<(), CompileError> { self.unwind_ops.push((self.get_offset().0, op)); Ok(()) } - fn emit_illegal_op_internal(&mut self, trap: TrapCode) -> Result<(), CodegenError> { + fn emit_illegal_op_internal(&mut self, trap: TrapCode) -> Result<(), CompileError> { let v = trap as u8; self.assembler.emit_ud1_payload(v) } @@ -1980,13 +2002,13 @@ impl Machine for MachineX86_64 { self.used_gprs_insert(gpr); } - fn push_used_gpr(&mut self, used_gprs: &[GPR]) -> Result { + fn push_used_gpr(&mut self, used_gprs: &[GPR]) -> Result { for r in used_gprs.iter() { self.assembler.emit_push(Size::S64, Location::GPR(*r))?; } Ok(used_gprs.len() * 8) } - fn pop_used_gpr(&mut self, used_gprs: &[GPR]) -> Result<(), CodegenError> { + fn pop_used_gpr(&mut self, used_gprs: &[GPR]) -> Result<(), CompileError> { for r in used_gprs.iter().rev() { self.assembler.emit_pop(Size::S64, Location::GPR(*r))?; } @@ -2035,7 +2057,7 @@ impl Machine for MachineX86_64 { assert!(self.used_simd_remove(&simd)); } - fn push_used_simd(&mut self, used_xmms: &[XMM]) -> Result { + fn push_used_simd(&mut self, used_xmms: &[XMM]) -> Result { self.adjust_stack((used_xmms.len() * 8) as u32)?; for (i, r) in used_xmms.iter().enumerate() { @@ -2048,7 +2070,7 @@ impl Machine for MachineX86_64 { Ok(used_xmms.len() * 8) } - fn pop_used_simd(&mut self, used_xmms: &[XMM]) -> Result<(), CodegenError> { + fn pop_used_simd(&mut self, used_xmms: &[XMM]) -> Result<(), CompileError> { for (i, r) in used_xmms.iter().enumerate() { self.move_location( Size::S64, @@ -2134,7 +2156,7 @@ impl Machine for MachineX86_64 { } // Adjust stack for locals - fn adjust_stack(&mut self, delta_stack_offset: u32) -> Result<(), CodegenError> { + fn adjust_stack(&mut self, delta_stack_offset: u32) -> Result<(), CompileError> { self.assembler.emit_sub( Size::S64, Location::Imm32(delta_stack_offset), @@ -2142,14 +2164,14 @@ impl Machine for MachineX86_64 { ) } // restore stack - fn restore_stack(&mut self, delta_stack_offset: u32) -> Result<(), CodegenError> { + fn restore_stack(&mut self, delta_stack_offset: u32) -> Result<(), CompileError> { self.assembler.emit_add( Size::S64, Location::Imm32(delta_stack_offset), Location::GPR(GPR::RSP), ) } - fn pop_stack_locals(&mut self, delta_stack_offset: u32) -> Result<(), CodegenError> { + fn pop_stack_locals(&mut self, delta_stack_offset: u32) -> Result<(), CompileError> { self.assembler.emit_add( Size::S64, Location::Imm32(delta_stack_offset), @@ -2162,7 +2184,7 @@ impl Machine for MachineX86_64 { _size: Size, loc: Location, dest: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match loc { Location::Imm64(_) | Location::Memory(_, _) | Location::Memory2(_, _, _, _) => { let tmp = self.pick_temp_gpr(); @@ -2183,7 +2205,7 @@ impl Machine for MachineX86_64 { } // Zero a location that is 32bits - fn zero_location(&mut self, size: Size, location: Location) -> Result<(), CodegenError> { + fn zero_location(&mut self, size: Size, location: Location) -> Result<(), CompileError> { self.assembler.emit_mov(size, Location::Imm32(0), location) } @@ -2209,7 +2231,7 @@ impl Machine for MachineX86_64 { } } // Move a local to the stack - fn move_local(&mut self, stack_offset: i32, location: Location) -> Result<(), CodegenError> { + fn move_local(&mut self, stack_offset: i32, location: Location) -> Result<(), CompileError> { self.assembler.emit_mov( Size::S64, location, @@ -2331,14 +2353,14 @@ impl Machine for MachineX86_64 { size: Size, source: Location, dest: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match source { Location::GPR(_) => self.assembler.emit_mov(size, source, dest), Location::Memory(_, _) => match dest { Location::GPR(_) | Location::SIMD(_) => self.assembler.emit_mov(size, source, dest), Location::Memory(_, _) | Location::Memory2(_, _, _, _) => { - let tmp = self.pick_temp_gpr().ok_or(CodegenError { - message: "singlepass can't pick a temp gpr".to_string(), + let tmp = self.pick_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass can't pick a temp gpr".to_owned()) })?; self.assembler.emit_mov(size, source, Location::GPR(tmp))?; self.assembler.emit_mov(size, Location::GPR(tmp), dest) @@ -2348,8 +2370,8 @@ impl Machine for MachineX86_64 { Location::Memory2(_, _, _, _) => match dest { Location::GPR(_) | Location::SIMD(_) => self.assembler.emit_mov(size, source, dest), Location::Memory(_, _) | Location::Memory2(_, _, _, _) => { - let tmp = self.pick_temp_gpr().ok_or(CodegenError { - message: "singlepass can't pick a temp gpr".to_string(), + let tmp = self.pick_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass can't pick a temp gpr".to_owned()) })?; self.assembler.emit_mov(size, source, Location::GPR(tmp))?; self.assembler.emit_mov(size, Location::GPR(tmp), dest) @@ -2359,8 +2381,8 @@ impl Machine for MachineX86_64 { Location::Imm8(_) | Location::Imm32(_) | Location::Imm64(_) => match dest { Location::GPR(_) | Location::SIMD(_) => self.assembler.emit_mov(size, source, dest), Location::Memory(_, _) | Location::Memory2(_, _, _, _) => { - let tmp = self.pick_temp_gpr().ok_or(CodegenError { - message: "singlepass can't pick a temp gpr".to_string(), + let tmp = self.pick_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass can't pick a temp gpr".to_owned()) })?; self.assembler.emit_mov(size, source, Location::GPR(tmp))?; self.assembler.emit_mov(size, Location::GPR(tmp), dest) @@ -2379,11 +2401,11 @@ impl Machine for MachineX86_64 { source: Location, size_op: Size, dest: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { let dst = match dest { Location::Memory(_, _) | Location::Memory2(_, _, _, _) => { - Location::GPR(self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + Location::GPR(self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?) } Location::GPR(_) | Location::SIMD(_) => dest, @@ -2393,7 +2415,8 @@ impl Machine for MachineX86_64 { Location::GPR(_) | Location::Memory(_, _) | Location::Memory2(_, _, _, _) - | Location::Imm32(_) => match size_val { + | Location::Imm32(_) + | Location::Imm64(_) => match size_val { Size::S32 | Size::S64 => self.assembler.emit_mov(size_val, source, dst), Size::S16 | Size::S8 => { if signed { @@ -2422,7 +2445,7 @@ impl Machine for MachineX86_64 { size: Size, reg: Location, mem: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match reg { Location::GPR(_) => { match mem { @@ -2445,7 +2468,7 @@ impl Machine for MachineX86_64 { &mut self, init_stack_loc_cnt: u64, last_stack_loc: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { // Since these assemblies take up to 24 bytes, if more than 2 slots are initialized, then they are smaller. self.assembler.emit_mov( Size::S64, @@ -2459,7 +2482,7 @@ impl Machine for MachineX86_64 { self.assembler.emit_rep_stosq() } // Restore save_area - fn restore_saved_area(&mut self, saved_area_offset: i32) -> Result<(), CodegenError> { + fn restore_saved_area(&mut self, saved_area_offset: i32) -> Result<(), CompileError> { self.assembler.emit_lea( Size::S64, Location::Memory(GPR::RBP, -saved_area_offset), @@ -2467,7 +2490,7 @@ impl Machine for MachineX86_64 { ) } // Pop a location - fn pop_location(&mut self, location: Location) -> Result<(), CodegenError> { + fn pop_location(&mut self, location: Location) -> Result<(), CompileError> { self.assembler.emit_pop(Size::S64, location) } // Create a new `MachineState` with default values. @@ -2484,19 +2507,19 @@ impl Machine for MachineX86_64 { self.assembler.get_offset() } - fn finalize_function(&mut self) -> Result<(), CodegenError> { + fn finalize_function(&mut self) -> Result<(), CompileError> { self.assembler.finalize_function()?; Ok(()) } - fn emit_function_prolog(&mut self) -> Result<(), CodegenError> { + fn emit_function_prolog(&mut self) -> Result<(), CompileError> { self.emit_push(Size::S64, Location::GPR(GPR::RBP))?; self.emit_unwind_op(UnwindOps::PushFP { up_to_sp: 16 })?; self.move_location(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RBP))?; self.emit_unwind_op(UnwindOps::DefineNewFrame) } - fn emit_function_epilog(&mut self) -> Result<(), CodegenError> { + fn emit_function_epilog(&mut self) -> Result<(), CompileError> { self.move_location(Size::S64, Location::GPR(GPR::RBP), Location::GPR(GPR::RSP))?; self.emit_pop(Size::S64, Location::GPR(GPR::RBP)) } @@ -2506,7 +2529,7 @@ impl Machine for MachineX86_64 { ty: WpType, canonicalize: bool, loc: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { if canonicalize { self.canonicalize_nan( match ty { @@ -2522,7 +2545,7 @@ impl Machine for MachineX86_64 { } } - fn emit_function_return_float(&mut self) -> Result<(), CodegenError> { + fn emit_function_return_float(&mut self) -> Result<(), CompileError> { self.move_location( Size::S64, Location::GPR(GPR::RAX), @@ -2538,20 +2561,20 @@ impl Machine for MachineX86_64 { sz: Size, input: Location, output: Location, - ) -> Result<(), CodegenError> { - let tmp1 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + ) -> Result<(), CompileError> { + let tmp1 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmp2 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp2 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmp3 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp3 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(sz, input, Location::SIMD(tmp1))?; - let tmpg1 = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmpg1 = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; match sz { @@ -2591,7 +2614,7 @@ impl Machine for MachineX86_64 { Ok(()) } - fn emit_illegal_op(&mut self, trap: TrapCode) -> Result<(), CodegenError> { + fn emit_illegal_op(&mut self, trap: TrapCode) -> Result<(), CompileError> { // code below is kept as a reference on how to emit illegal op with trap info // without an Undefined opcode with payload /* @@ -2612,16 +2635,16 @@ impl Machine for MachineX86_64 { fn get_label(&mut self) -> Label { self.assembler.new_dynamic_label() } - fn emit_label(&mut self, label: Label) -> Result<(), CodegenError> { + fn emit_label(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_label(label) } fn get_grp_for_call(&self) -> GPR { GPR::RAX } - fn emit_call_register(&mut self, reg: GPR) -> Result<(), CodegenError> { + fn emit_call_register(&mut self, reg: GPR) -> Result<(), CompileError> { self.assembler.emit_call_register(reg) } - fn emit_call_label(&mut self, label: Label) -> Result<(), CodegenError> { + fn emit_call_label(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_call_label(label) } fn get_gpr_for_ret(&self) -> GPR { @@ -2638,16 +2661,16 @@ impl Machine for MachineX86_64 { fn arch_emit_indirect_call_with_trampoline( &mut self, location: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.assembler .arch_emit_indirect_call_with_trampoline(location) } - fn emit_debug_breakpoint(&mut self) -> Result<(), CodegenError> { + fn emit_debug_breakpoint(&mut self) -> Result<(), CompileError> { self.assembler.emit_bkpt() } - fn emit_call_location(&mut self, location: Location) -> Result<(), CodegenError> { + fn emit_call_location(&mut self, location: Location) -> Result<(), CompileError> { self.assembler.emit_call_location(location) } @@ -2656,7 +2679,7 @@ impl Machine for MachineX86_64 { size: Size, source: Location, dest: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.assembler.emit_lea(size, source, dest) } // logic @@ -2666,7 +2689,7 @@ impl Machine for MachineX86_64 { source: Location, dest: Location, _flags: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.assembler.emit_and(size, source, dest) } fn location_xor( @@ -2675,7 +2698,7 @@ impl Machine for MachineX86_64 { source: Location, dest: Location, _flags: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.assembler.emit_xor(size, source, dest) } fn location_or( @@ -2684,7 +2707,7 @@ impl Machine for MachineX86_64 { source: Location, dest: Location, _flags: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.assembler.emit_or(size, source, dest) } fn location_test( @@ -2692,7 +2715,7 @@ impl Machine for MachineX86_64 { size: Size, source: Location, dest: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.assembler.emit_test(size, source, dest) } // math @@ -2702,7 +2725,7 @@ impl Machine for MachineX86_64 { source: Location, dest: Location, _flags: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.assembler.emit_add(size, source, dest) } fn location_sub( @@ -2711,7 +2734,7 @@ impl Machine for MachineX86_64 { source: Location, dest: Location, _flags: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.assembler.emit_sub(size, source, dest) } fn location_cmp( @@ -2719,42 +2742,42 @@ impl Machine for MachineX86_64 { size: Size, source: Location, dest: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.assembler.emit_cmp(size, source, dest) } // (un)conditionnal jmp // (un)conditionnal jmp - fn jmp_unconditionnal(&mut self, label: Label) -> Result<(), CodegenError> { + fn jmp_unconditionnal(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_jmp(Condition::None, label) } - fn jmp_on_equal(&mut self, label: Label) -> Result<(), CodegenError> { + fn jmp_on_equal(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_jmp(Condition::Equal, label) } - fn jmp_on_different(&mut self, label: Label) -> Result<(), CodegenError> { + fn jmp_on_different(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_jmp(Condition::NotEqual, label) } - fn jmp_on_above(&mut self, label: Label) -> Result<(), CodegenError> { + fn jmp_on_above(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_jmp(Condition::Above, label) } - fn jmp_on_aboveequal(&mut self, label: Label) -> Result<(), CodegenError> { + fn jmp_on_aboveequal(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_jmp(Condition::AboveEqual, label) } - fn jmp_on_belowequal(&mut self, label: Label) -> Result<(), CodegenError> { + fn jmp_on_belowequal(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_jmp(Condition::BelowEqual, label) } - fn jmp_on_overflow(&mut self, label: Label) -> Result<(), CodegenError> { + fn jmp_on_overflow(&mut self, label: Label) -> Result<(), CompileError> { self.assembler.emit_jmp(Condition::Carry, label) } // jmp table - fn emit_jmp_to_jumptable(&mut self, label: Label, cond: Location) -> Result<(), CodegenError> { - let tmp1 = self.pick_temp_gpr().ok_or(CodegenError { - message: "singlepass can't pick a temp gpr".to_string(), - })?; + fn emit_jmp_to_jumptable(&mut self, label: Label, cond: Location) -> Result<(), CompileError> { + let tmp1 = self + .pick_temp_gpr() + .ok_or_else(|| CompileError::Codegen("singlepass can't pick a temp gpr".to_owned()))?; self.reserve_gpr(tmp1); - let tmp2 = self.pick_temp_gpr().ok_or(CodegenError { - message: "singlepass can't pick a temp gpr".to_string(), - })?; + let tmp2 = self + .pick_temp_gpr() + .ok_or_else(|| CompileError::Codegen("singlepass can't pick a temp gpr".to_owned()))?; self.reserve_gpr(tmp2); self.assembler.emit_lea_label(label, Location::GPR(tmp1))?; @@ -2771,7 +2794,7 @@ impl Machine for MachineX86_64 { Ok(()) } - fn align_for_loop(&mut self) -> Result<(), CodegenError> { + fn align_for_loop(&mut self) -> Result<(), CompileError> { // Pad with NOPs to the next 16-byte boundary. // Here we don't use the dynasm `.align 16` attribute because it pads the alignment with single-byte nops // which may lead to efficiency problems. @@ -2785,18 +2808,18 @@ impl Machine for MachineX86_64 { Ok(()) } - fn emit_ret(&mut self) -> Result<(), CodegenError> { + fn emit_ret(&mut self) -> Result<(), CompileError> { self.assembler.emit_ret() } - fn emit_push(&mut self, size: Size, loc: Location) -> Result<(), CodegenError> { + fn emit_push(&mut self, size: Size, loc: Location) -> Result<(), CompileError> { self.assembler.emit_push(size, loc) } - fn emit_pop(&mut self, size: Size, loc: Location) -> Result<(), CodegenError> { + fn emit_pop(&mut self, size: Size, loc: Location) -> Result<(), CompileError> { self.assembler.emit_pop(size, loc) } - fn emit_memory_fence(&mut self) -> Result<(), CodegenError> { + fn emit_memory_fence(&mut self) -> Result<(), CompileError> { // nothing on x86_64 Ok(()) } @@ -2808,12 +2831,12 @@ impl Machine for MachineX86_64 { source: Location, size_op: Size, dest: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.move_location_extend(size_val, signed, source, size_op, dest)?; self.assembler.emit_neg(size_val, dest) } - fn emit_imul_imm32(&mut self, size: Size, imm32: u32, gpr: GPR) -> Result<(), CodegenError> { + fn emit_imul_imm32(&mut self, size: Size, imm32: u32, gpr: GPR) -> Result<(), CompileError> { match size { Size::S64 => self.assembler.emit_imul_imm32_gpr64(imm32, gpr), _ => { @@ -2828,7 +2851,7 @@ impl Machine for MachineX86_64 { sz: Size, src: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop(AssemblerX64::emit_mov, sz, src, dst) } fn emit_relaxed_cmp( @@ -2836,7 +2859,7 @@ impl Machine for MachineX86_64 { sz: Size, src: Location, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_binop(AssemblerX64::emit_cmp, sz, src, dst) } fn emit_relaxed_zero_extension( @@ -2845,7 +2868,7 @@ impl Machine for MachineX86_64 { src: Location, sz_dst: Size, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { if (sz_src == Size::S32 || sz_src == Size::S64) && sz_dst == Size::S64 { self.emit_relaxed_binop(AssemblerX64::emit_mov, sz_src, src, dst) } else { @@ -2858,7 +2881,7 @@ impl Machine for MachineX86_64 { src: Location, sz_dst: Size, dst: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_zx_sx(AssemblerX64::emit_movsx, sz_src, src, sz_dst, dst) } @@ -2867,7 +2890,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_binop_i32(AssemblerX64::emit_add, loc_a, loc_b, ret) } fn emit_binop_sub32( @@ -2875,7 +2898,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_binop_i32(AssemblerX64::emit_sub, loc_a, loc_b, ret) } fn emit_binop_mul32( @@ -2883,7 +2906,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_binop_i32(AssemblerX64::emit_imul, loc_a, loc_b, ret) } fn emit_binop_udiv32( @@ -2893,7 +2916,7 @@ impl Machine for MachineX86_64 { ret: Location, integer_division_by_zero: Label, _integer_overflow: Label, - ) -> Result { + ) -> Result { // We assume that RAX and RDX are temporary registers here. self.assembler .emit_mov(Size::S32, loc_a, Location::GPR(GPR::RAX))?; @@ -2916,7 +2939,7 @@ impl Machine for MachineX86_64 { ret: Location, integer_division_by_zero: Label, _integer_overflow: Label, - ) -> Result { + ) -> Result { // We assume that RAX and RDX are temporary registers here. self.assembler .emit_mov(Size::S32, loc_a, Location::GPR(GPR::RAX))?; @@ -2938,7 +2961,7 @@ impl Machine for MachineX86_64 { ret: Location, integer_division_by_zero: Label, _integer_overflow: Label, - ) -> Result { + ) -> Result { // We assume that RAX and RDX are temporary registers here. self.assembler .emit_mov(Size::S32, loc_a, Location::GPR(GPR::RAX))?; @@ -2961,7 +2984,7 @@ impl Machine for MachineX86_64 { ret: Location, integer_division_by_zero: Label, _integer_overflow: Label, - ) -> Result { + ) -> Result { // We assume that RAX and RDX are temporary registers here. let normal_path = self.assembler.get_label(); let end = self.assembler.get_label(); @@ -2994,7 +3017,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_binop_i32(AssemblerX64::emit_and, loc_a, loc_b, ret) } fn emit_binop_or32( @@ -3002,7 +3025,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_binop_i32(AssemblerX64::emit_or, loc_a, loc_b, ret) } fn emit_binop_xor32( @@ -3010,7 +3033,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_binop_i32(AssemblerX64::emit_xor, loc_a, loc_b, ret) } fn i32_cmp_ge_s( @@ -3018,7 +3041,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::GreaterEqual, loc_a, loc_b, ret) } fn i32_cmp_gt_s( @@ -3026,7 +3049,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Greater, loc_a, loc_b, ret) } fn i32_cmp_le_s( @@ -3034,7 +3057,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::LessEqual, loc_a, loc_b, ret) } fn i32_cmp_lt_s( @@ -3042,7 +3065,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Less, loc_a, loc_b, ret) } fn i32_cmp_ge_u( @@ -3050,7 +3073,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::AboveEqual, loc_a, loc_b, ret) } fn i32_cmp_gt_u( @@ -3058,7 +3081,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Above, loc_a, loc_b, ret) } fn i32_cmp_le_u( @@ -3066,7 +3089,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::BelowEqual, loc_a, loc_b, ret) } fn i32_cmp_lt_u( @@ -3074,7 +3097,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Below, loc_a, loc_b, ret) } fn i32_cmp_ne( @@ -3082,7 +3105,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::NotEqual, loc_a, loc_b, ret) } fn i32_cmp_eq( @@ -3090,14 +3113,14 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i32_dynamic_b(Condition::Equal, loc_a, loc_b, ret) } - fn i32_clz(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn i32_clz(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { let src = match loc { Location::Imm32(_) | Location::Memory(_, _) => { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S32, loc, Location::GPR(tmp))?; tmp @@ -3108,8 +3131,8 @@ impl Machine for MachineX86_64 { } }; let dst = match ret { - Location::Memory(_, _) => self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + Location::Memory(_, _) => self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?, Location::GPR(reg) => reg, _ => { @@ -3147,11 +3170,11 @@ impl Machine for MachineX86_64 { }; Ok(()) } - fn i32_ctz(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn i32_ctz(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { let src = match loc { Location::Imm32(_) | Location::Memory(_, _) => { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S32, loc, Location::GPR(tmp))?; tmp @@ -3162,8 +3185,8 @@ impl Machine for MachineX86_64 { } }; let dst = match ret { - Location::Memory(_, _) => self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + Location::Memory(_, _) => self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?, Location::GPR(reg) => reg, _ => { @@ -3200,16 +3223,16 @@ impl Machine for MachineX86_64 { }; Ok(()) } - fn i32_popcnt(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn i32_popcnt(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { match loc { Location::Imm32(_) => { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S32, loc, Location::GPR(tmp))?; if let Location::Memory(_, _) = ret { - let out_tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let out_tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler.emit_popcnt( Size::S32, @@ -3226,8 +3249,8 @@ impl Machine for MachineX86_64 { } Location::Memory(_, _) | Location::GPR(_) => { if let Location::Memory(_, _) = ret { - let out_tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let out_tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_popcnt(Size::S32, loc, Location::GPR(out_tmp))?; @@ -3248,7 +3271,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_shift_i32(AssemblerX64::emit_shl, loc_a, loc_b, ret) } fn i32_shr( @@ -3256,7 +3279,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_shift_i32(AssemblerX64::emit_shr, loc_a, loc_b, ret) } fn i32_sar( @@ -3264,7 +3287,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_shift_i32(AssemblerX64::emit_sar, loc_a, loc_b, ret) } fn i32_rol( @@ -3272,7 +3295,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_shift_i32(AssemblerX64::emit_rol, loc_a, loc_b, ret) } fn i32_ror( @@ -3280,7 +3303,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_shift_i32(AssemblerX64::emit_ror, loc_a, loc_b, ret) } fn i32_load( @@ -3292,7 +3315,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -3302,6 +3326,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_binop( AssemblerX64::emit_mov, @@ -3321,7 +3346,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -3331,6 +3357,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_zx_sx( AssemblerX64::emit_movzx, @@ -3351,7 +3378,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -3361,6 +3389,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_zx_sx( AssemblerX64::emit_movsx, @@ -3381,7 +3410,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -3391,6 +3421,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_zx_sx( AssemblerX64::emit_movzx, @@ -3411,7 +3442,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -3421,6 +3453,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_zx_sx( AssemblerX64::emit_movsx, @@ -3441,7 +3474,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -3451,6 +3485,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_mov(Size::S32, Location::Memory(addr, 0), ret), ) } @@ -3463,7 +3498,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -3473,6 +3509,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_zero_extension( Size::S8, @@ -3492,7 +3529,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -3502,6 +3540,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_zero_extension( Size::S16, @@ -3521,7 +3560,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -3531,6 +3571,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_binop( AssemblerX64::emit_mov, @@ -3550,7 +3591,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -3560,6 +3602,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_binop( AssemblerX64::emit_mov, @@ -3579,7 +3622,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -3589,6 +3633,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_binop( AssemblerX64::emit_mov, @@ -3611,7 +3656,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -3621,6 +3667,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_binop( AssemblerX64::emit_mov, @@ -3640,7 +3687,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -3650,6 +3698,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_binop( AssemblerX64::emit_mov, @@ -3669,7 +3718,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -3679,6 +3729,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_binop( AssemblerX64::emit_mov, @@ -3700,9 +3751,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S32, loc, Location::GPR(value))?; self.memory_op( @@ -3714,6 +3766,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_xadd( Size::S32, @@ -3737,9 +3790,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location_extend(Size::S8, false, loc, Size::S32, Location::GPR(value))?; self.memory_op( @@ -3751,6 +3805,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_xadd( Size::S8, @@ -3774,9 +3829,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location_extend(Size::S16, false, loc, Size::S32, Location::GPR(value))?; self.memory_op( @@ -3788,6 +3844,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_xadd( Size::S16, @@ -3811,9 +3868,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.location_neg(Size::S32, false, loc, Size::S32, Location::GPR(value))?; self.memory_op( @@ -3825,6 +3883,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_xadd( Size::S32, @@ -3848,9 +3907,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.location_neg(Size::S8, false, loc, Size::S32, Location::GPR(value))?; self.memory_op( @@ -3862,6 +3922,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_xadd( Size::S8, @@ -3885,9 +3946,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.location_neg(Size::S16, false, loc, Size::S32, Location::GPR(value))?; self.memory_op( @@ -3899,6 +3961,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_xadd( Size::S16, @@ -3922,7 +3985,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -3935,6 +3999,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.assembler .emit_and(Size::S32, Location::GPR(src), Location::GPR(dst)) @@ -3952,7 +4017,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -3965,6 +4031,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.assembler .emit_and(Size::S32, Location::GPR(src), Location::GPR(dst)) @@ -3982,7 +4049,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -3995,6 +4063,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.assembler .emit_and(Size::S32, Location::GPR(src), Location::GPR(dst)) @@ -4012,7 +4081,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -4025,6 +4095,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.assembler .emit_or(Size::S32, Location::GPR(src), Location::GPR(dst)) @@ -4042,7 +4113,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -4055,6 +4127,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.assembler .emit_or(Size::S32, Location::GPR(src), Location::GPR(dst)) @@ -4072,7 +4145,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -4085,6 +4159,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.assembler .emit_or(Size::S32, Location::GPR(src), Location::GPR(dst)) @@ -4102,7 +4177,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -4115,6 +4191,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.assembler .emit_xor(Size::S32, Location::GPR(src), Location::GPR(dst)) @@ -4132,7 +4209,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -4145,6 +4223,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.assembler .emit_xor(Size::S32, Location::GPR(src), Location::GPR(dst)) @@ -4162,7 +4241,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -4175,6 +4255,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.assembler .emit_xor(Size::S32, Location::GPR(src), Location::GPR(dst)) @@ -4192,9 +4273,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S32, loc, Location::GPR(value))?; self.memory_op( @@ -4206,6 +4288,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler .emit_xchg(Size::S32, Location::GPR(value), Location::Memory(addr, 0)) @@ -4226,9 +4309,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_movzx(Size::S8, loc, Size::S32, Location::GPR(value))?; @@ -4241,6 +4325,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler .emit_xchg(Size::S8, Location::GPR(value), Location::Memory(addr, 0)) @@ -4261,9 +4346,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_movzx(Size::S16, loc, Size::S32, Location::GPR(value))?; @@ -4276,6 +4362,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler .emit_xchg(Size::S16, Location::GPR(value), Location::Memory(addr, 0)) @@ -4297,7 +4384,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { let compare = self.reserve_unused_temp_gpr(GPR::RAX); let value = if cmp == Location::GPR(GPR::R14) { if new == Location::GPR(GPR::R13) { @@ -4323,6 +4411,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_cmpxchg( Size::S32, @@ -4349,7 +4438,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { let compare = self.reserve_unused_temp_gpr(GPR::RAX); let value = if cmp == Location::GPR(GPR::R14) { if new == Location::GPR(GPR::R13) { @@ -4375,6 +4465,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_cmpxchg( Size::S8, @@ -4401,7 +4492,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { let compare = self.reserve_unused_temp_gpr(GPR::RAX); let value = if cmp == Location::GPR(GPR::R14) { if new == Location::GPR(GPR::R13) { @@ -4427,6 +4519,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_cmpxchg( Size::S16, @@ -4446,7 +4539,7 @@ impl Machine for MachineX86_64 { &mut self, _calling_convention: CallingConvention, reloc_target: RelocationTarget, - ) -> Result, CodegenError> { + ) -> Result, CompileError> { let mut relocations = vec![]; let next = self.get_label(); let reloc_at = self.assembler.get_offset().0 + 1; // skip E8 @@ -4466,7 +4559,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_binop_i64(AssemblerX64::emit_add, loc_a, loc_b, ret) } fn emit_binop_sub64( @@ -4474,7 +4567,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_binop_i64(AssemblerX64::emit_sub, loc_a, loc_b, ret) } fn emit_binop_mul64( @@ -4482,7 +4575,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_binop_i64(AssemblerX64::emit_imul, loc_a, loc_b, ret) } fn emit_binop_udiv64( @@ -4492,7 +4585,7 @@ impl Machine for MachineX86_64 { ret: Location, integer_division_by_zero: Label, _integer_overflow: Label, - ) -> Result { + ) -> Result { // We assume that RAX and RDX are temporary registers here. self.assembler .emit_mov(Size::S64, loc_a, Location::GPR(GPR::RAX))?; @@ -4515,7 +4608,7 @@ impl Machine for MachineX86_64 { ret: Location, integer_division_by_zero: Label, _integer_overflow: Label, - ) -> Result { + ) -> Result { // We assume that RAX and RDX are temporary registers here. self.assembler .emit_mov(Size::S64, loc_a, Location::GPR(GPR::RAX))?; @@ -4537,7 +4630,7 @@ impl Machine for MachineX86_64 { ret: Location, integer_division_by_zero: Label, _integer_overflow: Label, - ) -> Result { + ) -> Result { // We assume that RAX and RDX are temporary registers here. self.assembler .emit_mov(Size::S64, loc_a, Location::GPR(GPR::RAX))?; @@ -4560,7 +4653,7 @@ impl Machine for MachineX86_64 { ret: Location, integer_division_by_zero: Label, _integer_overflow: Label, - ) -> Result { + ) -> Result { // We assume that RAX and RDX are temporary registers here. let normal_path = self.assembler.get_label(); let end = self.assembler.get_label(); @@ -4593,7 +4686,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_binop_i64(AssemblerX64::emit_and, loc_a, loc_b, ret) } fn emit_binop_or64( @@ -4601,7 +4694,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_binop_i64(AssemblerX64::emit_or, loc_a, loc_b, ret) } fn emit_binop_xor64( @@ -4609,7 +4702,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_binop_i64(AssemblerX64::emit_xor, loc_a, loc_b, ret) } fn i64_cmp_ge_s( @@ -4617,7 +4710,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::GreaterEqual, loc_a, loc_b, ret) } fn i64_cmp_gt_s( @@ -4625,7 +4718,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Greater, loc_a, loc_b, ret) } fn i64_cmp_le_s( @@ -4633,7 +4726,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::LessEqual, loc_a, loc_b, ret) } fn i64_cmp_lt_s( @@ -4641,7 +4734,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Less, loc_a, loc_b, ret) } fn i64_cmp_ge_u( @@ -4649,7 +4742,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::AboveEqual, loc_a, loc_b, ret) } fn i64_cmp_gt_u( @@ -4657,7 +4750,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Above, loc_a, loc_b, ret) } fn i64_cmp_le_u( @@ -4665,7 +4758,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::BelowEqual, loc_a, loc_b, ret) } fn i64_cmp_lt_u( @@ -4673,7 +4766,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Below, loc_a, loc_b, ret) } fn i64_cmp_ne( @@ -4681,7 +4774,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::NotEqual, loc_a, loc_b, ret) } fn i64_cmp_eq( @@ -4689,14 +4782,14 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_cmpop_i64_dynamic_b(Condition::Equal, loc_a, loc_b, ret) } - fn i64_clz(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn i64_clz(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { let src = match loc { Location::Imm64(_) | Location::Imm32(_) | Location::Memory(_, _) => { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S64, loc, Location::GPR(tmp))?; tmp @@ -4707,8 +4800,8 @@ impl Machine for MachineX86_64 { } }; let dst = match ret { - Location::Memory(_, _) => self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + Location::Memory(_, _) => self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?, Location::GPR(reg) => reg, _ => { @@ -4746,11 +4839,11 @@ impl Machine for MachineX86_64 { }; Ok(()) } - fn i64_ctz(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn i64_ctz(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { let src = match loc { Location::Imm64(_) | Location::Imm32(_) | Location::Memory(_, _) => { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S64, loc, Location::GPR(tmp))?; tmp @@ -4761,8 +4854,8 @@ impl Machine for MachineX86_64 { } }; let dst = match ret { - Location::Memory(_, _) => self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + Location::Memory(_, _) => self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?, Location::GPR(reg) => reg, _ => { @@ -4799,16 +4892,16 @@ impl Machine for MachineX86_64 { }; Ok(()) } - fn i64_popcnt(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn i64_popcnt(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { match loc { Location::Imm64(_) | Location::Imm32(_) => { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S64, loc, Location::GPR(tmp))?; if let Location::Memory(_, _) = ret { - let out_tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let out_tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler.emit_popcnt( Size::S64, @@ -4825,8 +4918,8 @@ impl Machine for MachineX86_64 { } Location::Memory(_, _) | Location::GPR(_) => { if let Location::Memory(_, _) = ret { - let out_tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let out_tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_popcnt(Size::S64, loc, Location::GPR(out_tmp))?; @@ -4847,7 +4940,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_shift_i64(AssemblerX64::emit_shl, loc_a, loc_b, ret) } fn i64_shr( @@ -4855,7 +4948,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_shift_i64(AssemblerX64::emit_shr, loc_a, loc_b, ret) } fn i64_sar( @@ -4863,7 +4956,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_shift_i64(AssemblerX64::emit_sar, loc_a, loc_b, ret) } fn i64_rol( @@ -4871,7 +4964,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_shift_i64(AssemblerX64::emit_rol, loc_a, loc_b, ret) } fn i64_ror( @@ -4879,7 +4972,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_shift_i64(AssemblerX64::emit_ror, loc_a, loc_b, ret) } fn i64_load( @@ -4891,7 +4984,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -4901,6 +4995,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_binop( AssemblerX64::emit_mov, @@ -4920,7 +5015,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -4930,6 +5026,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_zx_sx( AssemblerX64::emit_movzx, @@ -4950,7 +5047,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -4960,6 +5058,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_zx_sx( AssemblerX64::emit_movsx, @@ -4980,7 +5079,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -4990,6 +5090,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_zx_sx( AssemblerX64::emit_movzx, @@ -5010,7 +5111,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -5020,6 +5122,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_zx_sx( AssemblerX64::emit_movsx, @@ -5040,7 +5143,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -5050,6 +5154,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { match ret { Location::GPR(_) => {} @@ -5082,7 +5187,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -5092,6 +5198,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_zx_sx( AssemblerX64::emit_movsx, @@ -5112,7 +5219,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -5122,6 +5230,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_mov(Size::S64, Location::Memory(addr, 0), ret), ) } @@ -5134,7 +5243,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -5144,6 +5254,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_zero_extension( Size::S8, @@ -5163,7 +5274,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -5173,6 +5285,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_zero_extension( Size::S16, @@ -5192,7 +5305,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -5202,6 +5316,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { match ret { Location::GPR(_) => {} @@ -5234,7 +5349,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -5244,6 +5360,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_binop( AssemblerX64::emit_mov, @@ -5263,7 +5380,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -5273,6 +5391,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_binop( AssemblerX64::emit_mov, @@ -5292,7 +5411,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -5302,6 +5422,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_binop( AssemblerX64::emit_mov, @@ -5321,7 +5442,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -5331,6 +5453,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_binop( AssemblerX64::emit_mov, @@ -5350,7 +5473,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -5360,6 +5484,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_atomic_xchg(Size::S64, value, Location::Memory(addr, 0)), ) } @@ -5372,7 +5497,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -5382,6 +5508,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_atomic_xchg(Size::S8, value, Location::Memory(addr, 0)), ) } @@ -5394,7 +5521,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -5404,6 +5532,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_atomic_xchg(Size::S16, value, Location::Memory(addr, 0)), ) } @@ -5416,7 +5545,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( target_addr, memarg, @@ -5426,6 +5556,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| this.emit_relaxed_atomic_xchg(Size::S32, value, Location::Memory(addr, 0)), ) } @@ -5440,9 +5571,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S64, loc, Location::GPR(value))?; self.memory_op( @@ -5454,9 +5586,10 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_xadd( - Size::S32, + Size::S64, Location::GPR(value), Location::Memory(addr, 0), ) @@ -5477,9 +5610,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location_extend(Size::S8, false, loc, Size::S64, Location::GPR(value))?; self.memory_op( @@ -5491,6 +5625,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_xadd( Size::S8, @@ -5514,9 +5649,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location_extend(Size::S16, false, loc, Size::S64, Location::GPR(value))?; self.memory_op( @@ -5528,6 +5664,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_xadd( Size::S16, @@ -5551,9 +5688,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location_extend(Size::S32, false, loc, Size::S64, Location::GPR(value))?; self.memory_op( @@ -5565,6 +5703,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_xadd( Size::S32, @@ -5588,9 +5727,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.location_neg(Size::S64, false, loc, Size::S64, Location::GPR(value))?; self.memory_op( @@ -5602,6 +5742,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_xadd( Size::S64, @@ -5625,9 +5766,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.location_neg(Size::S8, false, loc, Size::S64, Location::GPR(value))?; self.memory_op( @@ -5639,6 +5781,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_xadd( Size::S8, @@ -5662,9 +5805,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.location_neg(Size::S16, false, loc, Size::S64, Location::GPR(value))?; self.memory_op( @@ -5676,6 +5820,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_xadd( Size::S16, @@ -5699,9 +5844,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.location_neg(Size::S32, false, loc, Size::S64, Location::GPR(value))?; self.memory_op( @@ -5713,6 +5859,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_xadd( Size::S32, @@ -5736,7 +5883,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -5749,6 +5897,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.assembler .emit_and(Size::S64, Location::GPR(src), Location::GPR(dst)) @@ -5766,7 +5915,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -5779,6 +5929,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.assembler .emit_and(Size::S64, Location::GPR(src), Location::GPR(dst)) @@ -5796,7 +5947,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -5809,6 +5961,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.assembler .emit_and(Size::S64, Location::GPR(src), Location::GPR(dst)) @@ -5826,7 +5979,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -5839,6 +5993,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.assembler .emit_and(Size::S64, Location::GPR(src), Location::GPR(dst)) @@ -5856,7 +6011,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -5869,6 +6025,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.location_or(Size::S64, Location::GPR(src), Location::GPR(dst), false) }, @@ -5885,7 +6042,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -5898,6 +6056,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.location_or(Size::S64, Location::GPR(src), Location::GPR(dst), false) }, @@ -5914,7 +6073,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -5927,6 +6087,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.location_or(Size::S64, Location::GPR(src), Location::GPR(dst), false) }, @@ -5943,7 +6104,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -5956,6 +6118,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.location_or(Size::S64, Location::GPR(src), Location::GPR(dst), false) }, @@ -5972,7 +6135,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -5985,6 +6149,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.location_xor(Size::S64, Location::GPR(src), Location::GPR(dst), false) }, @@ -6001,7 +6166,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -6014,6 +6180,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.location_xor(Size::S64, Location::GPR(src), Location::GPR(dst), false) }, @@ -6030,7 +6197,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -6043,6 +6211,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.location_xor(Size::S64, Location::GPR(src), Location::GPR(dst), false) }, @@ -6059,7 +6228,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.emit_compare_and_swap( loc, target, @@ -6072,6 +6242,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, src, dst| { this.location_xor(Size::S64, Location::GPR(src), Location::GPR(dst), false) }, @@ -6088,9 +6259,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S64, loc, Location::GPR(value))?; self.memory_op( @@ -6102,6 +6274,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler .emit_xchg(Size::S64, Location::GPR(value), Location::Memory(addr, 0)) @@ -6122,9 +6295,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_movzx(Size::S8, loc, Size::S64, Location::GPR(value))?; @@ -6137,6 +6311,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler .emit_xchg(Size::S8, Location::GPR(value), Location::Memory(addr, 0)) @@ -6157,9 +6332,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_movzx(Size::S16, loc, Size::S64, Location::GPR(value))?; @@ -6172,6 +6348,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler .emit_xchg(Size::S16, Location::GPR(value), Location::Memory(addr, 0)) @@ -6192,9 +6369,10 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { - let value = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + unaligned_atomic: Label, + ) -> Result<(), CompileError> { + let value = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.assembler .emit_movzx(Size::S32, loc, Size::S64, Location::GPR(value))?; @@ -6207,6 +6385,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler .emit_xchg(Size::S32, Location::GPR(value), Location::Memory(addr, 0)) @@ -6228,7 +6407,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { let compare = self.reserve_unused_temp_gpr(GPR::RAX); let value = if cmp == Location::GPR(GPR::R14) { if new == Location::GPR(GPR::R13) { @@ -6254,6 +6434,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_cmpxchg( Size::S64, @@ -6280,7 +6461,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { let compare = self.reserve_unused_temp_gpr(GPR::RAX); let value = if cmp == Location::GPR(GPR::R14) { if new == Location::GPR(GPR::R13) { @@ -6306,6 +6488,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_cmpxchg( Size::S8, @@ -6332,7 +6515,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { let compare = self.reserve_unused_temp_gpr(GPR::RAX); let value = if cmp == Location::GPR(GPR::R14) { if new == Location::GPR(GPR::R13) { @@ -6358,6 +6542,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_cmpxchg( Size::S16, @@ -6384,7 +6569,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { let compare = self.reserve_unused_temp_gpr(GPR::RAX); let value = if cmp == Location::GPR(GPR::R14) { if new == Location::GPR(GPR::R13) { @@ -6410,9 +6596,10 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.assembler.emit_lock_cmpxchg( - Size::S16, + Size::S32, Location::GPR(value), Location::Memory(addr, 0), )?; @@ -6434,7 +6621,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -6444,6 +6632,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_binop( AssemblerX64::emit_mov, @@ -6464,7 +6653,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { let canonicalize = canonicalize && self.arch_supports_canonicalize_nan(); self.memory_op( target_addr, @@ -6475,6 +6665,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { if !canonicalize { this.emit_relaxed_binop( @@ -6498,7 +6689,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { self.memory_op( addr, memarg, @@ -6508,6 +6700,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { this.emit_relaxed_binop( AssemblerX64::emit_mov, @@ -6528,7 +6721,8 @@ impl Machine for MachineX86_64 { imported_memories: bool, offset: i32, heap_access_oob: Label, - ) -> Result<(), CodegenError> { + unaligned_atomic: Label, + ) -> Result<(), CompileError> { let canonicalize = canonicalize && self.arch_supports_canonicalize_nan(); self.memory_op( target_addr, @@ -6539,6 +6733,7 @@ impl Machine for MachineX86_64 { imported_memories, offset, heap_access_oob, + unaligned_atomic, |this, addr| { if !canonicalize { this.emit_relaxed_binop( @@ -6559,12 +6754,12 @@ impl Machine for MachineX86_64 { loc: Location, signed: bool, ret: Location, - ) -> Result<(), CodegenError> { - let tmp_out = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + ) -> Result<(), CompileError> { + let tmp_out = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmp_in = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_in = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; if self.assembler.arch_has_fconverti() { self.emit_relaxed_mov(Size::S64, loc, Location::GPR(tmp_in))?; @@ -6581,8 +6776,8 @@ impl Machine for MachineX86_64 { .emit_vcvtsi2sd_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out)?; self.move_location(Size::S64, Location::SIMD(tmp_out), ret)?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; let do_convert = self.assembler.get_label(); @@ -6621,12 +6816,12 @@ impl Machine for MachineX86_64 { loc: Location, signed: bool, ret: Location, - ) -> Result<(), CodegenError> { - let tmp_out = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + ) -> Result<(), CompileError> { + let tmp_out = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmp_in = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_in = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; if self.assembler.arch_has_fconverti() { self.emit_relaxed_mov(Size::S32, loc, Location::GPR(tmp_in))?; @@ -6657,12 +6852,12 @@ impl Machine for MachineX86_64 { loc: Location, signed: bool, ret: Location, - ) -> Result<(), CodegenError> { - let tmp_out = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + ) -> Result<(), CompileError> { + let tmp_out = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmp_in = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_in = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; if self.assembler.arch_has_fconverti() { self.emit_relaxed_mov(Size::S64, loc, Location::GPR(tmp_in))?; @@ -6679,8 +6874,8 @@ impl Machine for MachineX86_64 { .emit_vcvtsi2ss_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out)?; self.move_location(Size::S32, Location::SIMD(tmp_out), ret)?; } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; let do_convert = self.assembler.get_label(); @@ -6719,12 +6914,12 @@ impl Machine for MachineX86_64 { loc: Location, signed: bool, ret: Location, - ) -> Result<(), CodegenError> { - let tmp_out = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + ) -> Result<(), CompileError> { + let tmp_out = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmp_in = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp_in = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; if self.assembler.arch_has_fconverti() { self.emit_relaxed_mov(Size::S32, loc, Location::GPR(tmp_in))?; @@ -6756,7 +6951,7 @@ impl Machine for MachineX86_64 { ret: Location, signed: bool, sat: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (signed, sat) { (false, true) => self.convert_i64_f64_u_s(loc, ret), (false, false) => self.convert_i64_f64_u_u(loc, ret), @@ -6770,7 +6965,7 @@ impl Machine for MachineX86_64 { ret: Location, signed: bool, sat: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (signed, sat) { (false, true) => self.convert_i32_f64_u_s(loc, ret), (false, false) => self.convert_i32_f64_u_u(loc, ret), @@ -6784,7 +6979,7 @@ impl Machine for MachineX86_64 { ret: Location, signed: bool, sat: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (signed, sat) { (false, true) => self.convert_i64_f32_u_s(loc, ret), (false, false) => self.convert_i64_f32_u_u(loc, ret), @@ -6798,7 +6993,7 @@ impl Machine for MachineX86_64 { ret: Location, signed: bool, sat: bool, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { match (signed, sat) { (false, true) => self.convert_i32_f32_u_s(loc, ret), (false, false) => self.convert_i32_f32_u_u(loc, ret), @@ -6806,24 +7001,24 @@ impl Machine for MachineX86_64 { (true, false) => self.convert_i32_f32_s_u(loc, ret), } } - fn convert_f64_f32(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn convert_f64_f32(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vcvtss2sd, loc, loc, ret) } - fn convert_f32_f64(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn convert_f32_f64(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vcvtsd2ss, loc, loc, ret) } - fn f64_neg(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f64_neg(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { if self.assembler.arch_has_fneg() { - let tmp = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S64, loc, Location::SIMD(tmp))?; self.assembler.arch_emit_f64_neg(tmp, tmp)?; self.emit_relaxed_mov(Size::S64, Location::SIMD(tmp), ret)?; self.release_simd(tmp); } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S64, loc, Location::GPR(tmp))?; self.assembler.emit_btc_gpr_imm8_64(63, tmp)?; @@ -6832,12 +7027,12 @@ impl Machine for MachineX86_64 { } Ok(()) } - fn f64_abs(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn f64_abs(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let c = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let c = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S64, loc, Location::GPR(tmp))?; @@ -6854,9 +7049,9 @@ impl Machine for MachineX86_64 { self.release_gpr(tmp); Ok(()) } - fn emit_i64_copysign(&mut self, tmp1: GPR, tmp2: GPR) -> Result<(), CodegenError> { - let c = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn emit_i64_copysign(&mut self, tmp1: GPR, tmp2: GPR) -> Result<(), CompileError> { + let c = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location( @@ -6881,19 +7076,19 @@ impl Machine for MachineX86_64 { self.release_gpr(c); Ok(()) } - fn f64_sqrt(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f64_sqrt(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vsqrtsd, loc, loc, ret) } - fn f64_trunc(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f64_trunc(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vroundsd_trunc, loc, loc, ret) } - fn f64_ceil(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f64_ceil(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vroundsd_ceil, loc, loc, ret) } - fn f64_floor(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f64_floor(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vroundsd_floor, loc, loc, ret) } - fn f64_nearest(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f64_nearest(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vroundsd_nearest, loc, loc, ret) } fn f64_cmp_ge( @@ -6901,7 +7096,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vcmpgesd, loc_a, loc_b, ret)?; self.assembler.emit_and(Size::S32, Location::Imm32(1), ret) } @@ -6910,7 +7105,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vcmpgtsd, loc_a, loc_b, ret)?; self.assembler.emit_and(Size::S32, Location::Imm32(1), ret) } @@ -6919,7 +7114,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vcmplesd, loc_a, loc_b, ret)?; self.assembler.emit_and(Size::S32, Location::Imm32(1), ret) } @@ -6928,7 +7123,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vcmpltsd, loc_a, loc_b, ret)?; self.assembler.emit_and(Size::S32, Location::Imm32(1), ret) } @@ -6937,7 +7132,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vcmpneqsd, loc_a, loc_b, ret)?; self.assembler.emit_and(Size::S32, Location::Imm32(1), ret) } @@ -6946,7 +7141,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vcmpeqsd, loc_a, loc_b, ret)?; self.assembler.emit_and(Size::S32, Location::Imm32(1), ret) } @@ -6955,21 +7150,21 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { if !self.arch_supports_canonicalize_nan() { self.emit_relaxed_avx(AssemblerX64::emit_vminsd, loc_a, loc_b, ret) } else { - let tmp1 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp1 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmp2 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp2 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmpg1 = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmpg1 = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmpg2 = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmpg2 = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; let src1 = match loc_a { @@ -7082,21 +7277,21 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { if !self.arch_supports_canonicalize_nan() { self.emit_relaxed_avx(AssemblerX64::emit_vmaxsd, loc_a, loc_b, ret) } else { - let tmp1 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp1 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmp2 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp2 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmpg1 = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmpg1 = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmpg2 = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmpg2 = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; let src1 = match loc_a { @@ -7204,7 +7399,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vaddsd, loc_a, loc_b, ret) } fn f64_sub( @@ -7212,7 +7407,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vsubsd, loc_a, loc_b, ret) } fn f64_mul( @@ -7220,7 +7415,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vmulsd, loc_a, loc_b, ret) } fn f64_div( @@ -7228,21 +7423,21 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vdivsd, loc_a, loc_b, ret) } - fn f32_neg(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f32_neg(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { if self.assembler.arch_has_fneg() { - let tmp = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; self.emit_relaxed_mov(Size::S32, loc, Location::SIMD(tmp))?; self.assembler.arch_emit_f32_neg(tmp, tmp)?; self.emit_relaxed_mov(Size::S32, Location::SIMD(tmp), ret)?; self.release_simd(tmp); } else { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S32, loc, Location::GPR(tmp))?; self.assembler.emit_btc_gpr_imm8_32(31, tmp)?; @@ -7251,9 +7446,9 @@ impl Machine for MachineX86_64 { } Ok(()) } - fn f32_abs(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { - let tmp = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + fn f32_abs(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { + let tmp = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; self.move_location(Size::S32, loc, Location::GPR(tmp))?; self.assembler.emit_and( @@ -7265,7 +7460,7 @@ impl Machine for MachineX86_64 { self.release_gpr(tmp); Ok(()) } - fn emit_i32_copysign(&mut self, tmp1: GPR, tmp2: GPR) -> Result<(), CodegenError> { + fn emit_i32_copysign(&mut self, tmp1: GPR, tmp2: GPR) -> Result<(), CompileError> { self.assembler.emit_and( Size::S32, Location::Imm32(0x7fffffffu32), @@ -7279,19 +7474,19 @@ impl Machine for MachineX86_64 { self.assembler .emit_or(Size::S32, Location::GPR(tmp2), Location::GPR(tmp1)) } - fn f32_sqrt(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f32_sqrt(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vsqrtss, loc, loc, ret) } - fn f32_trunc(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f32_trunc(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vroundss_trunc, loc, loc, ret) } - fn f32_ceil(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f32_ceil(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vroundss_ceil, loc, loc, ret) } - fn f32_floor(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f32_floor(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vroundss_floor, loc, loc, ret) } - fn f32_nearest(&mut self, loc: Location, ret: Location) -> Result<(), CodegenError> { + fn f32_nearest(&mut self, loc: Location, ret: Location) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vroundss_nearest, loc, loc, ret) } fn f32_cmp_ge( @@ -7299,7 +7494,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vcmpgess, loc_a, loc_b, ret)?; self.assembler.emit_and(Size::S32, Location::Imm32(1), ret) } @@ -7308,7 +7503,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vcmpgtss, loc_a, loc_b, ret)?; self.assembler.emit_and(Size::S32, Location::Imm32(1), ret) } @@ -7317,7 +7512,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vcmpless, loc_a, loc_b, ret)?; self.assembler.emit_and(Size::S32, Location::Imm32(1), ret) } @@ -7326,7 +7521,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vcmpltss, loc_a, loc_b, ret)?; self.assembler.emit_and(Size::S32, Location::Imm32(1), ret) } @@ -7335,7 +7530,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vcmpneqss, loc_a, loc_b, ret)?; self.assembler.emit_and(Size::S32, Location::Imm32(1), ret) } @@ -7344,7 +7539,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vcmpeqss, loc_a, loc_b, ret)?; self.assembler.emit_and(Size::S32, Location::Imm32(1), ret) } @@ -7353,21 +7548,21 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { if !self.arch_supports_canonicalize_nan() { self.emit_relaxed_avx(AssemblerX64::emit_vminss, loc_a, loc_b, ret) } else { - let tmp1 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp1 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmp2 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp2 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmpg1 = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmpg1 = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmpg2 = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmpg2 = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; let src1 = match loc_a { @@ -7480,21 +7675,21 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { if !self.arch_supports_canonicalize_nan() { self.emit_relaxed_avx(AssemblerX64::emit_vmaxss, loc_a, loc_b, ret) } else { - let tmp1 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp1 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmp2 = self.acquire_temp_simd().ok_or(CodegenError { - message: "singlepass cannot acquire temp simd".to_string(), + let tmp2 = self.acquire_temp_simd().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp simd".to_owned()) })?; - let tmpg1 = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmpg1 = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; - let tmpg2 = self.acquire_temp_gpr().ok_or(CodegenError { - message: "singlepass cannot acquire temp gpr".to_string(), + let tmpg2 = self.acquire_temp_gpr().ok_or_else(|| { + CompileError::Codegen("singlepass cannot acquire temp gpr".to_owned()) })?; let src1 = match loc_a { @@ -7602,7 +7797,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vaddss, loc_a, loc_b, ret) } fn f32_sub( @@ -7610,7 +7805,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vsubss, loc_a, loc_b, ret) } fn f32_mul( @@ -7618,7 +7813,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vmulss, loc_a, loc_b, ret) } fn f32_div( @@ -7626,7 +7821,7 @@ impl Machine for MachineX86_64 { loc_a: Location, loc_b: Location, ret: Location, - ) -> Result<(), CodegenError> { + ) -> Result<(), CompileError> { self.emit_relaxed_avx(AssemblerX64::emit_vdivss, loc_a, loc_b, ret) } @@ -7634,9 +7829,9 @@ impl Machine for MachineX86_64 { &self, sig: &FunctionType, calling_convention: CallingConvention, - ) -> Result { + ) -> Result { // the cpu feature here is irrelevant - let mut a = AssemblerX64::new(0, None); + let mut a = AssemblerX64::new(0, None)?; // Calculate stack offset. let mut stack_offset: u32 = 0; @@ -7749,9 +7944,9 @@ impl Machine for MachineX86_64 { vmoffsets: &VMOffsets, sig: &FunctionType, calling_convention: CallingConvention, - ) -> Result { + ) -> Result { // the cpu feature here is irrelevant - let mut a = AssemblerX64::new(0, None); + let mut a = AssemblerX64::new(0, None)?; // Allocate argument array. let stack_offset: usize = 16 * std::cmp::max(sig.params().len(), sig.results().len()) + 8; // 16 bytes each + 8 bytes sysv call padding @@ -7874,9 +8069,9 @@ impl Machine for MachineX86_64 { index: FunctionIndex, sig: &FunctionType, calling_convention: CallingConvention, - ) -> Result { + ) -> Result { // the cpu feature here is irrelevant - let mut a = AssemblerX64::new(0, None); + let mut a = AssemblerX64::new(0, None)?; // TODO: ARM entry trampoline is not emitted. diff --git a/lib/compiler/Cargo.toml b/lib/compiler/Cargo.toml index 6382ecba4..68096ee13 100644 --- a/lib/compiler/Cargo.toml +++ b/lib/compiler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-compiler" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Base compiler abstraction for Wasmer WebAssembly runtime" categories = ["wasm", "no-std"] keywords = ["wasm", "webassembly", "compiler"] @@ -11,8 +11,8 @@ readme = "README.md" edition = "2018" [dependencies] -wasmer-types = { path = "../types", version = "=3.0.0-rc.2", default-features = false, features = [ ] } -wasmer-object = { path = "../object", version = "=3.0.0-rc.2", optional = true } +wasmer-types = { path = "../types", version = "=3.0.2", default-features = false } +wasmer-object = { path = "../object", version = "=3.0.2", optional = true } wasmparser = { version = "0.83", optional = true, default-features = false } enumset = "1.0.2" hashbrown = { version = "0.11", optional = true } @@ -32,7 +32,7 @@ leb128 = "0.2" enum-iterator = "0.7.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -wasmer-vm = { path = "../vm", version = "=3.0.0-rc.2" } +wasmer-vm = { path = "../vm", version = "=3.0.2" } region = { version = "3.0" } [target.'cfg(target_os = "windows")'.dependencies] @@ -48,11 +48,10 @@ compiler = ["translator"] wasmer-artifact-load = [] wasmer-artifact-create = [] static-artifact-load = [] -static-artifact-create = ["wasmer-object", "enable-rkyv"] +static-artifact-create = ["wasmer-object"] std = ["wasmer-types/std"] core = ["hashbrown", "wasmer-types/core"] enable-serde = ["serde", "serde_bytes", "wasmer-types/enable-serde"] -enable-rkyv = [ "wasmer-types/enable-rkyv" ] [badges] maintenance = { status = "experimental" } diff --git a/lib/compiler/src/artifact_builders/artifact_builder.rs b/lib/compiler/src/artifact_builders/artifact_builder.rs index 80bf3fb2b..87d9e5b10 100644 --- a/lib/compiler/src/artifact_builders/artifact_builder.rs +++ b/lib/compiler/src/artifact_builders/artifact_builder.rs @@ -19,7 +19,6 @@ use wasmer_types::{ use wasmer_types::{ CompiledFunctionFrameInfo, FunctionBody, SerializableCompilation, SerializableModule, }; -#[cfg(feature = "enable-rkyv")] use wasmer_types::{MetadataHeader, SerializeError}; /// A compiled wasm module, ready to be instantiated. @@ -75,8 +74,6 @@ impl ArtifactBuild { translation.module_translation_state.as_ref().unwrap(), translation.function_body_inputs, )?; - let function_call_trampolines = compilation.get_function_call_trampolines(); - let dynamic_function_trampolines = compilation.get_dynamic_function_trampolines(); let data_initializers = translation .data_initializers @@ -85,25 +82,36 @@ impl ArtifactBuild { .collect::>() .into_boxed_slice(); - let frame_infos = compilation.get_frame_info(); - // Synthesize a custom section to hold the libcall trampolines. - let mut custom_sections = compilation.get_custom_sections(); - let mut custom_section_relocations = compilation.get_custom_section_relocations(); + let mut function_frame_info = PrimaryMap::with_capacity(compilation.functions.len()); + let mut function_bodies = PrimaryMap::with_capacity(compilation.functions.len()); + let mut function_relocations = PrimaryMap::with_capacity(compilation.functions.len()); + for (_, func) in compilation.functions.into_iter() { + function_bodies.push(func.body); + function_relocations.push(func.relocations); + function_frame_info.push(func.frame_info); + } + let mut custom_sections = compilation.custom_sections.clone(); + let mut custom_section_relocations = compilation + .custom_sections + .iter() + .map(|(_, section)| section.relocations.clone()) + .collect::>(); let libcall_trampolines_section = make_libcall_trampolines(target); custom_section_relocations.push(libcall_trampolines_section.relocations.clone()); let libcall_trampolines = custom_sections.push(libcall_trampolines_section); let libcall_trampoline_len = libcall_trampoline_len(target) as u32; + let cpu_features = compiler.get_cpu_features_used(target.cpu_features()); let serializable_compilation = SerializableCompilation { - function_bodies: compilation.get_function_bodies(), - function_relocations: compilation.get_relocations(), - function_frame_info: frame_infos, - function_call_trampolines, - dynamic_function_trampolines, + function_bodies, + function_relocations, + function_frame_info, + function_call_trampolines: compilation.function_call_trampolines, + dynamic_function_trampolines: compilation.dynamic_function_trampolines, custom_sections, custom_section_relocations, - debug: compilation.get_debug(), + debug: compilation.debug, libcall_trampolines, libcall_trampoline_len, }; @@ -111,8 +119,8 @@ impl ArtifactBuild { compilation: serializable_compilation, compile_info, data_initializers, + cpu_features: cpu_features.as_u64(), module_start, - cpu_features: target.cpu_features().as_u64(), }; Ok(Self { serializable }) } @@ -218,7 +226,6 @@ impl ArtifactCreate for ArtifactBuild { &self.serializable.compile_info.table_styles } - #[cfg(feature = "enable-rkyv")] fn serialize(&self) -> Result, SerializeError> { let serialized_data = self.serializable.serialize()?; assert!(std::mem::align_of::() <= MetadataHeader::ALIGN); diff --git a/lib/compiler/src/compiler.rs b/lib/compiler/src/compiler.rs index 25df3cd07..cb1d35f04 100644 --- a/lib/compiler/src/compiler.rs +++ b/lib/compiler/src/compiler.rs @@ -6,13 +6,14 @@ use crate::lib::std::sync::Arc; use crate::translator::ModuleMiddleware; use crate::FunctionBodyData; use crate::ModuleTranslationState; +use enumset::EnumSet; use wasmer_types::compilation::function::Compilation; use wasmer_types::compilation::module::CompileModuleInfo; use wasmer_types::compilation::symbols::SymbolRegistry; use wasmer_types::compilation::target::Target; use wasmer_types::entity::PrimaryMap; use wasmer_types::error::CompileError; -use wasmer_types::{Features, LocalFunctionIndex}; +use wasmer_types::{CpuFeature, Features, LocalFunctionIndex}; use wasmparser::{Validator, WasmFeatures}; /// The compiler configuration options. @@ -146,4 +147,9 @@ pub trait Compiler: Send { /// Get the middlewares for this compiler fn get_middlewares(&self) -> &[Arc]; + + /// Get the CpuFeatues used by the compiler + fn get_cpu_features_used(&self, cpu_features: &EnumSet) -> EnumSet { + *cpu_features + } } diff --git a/lib/compiler/src/engine/engineref.rs b/lib/compiler/src/engine/engineref.rs new file mode 100644 index 000000000..107cd9b11 --- /dev/null +++ b/lib/compiler/src/engine/engineref.rs @@ -0,0 +1,39 @@ +use super::Engine; +use crate::Tunables; + +/// A temporary handle to an [`Engine`] +/// EngineRef can be used to build a [`Module`][wasmer::Module] +/// It can be created directly with an [`Engine`] +/// Or from anything implementing [`AsEngineRef`] +/// like from [`Store`][wasmer::Store] typicaly +pub struct EngineRef<'a> { + /// The inner engine + pub(crate) inner: &'a Engine, +} + +impl<'a> EngineRef<'a> { + /// Get inner [`Engine`] + pub fn engine(&self) -> &Engine { + self.inner + } + /// Get the [`Tunables`] + pub fn tunables(&self) -> &dyn Tunables { + self.inner.tunables() + } + /// Create an EngineRef from an Engine and Tunables + pub fn new(engine: &'a Engine) -> Self { + EngineRef { inner: engine } + } +} + +/// Helper trait for a value that is convertible to a [`EngineRef`]. +pub trait AsEngineRef { + /// Returns a `EngineRef` pointing to the underlying context. + fn as_engine_ref(&self) -> EngineRef<'_>; +} + +impl AsEngineRef for EngineRef<'_> { + fn as_engine_ref(&self) -> EngineRef<'_> { + EngineRef { inner: self.inner } + } +} diff --git a/lib/compiler/src/engine/inner.rs b/lib/compiler/src/engine/inner.rs index c8605b3be..15e3bd6cb 100644 --- a/lib/compiler/src/engine/inner.rs +++ b/lib/compiler/src/engine/inner.rs @@ -4,23 +4,25 @@ use crate::engine::builder::EngineBuilder; #[cfg(not(target_arch = "wasm32"))] use crate::Artifact; #[cfg(not(target_arch = "wasm32"))] +use crate::BaseTunables; +#[cfg(not(target_arch = "wasm32"))] use crate::CodeMemory; +#[cfg(not(target_arch = "wasm32"))] +use crate::{AsEngineRef, EngineRef}; #[cfg(feature = "compiler")] use crate::{Compiler, CompilerConfig}; #[cfg(not(target_arch = "wasm32"))] use crate::{FunctionExtent, Tunables}; #[cfg(not(target_arch = "wasm32"))] -#[cfg(feature = "enable-rkyv")] use memmap2::Mmap; #[cfg(not(target_arch = "wasm32"))] -#[cfg(feature = "enable-rkyv")] use std::path::Path; use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use std::sync::{Arc, Mutex}; #[cfg(not(target_arch = "wasm32"))] use wasmer_types::{ - entity::PrimaryMap, FunctionBody, FunctionIndex, FunctionType, LocalFunctionIndex, ModuleInfo, - SignatureIndex, + entity::PrimaryMap, DeserializeError, FunctionBody, FunctionIndex, FunctionType, + LocalFunctionIndex, ModuleInfo, SignatureIndex, }; use wasmer_types::{CompileError, Features, Target}; #[cfg(not(target_arch = "wasm32"))] @@ -38,6 +40,8 @@ pub struct Engine { /// The target for the compiler target: Arc, engine_id: EngineId, + #[cfg(not(target_arch = "wasm32"))] + tunables: Arc, name: String, } @@ -49,6 +53,8 @@ impl Engine { target: Target, features: Features, ) -> Self { + #[cfg(not(target_arch = "wasm32"))] + let tunables = BaseTunables::for_target(&target); let compiler = compiler_config.compiler(); let name = format!("engine-{}", compiler.name()); Self { @@ -62,6 +68,8 @@ impl Engine { })), target: Arc::new(target), engine_id: EngineId::default(), + #[cfg(not(target_arch = "wasm32"))] + tunables: Arc::new(tunables), name, } } @@ -85,6 +93,9 @@ impl Engine { /// Headless engines can't compile or validate any modules, /// they just take already processed Modules (via `Module::serialize`). pub fn headless() -> Self { + let target = Target::default(); + #[cfg(not(target_arch = "wasm32"))] + let tunables = BaseTunables::for_target(&target); Self { inner: Arc::new(Mutex::new(EngineInner { #[cfg(feature = "compiler")] @@ -96,8 +107,10 @@ impl Engine { #[cfg(not(target_arch = "wasm32"))] signatures: SignatureRegistry::new(), })), - target: Arc::new(Target::default()), + target: Arc::new(target), engine_id: EngineId::default(), + #[cfg(not(target_arch = "wasm32"))] + tunables: Arc::new(tunables), name: format!("engine-headless"), } } @@ -140,12 +153,12 @@ impl Engine { /// Compile a WebAssembly binary #[cfg(feature = "compiler")] #[cfg(not(target_arch = "wasm32"))] - pub fn compile( - &self, - binary: &[u8], - tunables: &dyn Tunables, - ) -> Result, CompileError> { - Ok(Arc::new(Artifact::new(self, binary, tunables)?)) + pub fn compile(&self, binary: &[u8]) -> Result, CompileError> { + Ok(Arc::new(Artifact::new( + self, + binary, + self.tunables.as_ref(), + )?)) } /// Compile a WebAssembly binary @@ -167,11 +180,7 @@ impl Engine { /// # Safety /// /// The serialized content must represent a serialized WebAssembly module. - #[cfg(feature = "enable-rkyv")] - pub unsafe fn deserialize( - &self, - bytes: &[u8], - ) -> Result, wasmer_types::DeserializeError> { + pub unsafe fn deserialize(&self, bytes: &[u8]) -> Result, DeserializeError> { Ok(Arc::new(Artifact::deserialize(self, bytes)?)) } @@ -181,12 +190,10 @@ impl Engine { /// # Safety /// /// The file's content must represent a serialized WebAssembly module. - #[allow(dead_code, unused)] - #[cfg(feature = "enable-rkyv")] pub unsafe fn deserialize_from_file( &self, file_ref: &Path, - ) -> Result, wasmer_types::DeserializeError> { + ) -> Result, DeserializeError> { let file = std::fs::File::open(file_ref)?; let mmap = Mmap::map(&file)?; self.deserialize(&mmap) @@ -205,6 +212,25 @@ impl Engine { pub fn cloned(&self) -> Self { self.clone() } + + /// Attach a Tunable to this engine + #[cfg(not(target_arch = "wasm32"))] + pub fn set_tunables(&mut self, tunables: impl Tunables + Send + Sync + 'static) { + self.tunables = Arc::new(tunables); + } + + /// Get a reference to attached Tunable of this engine + #[cfg(not(target_arch = "wasm32"))] + pub fn tunables(&self) -> &dyn Tunables { + self.tunables.as_ref() + } +} + +#[cfg(not(target_arch = "wasm32"))] +impl AsEngineRef for Engine { + fn as_engine_ref(&self) -> EngineRef { + EngineRef { inner: self } + } } impl std::fmt::Debug for Engine { diff --git a/lib/compiler/src/engine/mod.rs b/lib/compiler/src/engine/mod.rs index c382be795..bf54a7913 100644 --- a/lib/compiler/src/engine/mod.rs +++ b/lib/compiler/src/engine/mod.rs @@ -1,5 +1,8 @@ //! The Wasmer Engine. +#[cfg(feature = "translator")] +#[cfg(not(target_arch = "wasm32"))] +mod engineref; mod error; #[cfg(not(target_arch = "wasm32"))] mod resolver; @@ -25,13 +28,16 @@ mod link; #[cfg(not(target_arch = "wasm32"))] mod unwind; +#[cfg(feature = "translator")] +#[cfg(not(target_arch = "wasm32"))] +pub use self::engineref::{AsEngineRef, EngineRef}; pub use self::error::{InstantiationError, LinkError}; #[cfg(not(target_arch = "wasm32"))] pub use self::resolver::resolve_imports; #[cfg(not(target_arch = "wasm32"))] pub use self::trap::*; #[cfg(not(target_arch = "wasm32"))] -pub use self::tunables::Tunables; +pub use self::tunables::{BaseTunables, Tunables}; #[cfg(feature = "translator")] #[cfg(not(target_arch = "wasm32"))] diff --git a/lib/compiler/src/engine/tunables.rs b/lib/compiler/src/engine/tunables.rs index 2f654a923..9eab1ce85 100644 --- a/lib/compiler/src/engine/tunables.rs +++ b/lib/compiler/src/engine/tunables.rs @@ -3,7 +3,7 @@ use std::ptr::NonNull; use wasmer_types::entity::{EntityRef, PrimaryMap}; use wasmer_types::{ GlobalType, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, MemoryType, - ModuleInfo, Pages, TableIndex, TableType, + ModuleInfo, Pages, PointerWidth, TableIndex, TableType, Target, }; use wasmer_vm::{InternalStoreHandle, MemoryError, StoreObjects}; use wasmer_vm::{MemoryStyle, TableStyle}; @@ -148,6 +148,131 @@ pub trait Tunables { } } +/// Tunable parameters for WebAssembly compilation. +/// This is the reference implementation of the `Tunables` trait, +/// used by default. +/// +/// You can use this as a template for creating a custom Tunables +/// implementation or use composition to wrap your Tunables around +/// this one. The later approach is demonstrated in the +/// tunables-limit-memory example. +#[derive(Clone)] +pub struct BaseTunables { + /// 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 BaseTunables { + /// 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, + } + } +} + +impl Tunables for BaseTunables { + /// Get a `MemoryStyle` for the provided `MemoryType` + 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`]. + fn table_style(&self, _table: &TableType) -> TableStyle { + TableStyle::CallerChecksSignature + } + + /// Create a memory owned by the host given a [`MemoryType`] and a [`MemoryStyle`]. + fn create_host_memory( + &self, + ty: &MemoryType, + style: &MemoryStyle, + ) -> Result { + VMMemory::new(ty, style) + } + + /// Create a memory owned by the VM given a [`MemoryType`] and a [`MemoryStyle`]. + /// + /// # Safety + /// - `vm_definition_location` must point to a valid, owned `VMMemoryDefinition`, + /// for example in `VMContext`. + unsafe fn create_vm_memory( + &self, + ty: &MemoryType, + style: &MemoryStyle, + vm_definition_location: NonNull, + ) -> Result { + VMMemory::from_definition(ty, style, vm_definition_location) + } + + /// Create a table owned by the host given a [`TableType`] and a [`TableStyle`]. + fn create_host_table(&self, ty: &TableType, style: &TableStyle) -> Result { + VMTable::new(ty, style) + } + + /// Create a table owned by the VM given a [`TableType`] and a [`TableStyle`]. + /// + /// # Safety + /// - `vm_definition_location` must point to a valid, owned `VMTableDefinition`, + /// for example in `VMContext`. + unsafe fn create_vm_table( + &self, + ty: &TableType, + style: &TableStyle, + vm_definition_location: NonNull, + ) -> Result { + VMTable::from_definition(ty, style, vm_definition_location) + } +} + impl Tunables for Box { fn memory_style(&self, memory: &MemoryType) -> MemoryStyle { self.as_ref().memory_style(memory) diff --git a/lib/compiler/src/translator/sections.rs b/lib/compiler/src/translator/sections.rs index 451360ba8..e5ee7bb7b 100644 --- a/lib/compiler/src/translator/sections.rs +++ b/lib/compiler/src/translator/sections.rs @@ -61,14 +61,14 @@ pub fn parse_type_section( for entry in types { if let Ok(TypeDef::Func(WPFunctionType { params, returns })) = entry { - let sig_params: Vec = params + let sig_params: Box<[Type]> = params .iter() .map(|ty| { wptype_to_type(*ty) .expect("only numeric types are supported in function signatures") }) .collect(); - let sig_returns: Vec = returns + let sig_returns: Box<[Type]> = returns .iter() .map(|ty| { wptype_to_type(*ty) diff --git a/lib/derive/Cargo.toml b/lib/derive/Cargo.toml index db76ca79b..2a697ef80 100644 --- a/lib/derive/Cargo.toml +++ b/lib/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-derive" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Wasmer derive macros" authors = ["Wasmer Engineering Team "] repository = "https://github.com/wasmerio/wasmer" diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index d3f30c6c9..6c0446f27 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-emscripten" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Emscripten implementation library for Wasmer WebAssembly runtime" categories = ["wasm", "os"] keywords = ["wasm", "webassembly", "abi", "emscripten", "posix"] @@ -16,8 +16,8 @@ lazy_static = "1.4" libc = "^0.2" log = "0.4" time = { version = "0.2", features = ["std"] } -wasmer = { path = "../api", version = "=3.0.0-rc.2", default-features = false, features = ["sys", "compiler"] } -wasmer-types = { path = "../types", version = "=3.0.0-rc.2" } +wasmer = { path = "../api", version = "=3.0.2", default-features = false, features = ["sys", "compiler"] } +wasmer-types = { path = "../types", version = "=3.0.2" } [target.'cfg(windows)'.dependencies] getrandom = "0.2" diff --git a/lib/middlewares/Cargo.toml b/lib/middlewares/Cargo.toml index b1d11c203..5dadce3b5 100644 --- a/lib/middlewares/Cargo.toml +++ b/lib/middlewares/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-middlewares" -version = "3.0.0-rc.2" +version = "3.0.2" authors = ["Wasmer Engineering Team "] description = "A collection of various useful middlewares" license = "MIT OR Apache-2.0 WITH LLVM-exception" @@ -11,12 +11,12 @@ readme = "README.md" edition = "2018" [dependencies] -wasmer = { path = "../api", version = "=3.0.0-rc.2", default-features = false, features = ["compiler"] } -wasmer-types = { path = "../types", version = "=3.0.0-rc.2" } -wasmer-vm = { path = "../vm", version = "=3.0.0-rc.2" } +wasmer = { path = "../api", version = "=3.0.2", default-features = false, features = ["compiler"] } +wasmer-types = { path = "../types", version = "=3.0.2" } +wasmer-vm = { path = "../vm", version = "=3.0.2" } [dev-dependencies] -wasmer = { path = "../api", version = "=3.0.0-rc.2", features = ["compiler"] } +wasmer = { path = "../api", version = "=3.0.2", features = ["compiler"] } [badges] maintenance = { status = "actively-developed" } diff --git a/lib/object/Cargo.toml b/lib/object/Cargo.toml index 1d3cb2c42..2a7ca2a1d 100644 --- a/lib/object/Cargo.toml +++ b/lib/object/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-object" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Wasmer Native Object generator" categories = ["wasm"] keywords = ["wasm", "webassembly"] @@ -11,6 +11,6 @@ readme = "README.md" edition = "2018" [dependencies] -wasmer-types = { path = "../types", version = "=3.0.0-rc.2" } +wasmer-types = { path = "../types", version = "=3.0.2" } object = { version = "0.28.3", default-features = false, features = ["write"] } thiserror = "1.0" diff --git a/lib/object/src/module.rs b/lib/object/src/module.rs index ad20961ac..cece8077b 100644 --- a/lib/object/src/module.rs +++ b/lib/object/src/module.rs @@ -132,14 +132,19 @@ pub fn emit_compilation( symbol_registry: &impl SymbolRegistry, triple: &Triple, ) -> Result<(), ObjectError> { - let function_bodies = compilation.get_function_bodies(); - let function_relocations = compilation.get_relocations(); - let custom_sections = compilation.get_custom_sections(); - let custom_section_relocations = compilation.get_custom_section_relocations(); - let function_call_trampolines = compilation.get_function_call_trampolines(); - let dynamic_function_trampolines = compilation.get_dynamic_function_trampolines(); + let mut function_bodies = PrimaryMap::with_capacity(compilation.functions.len()); + let mut function_relocations = PrimaryMap::with_capacity(compilation.functions.len()); + for (_, func) in compilation.functions.into_iter() { + function_bodies.push(func.body); + function_relocations.push(func.relocations); + } + let custom_section_relocations = compilation + .custom_sections + .iter() + .map(|(_, section)| section.relocations.clone()) + .collect::>(); - let debug_index = compilation.get_debug().map(|d| d.eh_frame); + let debug_index = compilation.debug.map(|d| d.eh_frame); let align = match triple.architecture { Architecture::X86_64 => 1, @@ -149,7 +154,8 @@ pub fn emit_compilation( }; // Add sections - let custom_section_ids = custom_sections + let custom_section_ids = compilation + .custom_sections .into_iter() .map(|(section_index, custom_section)| { if debug_index.map_or(false, |d| d == section_index) { @@ -223,7 +229,7 @@ pub fn emit_compilation( .collect::>(); // Add function call trampolines - for (signature_index, function) in function_call_trampolines.into_iter() { + for (signature_index, function) in compilation.function_call_trampolines.into_iter() { let function_name = symbol_registry.symbol_to_name(Symbol::FunctionCallTrampoline(signature_index)); let section_id = obj.section_id(StandardSection::Text); @@ -241,7 +247,7 @@ pub fn emit_compilation( } // Add dynamic function trampolines - for (func_index, function) in dynamic_function_trampolines.into_iter() { + for (func_index, function) in compilation.dynamic_function_trampolines.into_iter() { let function_name = symbol_registry.symbol_to_name(Symbol::DynamicFunctionTrampoline(func_index)); let section_id = obj.section_id(StandardSection::Text); diff --git a/lib/registry/Cargo.toml b/lib/registry/Cargo.toml index 03a3a97ea..aa1204a93 100644 --- a/lib/registry/Cargo.toml +++ b/lib/registry/Cargo.toml @@ -1,16 +1,20 @@ [package] name = "wasmer-registry" -version = "3.0.0-rc.2" +version = "3.0.2" edition = "2021" license = "MIT" description = "Crate to interact with the wasmer registry (wapm.io), download packages, etc." +[dev-dependencies] +rand = "0.8.5" + [dependencies] dirs = "4.0.0" graphql_client = "0.11.0" serde = { version = "1.0.145", features = ["derive"] } anyhow = "1.0.65" -reqwest = { version = "0.11.12", default-features = false, features = ["rustls-tls", "blocking", "multipart", "json"] } +reqwest = { version = "0.11.12", default-features = false, features = ["rustls-tls", "blocking", "multipart", "json", "stream"] } +futures-util = "0.3.25" whoami = "1.2.3" serde_json = "1.0.85" url = "2.3.1" @@ -20,4 +24,9 @@ wapm-toml = "0.2.0" tar = "0.4.38" flate2 = "1.0.24" semver = "1.0.14" -lzma-rs = "0.2.0" \ No newline at end of file +lzma-rs = "0.2.0" +webc = { version ="3.0.1", features = ["mmap"] } +hex = "0.4.3" +tokio = "1.21.2" +tempdir = "0.3.7" +log = "0.4.17" diff --git a/lib/registry/graphql/queries/get_bindings.graphql b/lib/registry/graphql/queries/get_bindings.graphql new file mode 100644 index 000000000..bb4d8f966 --- /dev/null +++ b/lib/registry/graphql/queries/get_bindings.graphql @@ -0,0 +1,22 @@ +query GetBindingsQuery ($name: String!, $version: String = "latest") { + packageVersion: getPackageVersion(name:$name, version:$version) { + bindings { + id + language + url + + generator { + packageVersion { + id + version + package { + name + } + } + commandName + } + + __typename + } + } +} diff --git a/lib/registry/graphql/queries/get_package_by_command.graphql b/lib/registry/graphql/queries/get_package_by_command.graphql index 36c64eb19..f201f0190 100644 --- a/lib/registry/graphql/queries/get_package_by_command.graphql +++ b/lib/registry/graphql/queries/get_package_by_command.graphql @@ -7,10 +7,11 @@ query GetPackageByCommandQuery ($commandName: String!) { manifest distribution { downloadUrl + piritaDownloadUrl } package { displayName } } } -} \ No newline at end of file +} diff --git a/lib/registry/graphql/queries/get_package_version.graphql b/lib/registry/graphql/queries/get_package_version.graphql index 6fdd84c9b..b6b09d4b8 100644 --- a/lib/registry/graphql/queries/get_package_version.graphql +++ b/lib/registry/graphql/queries/get_package_version.graphql @@ -7,7 +7,8 @@ query GetPackageVersionQuery ($name: String!, $version: String) { isLastVersion distribution { downloadUrl + piritaDownloadUrl } manifest } -} \ No newline at end of file +} diff --git a/lib/registry/graphql/queries/whoami.graphql b/lib/registry/graphql/queries/whoami.graphql new file mode 100644 index 000000000..0c42eec26 --- /dev/null +++ b/lib/registry/graphql/queries/whoami.graphql @@ -0,0 +1,5 @@ +query WhoAmIQuery { + viewer { + username + } +} \ No newline at end of file diff --git a/lib/registry/graphql/schema.graphql b/lib/registry/graphql/schema.graphql index 07687311d..c79035d96 100644 --- a/lib/registry/graphql/schema.graphql +++ b/lib/registry/graphql/schema.graphql @@ -1,318 +1,304 @@ -type APIToken { - createdAt: DateTime! +interface Node { + """The ID of the object""" id: ID! - identifier: String - lastUsedAt: DateTime +} + +type PublicKey implements Node { + """The ID of the object""" + id: ID! + owner: User! + keyId: String! + key: String! revokedAt: DateTime - user: User! + uploadedAt: DateTime! + verifyingSignature: Signature + revoked: Boolean! } -type APITokenConnection { - # Contains the nodes in this connection. - edges: [APITokenEdge]! +type User implements Node & PackageOwner { + """Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.""" + username: String! + firstName: String! + lastName: String! + email: String! + dateJoined: DateTime! + isEmailValidated: Boolean! + bio: String + location: String + websiteUrl: String - # Pagination data for this connection. + """The ID of the object""" + id: ID! + globalName: String! + avatar(size: Int = 80): String! + isViewer: Boolean! + hasUsablePassword: Boolean + fullName: String! + githubUrl: String + twitterUrl: String + publicActivity(before: String, after: String, first: Int, last: Int): ActivityEventConnection! + namespaces(before: String, after: String, first: Int, last: Int): NamespaceConnection! + packages(collaborating: Boolean = false, before: String, after: String, first: Int, last: Int): PackageConnection! + packageVersions(before: String, after: String, first: Int, last: Int): PackageVersionConnection! + packageTransfersIncoming(before: String, after: String, first: Int, last: Int): PackageTransferRequestConnection! + packageInvitesIncoming(before: String, after: String, first: Int, last: Int): PackageCollaboratorInviteConnection! + namespaceInvitesIncoming(before: String, after: String, first: Int, last: Int): NamespaceCollaboratorInviteConnection! + apiTokens(before: String, after: String, first: Int, last: Int): APITokenConnection! + notifications(before: String, after: String, first: Int, last: Int): UserNotificationConnection! +} + +interface PackageOwner { + globalName: String! +} + +""" +The `DateTime` scalar type represents a DateTime +value as specified by +[iso8601](https://en.wikipedia.org/wiki/ISO_8601). +""" +scalar DateTime + +type ActivityEventConnection { + """Pagination data for this connection.""" pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [ActivityEventEdge]! } -# A Relay edge containing a `APIToken` and its cursor. -type APITokenEdge { - # A cursor for use in pagination +""" +The Relay compliant `PageInfo` type, containing data necessary to paginate this connection. +""" +type PageInfo { + """When paginating forwards, are there more items?""" + hasNextPage: Boolean! + + """When paginating backwards, are there more items?""" + hasPreviousPage: Boolean! + + """When paginating backwards, the cursor to continue.""" + startCursor: String + + """When paginating forwards, the cursor to continue.""" + endCursor: String +} + +"""A Relay edge containing a `ActivityEvent` and its cursor.""" +type ActivityEventEdge { + """The item at the end of the edge""" + node: ActivityEvent + + """A cursor for use in pagination""" cursor: String! - - # The item at the end of the edge - node: APIToken -} - -input AcceptNamespaceCollaboratorInviteInput { - clientMutationId: String - inviteId: ID! -} - -type AcceptNamespaceCollaboratorInvitePayload { - clientMutationId: String - namespaceCollaboratorInvite: NamespaceCollaboratorInvite! -} - -input AcceptPackageCollaboratorInviteInput { - clientMutationId: String - inviteId: ID! -} - -type AcceptPackageCollaboratorInvitePayload { - clientMutationId: String - packageCollaboratorInvite: PackageCollaboratorInvite! -} - -input AcceptPackageTransferRequestInput { - clientMutationId: String - packageTransferRequestId: ID! -} - -type AcceptPackageTransferRequestPayload { - clientMutationId: String - package: Package! - packageTransferRequest: PackageTransferRequest! } type ActivityEvent implements Node { - actorIcon: String! - body: ActivityEventBody! - createdAt: DateTime! - - # The ID of the object + """The ID of the object""" id: ID! + body: ActivityEventBody! + actorIcon: String! + createdAt: DateTime! } type ActivityEventBody { - ranges: [NodeBodyRange!]! text: String! + ranges: [NodeBodyRange!]! } -type ActivityEventConnection { - # Contains the nodes in this connection. - edges: [ActivityEventEdge]! +type NodeBodyRange { + entity: Node! + offset: Int! + length: Int! +} - # Pagination data for this connection. +type NamespaceConnection { + """Pagination data for this connection.""" pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [NamespaceEdge]! } -# A Relay edge containing a `ActivityEvent` and its cursor. -type ActivityEventEdge { - # A cursor for use in pagination +"""A Relay edge containing a `Namespace` and its cursor.""" +type NamespaceEdge { + """The item at the end of the edge""" + node: Namespace + + """A cursor for use in pagination""" cursor: String! - - # The item at the end of the edge - node: ActivityEvent } -input ArchivePackageInput { - clientMutationId: String - packageId: ID! -} - -type ArchivePackagePayload { - clientMutationId: String - package: Package! -} - -input ChangePackageVersionArchivedStatusInput { - clientMutationId: String - isArchived: Boolean - packageVersionId: ID! -} - -type ChangePackageVersionArchivedStatusPayload { - clientMutationId: String - packageVersion: PackageVersion! -} - -input ChangeUserEmailInput { - clientMutationId: String - newEmail: String! -} - -type ChangeUserEmailPayload { - clientMutationId: String - user: User! -} - -input ChangeUserPasswordInput { - clientMutationId: String - password: String! - - # The token associated to change the password. If not existing it will use the request user by default - token: String -} - -type ChangeUserPasswordPayload { - clientMutationId: String - token: String -} - -input ChangeUserUsernameInput { - clientMutationId: String - - # The new user username - username: String! -} - -type ChangeUserUsernamePayload { - clientMutationId: String - token: String - user: User -} - -input CheckUserExistsInput { - clientMutationId: String - - # The user - user: String! -} - -type CheckUserExistsPayload { - clientMutationId: String - exists: Boolean! - - # The user is only returned if the user input was the username - user: User -} - -type Command { - command: String! - module: PackageVersionModule! - packageVersion: PackageVersion! -} - -input CreateNamespaceInput { - # The namespace avatar - avatar: String - clientMutationId: String - - # The namespace description - description: String - - # The namespace display name +type Namespace implements Node & PackageOwner { + """The ID of the object""" + id: ID! + name: String! displayName: String - name: String! -} - -type CreateNamespacePayload { - clientMutationId: String - namespace: Namespace! - user: User! -} - -# The `DateTime` scalar type represents a DateTime -# value as specified by -# [iso8601](https://en.wikipedia.org/wiki/ISO_8601). -scalar DateTime - -input DeleteNamespaceInput { - clientMutationId: String - namespaceId: ID! -} - -type DeleteNamespacePayload { - clientMutationId: String - success: Boolean! -} - -type ErrorType { - field: String! - messages: [String!]! -} - -input GenerateAPITokenInput { - clientMutationId: String - identifier: String -} - -type GenerateAPITokenPayload { - clientMutationId: String - token: APIToken - tokenRaw: String - user: User -} - -# The `GenericScalar` scalar type represents a generic -# GraphQL scalar value that could be: -# String, Boolean, Int, Float, List or Object. -scalar GenericScalar - -type GetPasswordResetToken { - user: User - valid: Boolean! -} - -union GlobalObject = Namespace | User - -input InputSignature { - data: String! - publicKeyKeyId: String! -} - -type Interface implements Node { - createdAt: DateTime! description: String! - displayName: String! - homepage: String - icon: String - - # The ID of the object - id: ID! - lastVersion: InterfaceVersion - name: String! - updatedAt: DateTime! - versions(after: String = null, before: String = null, first: Int = null, last: Int = null, offset: Int = null): InterfaceVersionConnection! -} - -type InterfaceVersion implements Node { - content: String! + avatar: String! + avatarUpdatedAt: DateTime createdAt: DateTime! - - # The ID of the object - id: ID! - interface: Interface! - packageVersions(after: String = null, before: String = null, first: Int = null, last: Int = null, offset: Int = null): PackageVersionConnection! - publishedBy: User! updatedAt: DateTime! - version: String! + maintainerInvites(offset: Int, before: String, after: String, first: Int, last: Int): NamespaceCollaboratorInviteConnection! + userSet(offset: Int, before: String, after: String, first: Int, last: Int): UserConnection! + globalName: String! + packages(before: String, after: String, first: Int, last: Int): PackageConnection! + packageVersions(before: String, after: String, first: Int, last: Int): PackageVersionConnection! + collaborators(before: String, after: String, first: Int, last: Int): NamespaceCollaboratorConnection! + publicActivity(before: String, after: String, first: Int, last: Int): ActivityEventConnection! + pendingInvites(before: String, after: String, first: Int, last: Int): NamespaceCollaboratorInviteConnection! + viewerHasRole(role: Role!): Boolean! + packageTransfersIncoming(before: String, after: String, first: Int, last: Int): PackageTransferRequestConnection! } -type InterfaceVersionConnection { - # Contains the nodes in this connection. - edges: [InterfaceVersionEdge]! - - # Pagination data for this connection. +type NamespaceCollaboratorInviteConnection { + """Pagination data for this connection.""" pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [NamespaceCollaboratorInviteEdge]! } -# A Relay edge containing a `InterfaceVersion` and its cursor. -type InterfaceVersionEdge { - # A cursor for use in pagination +""" +A Relay edge containing a `NamespaceCollaboratorInvite` and its cursor. +""" +type NamespaceCollaboratorInviteEdge { + """The item at the end of the edge""" + node: NamespaceCollaboratorInvite + + """A cursor for use in pagination""" cursor: String! - - # The item at the end of the edge - node: InterfaceVersion } -input InviteNamespaceCollaboratorInput { - clientMutationId: String - email: String - namespaceId: ID! - role: Role! - username: String -} - -type InviteNamespaceCollaboratorPayload { - clientMutationId: String - invite: NamespaceCollaboratorInvite! +type NamespaceCollaboratorInvite implements Node { + """The ID of the object""" + id: ID! + requestedBy: User! + user: User + inviteEmail: String namespace: Namespace! + role: RegistryNamespaceMaintainerInviteRoleChoices! + accepted: NamespaceCollaborator + approvedBy: User + declinedBy: User + createdAt: DateTime! + expiresAt: DateTime! + closedAt: DateTime } -input InvitePackageCollaboratorInput { - clientMutationId: String - email: String +"""An enumeration.""" +enum RegistryNamespaceMaintainerInviteRoleChoices { + """Admin""" + ADMIN + + """Editor""" + EDITOR + + """Viewer""" + VIEWER +} + +type NamespaceCollaborator implements Node { + """The ID of the object""" + id: ID! + user: User! + role: RegistryNamespaceMaintainerRoleChoices! + namespace: Namespace! + createdAt: DateTime! + updatedAt: DateTime! + invite: NamespaceCollaboratorInvite +} + +"""An enumeration.""" +enum RegistryNamespaceMaintainerRoleChoices { + """Admin""" + ADMIN + + """Editor""" + EDITOR + + """Viewer""" + VIEWER +} + +type UserConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [UserEdge]! +} + +"""A Relay edge containing a `User` and its cursor.""" +type UserEdge { + """The item at the end of the edge""" + node: User + + """A cursor for use in pagination""" + cursor: String! +} + +type PackageConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [PackageEdge]! +} + +"""A Relay edge containing a `Package` and its cursor.""" +type PackageEdge { + """The item at the end of the edge""" + node: Package + + """A cursor for use in pagination""" + cursor: String! +} + +type Package implements Likeable & Node & PackageOwner { + """The ID of the object""" + id: ID! + name: String! + namespace: String + private: Boolean! + createdAt: DateTime! + updatedAt: DateTime! + maintainers: [User]! @deprecated(reason: "Please use collaborators instead") + curated: Boolean! + ownerObjectId: Int! + lastVersion: PackageVersion + + """The app icon. It should be formatted in the same way as Apple icons""" + icon: String! + totalDownloads: Int! + iconUpdatedAt: DateTime + watchersCount: Int! + versions: [PackageVersion]! + collectionSet: [Collection!]! + likersCount: Int! + viewerHasLiked: Boolean! + globalName: String! + alias: String + displayName: String! + + """The name of the package without the owner""" packageName: String! - role: Role! - username: String -} -type InvitePackageCollaboratorPayload { - clientMutationId: String - invite: PackageCollaboratorInvite! - package: Package! -} + """The app icon. It should be formatted in the same way as Apple icons""" + appIcon: String! @deprecated(reason: "Please use icon instead") -input LikePackageInput { - clientMutationId: String - packageId: ID! -} + """The total number of downloads of the package""" + downloadsCount: Int -type LikePackagePayload { - clientMutationId: String - package: Package! + """The public keys for all the published versions""" + publicKeys: [PublicKey!]! + collaborators(before: String, after: String, first: Int, last: Int): PackageCollaboratorConnection! + pendingInvites(before: String, after: String, first: Int, last: Int): PackageCollaboratorInviteConnection! + viewerHasRole(role: Role!): Boolean! + owner: PackageOwner! + isTransferring: Boolean! + activeTransferRequest: PackageTransferRequest + isArchived: Boolean! + viewerIsWatching: Boolean! } interface Likeable { @@ -321,726 +307,424 @@ interface Likeable { viewerHasLiked: Boolean! } -type Mutation { - acceptNamespaceCollaboratorInvite(input: AcceptNamespaceCollaboratorInviteInput!): AcceptNamespaceCollaboratorInvitePayload - acceptPackageCollaboratorInvite(input: AcceptPackageCollaboratorInviteInput!): AcceptPackageCollaboratorInvitePayload - acceptPackageTransferRequest(input: AcceptPackageTransferRequestInput!): AcceptPackageTransferRequestPayload - archivePackage(input: ArchivePackageInput!): ArchivePackagePayload - changePackageVersionArchivedStatus(input: ChangePackageVersionArchivedStatusInput!): ChangePackageVersionArchivedStatusPayload - changeUserEmail(input: ChangeUserEmailInput!): ChangeUserEmailPayload - changeUserPassword(input: ChangeUserPasswordInput!): ChangeUserPasswordPayload - changeUserUsername(input: ChangeUserUsernameInput!): ChangeUserUsernamePayload - checkUserExists(input: CheckUserExistsInput!): CheckUserExistsPayload - createNamespace(input: CreateNamespaceInput!): CreateNamespacePayload - deleteNamespace(input: DeleteNamespaceInput!): DeleteNamespacePayload - generateApiToken(input: GenerateAPITokenInput!): GenerateAPITokenPayload - inviteNamespaceCollaborator(input: InviteNamespaceCollaboratorInput!): InviteNamespaceCollaboratorPayload - invitePackageCollaborator(input: InvitePackageCollaboratorInput!): InvitePackageCollaboratorPayload - likePackage(input: LikePackageInput!): LikePackagePayload - publishPackage(input: PublishPackageInput!): PublishPackagePayload - publishPublicKey(input: PublishPublicKeyInput!): PublishPublicKeyPayload - readNotification(input: ReadNotificationInput!): ReadNotificationPayload - refreshToken(input: RefreshInput!): RefreshPayload - registerUser(input: RegisterUserInput!): RegisterUserPayload - removeNamespaceCollaborator(input: RemoveNamespaceCollaboratorInput!): RemoveNamespaceCollaboratorPayload - removeNamespaceCollaboratorInvite(input: RemoveNamespaceCollaboratorInviteInput!): RemoveNamespaceCollaboratorInvitePayload - removePackageCollaborator(input: RemovePackageCollaboratorInput!): RemovePackageCollaboratorPayload - removePackageCollaboratorInvite(input: RemovePackageCollaboratorInviteInput!): RemovePackageCollaboratorInvitePayload - removePackageTransferRequest(input: RemovePackageTransferRequestInput!): RemovePackageTransferRequestPayload - requestPackageTransfer(input: RequestPackageTransferInput!): RequestPackageTransferPayload - requestPasswordReset(input: RequestPasswordResetInput!): RequestPasswordResetPayload - requestValidationEmail(input: RequestValidationEmailInput!): RequestValidationEmailPayload - revokeApiToken(input: RevokeAPITokenInput!): RevokeAPITokenPayload - seePendingNotifications(input: SeePendingNotificationsInput!): SeePendingNotificationsPayload - - # Social Auth for JSON Web Token (JWT) - socialAuth(input: SocialAuthJWTInput!): SocialAuthJWTPayload - - # Obtain JSON Web Token mutation - tokenAuth(input: ObtainJSONWebTokenInput!): ObtainJSONWebTokenPayload - unlikePackage(input: UnlikePackageInput!): UnlikePackagePayload - unwatchPackage(input: UnwatchPackageInput!): UnwatchPackagePayload - updateNamespace(input: UpdateNamespaceInput!): UpdateNamespacePayload - updateNamespaceCollaboratorRole(input: UpdateNamespaceCollaboratorRoleInput!): UpdateNamespaceCollaboratorRolePayload - updatePackage(input: UpdatePackageInput!): UpdatePackagePayload - updatePackageCollaboratorRole(input: UpdatePackageCollaboratorRoleInput!): UpdatePackageCollaboratorRolePayload - updateUserInfo(input: UpdateUserInfoInput!): UpdateUserInfoPayload - validateUserEmail(input: ValidateUserEmailInput!): ValidateUserEmailPayload - validateUserPassword(input: ValidateUserPasswordInput!): ValidateUserPasswordPayload - verifyToken(input: VerifyInput!): VerifyPayload - watchPackage(input: WatchPackageInput!): WatchPackagePayload -} - -type Namespace implements Node & PackageOwner { - avatar: String! - avatarUpdatedAt: DateTime - collaborators(after: String = null, before: String = null, first: Int = null, last: Int = null): NamespaceCollaboratorConnection - createdAt: DateTime! +type PackageVersion implements Node { + """The ID of the object""" + id: ID! + package: Package! + version: String! description: String! - displayName: String - globalName: String! + manifest: String! + license: String + licenseFile: String + readme: String + witMd: String + repository: String + homepage: String + createdAt: DateTime! + updatedAt: DateTime! + staticObjectsCompiled: Boolean! + nativeExecutablesCompiled: Boolean! + publishedBy: User! + signature: Signature + isArchived: Boolean! + file: String! - # The ID of the object - id: ID! - maintainerInvites: [NamespaceCollaboratorInvite!]! - maintainersWithRoles(after: String = null, before: String = null, first: Int = null, last: Int = null, offset: Int = null): NamespaceMaintainerConnection! + """""" + fileSize: BigInt! + piritaFile: String + + """""" + piritaFileSize: BigInt! + piritaManifest: JSONString + piritaVolumes: JSONString + totalDownloads: Int! + hasBindings: Boolean! + lastversionPackage(offset: Int, before: String, after: String, first: Int, last: Int): PackageConnection! + commands: [Command!]! + nativeexecutableSet(offset: Int, before: String, after: String, first: Int, last: Int): NativeExecutableConnection! + bindingsgeneratorSet(offset: Int, before: String, after: String, first: Int, last: Int): BindingsGeneratorConnection! + javascriptlanguagebindingSet(offset: Int, before: String, after: String, first: Int, last: Int): PackageVersionNPMBindingConnection! + pythonlanguagebindingSet(offset: Int, before: String, after: String, first: Int, last: Int): PackageVersionPythonBindingConnection! + distribution: PackageDistribution! + filesystem: [PackageVersionFilesystem]! + isLastVersion: Boolean! + witFile: String + isSigned: Boolean! + moduleInterfaces: [InterfaceVersion!]! + modules: [PackageVersionModule!]! + getPiritaContents(volume: String! = "atom", root: String! = ""): [PiritaFilesystemItem!]! + nativeExecutables(triple: String, wasmerCompilerVersion: String): [NativeExecutable] + bindings: [PackageVersionLanguageBinding]! + npmBindings: PackageVersionNPMBinding + pythonBindings: PackageVersionPythonBinding +} + +""" +The `BigInt` scalar type represents non-fractional whole numeric values. +`BigInt` is not constrained to 32-bit like the `Int` type and thus is a less +compatible type. +""" +scalar BigInt + +""" +Allows use of a JSON String for input / output from the GraphQL schema. + +Use of this type is *not recommended* as you lose the benefits of having a defined, static +schema (one of the key benefits of GraphQL). +""" +scalar JSONString + +type Command { + command: String! + packageVersion: PackageVersion! + module: PackageVersionModule! +} + +type PackageVersionModule { name: String! - packageVersions(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageVersionConnection - packages(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageConnection - pendingInvites(after: String = null, before: String = null, first: Int = null, last: Int = null): NamespaceCollaboratorInviteConnection - publicActivity(after: String = null, before: String = null, first: Int = null, last: Int = null): ActivityEventConnection! - updatedAt: DateTime! - userSet(after: String = null, before: String = null, first: Int = null, last: Int = null, offset: Int = null): UserConnection! - viewerHasRole(role: Role!): Boolean! + source: String! + abi: String + publicUrl: String! } -type NamespaceCollaborator { - createdAt: DateTime! +type NativeExecutableConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [NativeExecutableEdge]! +} + +"""A Relay edge containing a `NativeExecutable` and its cursor.""" +type NativeExecutableEdge { + """The item at the end of the edge""" + node: NativeExecutable + + """A cursor for use in pagination""" + cursor: String! +} + +type NativeExecutable implements Node { + """The ID of the object""" id: ID! - invite: NamespaceCollaboratorInvite - namespace: Namespace! - role: RegistryNamespaceMaintainerRoleChoices! - updatedAt: DateTime! - user: User! + module: String! @deprecated(reason: "Use filename instead") + filename: String! + targetTriple: String! + downloadUrl: String! } -type NamespaceCollaboratorConnection { - # Contains the nodes in this connection. - edges: [NamespaceCollaboratorEdge]! - - # Pagination data for this connection. +type BindingsGeneratorConnection { + """Pagination data for this connection.""" pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [BindingsGeneratorEdge]! } -# A Relay edge containing a `NamespaceCollaborator` and its cursor. -type NamespaceCollaboratorEdge { - # A cursor for use in pagination +"""A Relay edge containing a `BindingsGenerator` and its cursor.""" +type BindingsGeneratorEdge { + """The item at the end of the edge""" + node: BindingsGenerator + + """A cursor for use in pagination""" cursor: String! - - # The item at the end of the edge - node: NamespaceCollaborator } -type NamespaceCollaboratorInvite { - accepted: NamespaceMaintainer - approvedBy: User - closedAt: DateTime - createdAt: DateTime! - declinedBy: User - expiresAt: DateTime! +type BindingsGenerator implements Node { + """The ID of the object""" id: ID! - inviteEmail: String - namespace: Namespace! - requestedBy: User! - role: RegistryNamespaceMaintainerInviteRoleChoices! - user: User + packageVersion: PackageVersion! + commandName: String! + registryJavascriptlanguagebindings(offset: Int, before: String, after: String, first: Int, last: Int): PackageVersionNPMBindingConnection! + registryPythonlanguagebindings(offset: Int, before: String, after: String, first: Int, last: Int): PackageVersionPythonBindingConnection! } -type NamespaceCollaboratorInviteConnection { - # Contains the nodes in this connection. - edges: [NamespaceCollaboratorInviteEdge]! - - # Pagination data for this connection. +type PackageVersionNPMBindingConnection { + """Pagination data for this connection.""" pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [PackageVersionNPMBindingEdge]! } -# A Relay edge containing a `NamespaceCollaboratorInvite` and its cursor. -type NamespaceCollaboratorInviteEdge { - # A cursor for use in pagination +"""A Relay edge containing a `PackageVersionNPMBinding` and its cursor.""" +type PackageVersionNPMBindingEdge { + """The item at the end of the edge""" + node: PackageVersionNPMBinding + + """A cursor for use in pagination""" cursor: String! - - # The item at the end of the edge - node: NamespaceCollaboratorInvite } -type NamespaceConnection { - # Contains the nodes in this connection. - edges: [NamespaceEdge]! +type PackageVersionNPMBinding implements PackageVersionLanguageBinding & Node { + """The ID of the object""" + id: ID! + language: ProgrammingLanguage! - # Pagination data for this connection. - pageInfo: PageInfo! -} + """The URL of the generated artifacts on WAPM's CDN.""" + url: String! -# A Relay edge containing a `Namespace` and its cursor. -type NamespaceEdge { - # A cursor for use in pagination - cursor: String! - - # The item at the end of the edge - node: Namespace -} - -type NamespaceMaintainer implements Node { + """When the binding was generated""" createdAt: DateTime! - # The ID of the object - id: ID! - invite: NamespaceCollaboratorInvite - namespace: Namespace! - role: RegistryNamespaceMaintainerRoleChoices! - updatedAt: DateTime! - user: User! -} + """Package version used to generate this binding""" + generator: BindingsGenerator! + name: String! @deprecated(reason: "Do not use this field, since bindings for all modules are generated at once now.") + kind: String! @deprecated(reason: "Do not use this field, since bindings for all modules are generated at once now.") -type NamespaceMaintainerConnection { - # Contains the nodes in this connection. - edges: [NamespaceMaintainerEdge]! - - # Pagination data for this connection. - pageInfo: PageInfo! -} - -# A Relay edge containing a `NamespaceMaintainer` and its cursor. -type NamespaceMaintainerEdge { - # A cursor for use in pagination - cursor: String! - - # The item at the end of the edge - node: NamespaceMaintainer -} - -# An object with an ID -interface Node { - # The ID of the object - id: ID! -} - -type NodeBodyRange { - entity: Node! - length: Int! - offset: Int! -} - -input ObtainJSONWebTokenInput { - clientMutationId: String - password: String! - username: String! -} - -# Obtain JSON Web Token mutation -type ObtainJSONWebTokenPayload { - clientMutationId: String - payload: GenericScalar! - refreshExpiresIn: Int! - refreshToken: String! - token: String! -} - -type Package implements Likeable & Node & PackageOwner { - alias: String - - # The app icon. It should be formatted in the same way as Apple icons - appIcon: String! @deprecated(reason: "Please use icon instead") - collaborators(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageCollaboratorConnection - createdAt: DateTime! - curated: Boolean! - displayName: String! - - # The total number of downloads of the package - downloadsCount: Int - globalName: String! - - # The app icon. It should be formatted in the same way as Apple icons - icon: String! - iconUpdatedAt: DateTime - - # The ID of the object - id: ID! - isTransferring: Boolean! - lastVersion: PackageVersion - likeCount: Int! - likersCount: Int! - maintainers: [User]! @deprecated(reason: "Please use collaborators instead") - name: String! - namespace: String - owner: PackageOwner - ownerObjectId: Int! - - # The name of the package without the owner + """Name of package source""" packageName: String! - pendingInvites(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageCollaboratorInviteConnection - private: Boolean! - - # The public keys for all the published versions - publicKeys: [PublicKey!]! - updatedAt: DateTime! - versions: [PackageVersion] - viewerHasLiked: Boolean! - viewerHasRole(role: Role!): Boolean! - viewerIsWatching: Boolean! - watchCount: Int! + module: String! @deprecated(reason: "Do not use this field, since bindings for all modules are generated at once now.") + npmDefaultInstallPackageName(url: String): String! @deprecated(reason: "Please use packageName instead") } -type PackageCollaborator implements Node { +interface PackageVersionLanguageBinding { + id: ID! + language: ProgrammingLanguage! + + """The URL of the generated artifacts on WAPM's CDN.""" + url: String! + + """When the binding was generated""" createdAt: DateTime! - # The ID of the object - id: ID! - invite: PackageCollaboratorInvite - package: Package! - role: RegistryPackageMaintainerRoleChoices! - updatedAt: DateTime! - user: User! + """Package version used to generate this binding""" + generator: BindingsGenerator! + name: String! @deprecated(reason: "Do not use this field, since bindings for all modules are generated at once now.") + kind: String! @deprecated(reason: "Do not use this field, since bindings for all modules are generated at once now.") + + """Name of package source""" + packageName: String! + module: String! @deprecated(reason: "Do not use this field, since bindings for all modules are generated at once now.") } -type PackageCollaboratorConnection { - # Contains the nodes in this connection. - edges: [PackageCollaboratorEdge]! +enum ProgrammingLanguage { + PYTHON + JAVASCRIPT +} - # Pagination data for this connection. +type PackageVersionPythonBindingConnection { + """Pagination data for this connection.""" pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [PackageVersionPythonBindingEdge]! } -# A Relay edge containing a `PackageCollaborator` and its cursor. -type PackageCollaboratorEdge { - # A cursor for use in pagination +""" +A Relay edge containing a `PackageVersionPythonBinding` and its cursor. +""" +type PackageVersionPythonBindingEdge { + """The item at the end of the edge""" + node: PackageVersionPythonBinding + + """A cursor for use in pagination""" cursor: String! - - # The item at the end of the edge - node: PackageCollaborator } -type PackageCollaboratorInvite implements Node { - accepted: PackageCollaborator - approvedBy: User - closedAt: DateTime +type PackageVersionPythonBinding implements PackageVersionLanguageBinding & Node { + """The ID of the object""" + id: ID! + language: ProgrammingLanguage! + + """The URL of the generated artifacts on WAPM's CDN.""" + url: String! + + """When the binding was generated""" createdAt: DateTime! - declinedBy: User - expiresAt: DateTime! - # The ID of the object - id: ID! - inviteEmail: String - package: Package! - requestedBy: User! - role: RegistryPackageMaintainerInviteRoleChoices! - user: User -} + """Package version used to generate this binding""" + generator: BindingsGenerator! + name: String! @deprecated(reason: "Do not use this field, since bindings for all modules are generated at once now.") + kind: String! @deprecated(reason: "Do not use this field, since bindings for all modules are generated at once now.") -type PackageCollaboratorInviteConnection { - # Contains the nodes in this connection. - edges: [PackageCollaboratorInviteEdge]! - - # Pagination data for this connection. - pageInfo: PageInfo! -} - -# A Relay edge containing a `PackageCollaboratorInvite` and its cursor. -type PackageCollaboratorInviteEdge { - # A cursor for use in pagination - cursor: String! - - # The item at the end of the edge - node: PackageCollaboratorInvite -} - -type PackageConnection { - # Contains the nodes in this connection. - edges: [PackageEdge]! - - # Pagination data for this connection. - pageInfo: PageInfo! + """Name of package source""" + packageName: String! + module: String! @deprecated(reason: "Do not use this field, since bindings for all modules are generated at once now.") + pythonDefaultInstallPackageName(url: String): String! } type PackageDistribution { downloadUrl: String! size: Int! -} - -# A Relay edge containing a `Package` and its cursor. -type PackageEdge { - # A cursor for use in pagination - cursor: String! - - # The item at the end of the edge - node: Package -} - -interface PackageOwner { - globalName: String! -} - -type PackageTransferRequest implements Node { - approvedBy: User - closedAt: DateTime - createdAt: DateTime! - declinedBy: User - expiresAt: DateTime! - - # The ID of the object - id: ID! - newOwnerObjectId: Int! - package: Package! - previousOwnerObjectId: Int! - requestedBy: User! -} - -type PackageTransferRequestConnection { - # Contains the nodes in this connection. - edges: [PackageTransferRequestEdge]! - - # Pagination data for this connection. - pageInfo: PageInfo! -} - -# A Relay edge containing a `PackageTransferRequest` and its cursor. -type PackageTransferRequestEdge { - # A cursor for use in pagination - cursor: String! - - # The item at the end of the edge - node: PackageTransferRequest -} - -type PackageVersion implements Node { - bindings: [PackageVersionBinding]! - commands: [Command!]! - createdAt: DateTime! - description: String! - distribution: PackageDistribution! - file: String! - fileSize: Int! - filesystem: [PackageVersionFilesystem]! - homepage: String - - # The ID of the object - id: ID! - isArchived: Boolean! - isLastVersion: Boolean! - isSigned: Boolean! - license: String - licenseFile: String - manifest: String! - moduleInterfaces: [InterfaceVersion!]! - modules: [PackageVersionModule!]! - package: Package! - publishedBy: User! - readme: String - repository: String - signature: Signature - updatedAt: DateTime! - version: String! -} - -interface PackageVersionBinding { - # The module these bindings are associated with. - module: String! -} - -type PackageVersionNPMBinding implements PackageVersionBinding { - npmDefaultInstallPackageName: String! -} - -type PackageVersionPythonBinding implements PackageVersionBinding { - pythonDefaultInstallPackageName: String! -} - -type PackageVersionConnection { - # Contains the nodes in this connection. - edges: [PackageVersionEdge]! - - # Pagination data for this connection. - pageInfo: PageInfo! -} - -# A Relay edge containing a `PackageVersion` and its cursor. -type PackageVersionEdge { - # A cursor for use in pagination - cursor: String! - - # The item at the end of the edge - node: PackageVersion + piritaDownloadUrl: String + piritaSize: Int! } type PackageVersionFilesystem { - host: String! wasm: String! + host: String! } -type PackageVersionModule { - abi: String - name: String! - publicUrl: String! - source: String! -} - -# The Relay compliant `PageInfo` type, containing data necessary to paginate this connection. -type PageInfo { - # When paginating forwards, the cursor to continue. - endCursor: String - - # When paginating forwards, are there more items? - hasNextPage: Boolean! - - # When paginating backwards, are there more items? - hasPreviousPage: Boolean! - - # When paginating backwards, the cursor to continue. - startCursor: String -} - -type PublicKey implements Node { - # The ID of the object +type InterfaceVersion implements Node { + """The ID of the object""" id: ID! - key: String! - keyId: String! - owner: User! - revoked: Boolean! - revokedAt: DateTime - uploadedAt: DateTime! - verifyingSignature: Signature -} - -input PublishPackageInput { - clientMutationId: String - description: String! - file: String - homepage: String - - # The package icon - icon: String - license: String - licenseFile: String - manifest: String! - name: String! - readme: String - repository: String - signature: InputSignature + interface: Interface! version: String! + content: String! + createdAt: DateTime! + updatedAt: DateTime! + publishedBy: User! + packageVersions(offset: Int, before: String, after: String, first: Int, last: Int): PackageVersionConnection! } -type PublishPackagePayload { - clientMutationId: String - packageVersion: PackageVersion! - success: Boolean! +type Interface implements Node { + """The ID of the object""" + id: ID! + name: String! + displayName: String! + description: String! + homepage: String + icon: String + createdAt: DateTime! + updatedAt: DateTime! + versions(offset: Int, before: String, after: String, first: Int, last: Int): InterfaceVersionConnection! + lastVersion: InterfaceVersion } -input PublishPublicKeyInput { - clientMutationId: String - key: String! - keyId: String! - verifyingSignatureId: String +type InterfaceVersionConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [InterfaceVersionEdge]! } -type PublishPublicKeyPayload { - clientMutationId: String - publicKey: PublicKey! - success: Boolean! +"""A Relay edge containing a `InterfaceVersion` and its cursor.""" +type InterfaceVersionEdge { + """The item at the end of the edge""" + node: InterfaceVersion + + """A cursor for use in pagination""" + cursor: String! } -type SignedUrl { - url: String! +type PackageVersionConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [PackageVersionEdge]! } -type Query { - getCommand(name: String!): Command - getCommands(names: [String!]!): [Command] - getContract(name: String!): Interface @deprecated(reason: "Please use getInterface instead") - getContractVersion(name: String!, version: String = null): InterfaceVersion @deprecated(reason: "Please use getInterfaceVersion instead") - getContracts(names: [String!]!): [Interface]! @deprecated(reason: "Please use getInterfaces instead") - getGlobalObject(slug: String!): GlobalObject - getInterface(name: String!): Interface - getInterfaceVersion(name: String!, version: String = "latest"): InterfaceVersion - getInterfaces(names: [String!]!): [Interface]! - getNamespace(name: String!): Namespace - getPackage(name: String!): Package - getPackageVersion(name: String!, version: String = "latest"): PackageVersion - getPackageVersions(names: [String!]!): [PackageVersion] - getPackages(names: [String!]!): [Package]! - getPasswordResetToken(token: String!): GetPasswordResetToken - getSignedUrlForPackageUpload(name:String!,version:String!): SignedUrl - getUser(username: String!): User - node( - # The ID of the object - id: ID! - ): Node - packages(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageConnection - recentPackageVersions(after: String = null, before: String = null, curated: Boolean = null, first: Int = null, last: Int = null, offset: Int = null): PackageVersionConnection - search(after: String = null, before: String = null, curated: Boolean = null, first: Int = null, hasBindings: Boolean = null, isStandalone: Boolean = null, kind: [SearchKind!] = null, last: Int = null, orderBy: SearchOrderBy = null, publishDate: SearchPublishDate = null, query: String!, sort: SearchOrderSort = null, withInterfaces: [String!] = null): SearchConnection! - searchAutocomplete(after: String = null, before: String = null, first: Int = null, kind: [SearchKind!] = null, last: Int = null, query: String!): SearchConnection! - viewer: User +"""A Relay edge containing a `PackageVersion` and its cursor.""" +type PackageVersionEdge { + """The item at the end of the edge""" + node: PackageVersion + + """A cursor for use in pagination""" + cursor: String! } -input ReadNotificationInput { - clientMutationId: String - notificationId: ID! +union PiritaFilesystemItem = PiritaFilesystemFile | PiritaFilesystemDir + +type PiritaFilesystemFile { + name(display: PiritaFilesystemNameDisplay): String! + size: Int! + offset: Int! } -type ReadNotificationPayload { - clientMutationId: String - notification: UserNotification +enum PiritaFilesystemNameDisplay { + RELATIVE + ABSOLUTE } -input RefreshInput { - clientMutationId: String - refreshToken: String +type PiritaFilesystemDir { + name(display: PiritaFilesystemNameDisplay): String! } -type RefreshPayload { - clientMutationId: String - payload: GenericScalar! - refreshExpiresIn: Int! - refreshToken: String! - token: String! +type Collection { + slug: String! + displayName: String! + description: String! + createdAt: DateTime! + banner: String! + packages(before: String, after: String, first: Int, last: Int): PackageConnection! } -input RegisterUserInput { - clientMutationId: String - email: String! - fullName: String! - password: String! - username: String! +type PackageCollaboratorConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [PackageCollaboratorEdge]! } -type RegisterUserPayload { - clientMutationId: String - token: String +"""A Relay edge containing a `PackageCollaborator` and its cursor.""" +type PackageCollaboratorEdge { + """The item at the end of the edge""" + node: PackageCollaborator + + """A cursor for use in pagination""" + cursor: String! } -# An enumeration. -enum RegistryNamespaceMaintainerInviteRoleChoices { - # Admin - ADMIN - - # Editor - EDITOR - - # Viewer - VIEWER +type PackageCollaborator implements Node { + """The ID of the object""" + id: ID! + user: User! + role: RegistryPackageMaintainerRoleChoices! + package: Package! + createdAt: DateTime! + updatedAt: DateTime! + invite: PackageCollaboratorInvite } -# An enumeration. -enum RegistryNamespaceMaintainerRoleChoices { - # Admin - ADMIN - - # Editor - EDITOR - - # Viewer - VIEWER -} - -# An enumeration. -enum RegistryPackageMaintainerInviteRoleChoices { - # Admin - ADMIN - - # Editor - EDITOR - - # Viewer - VIEWER -} - -# An enumeration. +"""An enumeration.""" enum RegistryPackageMaintainerRoleChoices { - # Admin + """Admin""" ADMIN - # Editor + """Editor""" EDITOR - # Viewer + """Viewer""" VIEWER } -input RemoveNamespaceCollaboratorInput { - clientMutationId: String - namespaceCollaboratorId: ID! -} - -input RemoveNamespaceCollaboratorInviteInput { - clientMutationId: String - inviteId: ID! -} - -type RemoveNamespaceCollaboratorInvitePayload { - clientMutationId: String - namespace: Namespace! -} - -type RemoveNamespaceCollaboratorPayload { - clientMutationId: String - namespace: Namespace! -} - -input RemovePackageCollaboratorInput { - clientMutationId: String - packageCollaboratorId: ID! -} - -input RemovePackageCollaboratorInviteInput { - clientMutationId: String - inviteId: ID! -} - -type RemovePackageCollaboratorInvitePayload { - clientMutationId: String - package: Package! -} - -type RemovePackageCollaboratorPayload { - clientMutationId: String - package: Package! -} - -input RemovePackageTransferRequestInput { - clientMutationId: String - packageTransferRequestId: ID! -} - -type RemovePackageTransferRequestPayload { - clientMutationId: String - package: Package! -} - -input RequestPackageTransferInput { - clientMutationId: String - newOwnerId: ID! - packageId: ID! -} - -type RequestPackageTransferPayload { - clientMutationId: String - package: Package! -} - -input RequestPasswordResetInput { - clientMutationId: String - email: String! -} - -type RequestPasswordResetPayload { - clientMutationId: String - email: String! - errors: [ErrorType] -} - -input RequestValidationEmailInput { - clientMutationId: String - - # The user id - userId: ID -} - -type RequestValidationEmailPayload { - clientMutationId: String - success: Boolean! +type PackageCollaboratorInvite implements Node { + """The ID of the object""" + id: ID! + requestedBy: User! user: User + inviteEmail: String + package: Package! + role: RegistryPackageMaintainerInviteRoleChoices! + accepted: PackageCollaborator + approvedBy: User + declinedBy: User + createdAt: DateTime! + expiresAt: DateTime! + closedAt: DateTime } -input RevokeAPITokenInput { - clientMutationId: String +"""An enumeration.""" +enum RegistryPackageMaintainerInviteRoleChoices { + """Admin""" + ADMIN - # The API token ID - tokenId: ID! + """Editor""" + EDITOR + + """Viewer""" + VIEWER } -type RevokeAPITokenPayload { - clientMutationId: String - success: Boolean - token: APIToken +type PackageCollaboratorInviteConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [PackageCollaboratorInviteEdge]! +} + +"""A Relay edge containing a `PackageCollaboratorInvite` and its cursor.""" +type PackageCollaboratorInviteEdge { + """The item at the end of the edge""" + node: PackageCollaboratorInvite + + """A cursor for use in pagination""" + cursor: String! } enum Role { @@ -1049,34 +733,226 @@ enum Role { VIEWER } -type SearchConnection { - # Contains the nodes in this connection. - edges: [SearchEdge]! +type PackageTransferRequest implements Node { + """The ID of the object""" + id: ID! + requestedBy: User! + previousOwnerObjectId: Int! + newOwnerObjectId: Int! + package: Package! + approvedBy: User + declinedBy: User + createdAt: DateTime! + expiresAt: DateTime! + closedAt: DateTime + previousOwner: PackageOwner! + newOwner: PackageOwner! +} - # Pagination data for this connection. +type NamespaceCollaboratorConnection { + """Pagination data for this connection.""" pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [NamespaceCollaboratorEdge]! } -# A Relay edge containing a `Search` and its cursor. -type SearchEdge { - # A cursor for use in pagination +"""A Relay edge containing a `NamespaceCollaborator` and its cursor.""" +type NamespaceCollaboratorEdge { + """The item at the end of the edge""" + node: NamespaceCollaborator + + """A cursor for use in pagination""" cursor: String! +} - # The item at the end of the edge +type PackageTransferRequestConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [PackageTransferRequestEdge]! +} + +"""A Relay edge containing a `PackageTransferRequest` and its cursor.""" +type PackageTransferRequestEdge { + """The item at the end of the edge""" + node: PackageTransferRequest + + """A cursor for use in pagination""" + cursor: String! +} + +type APITokenConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [APITokenEdge]! +} + +"""A Relay edge containing a `APIToken` and its cursor.""" +type APITokenEdge { + """The item at the end of the edge""" + node: APIToken + + """A cursor for use in pagination""" + cursor: String! +} + +type APIToken { + id: ID! + user: User! + identifier: String + createdAt: DateTime! + revokedAt: DateTime + lastUsedAt: DateTime +} + +type UserNotificationConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [UserNotificationEdge]! + hasPendingNotifications: Boolean! +} + +"""A Relay edge containing a `UserNotification` and its cursor.""" +type UserNotificationEdge { + """The item at the end of the edge""" + node: UserNotification + + """A cursor for use in pagination""" + cursor: String! +} + +type UserNotification implements Node { + """The ID of the object""" + id: ID! + icon: String + body: UserNotificationBody! + seenState: UserNotificationSeenState! + kind: UserNotificationKind + createdAt: DateTime! +} + +type UserNotificationBody { + text: String! + ranges: [NodeBodyRange]! +} + +enum UserNotificationSeenState { + UNSEEN + SEEN + SEEN_AND_READ +} + +union UserNotificationKind = UserNotificationKindPublishedPackageVersion | UserNotificationKindIncomingPackageTransfer | UserNotificationKindIncomingPackageInvite | UserNotificationKindIncomingNamespaceInvite + +type UserNotificationKindPublishedPackageVersion { + packageVersion: PackageVersion! +} + +type UserNotificationKindIncomingNamespaceInvite { + namespaceInvite: NamespaceCollaboratorInvite! +} + +type Signature { + id: ID! + publicKey: PublicKey! + data: String! + createdAt: DateTime! +} + +type UserNotificationKindIncomingPackageTransfer { + packageTransferRequest: PackageTransferRequest! +} + +type UserNotificationKindIncomingPackageInvite { + packageInvite: PackageCollaboratorInvite! +} + +type Query { + viewer: User + getUser(username: String!): User + getPasswordResetToken(token: String!): GetPasswordResetToken + packages(before: String, after: String, first: Int, last: Int): PackageConnection + recentPackageVersions(curated: Boolean, offset: Int, before: String, after: String, first: Int, last: Int): PackageVersionConnection! + getNamespace(name: String!): Namespace + getPackage(name: String!): Package + getPackages(names: [String!]!): [Package]! + getPackageVersion(name: String!, version: String = "latest"): PackageVersion + getPackageVersions(names: [String!]!): [PackageVersion] + getInterface(name: String!): Interface + getInterfaces(names: [String!]!): [Interface]! + getInterfaceVersion(name: String!, version: String = "latest"): InterfaceVersion + getContract(name: String!): Interface @deprecated(reason: "Please use getInterface instead") + getContracts(names: [String!]!): [Interface]! @deprecated(reason: "Please use getInterfaces instead") + getContractVersion(name: String!, version: String): InterfaceVersion @deprecated(reason: "Please use getInterfaceVersion instead") + getCommand(name: String!): Command + getCommands(names: [String!]!): [Command] + getCollections(before: String, after: String, first: Int, last: Int): CollectionConnection + getSignedUrlForPackageUpload(name: String!, version: String = "latest", expiresAfterSeconds: Int = 60): SignedUrl + search(query: String!, curated: Boolean, orderBy: SearchOrderBy, sort: SearchOrderSort, kind: [SearchKind!], publishDate: SearchPublishDate, hasBindings: Boolean, isStandalone: Boolean, withInterfaces: [String!], before: String, after: String, first: Int, last: Int): SearchConnection! + searchAutocomplete(kind: [SearchKind!], query: String!, before: String, after: String, first: Int, last: Int): SearchConnection! + getGlobalObject(slug: String!): GlobalObject + node( + """The ID of the object""" + id: ID! + ): Node +} + +type GetPasswordResetToken { + valid: Boolean! + user: User +} + +type CollectionConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [CollectionEdge]! +} + +"""A Relay edge containing a `Collection` and its cursor.""" +type CollectionEdge { + """The item at the end of the edge""" + node: Collection + + """A cursor for use in pagination""" + cursor: String! +} + +type SignedUrl { + url: String! +} + +type SearchConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [SearchEdge]! +} + +"""A Relay edge containing a `Search` and its cursor.""" +type SearchEdge { + """The item at the end of the edge""" node: SearchResult + + """A cursor for use in pagination""" + cursor: String! } -enum SearchKind { - NAMESPACE - PACKAGE - USER -} +union SearchResult = PackageVersion | User | Namespace enum SearchOrderBy { ALPHABETICALLY - PUBLISHED_DATE SIZE TOTAL_DOWNLOADS + PUBLISHED_DATE } enum SearchOrderSort { @@ -1084,318 +960,643 @@ enum SearchOrderSort { DESC } +enum SearchKind { + PACKAGE + NAMESPACE + USER +} + enum SearchPublishDate { LAST_DAY - LAST_MONTH LAST_WEEK + LAST_MONTH LAST_YEAR } -union SearchResult = Namespace | PackageVersion | User +union GlobalObject = User | Namespace + +type Mutation { + tokenAuth(input: ObtainJSONWebTokenInput!): ObtainJSONWebTokenPayload + registerUser(input: RegisterUserInput!): RegisterUserPayload + socialAuth(input: SocialAuthJWTInput!): SocialAuthJWTPayload + validateUserEmail(input: ValidateUserEmailInput!): ValidateUserEmailPayload + requestPasswordReset(input: RequestPasswordResetInput!): RequestPasswordResetPayload + requestValidationEmail(input: RequestValidationEmailInput!): RequestValidationEmailPayload + changeUserPassword(input: ChangeUserPasswordInput!): ChangeUserPasswordPayload + changeUserUsername(input: ChangeUserUsernameInput!): ChangeUserUsernamePayload + changeUserEmail(input: ChangeUserEmailInput!): ChangeUserEmailPayload + updateUserInfo(input: UpdateUserInfoInput!): UpdateUserInfoPayload + validateUserPassword(input: ValidateUserPasswordInput!): ValidateUserPasswordPayload + generateApiToken(input: GenerateAPITokenInput!): GenerateAPITokenPayload + revokeApiToken(input: RevokeAPITokenInput!): RevokeAPITokenPayload + checkUserExists(input: CheckUserExistsInput!): CheckUserExistsPayload + readNotification(input: ReadNotificationInput!): ReadNotificationPayload + seePendingNotifications(input: SeePendingNotificationsInput!): SeePendingNotificationsPayload + publishPublicKey(input: PublishPublicKeyInput!): PublishPublicKeyPayload + publishPackage(input: PublishPackageInput!): PublishPackagePayload + updatePackage(input: UpdatePackageInput!): UpdatePackagePayload + likePackage(input: LikePackageInput!): LikePackagePayload + unlikePackage(input: UnlikePackageInput!): UnlikePackagePayload + watchPackage(input: WatchPackageInput!): WatchPackagePayload + unwatchPackage(input: UnwatchPackageInput!): UnwatchPackagePayload + archivePackage(input: ArchivePackageInput!): ArchivePackagePayload + changePackageVersionArchivedStatus(input: ChangePackageVersionArchivedStatusInput!): ChangePackageVersionArchivedStatusPayload + createNamespace(input: CreateNamespaceInput!): CreateNamespacePayload + updateNamespace(input: UpdateNamespaceInput!): UpdateNamespacePayload + deleteNamespace(input: DeleteNamespaceInput!): DeleteNamespacePayload + inviteNamespaceCollaborator(input: InviteNamespaceCollaboratorInput!): InviteNamespaceCollaboratorPayload + acceptNamespaceCollaboratorInvite(input: AcceptNamespaceCollaboratorInviteInput!): AcceptNamespaceCollaboratorInvitePayload + removeNamespaceCollaboratorInvite(input: RemoveNamespaceCollaboratorInviteInput!): RemoveNamespaceCollaboratorInvitePayload + removeNamespaceCollaborator(input: RemoveNamespaceCollaboratorInput!): RemoveNamespaceCollaboratorPayload + updateNamespaceCollaboratorRole(input: UpdateNamespaceCollaboratorRoleInput!): UpdateNamespaceCollaboratorRolePayload + updateNamespaceCollaboratorInviteRole(input: UpdateNamespaceCollaboratorInviteRoleInput!): UpdateNamespaceCollaboratorInviteRolePayload + invitePackageCollaborator(input: InvitePackageCollaboratorInput!): InvitePackageCollaboratorPayload + acceptPackageCollaboratorInvite(input: AcceptPackageCollaboratorInviteInput!): AcceptPackageCollaboratorInvitePayload + removePackageCollaboratorInvite(input: RemovePackageCollaboratorInviteInput!): RemovePackageCollaboratorInvitePayload + updatePackageCollaboratorRole(input: UpdatePackageCollaboratorRoleInput!): UpdatePackageCollaboratorRolePayload + updatePackageCollaboratorInviteRole(input: UpdatePackageCollaboratorInviteRoleInput!): UpdatePackageCollaboratorInviteRolePayload + removePackageCollaborator(input: RemovePackageCollaboratorInput!): RemovePackageCollaboratorPayload + requestPackageTransfer(input: RequestPackageTransferInput!): RequestPackageTransferPayload + acceptPackageTransferRequest(input: AcceptPackageTransferRequestInput!): AcceptPackageTransferRequestPayload + removePackageTransferRequest(input: RemovePackageTransferRequestInput!): RemovePackageTransferRequestPayload +} + +type ObtainJSONWebTokenPayload { + payload: GenericScalar! + refreshExpiresIn: Int! + clientMutationId: String + token: String! + refreshToken: String! +} + +""" +The `GenericScalar` scalar type represents a generic +GraphQL scalar value that could be: +String, Boolean, Int, Float, List or Object. +""" +scalar GenericScalar + +input ObtainJSONWebTokenInput { + clientMutationId: String + username: String! + password: String! +} + +type RegisterUserPayload { + token: String + clientMutationId: String +} + +input RegisterUserInput { + fullName: String! + email: String! + username: String! + password: String! + clientMutationId: String +} + +type SocialAuthJWTPayload { + social: SocialAuth + token: String + clientMutationId: String +} + +type SocialAuth implements Node { + """The ID of the object""" + id: ID! + user: User! + provider: String! + uid: String! + extraData: String! + created: DateTime! + modified: DateTime! +} + +input SocialAuthJWTInput { + provider: String! + accessToken: String! + clientMutationId: String +} + +type ValidateUserEmailPayload { + user: User + clientMutationId: String +} + +input ValidateUserEmailInput { + """The user id""" + userId: ID + challenge: String! + clientMutationId: String +} + +type RequestPasswordResetPayload { + email: String! + errors: [ErrorType] + clientMutationId: String +} + +type ErrorType { + field: String! + messages: [String!]! +} + +input RequestPasswordResetInput { + email: String! + clientMutationId: String +} + +type RequestValidationEmailPayload { + user: User + success: Boolean! + clientMutationId: String +} + +input RequestValidationEmailInput { + """The user id""" + userId: ID + clientMutationId: String +} + +type ChangeUserPasswordPayload { + token: String + clientMutationId: String +} + +input ChangeUserPasswordInput { + """ + The token associated to change the password. If not existing it will use the request user by default + """ + token: String + oldPassword: String + password: String! + clientMutationId: String +} + +type ChangeUserUsernamePayload { + user: User + token: String + clientMutationId: String +} + +input ChangeUserUsernameInput { + """The new user username""" + username: String! + clientMutationId: String +} + +type ChangeUserEmailPayload { + user: User! + clientMutationId: String +} + +input ChangeUserEmailInput { + newEmail: String! + clientMutationId: String +} + +type UpdateUserInfoPayload { + user: User + clientMutationId: String +} + +input UpdateUserInfoInput { + """The user id""" + userId: ID + + """The user full name""" + fullName: String + + """The user bio""" + bio: String + + """The user avatar""" + avatar: String + + """ + The user Twitter (it can be the url, or the handle with or without the @) + """ + twitter: String + + """ + The user Github (it can be the url, or the handle with or without the @) + """ + github: String + + """The user website (it must be a valid url)""" + websiteUrl: String + + """The user location""" + location: String + clientMutationId: String +} + +type ValidateUserPasswordPayload { + success: Boolean + clientMutationId: String +} + +input ValidateUserPasswordInput { + password: String! + clientMutationId: String +} + +type GenerateAPITokenPayload { + token: APIToken + tokenRaw: String + user: User + clientMutationId: String +} + +input GenerateAPITokenInput { + identifier: String + clientMutationId: String +} + +type RevokeAPITokenPayload { + token: APIToken + success: Boolean + clientMutationId: String +} + +input RevokeAPITokenInput { + """The API token ID""" + tokenId: ID! + clientMutationId: String +} + +type CheckUserExistsPayload { + exists: Boolean! + + """The user is only returned if the user input was the username""" + user: User + clientMutationId: String +} + +input CheckUserExistsInput { + """The user""" + user: String! + clientMutationId: String +} + +type ReadNotificationPayload { + notification: UserNotification + clientMutationId: String +} + +input ReadNotificationInput { + notificationId: ID! + clientMutationId: String +} + +type SeePendingNotificationsPayload { + success: Boolean + clientMutationId: String +} input SeePendingNotificationsInput { clientMutationId: String } -type SeePendingNotificationsPayload { - clientMutationId: String - success: Boolean -} - -type Signature { - createdAt: DateTime! - data: String! - id: ID! +type PublishPublicKeyPayload { + success: Boolean! publicKey: PublicKey! -} - -input SocialAuthJWTInput { - accessToken: String! clientMutationId: String - provider: String! } -# Social Auth for JSON Web Token (JWT) -type SocialAuthJWTPayload { +input PublishPublicKeyInput { + keyId: String! + key: String! + verifyingSignatureId: String clientMutationId: String - social: SocialNode - token: String } -scalar SocialCamelJSON - -type SocialNode implements Node { - created: DateTime! - extraData: SocialCamelJSON - - # The ID of the object - id: ID! - modified: DateTime! - provider: String! - uid: String! - user: User! -} - -type Subscription { - packageVersionCreated(ownerId: ID = null, publishedBy: ID = null): PackageVersion! - userNotificationCreated(userId: ID!): UserNotificationCreated! -} - -input UnlikePackageInput { +type PublishPackagePayload { + success: Boolean! + packageVersion: PackageVersion! clientMutationId: String - packageId: ID! } -type UnlikePackagePayload { - clientMutationId: String - package: Package! -} +input PublishPackageInput { + name: String! + version: String! + description: String! + manifest: String! + license: String + licenseFile: String + readme: String + repository: String + homepage: String + file: String + signedUrl: String + signature: InputSignature -input UnwatchPackageInput { - clientMutationId: String - packageId: ID! -} - -type UnwatchPackagePayload { - clientMutationId: String - package: Package! -} - -input UpdateNamespaceCollaboratorRoleInput { - clientMutationId: String - namespaceCollaboratorId: ID! - role: Role! -} - -type UpdateNamespaceCollaboratorRolePayload { - clientMutationId: String - collaborator: NamespaceCollaborator! -} - -input UpdateNamespaceInput { - # The namespace avatar - avatar: String - clientMutationId: String - - # The namespace description - description: String - - # The namespace display name - displayName: String - - # The namespace slug name - name: String - namespaceId: ID! -} - -type UpdateNamespacePayload { - clientMutationId: String - namespace: Namespace! -} - -input UpdatePackageCollaboratorRoleInput { - clientMutationId: String - packageCollaboratorId: ID! - role: Role! -} - -type UpdatePackageCollaboratorRolePayload { - clientMutationId: String - collaborator: PackageCollaborator! -} - -input UpdatePackageInput { - clientMutationId: String - - # The package icon + """The package icon""" icon: String - packageId: ID! + clientMutationId: String +} + +input InputSignature { + publicKeyKeyId: String! + data: String! } type UpdatePackagePayload { - clientMutationId: String package: Package! -} - -input UpdateUserInfoInput { - # The user avatar - avatar: String - - # The user bio - bio: String clientMutationId: String - - # The user full name - fullName: String - - # The user Github (it can be the url, or the handle with or without the @) - github: String - - # The user location - location: String - - # The user Twitter (it can be the url, or the handle with or without the @) - twitter: String - - # The user id - userId: ID - - # The user website (it must be a valid url) - websiteUrl: String } -type UpdateUserInfoPayload { - clientMutationId: String - user: User -} +input UpdatePackageInput { + packageId: ID! -type User implements Node & PackageOwner { - apiTokens(after: String = null, before: String = null, first: Int = null, last: Int = null): APITokenConnection - avatar(size: Int = 80): String! - bio: String - dateJoined: DateTime! - email: String! - firstName: String! - fullName: String! - githubUrl: String - globalName: String! - - # The ID of the object - id: ID! - isEmailValidated: Boolean! - isViewer: Boolean! - lastName: String! - location: String - namespaceInvitesIncoming(after: String = null, before: String = null, first: Int = null, last: Int = null): NamespaceCollaboratorInviteConnection - namespaces(after: String = null, before: String = null, first: Int = null, last: Int = null): NamespaceConnection - notifications(after: String = null, before: String = null, first: Int = null, last: Int = null): UserNotificationConnection - packageInvitesIncoming(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageCollaboratorInviteConnection - packageTransfersIncoming(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageTransferRequestConnection - packageVersions(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageVersionConnection - packages(after: String = null, before: String = null, collaborating: Boolean = null, first: Int = null, last: Int = null): PackageConnection - publicActivity(after: String = null, before: String = null, first: Int = null, last: Int = null): ActivityEventConnection! - twitterUrl: String - - # Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. - username: String! - websiteUrl: String -} - -type UserConnection { - # Contains the nodes in this connection. - edges: [UserEdge]! - - # Pagination data for this connection. - pageInfo: PageInfo! -} - -# A Relay edge containing a `User` and its cursor. -type UserEdge { - # A cursor for use in pagination - cursor: String! - - # The item at the end of the edge - node: User -} - -type UserNotification implements Node { - body: UserNotificationBody! - createdAt: DateTime! + """The package icon""" icon: String - - # The ID of the object - id: ID! - kind: UserNotificationKind - seenState: UserNotificationSeenState! + clientMutationId: String } -type UserNotificationBody { - ranges: [NodeBodyRange]! - text: String! +type LikePackagePayload { + package: Package! + clientMutationId: String } -type UserNotificationConnection { - # Contains the nodes in this connection. - edges: [UserNotificationEdge]! - hasPendingNotifications: Boolean! +input LikePackageInput { + packageId: ID! + clientMutationId: String +} - # Pagination data for this connection. - pageInfo: PageInfo! +type UnlikePackagePayload { + package: Package! + clientMutationId: String +} + +input UnlikePackageInput { + packageId: ID! + clientMutationId: String +} + +type WatchPackagePayload { + package: Package! + clientMutationId: String +} + +input WatchPackageInput { + packageId: ID! + clientMutationId: String +} + +type UnwatchPackagePayload { + package: Package! + clientMutationId: String +} + +input UnwatchPackageInput { + packageId: ID! + clientMutationId: String +} + +type ArchivePackagePayload { + package: Package! + clientMutationId: String +} + +input ArchivePackageInput { + packageId: ID! + clientMutationId: String +} + +type ChangePackageVersionArchivedStatusPayload { + packageVersion: PackageVersion! + clientMutationId: String +} + +input ChangePackageVersionArchivedStatusInput { + packageVersionId: ID! + isArchived: Boolean + clientMutationId: String +} + +type CreateNamespacePayload { + namespace: Namespace! + user: User! + clientMutationId: String +} + +input CreateNamespaceInput { + name: String! + + """The namespace display name""" + displayName: String + + """The namespace description""" + description: String + + """The namespace avatar""" + avatar: String + clientMutationId: String +} + +type UpdateNamespacePayload { + namespace: Namespace! + clientMutationId: String +} + +input UpdateNamespaceInput { + namespaceId: ID! + + """The namespace slug name""" + name: String + + """The namespace display name""" + displayName: String + + """The namespace description""" + description: String + + """The namespace avatar""" + avatar: String + clientMutationId: String +} + +type DeleteNamespacePayload { + success: Boolean! + clientMutationId: String +} + +input DeleteNamespaceInput { + namespaceId: ID! + clientMutationId: String +} + +type InviteNamespaceCollaboratorPayload { + invite: NamespaceCollaboratorInvite! + namespace: Namespace! + clientMutationId: String +} + +input InviteNamespaceCollaboratorInput { + namespaceId: ID! + role: Role! + username: String + email: String + clientMutationId: String +} + +type AcceptNamespaceCollaboratorInvitePayload { + namespaceCollaboratorInvite: NamespaceCollaboratorInvite! + clientMutationId: String +} + +input AcceptNamespaceCollaboratorInviteInput { + inviteId: ID! + clientMutationId: String +} + +type RemoveNamespaceCollaboratorInvitePayload { + namespace: Namespace! + clientMutationId: String +} + +input RemoveNamespaceCollaboratorInviteInput { + inviteId: ID! + clientMutationId: String +} + +type RemoveNamespaceCollaboratorPayload { + namespace: Namespace! + clientMutationId: String +} + +input RemoveNamespaceCollaboratorInput { + namespaceCollaboratorId: ID! + clientMutationId: String +} + +type UpdateNamespaceCollaboratorRolePayload { + collaborator: NamespaceCollaborator! + clientMutationId: String +} + +input UpdateNamespaceCollaboratorRoleInput { + namespaceCollaboratorId: ID! + role: Role! + clientMutationId: String +} + +type UpdateNamespaceCollaboratorInviteRolePayload { + collaboratorInvite: NamespaceCollaboratorInvite! + clientMutationId: String +} + +input UpdateNamespaceCollaboratorInviteRoleInput { + namespaceCollaboratorInviteId: ID! + role: Role! + clientMutationId: String +} + +type InvitePackageCollaboratorPayload { + invite: PackageCollaboratorInvite! + package: Package! + clientMutationId: String +} + +input InvitePackageCollaboratorInput { + packageName: String! + role: Role! + username: String + email: String + clientMutationId: String +} + +type AcceptPackageCollaboratorInvitePayload { + packageCollaboratorInvite: PackageCollaboratorInvite! + clientMutationId: String +} + +input AcceptPackageCollaboratorInviteInput { + inviteId: ID! + clientMutationId: String +} + +type RemovePackageCollaboratorInvitePayload { + package: Package! + clientMutationId: String +} + +input RemovePackageCollaboratorInviteInput { + inviteId: ID! + clientMutationId: String +} + +type UpdatePackageCollaboratorRolePayload { + collaborator: PackageCollaborator! + clientMutationId: String +} + +input UpdatePackageCollaboratorRoleInput { + packageCollaboratorId: ID! + role: Role! + clientMutationId: String +} + +type UpdatePackageCollaboratorInviteRolePayload { + collaboratorInvite: PackageCollaboratorInvite! + clientMutationId: String +} + +input UpdatePackageCollaboratorInviteRoleInput { + packageCollaboratorInviteId: ID! + role: Role! + clientMutationId: String +} + +type RemovePackageCollaboratorPayload { + package: Package! + clientMutationId: String +} + +input RemovePackageCollaboratorInput { + packageCollaboratorId: ID! + clientMutationId: String +} + +type RequestPackageTransferPayload { + package: Package! + clientMutationId: String +} + +input RequestPackageTransferInput { + packageId: ID! + newOwnerId: ID! + clientMutationId: String +} + +type AcceptPackageTransferRequestPayload { + package: Package! + packageTransferRequest: PackageTransferRequest! + clientMutationId: String +} + +input AcceptPackageTransferRequestInput { + packageTransferRequestId: ID! + clientMutationId: String +} + +type RemovePackageTransferRequestPayload { + package: Package! + clientMutationId: String +} + +input RemovePackageTransferRequestInput { + packageTransferRequestId: ID! + clientMutationId: String +} + +type Subscription { + packageVersionCreated(publishedBy: ID, ownerId: ID): PackageVersion! + userNotificationCreated(userId: ID!): UserNotificationCreated! } type UserNotificationCreated { notification: UserNotification notificationDeletedId: ID } - -# A Relay edge containing a `UserNotification` and its cursor. -type UserNotificationEdge { - # A cursor for use in pagination - cursor: String! - - # The item at the end of the edge - node: UserNotification -} - -union UserNotificationKind = UserNotificationKindIncomingPackageInvite | UserNotificationKindIncomingPackageTransfer | UserNotificationKindPublishedPackageVersion - -type UserNotificationKindIncomingPackageInvite { - packageInvite: PackageCollaboratorInvite! -} - -type UserNotificationKindIncomingPackageTransfer { - packageTransferRequest: PackageTransferRequest! -} - -type UserNotificationKindPublishedPackageVersion { - packageVersion: PackageVersion! -} - -enum UserNotificationSeenState { - SEEN - SEEN_AND_READ - UNSEEN -} - -input ValidateUserEmailInput { - challenge: String! - clientMutationId: String - - # The user id - userId: ID -} - -type ValidateUserEmailPayload { - clientMutationId: String - user: User -} - -input ValidateUserPasswordInput { - clientMutationId: String - password: String! -} - -type ValidateUserPasswordPayload { - clientMutationId: String - success: Boolean -} - -input VerifyInput { - clientMutationId: String - token: String -} - -type VerifyPayload { - clientMutationId: String - payload: GenericScalar! -} - -input WatchPackageInput { - clientMutationId: String - packageId: ID! -} - -type WatchPackagePayload { - clientMutationId: String - package: Package! -} diff --git a/lib/registry/src/config.rs b/lib/registry/src/config.rs new file mode 100644 index 000000000..422da94b4 --- /dev/null +++ b/lib/registry/src/config.rs @@ -0,0 +1,314 @@ +use graphql_client::GraphQLQuery; +use serde::Deserialize; +use serde::Serialize; +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; + +#[derive(Deserialize, Default, Serialize, Debug, PartialEq, Eq)] +pub struct PartialWapmConfig { + /// The number of seconds to wait before checking the registry for a new + /// version of the package. + #[serde(default = "wax_default_cooldown")] + pub wax_cooldown: i32, + + /// The registry that wapm will connect to. + pub registry: Registries, + + /// Whether or not telemetry is enabled. + #[serde(default)] + pub telemetry: Telemetry, + + /// Whether or not updated notifications are enabled. + #[serde(default)] + pub update_notifications: UpdateNotifications, + + /// The proxy to use when connecting to the Internet. + #[serde(default)] + pub proxy: Proxy, +} + +pub const fn wax_default_cooldown() -> i32 { + 5 * 60 +} + +#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Default)] +pub struct Proxy { + pub url: Option, +} + +#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Default)] +pub struct UpdateNotifications { + pub enabled: String, +} + +#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Default)] +pub struct Telemetry { + pub enabled: String, +} + +#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)] +#[serde(untagged)] +pub enum Registries { + Single(Registry), + Multi(MultiRegistry), +} + +#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)] +pub struct MultiRegistry { + /// Currently active registry + pub current: String, + /// Map from "RegistryUrl" to "LoginToken", in order to + /// be able to be able to easily switch between registries + pub tokens: BTreeMap, +} + +impl Default for Registries { + fn default() -> Self { + Registries::Single(Registry { + url: format_graphql("https://registry.wapm.io"), + token: None, + }) + } +} + +#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)] +pub struct Registry { + pub url: String, + pub token: Option, +} + +pub fn format_graphql(registry: &str) -> String { + let mut registry = registry.to_string(); + if registry.contains("wapm.dev") { + registry = "https://registry.wapm.dev/graphql".to_string(); + } else if registry.contains("wapm.io") { + registry = "https://registry.wapm.io/graphql".to_string(); + } + if !registry.starts_with("https://") { + registry = format!("https://{registry}"); + } + if registry.ends_with("/graphql") { + registry + } else if registry.ends_with('/') { + format!("{}graphql", registry) + } else { + format!("{}/graphql", registry) + } +} + +fn test_if_registry_present(registry: &str) -> Result<(), String> { + crate::utils::get_username_registry_token(registry, "") + .map(|_| ()) + .map_err(|e| format!("{e}")) +} + +#[derive(PartialEq, Eq, Copy, Clone)] +pub enum UpdateRegistry { + Update, + LeaveAsIs, +} + +#[test] +fn test_registries_switch_token() { + let mut registries = Registries::default(); + + registries.set_current_registry("https://registry.wapm.dev"); + assert_eq!( + registries.get_current_registry(), + "https://registry.wapm.dev/graphql".to_string() + ); + registries.set_login_token_for_registry( + "https://registry.wapm.io", + "token1", + UpdateRegistry::LeaveAsIs, + ); + assert_eq!( + registries.get_current_registry(), + "https://registry.wapm.dev/graphql".to_string() + ); + assert_eq!( + registries.get_login_token_for_registry(®istries.get_current_registry()), + None + ); + registries.set_current_registry("https://registry.wapm.io"); + assert_eq!( + registries.get_login_token_for_registry(®istries.get_current_registry()), + Some("token1".to_string()) + ); + registries.clear_current_registry_token(); + assert_eq!( + registries.get_login_token_for_registry(®istries.get_current_registry()), + None + ); +} + +impl Registries { + /// Gets the current (active) registry URL + pub fn clear_current_registry_token(&mut self) { + match self { + Registries::Single(s) => { + s.token = None; + } + Registries::Multi(m) => { + m.tokens.remove(&m.current); + m.tokens.remove(&format_graphql(&m.current)); + } + } + } + + pub fn get_graphql_url(&self) -> String { + let registry = self.get_current_registry(); + format_graphql(®istry) + } + + /// Gets the current (active) registry URL + pub fn get_current_registry(&self) -> String { + match self { + Registries::Single(s) => format_graphql(&s.url), + Registries::Multi(m) => format_graphql(&m.current), + } + } + + /// Sets the current (active) registry URL + pub fn set_current_registry(&mut self, registry: &str) { + let registry = format_graphql(registry); + if let Err(e) = test_if_registry_present(®istry) { + println!("Error when trying to ping registry {registry:?}: {e}"); + println!("WARNING: Registry {registry:?} will be used, but commands may not succeed."); + } + match self { + Registries::Single(s) => s.url = registry, + Registries::Multi(m) => m.current = registry, + } + } + + /// Returns the login token for the registry + pub fn get_login_token_for_registry(&self, registry: &str) -> Option { + match self { + Registries::Single(s) if s.url == registry || format_graphql(registry) == s.url => { + s.token.clone() + } + Registries::Multi(m) => m + .tokens + .get(registry) + .or_else(|| m.tokens.get(&format_graphql(registry))) + .cloned(), + _ => None, + } + } + + /// Sets the login token for the registry URL + pub fn set_login_token_for_registry( + &mut self, + registry: &str, + token: &str, + update_current_registry: UpdateRegistry, + ) { + let new_map = match self { + Registries::Single(s) => { + if s.url == registry { + Registries::Single(Registry { + url: format_graphql(registry), + token: Some(token.to_string()), + }) + } else { + let mut map = BTreeMap::new(); + if let Some(token) = s.token.clone() { + map.insert(format_graphql(&s.url), token); + } + map.insert(format_graphql(registry), token.to_string()); + Registries::Multi(MultiRegistry { + current: format_graphql(&s.url), + tokens: map, + }) + } + } + Registries::Multi(m) => { + m.tokens.insert(format_graphql(registry), token.to_string()); + if update_current_registry == UpdateRegistry::Update { + m.current = format_graphql(registry); + } + Registries::Multi(m.clone()) + } + }; + *self = new_map; + } +} + +impl PartialWapmConfig { + /// Save the config to a file + pub fn save>(&self, to: P) -> anyhow::Result<()> { + use std::{fs::File, io::Write}; + let config_serialized = toml::to_string(&self)?; + let mut file = File::create(to)?; + file.write_all(config_serialized.as_bytes())?; + Ok(()) + } + + pub fn from_file(#[cfg(test)] test_name: &str) -> Result { + #[cfg(test)] + let path = Self::get_file_location(test_name)?; + #[cfg(not(test))] + let path = Self::get_file_location()?; + + match std::fs::read_to_string(&path) { + Ok(config_toml) => { + toml::from_str(&config_toml).map_err(|e| format!("could not parse {path:?}: {e}")) + } + Err(_e) => Ok(Self::default()), + } + } + + pub fn get_current_dir() -> std::io::Result { + std::env::current_dir() + } + + #[cfg(test)] + pub fn get_folder(test_name: &str) -> Result { + let test_dir = std::env::temp_dir().join("test_wasmer").join(test_name); + let _ = std::fs::create_dir_all(&test_dir); + Ok(test_dir) + } + + #[cfg(not(test))] + pub fn get_folder() -> Result { + Ok( + if let Some(folder_str) = std::env::var("WASMER_DIR").ok().filter(|s| !s.is_empty()) { + let folder = PathBuf::from(folder_str); + std::fs::create_dir_all(folder.clone()) + .map_err(|e| format!("cannot create config directory: {e}"))?; + folder + } else { + #[allow(unused_variables)] + let default_dir = Self::get_current_dir() + .ok() + .unwrap_or_else(|| PathBuf::from("/".to_string())); + let home_dir = + dirs::home_dir().ok_or_else(|| "cannot find home directory".to_string())?; + let mut folder = home_dir; + folder.push(".wasmer"); + std::fs::create_dir_all(folder.clone()) + .map_err(|e| format!("cannot create config directory: {e}"))?; + folder + }, + ) + } + + #[cfg(test)] + pub fn get_file_location(test_name: &str) -> Result { + Ok(Self::get_folder(test_name)?.join(crate::GLOBAL_CONFIG_FILE_NAME)) + } + + #[cfg(not(test))] + pub fn get_file_location() -> Result { + Ok(Self::get_folder()?.join(crate::GLOBAL_CONFIG_FILE_NAME)) + } +} + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/queries/test_if_registry_present.graphql", + response_derives = "Debug" +)] +struct TestIfRegistryPresent; diff --git a/lib/registry/src/graphql.rs b/lib/registry/src/graphql.rs new file mode 100644 index 000000000..86c4d01d8 --- /dev/null +++ b/lib/registry/src/graphql.rs @@ -0,0 +1,246 @@ +use graphql_client::*; +use reqwest::{ + blocking::{multipart::Form, Client}, + header::USER_AGENT, +}; +use std::env; +use std::time::Duration; + +pub(crate) mod proxy { + //! Code for dealing with setting things up to proxy network requests + use thiserror::Error; + + #[derive(Debug, Error)] + pub enum ProxyError { + #[error("Failed to parse URL from {}: {}", url_location, error_message)] + UrlParseError { + url_location: String, + error_message: String, + }, + + #[error("Could not connect to proxy: {0}")] + ConnectionError(String), + } + + pub fn maybe_set_up_proxy_blocking( + builder: reqwest::blocking::ClientBuilder, + ) -> anyhow::Result { + use anyhow::Context; + if let Some(proxy) = maybe_set_up_proxy_inner() + .map_err(|e| anyhow::anyhow!("{e}")) + .context("install_webc_package: failed to setup proxy for reqwest Client")? + { + return Ok(builder.proxy(proxy)); + } + Ok(builder) + } + + pub fn maybe_set_up_proxy( + builder: reqwest::ClientBuilder, + ) -> anyhow::Result { + use anyhow::Context; + if let Some(proxy) = maybe_set_up_proxy_inner() + .map_err(|e| anyhow::anyhow!("{e}")) + .context("install_webc_package: failed to setup proxy for reqwest Client")? + { + return Ok(builder.proxy(proxy)); + } + Ok(builder) + } + + /// Tries to set up a proxy + /// + /// This function reads from wapm config's `proxy.url` first, then checks + /// `ALL_PROXY`, `HTTPS_PROXY`, and `HTTP_PROXY` environment variables, in both + /// upper case and lower case, in that order. + /// + /// If a proxy is specified in wapm config's `proxy.url`, it is assumed + /// to be a general proxy + /// + /// A return value of `Ok(None)` means that there was no attempt to set up a proxy, + /// `Ok(Some(proxy))` means that the proxy was set up successfully, and `Err(e)` that + /// there was a failure while attempting to set up the proxy. + fn maybe_set_up_proxy_inner() -> anyhow::Result> { + use std::env; + let proxy = if let Ok(proxy_url) = env::var("ALL_PROXY").or_else(|_| env::var("all_proxy")) + { + reqwest::Proxy::all(&proxy_url).map(|proxy| (proxy_url, proxy, "ALL_PROXY")) + } else if let Ok(https_proxy_url) = + env::var("HTTPS_PROXY").or_else(|_| env::var("https_proxy")) + { + reqwest::Proxy::https(&https_proxy_url) + .map(|proxy| (https_proxy_url, proxy, "HTTPS_PROXY")) + } else if let Ok(http_proxy_url) = + env::var("HTTP_PROXY").or_else(|_| env::var("http_proxy")) + { + reqwest::Proxy::http(&http_proxy_url).map(|proxy| (http_proxy_url, proxy, "http_proxy")) + } else { + return Ok(None); + } + .map_err(|e| ProxyError::ConnectionError(e.to_string())) + .and_then( + |(proxy_url_str, proxy, url_location): (String, _, &'static str)| { + url::Url::parse(&proxy_url_str) + .map_err(|e| ProxyError::UrlParseError { + url_location: url_location.to_string(), + error_message: e.to_string(), + }) + .map(|url| { + if !(url.username().is_empty()) && url.password().is_some() { + proxy.basic_auth(url.username(), url.password().unwrap_or_default()) + } else { + proxy + } + }) + }, + )?; + + Ok(Some(proxy)) + } +} + +pub fn whoami_distro() -> String { + whoami::distro().to_lowercase() +} + +fn setup_client() -> Result { + let builder = Client::builder(); + let builder = proxy::maybe_set_up_proxy_blocking(builder)?; + builder.build().map_err(|e| e.into()) +} + +/// This function is being used to "ping" the registry +/// (see test_if_registry_present and see whether the response +/// is valid JSON, it doesn't check the response itself, +/// since the response format might change +pub fn execute_query_modifier_inner_check_json( + registry_url: &str, + login_token: &str, + query: &QueryBody, + timeout: Option, + form_modifier: F, +) -> anyhow::Result<()> +where + V: serde::Serialize, + F: FnOnce(Form) -> Form, +{ + let client = setup_client()?; + + let vars = serde_json::to_string(&query.variables).unwrap(); + + let form = Form::new() + .text("query", query.query.to_string()) + .text("operationName", query.operation_name.to_string()) + .text("variables", vars); + + let form = form_modifier(form); + + let user_agent = format!( + "wasmer/{} {} {}", + env!("CARGO_PKG_VERSION"), + whoami::platform(), + whoami_distro(), + ); + + let mut res = client + .post(registry_url) + .multipart(form) + .bearer_auth( + env::var("WASMER_TOKEN") + .ok() + .or_else(|| env::var("WAPM_REGISTRY_TOKEN").ok()) + .unwrap_or_else(|| login_token.to_string()), + ) + .header(USER_AGENT, user_agent); + + if let Some(t) = timeout { + res = res.timeout(t); + } + + let res = res.send()?; + + let _: Response = res.json()?; + + Ok(()) +} + +pub fn execute_query_modifier_inner( + registry_url: &str, + login_token: &str, + query: &QueryBody, + timeout: Option, + form_modifier: F, +) -> anyhow::Result +where + for<'de> R: serde::Deserialize<'de>, + V: serde::Serialize, + F: FnOnce(Form) -> Form, +{ + let client = setup_client()?; + + let vars = serde_json::to_string(&query.variables).unwrap(); + + let form = Form::new() + .text("query", query.query.to_string()) + .text("operationName", query.operation_name.to_string()) + .text("variables", vars); + + let form = form_modifier(form); + + let user_agent = format!( + "wasmer/{} {} {}", + env!("CARGO_PKG_VERSION"), + whoami::platform(), + whoami_distro(), + ); + + let mut res = client + .post(registry_url) + .multipart(form) + .bearer_auth( + env::var("WASMER_TOKEN") + .ok() + .or_else(|| env::var("WAPM_REGISTRY_TOKEN").ok()) + .unwrap_or_else(|| login_token.to_string()), + ) + .header(USER_AGENT, user_agent); + + if let Some(t) = timeout { + res = res.timeout(t); + } + + let res = res.send()?; + let response_body: Response = res.json()?; + if let Some(errors) = response_body.errors { + let error_messages: Vec = errors.into_iter().map(|err| err.message).collect(); + return Err(anyhow::anyhow!("{}", error_messages.join(", "))); + } + response_body + .data + .ok_or_else(|| anyhow::anyhow!("missing response data")) +} + +pub fn execute_query( + registry_url: &str, + login_token: &str, + query: &QueryBody, +) -> anyhow::Result +where + for<'de> R: serde::Deserialize<'de>, + V: serde::Serialize, +{ + execute_query_modifier_inner(registry_url, login_token, query, None, |f| f) +} + +pub fn execute_query_with_timeout( + registry_url: &str, + login_token: &str, + timeout: Duration, + query: &QueryBody, +) -> anyhow::Result +where + for<'de> R: serde::Deserialize<'de>, + V: serde::Serialize, +{ + execute_query_modifier_inner(registry_url, login_token, query, Some(timeout), |f| f) +} diff --git a/lib/registry/src/lib.rs b/lib/registry/src/lib.rs index 4d034d581..5d2798671 100644 --- a/lib/registry/src/lib.rs +++ b/lib/registry/src/lib.rs @@ -1,417 +1,39 @@ -use std::collections::BTreeMap; -use std::env; +//! High-level interactions with the WAPM backend. +//! +//! The GraphQL schema can be updated by running `make` in the Wasmer repo's +//! root directory. +//! +//! ```console +//! $ make update-graphql-schema +//! curl -sSfL https://registry.wapm.io/graphql/schema.graphql > lib/registry/graphql/schema.graphql +//! ``` + +use crate::config::Registries; +use anyhow::Context; +use core::ops::Range; +use reqwest::header::{ACCEPT, RANGE}; use std::fmt; +use std::io::Write; use std::path::{Path, PathBuf}; use std::time::Duration; +use std::{ + collections::BTreeMap, + fmt::{Display, Formatter}, +}; +use url::Url; -use serde::Deserialize; -use serde::Serialize; +pub mod config; +pub mod graphql; +pub mod login; +pub mod queries; +pub mod utils; -pub mod graphql { - - use graphql_client::*; - #[cfg(not(target_os = "wasi"))] - use reqwest::{ - blocking::{multipart::Form, Client}, - header::USER_AGENT, - }; - use std::env; - use std::time::Duration; - #[cfg(target_os = "wasi")] - use {wasm_bus_reqwest::prelude::header::*, wasm_bus_reqwest::prelude::*}; - - mod proxy { - //! Code for dealing with setting things up to proxy network requests - use thiserror::Error; - - #[derive(Debug, Error)] - pub enum ProxyError { - #[error("Failed to parse URL from {}: {}", url_location, error_message)] - UrlParseError { - url_location: String, - error_message: String, - }, - - #[error("Could not connect to proxy: {0}")] - ConnectionError(String), - } - - /// Tries to set up a proxy - /// - /// This function reads from wapm config's `proxy.url` first, then checks - /// `ALL_PROXY`, `HTTPS_PROXY`, and `HTTP_PROXY` environment variables, in both - /// upper case and lower case, in that order. - /// - /// If a proxy is specified in wapm config's `proxy.url`, it is assumed - /// to be a general proxy - /// - /// A return value of `Ok(None)` means that there was no attempt to set up a proxy, - /// `Ok(Some(proxy))` means that the proxy was set up successfully, and `Err(e)` that - /// there was a failure while attempting to set up the proxy. - pub fn maybe_set_up_proxy() -> anyhow::Result> { - use std::env; - let proxy = if let Ok(proxy_url) = - env::var("ALL_PROXY").or_else(|_| env::var("all_proxy")) - { - reqwest::Proxy::all(&proxy_url).map(|proxy| (proxy_url, proxy, "ALL_PROXY")) - } else if let Ok(https_proxy_url) = - env::var("HTTPS_PROXY").or_else(|_| env::var("https_proxy")) - { - reqwest::Proxy::https(&https_proxy_url) - .map(|proxy| (https_proxy_url, proxy, "HTTPS_PROXY")) - } else if let Ok(http_proxy_url) = - env::var("HTTP_PROXY").or_else(|_| env::var("http_proxy")) - { - reqwest::Proxy::http(&http_proxy_url) - .map(|proxy| (http_proxy_url, proxy, "http_proxy")) - } else { - return Ok(None); - } - .map_err(|e| ProxyError::ConnectionError(e.to_string())) - .and_then( - |(proxy_url_str, proxy, url_location): (String, _, &'static str)| { - url::Url::parse(&proxy_url_str) - .map_err(|e| ProxyError::UrlParseError { - url_location: url_location.to_string(), - error_message: e.to_string(), - }) - .map(|url| { - if !(url.username().is_empty()) && url.password().is_some() { - proxy.basic_auth(url.username(), url.password().unwrap_or_default()) - } else { - proxy - } - }) - }, - )?; - - Ok(Some(proxy)) - } - } - - #[derive(GraphQLQuery)] - #[graphql( - schema_path = "graphql/schema.graphql", - query_path = "graphql/queries/get_package_version.graphql", - response_derives = "Debug" - )] - pub(crate) struct GetPackageVersionQuery; - - #[derive(GraphQLQuery)] - #[graphql( - schema_path = "graphql/schema.graphql", - query_path = "graphql/queries/get_package_by_command.graphql", - response_derives = "Debug" - )] - pub(crate) struct GetPackageByCommandQuery; - - #[derive(GraphQLQuery)] - #[graphql( - schema_path = "graphql/schema.graphql", - query_path = "graphql/queries/test_if_registry_present.graphql", - response_derives = "Debug" - )] - pub(crate) struct TestIfRegistryPresent; - - #[cfg(target_os = "wasi")] - pub fn whoami_distro() -> String { - whoami::os().to_lowercase() - } - - #[cfg(not(target_os = "wasi"))] - pub fn whoami_distro() -> String { - whoami::distro().to_lowercase() - } - - pub fn execute_query_modifier_inner_check_json( - registry_url: &str, - login_token: &str, - query: &QueryBody, - timeout: Option, - form_modifier: F, - ) -> anyhow::Result<()> - where - V: serde::Serialize, - F: FnOnce(Form) -> Form, - { - let client = { - let builder = Client::builder(); - - #[cfg(not(target_os = "wasi"))] - let builder = if let Some(proxy) = proxy::maybe_set_up_proxy()? { - builder.proxy(proxy) - } else { - builder - }; - builder.build()? - }; - - let vars = serde_json::to_string(&query.variables).unwrap(); - - let form = Form::new() - .text("query", query.query.to_string()) - .text("operationName", query.operation_name.to_string()) - .text("variables", vars); - - let form = form_modifier(form); - - let user_agent = format!( - "wapm/{} {} {}", - env!("CARGO_PKG_VERSION"), - whoami::platform(), - whoami_distro(), - ); - - let mut res = client - .post(registry_url) - .multipart(form) - .bearer_auth( - env::var("WAPM_REGISTRY_TOKEN").unwrap_or_else(|_| login_token.to_string()), - ) - .header(USER_AGENT, user_agent); - - if let Some(t) = timeout { - res = res.timeout(t); - } - - let res = res.send()?; - - let _: Response = res.json()?; - - Ok(()) - } - - pub fn execute_query_modifier_inner( - registry_url: &str, - login_token: &str, - query: &QueryBody, - timeout: Option, - form_modifier: F, - ) -> anyhow::Result - where - for<'de> R: serde::Deserialize<'de>, - V: serde::Serialize, - F: FnOnce(Form) -> Form, - { - let client = { - let builder = Client::builder(); - - #[cfg(not(target_os = "wasi"))] - let builder = if let Some(proxy) = proxy::maybe_set_up_proxy()? { - builder.proxy(proxy) - } else { - builder - }; - builder.build()? - }; - - let vars = serde_json::to_string(&query.variables).unwrap(); - - let form = Form::new() - .text("query", query.query.to_string()) - .text("operationName", query.operation_name.to_string()) - .text("variables", vars); - - let form = form_modifier(form); - - let user_agent = format!( - "wapm/{} {} {}", - env!("CARGO_PKG_VERSION"), - whoami::platform(), - whoami_distro(), - ); - - let mut res = client - .post(registry_url) - .multipart(form) - .bearer_auth( - env::var("WAPM_REGISTRY_TOKEN").unwrap_or_else(|_| login_token.to_string()), - ) - .header(USER_AGENT, user_agent); - - if let Some(t) = timeout { - res = res.timeout(t); - } - - let res = res.send()?; - let response_body: Response = res.json()?; - if let Some(errors) = response_body.errors { - let error_messages: Vec = errors.into_iter().map(|err| err.message).collect(); - return Err(anyhow::anyhow!("{}", error_messages.join(", "))); - } - Ok(response_body.data.expect("missing response data")) - } - - pub fn execute_query( - registry_url: &str, - login_token: &str, - query: &QueryBody, - ) -> anyhow::Result - where - for<'de> R: serde::Deserialize<'de>, - V: serde::Serialize, - { - execute_query_modifier_inner(registry_url, login_token, query, None, |f| f) - } - - pub fn execute_query_with_timeout( - registry_url: &str, - login_token: &str, - timeout: Duration, - query: &QueryBody, - ) -> anyhow::Result - where - for<'de> R: serde::Deserialize<'de>, - V: serde::Serialize, - { - execute_query_modifier_inner(registry_url, login_token, query, Some(timeout), |f| f) - } -} - -pub static GLOBAL_CONFIG_FILE_NAME: &str = if cfg!(target_os = "wasi") { - "/.private/wapm.toml" -} else { - "wapm.toml" +pub use crate::{ + config::{format_graphql, PartialWapmConfig}, + queries::get_bindings_query::ProgrammingLanguage, }; -#[derive(Deserialize, Default, Serialize, Debug, PartialEq)] -pub struct PartialWapmConfig { - /// The number of seconds to wait before checking the registry for a new - /// version of the package. - #[serde(default = "wax_default_cooldown")] - pub wax_cooldown: i32, - - /// The registry that wapm will connect to. - pub registry: Registries, - - /// Whether or not telemetry is enabled. - #[cfg(feature = "telemetry")] - #[serde(default)] - pub telemetry: Telemetry, - - /// Whether or not updated notifications are enabled. - #[cfg(feature = "update-notifications")] - #[serde(default)] - pub update_notifications: UpdateNotifications, - - /// The proxy to use when connecting to the Internet. - #[serde(default)] - pub proxy: Proxy, -} - -pub const fn wax_default_cooldown() -> i32 { - 5 * 60 -} - -#[derive(Deserialize, Serialize, Debug, PartialEq, Default)] -pub struct Proxy { - pub url: Option, -} - -#[derive(Deserialize, Serialize, Debug, PartialEq, Default)] -pub struct UpdateNotifications { - pub enabled: String, -} - -#[cfg(feature = "telemetry")] -#[derive(Deserialize, Serialize, Debug, PartialEq)] -pub struct Telemetry { - pub enabled: String, -} - -#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)] -#[serde(untagged)] -pub enum Registries { - Single(Registry), - Multi(MultiRegistry), -} - -#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)] -pub struct MultiRegistry { - /// Currently active registry - pub current: String, - /// Map from "RegistryUrl" to "LoginToken", in order to - /// be able to be able to easily switch between registries - pub tokens: BTreeMap, -} - -impl Default for Registries { - fn default() -> Self { - Registries::Single(Registry { - url: format_graphql("https://registry.wapm.io"), - token: None, - }) - } -} - -#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)] -pub struct Registry { - pub url: String, - pub token: Option, -} - -fn format_graphql(registry: &str) -> String { - if registry.ends_with("/graphql") { - registry.to_string() - } else if registry.ends_with('/') { - format!("{}graphql", registry) - } else { - format!("{}/graphql", registry) - } -} - -impl PartialWapmConfig { - pub fn from_file() -> Result { - let path = Self::get_file_location()?; - - match std::fs::read_to_string(&path) { - Ok(config_toml) => { - toml::from_str(&config_toml).map_err(|e| format!("could not parse {path:?}: {e}")) - } - Err(_e) => Ok(Self::default()), - } - } - - pub fn get_current_dir() -> std::io::Result { - #[cfg(target_os = "wasi")] - if let Some(pwd) = std::env::var("PWD").ok() { - return Ok(PathBuf::from(pwd)); - } - std::env::current_dir() - } - - pub fn get_folder() -> Result { - Ok( - if let Some(folder_str) = env::var("WASMER_DIR").ok().filter(|s| !s.is_empty()) { - let folder = PathBuf::from(folder_str); - std::fs::create_dir_all(folder.clone()) - .map_err(|e| format!("cannot create config directory: {e}"))?; - folder - } else { - #[allow(unused_variables)] - let default_dir = Self::get_current_dir() - .ok() - .unwrap_or_else(|| PathBuf::from("/".to_string())); - #[cfg(feature = "dirs")] - let home_dir = - dirs::home_dir().ok_or(GlobalConfigError::CannotFindHomeDirectory)?; - #[cfg(not(feature = "dirs"))] - let home_dir = std::env::var("HOME") - .ok() - .unwrap_or_else(|| default_dir.to_string_lossy().to_string()); - let mut folder = PathBuf::from(home_dir); - folder.push(".wasmer"); - std::fs::create_dir_all(folder.clone()) - .map_err(|e| format!("cannot create config directory: {e}"))?; - folder - }, - ) - } - - fn get_file_location() -> Result { - Ok(Self::get_folder()?.join(GLOBAL_CONFIG_FILE_NAME)) - } -} +pub static GLOBAL_CONFIG_FILE_NAME: &str = "wapm.toml"; #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)] pub struct PackageDownloadInfo { @@ -422,9 +44,11 @@ pub struct PackageDownloadInfo { pub commands: String, pub manifest: String, pub url: String, + pub pirita_url: Option, } pub fn get_package_local_dir( + #[cfg(test)] test_name: &str, registry_host: &str, name: &str, version: &str, @@ -437,18 +61,26 @@ pub fn get_package_local_dir( let (namespace, name) = name .split_once('/') .ok_or_else(|| format!("missing namespace / name for {name:?}"))?; - let install_dir = get_global_install_dir(registry_host) - .ok_or_else(|| format!("no install dir for {name:?}"))?; + #[cfg(test)] + let global_install_dir = get_global_install_dir(test_name, registry_host); + #[cfg(not(test))] + let global_install_dir = get_global_install_dir(registry_host); + let install_dir = global_install_dir.ok_or_else(|| format!("no install dir for {name:?}"))?; Ok(install_dir.join(namespace).join(name).join(version)) } -pub fn try_finding_local_command(cmd: &str) -> Option { - for p in get_all_local_packages(None) { - if p.get_commands() - .unwrap_or_default() - .iter() - .any(|c| c == cmd) - { +pub fn try_finding_local_command(#[cfg(test)] test_name: &str, cmd: &str) -> Option { + #[cfg(test)] + let local_packages = get_all_local_packages(test_name, None); + #[cfg(not(test))] + let local_packages = get_all_local_packages(None); + for p in local_packages { + #[cfg(not(test))] + let commands = p.get_commands(); + #[cfg(test)] + let commands = p.get_commands(test_name); + + if commands.unwrap_or_default().iter().any(|c| c == cmd) { return Some(p); } } @@ -463,16 +95,28 @@ pub struct LocalPackage { } impl LocalPackage { - pub fn get_path(&self) -> Result { + pub fn get_path(&self, #[cfg(test)] test_name: &str) -> Result { let host = url::Url::parse(&self.registry) .ok() .and_then(|o| o.host_str().map(|s| s.to_string())) .unwrap_or_else(|| self.registry.clone()); - get_package_local_dir(&host, &self.name, &self.version) + #[cfg(test)] + { + get_package_local_dir(test_name, &host, &self.name, &self.version) + } + + #[cfg(not(test))] + { + get_package_local_dir(&host, &self.name, &self.version) + } } - pub fn get_commands(&self) -> Result, String> { - let toml_path = self.get_path()?.join("wapm.toml"); + pub fn get_commands(&self, #[cfg(test)] test_name: &str) -> Result, String> { + #[cfg(not(test))] + let path = self.get_path()?; + #[cfg(test)] + let path = self.get_path(test_name)?; + let toml_path = path.join("wapm.toml"); let toml = std::fs::read_to_string(&toml_path) .map_err(|e| format!("error reading {}: {e}", toml_path.display()))?; let toml_parsed = toml::from_str::(&toml) @@ -552,11 +196,23 @@ fn get_all_names_in_dir(dir: &PathBuf) -> Vec<(PathBuf, String)> { } /// Returns a list of all locally installed packages -pub fn get_all_local_packages(registry: Option<&str>) -> Vec { +pub fn get_all_local_packages( + #[cfg(test)] test_name: &str, + registry: Option<&str>, +) -> Vec { let mut packages = Vec::new(); let registries = match registry { Some(s) => vec![s.to_string()], - None => get_all_available_registries().unwrap_or_default(), + None => { + #[cfg(test)] + { + get_all_available_registries(test_name).unwrap_or_default() + } + #[cfg(not(test))] + { + get_all_available_registries().unwrap_or_default() + } + } }; let mut registry_hosts = registries @@ -564,7 +220,12 @@ pub fn get_all_local_packages(registry: Option<&str>) -> Vec { .filter_map(|s| url::Url::parse(&s).ok()?.host_str().map(|s| s.to_string())) .collect::>(); - let mut registries_in_root_dir = get_checkouts_dir() + #[cfg(not(test))] + let checkouts_dir = get_checkouts_dir(); + #[cfg(test)] + let checkouts_dir = get_checkouts_dir(test_name); + + let mut registries_in_root_dir = checkouts_dir .as_ref() .map(get_all_names_in_dir) .unwrap_or_default() @@ -577,7 +238,11 @@ pub fn get_all_local_packages(registry: Option<&str>) -> Vec { registry_hosts.dedup(); for host in registry_hosts { - let root_dir = match get_global_install_dir(&host) { + #[cfg(not(test))] + let global_install_dir = get_global_install_dir(&host); + #[cfg(test)] + let global_install_dir = get_global_install_dir(test_name, &host); + let root_dir = match global_install_dir { Some(o) => o, None => continue, }; @@ -603,11 +268,17 @@ pub fn get_all_local_packages(registry: Option<&str>) -> Vec { } pub fn get_local_package( + #[cfg(test)] test_name: &str, registry: Option<&str>, name: &str, version: Option<&str>, ) -> Option { - get_all_local_packages(registry) + #[cfg(not(test))] + let local_packages = get_all_local_packages(registry); + #[cfg(test)] + let local_packages = get_all_local_packages(test_name, registry); + + local_packages .iter() .find(|p| { if p.name != name { @@ -627,7 +298,10 @@ pub fn query_command_from_registry( registry_url: &str, command_name: &str, ) -> Result { - use crate::graphql::{execute_query, get_package_by_command_query, GetPackageByCommandQuery}; + use crate::{ + graphql::execute_query, + queries::{get_package_by_command_query, GetPackageByCommandQuery}, + }; use graphql_client::GraphQLQuery; let q = GetPackageByCommandQuery::build_query(get_package_by_command_query::Variables { @@ -644,6 +318,7 @@ pub fn query_command_from_registry( let package = command.package_version.package.display_name; let version = command.package_version.version; let url = command.package_version.distribution.download_url; + let pirita_url = command.package_version.distribution.pirita_download_url; Ok(PackageDownloadInfo { registry: registry_url.to_string(), @@ -653,10 +328,11 @@ pub fn query_command_from_registry( manifest: command.package_version.manifest, commands: command_name.to_string(), url, + pirita_url, }) } -#[derive(Debug, Clone, PartialEq, PartialOrd)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)] pub enum QueryPackageError { ErrorSendingQuery(String), NoPackageFound { @@ -666,7 +342,7 @@ pub enum QueryPackageError { } impl fmt::Display for QueryPackageError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { QueryPackageError::ErrorSendingQuery(q) => write!(f, "error sending query: {q}"), QueryPackageError::NoPackageFound { name, version } => { @@ -676,7 +352,7 @@ impl fmt::Display for QueryPackageError { } } -#[derive(Debug, Clone, PartialEq, PartialOrd)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)] pub enum GetIfPackageHasNewVersionResult { // if version = Some(...) and the ~/.wasmer/checkouts/.../{version} exists, the package is already installed UseLocalAlreadyInstalled { @@ -706,15 +382,17 @@ pub enum GetIfPackageHasNewVersionResult { #[test] fn test_get_if_package_has_new_version() { + const TEST_NAME: &str = "test_get_if_package_has_new_version"; let fake_registry = "https://h0.com"; let fake_name = "namespace0/project1"; let fake_version = "1.0.0"; - let package_path = get_package_local_dir("h0.com", fake_name, fake_version).unwrap(); + let package_path = get_package_local_dir(TEST_NAME, "h0.com", fake_name, fake_version).unwrap(); let _ = std::fs::remove_file(&package_path.join("wapm.toml")); let _ = std::fs::remove_file(&package_path.join("wapm.toml")); let r1 = get_if_package_has_new_version( + TEST_NAME, fake_registry, "namespace0/project1", Some(fake_version.to_string()), @@ -731,11 +409,12 @@ fn test_get_if_package_has_new_version() { } ); - let package_path = get_package_local_dir("h0.com", fake_name, fake_version).unwrap(); + let package_path = get_package_local_dir(TEST_NAME, "h0.com", fake_name, fake_version).unwrap(); std::fs::create_dir_all(&package_path).unwrap(); std::fs::write(&package_path.join("wapm.toml"), b"").unwrap(); let r1 = get_if_package_has_new_version( + TEST_NAME, fake_registry, "namespace0/project1", Some(fake_version.to_string()), @@ -758,6 +437,7 @@ fn test_get_if_package_has_new_version() { /// /// Also returns true if the package is not installed yet. pub fn get_if_package_has_new_version( + #[cfg(test)] test_name: &str, registry_url: &str, name: &str, version: Option, @@ -775,7 +455,12 @@ pub fn get_if_package_has_new_version( .split_once('/') .ok_or_else(|| format!("missing namespace / name for {name:?}"))?; - let package_dir = get_global_install_dir(&host).map(|path| path.join(namespace).join(name)); + #[cfg(not(test))] + let global_install_dir = get_global_install_dir(&host); + #[cfg(test)] + let global_install_dir = get_global_install_dir(test_name, &host); + + let package_dir = global_install_dir.map(|path| path.join(namespace).join(name)); let package_dir = match package_dir { Some(s) => s, @@ -890,7 +575,10 @@ pub fn query_package_from_registry( name: &str, version: Option<&str>, ) -> Result { - use crate::graphql::{execute_query, get_package_version_query, GetPackageVersionQuery}; + use crate::{ + graphql::execute_query, + queries::{get_package_version_query, GetPackageVersionQuery}, + }; use graphql_client::GraphQLQuery; let q = GetPackageVersionQuery::build_query(get_package_version_query::Variables { @@ -905,7 +593,7 @@ pub fn query_package_from_registry( let v = response.package_version.as_ref().ok_or_else(|| { QueryPackageError::ErrorSendingQuery(format!( - "Invalid response for crate {name:?}: no manifest" + "Invalid response for crate {name:?}: no package version: {response:#?}" )) })?; @@ -930,56 +618,61 @@ pub fn query_package_from_registry( .join(", "), url: v.distribution.download_url.clone(), + pirita_url: v.distribution.pirita_download_url.clone(), }) } -pub fn get_wasmer_root_dir() -> Option { - PartialWapmConfig::get_folder().ok() +pub fn get_wasmer_root_dir(#[cfg(test)] test_name: &str) -> Option { + #[cfg(test)] + { + PartialWapmConfig::get_folder(test_name).ok() + } + #[cfg(not(test))] + { + PartialWapmConfig::get_folder().ok() + } } -pub fn get_checkouts_dir() -> Option { - Some(get_wasmer_root_dir()?.join("checkouts")) + +pub fn get_checkouts_dir(#[cfg(test)] test_name: &str) -> Option { + #[cfg(test)] + let root_dir = get_wasmer_root_dir(test_name)?; + #[cfg(not(test))] + let root_dir = get_wasmer_root_dir()?; + Some(root_dir.join("checkouts")) +} + +pub fn get_webc_dir(#[cfg(test)] test_name: &str) -> Option { + #[cfg(test)] + let root_dir = get_wasmer_root_dir(test_name)?; + #[cfg(not(test))] + let root_dir = get_wasmer_root_dir()?; + Some(root_dir.join("webc")) } /// Returs the path to the directory where all packages on this computer are being stored -pub fn get_global_install_dir(registry_host: &str) -> Option { - Some(get_checkouts_dir()?.join(registry_host)) +pub fn get_global_install_dir( + #[cfg(test)] test_name: &str, + registry_host: &str, +) -> Option { + #[cfg(test)] + let root_dir = get_checkouts_dir(test_name)?; + #[cfg(not(test))] + let root_dir = get_checkouts_dir()?; + Some(root_dir.join(registry_host)) } -/// Whether the top-level directory should be stripped -pub fn download_and_unpack_targz( - url: &str, - target_path: &Path, +/// Convenience function that will unpack .tar.gz files and .tar.bz +/// files to a target directory (does NOT remove the original .tar.gz) +pub fn try_unpack_targz>( + target_targz_path: P, + target_path: P, strip_toplevel: bool, -) -> Result { - let target_targz_path = target_path.to_path_buf().join("package.tar.gz"); - - let mut resp = - reqwest::blocking::get(url).map_err(|e| format!("failed to download {url}: {e}"))?; - - if !target_targz_path.exists() { - // create all the parent paths, only remove the created directory, not the parent dirs - let _ = std::fs::create_dir_all(&target_targz_path); - let _ = std::fs::remove_dir(&target_targz_path); - } - - { - let mut file = std::fs::File::create(&target_targz_path).map_err(|e| { - format!( - "failed to download {url} into {}: {e}", - target_targz_path.display() - ) - })?; - - resp.copy_to(&mut file).map_err(|e| format!("{e}"))?; - } - +) -> Result { + let target_targz_path = target_targz_path.as_ref(); + let target_path = target_path.as_ref(); let open_file = || { - std::fs::File::open(&target_targz_path).map_err(|e| { - format!( - "failed to download {url} into {}: {e}", - target_targz_path.display() - ) - }) + std::fs::File::open(&target_targz_path) + .map_err(|e| anyhow::anyhow!("failed to open {}: {e}", target_targz_path.display())) }; let try_decode_gz = || { @@ -987,11 +680,13 @@ pub fn download_and_unpack_targz( let gz_decoded = flate2::read::GzDecoder::new(&file); let mut ar = tar::Archive::new(gz_decoded); if strip_toplevel { - unpack_sans_parent(ar, target_path) - .map_err(|e| format!("failed to unpack {}: {e}", target_targz_path.display())) + unpack_sans_parent(ar, target_path).map_err(|e| { + anyhow::anyhow!("failed to unpack {}: {e}", target_targz_path.display()) + }) } else { - ar.unpack(target_path) - .map_err(|e| format!("failed to unpack {}: {e}", target_targz_path.display())) + ar.unpack(target_path).map_err(|e| { + anyhow::anyhow!("failed to unpack {}: {e}", target_targz_path.display()) + }) } }; @@ -999,23 +694,55 @@ pub fn download_and_unpack_targz( let file = open_file()?; let mut decomp: Vec = Vec::new(); let mut bufread = std::io::BufReader::new(&file); - lzma_rs::xz_decompress(&mut bufread, &mut decomp) - .map_err(|e| format!("failed to unpack {}: {e}", target_targz_path.display()))?; + lzma_rs::xz_decompress(&mut bufread, &mut decomp).map_err(|e| { + anyhow::anyhow!("failed to unpack {}: {e}", target_targz_path.display()) + })?; let cursor = std::io::Cursor::new(decomp); let mut ar = tar::Archive::new(cursor); if strip_toplevel { - unpack_sans_parent(ar, target_path) - .map_err(|e| format!("failed to unpack {}: {e}", target_targz_path.display())) + unpack_sans_parent(ar, target_path).map_err(|e| { + anyhow::anyhow!("failed to unpack {}: {e}", target_targz_path.display()) + }) } else { - ar.unpack(target_path) - .map_err(|e| format!("failed to unpack {}: {e}", target_targz_path.display())) + ar.unpack(target_path).map_err(|e| { + anyhow::anyhow!("failed to unpack {}: {e}", target_targz_path.display()) + }) } }; try_decode_gz().or_else(|_| try_decode_xz())?; - let _ = std::fs::remove_file(target_targz_path); + Ok(target_targz_path.to_path_buf()) +} + +/// Whether the top-level directory should be stripped +pub fn download_and_unpack_targz( + url: &str, + target_path: &Path, + strip_toplevel: bool, +) -> Result { + let tempdir = tempdir::TempDir::new("wasmer-download-targz")?; + + let target_targz_path = tempdir.path().join("package.tar.gz"); + + let mut resp = reqwest::blocking::get(url) + .map_err(|e| anyhow::anyhow!("failed to download {url}: {e}"))?; + + { + let mut file = std::fs::File::create(&target_targz_path).map_err(|e| { + anyhow::anyhow!( + "failed to download {url} into {}: {e}", + target_targz_path.display() + ) + })?; + + resp.copy_to(&mut file) + .map_err(|e| anyhow::anyhow!("{e}"))?; + } + + try_unpack_targz(target_targz_path.as_path(), target_path, strip_toplevel) + .with_context(|| anyhow::anyhow!("Could not download {url}"))?; Ok(target_path.to_path_buf()) } @@ -1042,6 +769,7 @@ where /// Given a triple of [registry, name, version], downloads and installs the /// .tar.gz if it doesn't yet exist, returns the (package dir, entrypoint .wasm file path) pub fn install_package( + #[cfg(test)] test_name: &str, registry: Option<&str>, name: &str, version: Option<&str>, @@ -1053,7 +781,16 @@ pub fn install_package( None => { let registries = match registry { Some(s) => vec![s.to_string()], - None => get_all_available_registries()?, + None => { + #[cfg(test)] + { + get_all_available_registries(test_name)? + } + #[cfg(not(test))] + { + get_all_available_registries()? + } + } }; let mut url_of_package = None; @@ -1072,12 +809,21 @@ pub fn install_package( for r in registries.iter() { if !force_install { + #[cfg(not(test))] let package_has_new_version = get_if_package_has_new_version( r, name, version.map(|s| s.to_string()), Duration::from_secs(60 * 5), )?; + #[cfg(test)] + let package_has_new_version = get_if_package_has_new_version( + test_name, + r, + name, + version.map(|s| s.to_string()), + Duration::from_secs(60 * 5), + )?; if let GetIfPackageHasNewVersionResult::UseLocalAlreadyInstalled { registry_host, namespace, @@ -1128,13 +874,21 @@ pub fn install_package( .ok_or_else(|| format!("invalid url: {}", package_info.registry))? .to_string(); + #[cfg(test)] + let dir = get_package_local_dir( + test_name, + &host, + &package_info.package, + &package_info.version, + )?; + #[cfg(not(test))] let dir = get_package_local_dir(&host, &package_info.package, &package_info.version)?; let version = package_info.version; let name = package_info.package; if !dir.join("wapm.toml").exists() || force_install { - download_and_unpack_targz(&package_info.url, &dir, false)?; + download_and_unpack_targz(&package_info.url, &dir, false).map_err(|e| format!("{e}"))?; } Ok(( @@ -1147,12 +901,53 @@ pub fn install_package( )) } +pub fn whoami( + #[cfg(test)] test_name: &str, + registry: Option<&str>, +) -> Result<(String, String), anyhow::Error> { + use crate::queries::{who_am_i_query, WhoAmIQuery}; + use graphql_client::GraphQLQuery; + + #[cfg(test)] + let config = PartialWapmConfig::from_file(test_name); + #[cfg(not(test))] + let config = PartialWapmConfig::from_file(); + + let config = config + .map_err(|e| anyhow::anyhow!("{e}")) + .with_context(|| format!("{registry:?}"))?; + + let registry = match registry { + Some(s) => format_graphql(s), + None => config.registry.get_current_registry(), + }; + + let login_token = config + .registry + .get_login_token_for_registry(®istry) + .ok_or_else(|| anyhow::anyhow!("not logged into registry {:?}", registry))?; + + let q = WhoAmIQuery::build_query(who_am_i_query::Variables {}); + let response: who_am_i_query::ResponseData = + crate::graphql::execute_query(®istry, &login_token, &q) + .with_context(|| format!("{registry:?}"))?; + + let username = response + .viewer + .as_ref() + .ok_or_else(|| anyhow::anyhow!("not logged into registry {:?}", registry))? + .username + .to_string(); + + Ok((registry, username)) +} + pub fn test_if_registry_present(registry: &str) -> Result { - use crate::graphql::{test_if_registry_present, TestIfRegistryPresent}; + use crate::queries::{test_if_registry_present, TestIfRegistryPresent}; use graphql_client::GraphQLQuery; let q = TestIfRegistryPresent::build_query(test_if_registry_present::Variables {}); - let _ = crate::graphql::execute_query_modifier_inner_check_json( + crate::graphql::execute_query_modifier_inner_check_json( registry, "", &q, @@ -1164,8 +959,12 @@ pub fn test_if_registry_present(registry: &str) -> Result { Ok(true) } -pub fn get_all_available_registries() -> Result, String> { +pub fn get_all_available_registries(#[cfg(test)] test_name: &str) -> Result, String> { + #[cfg(test)] + let config = PartialWapmConfig::from_file(test_name)?; + #[cfg(not(test))] let config = PartialWapmConfig::from_file()?; + let mut registries = Vec::new(); match config.registry { Registries::Single(s) => { @@ -1180,11 +979,239 @@ pub fn get_all_available_registries() -> Result, String> { Ok(registries) } +#[derive(Debug, PartialEq, Clone)] +pub struct RemoteWebcInfo { + pub checksum: String, + pub manifest: webc::Manifest, +} + +pub fn install_webc_package( + #[cfg(test)] test_name: &str, + url: &Url, + checksum: &str, +) -> Result<(), anyhow::Error> { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { + { + #[cfg(test)] + { + install_webc_package_inner(test_name, url, checksum).await + } + #[cfg(not(test))] + { + install_webc_package_inner(url, checksum).await + } + } + }) +} + +async fn install_webc_package_inner( + #[cfg(test)] test_name: &str, + url: &Url, + checksum: &str, +) -> Result<(), anyhow::Error> { + use futures_util::StreamExt; + + #[cfg(test)] + let path = get_webc_dir(test_name).ok_or_else(|| anyhow::anyhow!("no webc dir"))?; + #[cfg(not(test))] + let path = get_webc_dir().ok_or_else(|| anyhow::anyhow!("no webc dir"))?; + + let _ = std::fs::create_dir_all(&path); + + let webc_path = path.join(checksum); + + let mut file = std::fs::File::create(&webc_path) + .map_err(|e| anyhow::anyhow!("{e}")) + .context(anyhow::anyhow!("{}", webc_path.display()))?; + + let client = { + let builder = reqwest::Client::builder(); + let builder = crate::graphql::proxy::maybe_set_up_proxy(builder)?; + builder + .build() + .map_err(|e| anyhow::anyhow!("{e}")) + .context("install_webc_package: failed to build reqwest Client")? + }; + + let res = client + .get(url.clone()) + .header(ACCEPT, "application/webc") + .send() + .await + .and_then(|response| response.error_for_status()) + .map_err(|e| anyhow::anyhow!("{e}")) + .context(anyhow::anyhow!("install_webc_package: failed to GET {url}"))?; + + let mut stream = res.bytes_stream(); + + while let Some(item) = stream.next().await { + let item = item + .map_err(|e| anyhow::anyhow!("{e}")) + .context(anyhow::anyhow!("install_webc_package: failed to GET {url}"))?; + file.write_all(&item) + .map_err(|e| anyhow::anyhow!("{e}")) + .context(anyhow::anyhow!( + "install_webc_package: failed to write chunk to {}", + webc_path.display() + ))?; + } + + Ok(()) +} + +/// Returns a list of all installed webc packages +#[cfg(test)] +pub fn get_all_installed_webc_packages(test_name: &str) -> Vec { + get_all_installed_webc_packages_inner(test_name) +} + +#[cfg(not(test))] +pub fn get_all_installed_webc_packages() -> Vec { + get_all_installed_webc_packages_inner("") +} + +fn get_all_installed_webc_packages_inner(_test_name: &str) -> Vec { + #[cfg(test)] + let dir = match get_webc_dir(_test_name) { + Some(s) => s, + None => return Vec::new(), + }; + + #[cfg(not(test))] + let dir = match get_webc_dir() { + Some(s) => s, + None => return Vec::new(), + }; + + let read_dir = match std::fs::read_dir(dir) { + Ok(s) => s, + Err(_) => return Vec::new(), + }; + + read_dir + .filter_map(|r| Some(r.ok()?.path())) + .filter_map(|path| { + webc::WebCMmap::parse( + path, + &webc::ParseOptions { + parse_atoms: false, + parse_volumes: false, + ..Default::default() + }, + ) + .ok() + }) + .filter_map(|webc| { + let checksum = webc.checksum.as_ref().map(|s| &s.data)?.to_vec(); + let hex_string = get_checksum_hash(&checksum); + Some(RemoteWebcInfo { + checksum: hex_string, + manifest: webc.manifest.clone(), + }) + }) + .collect() +} + +/// The checksum of the webc file has a bunch of zeros at the end +/// (it's currently encoded that way in the webc format). This function +/// strips the zeros because otherwise the filename would become too long. +/// +/// So: +/// +/// `3ea47cb0000000000000` -> `3ea47cb` +/// +pub fn get_checksum_hash(bytes: &[u8]) -> String { + let mut checksum = bytes.to_vec(); + while checksum.last().copied() == Some(0) { + checksum.pop(); + } + hex::encode(&checksum) +} + +/// Returns the checksum of the .webc file, so that we can check whether the +/// file is already installed before downloading it +pub fn get_remote_webc_checksum(url: &Url) -> Result { + let request_max_bytes = webc::WebC::get_signature_offset_start() + 4 + 1024 + 8 + 8; + let data = get_webc_bytes(url, Some(0..request_max_bytes)) + .with_context(|| format!("get_webc_bytes failed on {url}"))?; + let checksum = webc::WebC::get_checksum_bytes(&data) + .map_err(|e| anyhow::anyhow!("{e}")) + .context("get_checksum_bytes failed")? + .to_vec(); + Ok(get_checksum_hash(&checksum)) +} + +/// Before fetching the entire file from a remote URL, just fetch the manifest +/// so we can see if the package has already been installed +pub fn get_remote_webc_manifest(url: &Url) -> Result { + // Request up unti manifest size / manifest len + let request_max_bytes = webc::WebC::get_signature_offset_start() + 4 + 1024 + 8 + 8; + let data = get_webc_bytes(url, Some(0..request_max_bytes))?; + let checksum = webc::WebC::get_checksum_bytes(&data) + .map_err(|e| anyhow::anyhow!("{e}")) + .context("WebC::get_checksum_bytes failed")? + .to_vec(); + let hex_string = get_checksum_hash(&checksum); + + let (manifest_start, manifest_len) = webc::WebC::get_manifest_offset_size(&data) + .map_err(|e| anyhow::anyhow!("{e}")) + .context("WebC::get_manifest_offset_size failed")?; + let data_with_manifest = get_webc_bytes(url, Some(0..manifest_start + manifest_len))?; + let manifest = webc::WebC::get_manifest(&data_with_manifest) + .map_err(|e| anyhow::anyhow!("{e}")) + .context("WebC::get_manifest failed")?; + Ok(RemoteWebcInfo { + checksum: hex_string, + manifest, + }) +} + +fn setup_webc_client(url: &Url) -> Result { + let client = { + let builder = reqwest::blocking::Client::builder(); + let builder = crate::graphql::proxy::maybe_set_up_proxy_blocking(builder) + .context("setup_webc_client")?; + builder + .build() + .map_err(|e| anyhow::anyhow!("{e}")) + .context("setup_webc_client: builder.build() failed")? + }; + + Ok(client.get(url.clone()).header(ACCEPT, "application/webc")) +} + +fn get_webc_bytes(url: &Url, range: Option>) -> Result, anyhow::Error> { + // curl -r 0-500 -L https://wapm.dev/syrusakbary/python -H "Accept: application/webc" --output python.webc + + let mut res = setup_webc_client(url)?; + + if let Some(range) = range.as_ref() { + res = res.header(RANGE, format!("bytes={}-{}", range.start, range.end)); + } + + let res = res + .send() + .map_err(|e| anyhow::anyhow!("{e}")) + .context("send() failed")?; + let bytes = res + .bytes() + .map_err(|e| anyhow::anyhow!("{e}")) + .context("bytes() failed")?; + + Ok(bytes.to_vec()) +} + // TODO: this test is segfaulting only on linux-musl, no other OS // See https://github.com/wasmerio/wasmer/pull/3215 #[cfg(not(target_env = "musl"))] #[test] fn test_install_package() { + const TEST_NAME: &str = "test_install_package"; + println!("test install package..."); let registry = "https://registry.wapm.io/graphql"; if !test_if_registry_present(registry).unwrap_or(false) { @@ -1208,21 +1235,28 @@ fn test_install_package() { "https://registry-cdn.wapm.io/packages/wasmer/wabt/wabt-1.0.29.tar.gz".to_string() ); - let (package, _) = - install_package(Some(registry), "wasmer/wabt", Some("1.0.29"), None, true).unwrap(); + let (package, _) = install_package( + TEST_NAME, + Some(registry), + "wasmer/wabt", + Some("1.0.29"), + None, + true, + ) + .unwrap(); println!("package installed: {package:#?}"); assert_eq!( - package.get_path().unwrap(), - get_global_install_dir("registry.wapm.io") + package.get_path(TEST_NAME).unwrap(), + get_global_install_dir(TEST_NAME, "registry.wapm.io") .unwrap() .join("wasmer") .join("wabt") .join("1.0.29") ); - let all_installed_packages = get_all_local_packages(Some(registry)); + let all_installed_packages = get_all_local_packages(TEST_NAME, Some(registry)); println!("all_installed_packages: {all_installed_packages:#?}"); @@ -1233,7 +1267,7 @@ fn test_install_package() { println!("is_installed: {is_installed:#?}"); if !is_installed { - let panic_str = get_all_local_packages(Some(registry)) + let panic_str = get_all_local_packages(TEST_NAME, Some(registry)) .iter() .map(|p| format!("{} {} {}", p.registry, p.name, p.version)) .collect::>() @@ -1243,3 +1277,90 @@ fn test_install_package() { println!("ok, done"); } + +/// A library that exposes bindings to a WAPM package. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Bindings { + /// A unique ID specifying this set of bindings. + pub id: String, + /// The URL which can be used to download the files that were generated + /// (typically as a `*.tar.gz` file). + pub url: String, + /// The programming language these bindings are written in. + pub language: ProgrammingLanguage, + /// The generator used to generate these bindings. + pub generator: BindingsGenerator, +} + +/// The generator used to create [`Bindings`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BindingsGenerator { + /// A unique ID specifying this generator. + pub id: String, + /// The generator package's name (e.g. `wasmer/wasmer-pack`). + pub package_name: String, + /// The exact package version. + pub version: String, + /// The name of the command that was used for generating bindings. + pub command: String, +} + +impl Display for BindingsGenerator { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let BindingsGenerator { + package_name, + version, + command, + .. + } = self; + + write!(f, "{package_name}@{version}:{command}")?; + + Ok(()) + } +} + +/// List all bindings associated with a particular package. +/// +/// If a version number isn't provided, this will default to the most recently +/// published version. +pub fn list_bindings( + registry: &str, + name: &str, + version: Option<&str>, +) -> Result, anyhow::Error> { + use crate::queries::{ + get_bindings_query::{ResponseData, Variables}, + GetBindingsQuery, + }; + use graphql_client::GraphQLQuery; + + let variables = Variables { + name: name.to_string(), + version: version.map(String::from), + }; + + let q = GetBindingsQuery::build_query(variables); + let response: ResponseData = crate::graphql::execute_query(registry, "", &q)?; + + let package_version = response.package_version.context("Package not found")?; + + let mut bindings_packages = Vec::new(); + + for b in package_version.bindings.into_iter().flatten() { + let pkg = Bindings { + id: b.id, + url: b.url, + language: b.language, + generator: BindingsGenerator { + id: b.generator.package_version.id, + package_name: b.generator.package_version.package.name, + version: b.generator.package_version.version, + command: b.generator.command_name, + }, + }; + bindings_packages.push(pkg); + } + + Ok(bindings_packages) +} diff --git a/lib/registry/src/login.rs b/lib/registry/src/login.rs new file mode 100644 index 000000000..f5df8d82c --- /dev/null +++ b/lib/registry/src/login.rs @@ -0,0 +1,33 @@ +use crate::config::{format_graphql, UpdateRegistry}; +use crate::PartialWapmConfig; + +/// Login to a registry and save the token associated with it. +/// +/// Also sets the registry as the currently active registry to provide a better UX. +pub fn login_and_save_token( + #[cfg(test)] test_name: &str, + registry: &str, + token: &str, +) -> Result, anyhow::Error> { + let registry = format_graphql(registry); + #[cfg(test)] + let mut config = PartialWapmConfig::from_file(test_name) + .map_err(|e| anyhow::anyhow!("config from file: {e}"))?; + #[cfg(not(test))] + let mut config = + PartialWapmConfig::from_file().map_err(|e| anyhow::anyhow!("config from file: {e}"))?; + config.registry.set_current_registry(®istry); + config.registry.set_login_token_for_registry( + &config.registry.get_current_registry(), + token, + UpdateRegistry::Update, + ); + #[cfg(test)] + let path = PartialWapmConfig::get_file_location(test_name) + .map_err(|e| anyhow::anyhow!("get file location: {e}"))?; + #[cfg(not(test))] + let path = PartialWapmConfig::get_file_location() + .map_err(|e| anyhow::anyhow!("get file location: {e}"))?; + config.save(&path)?; + crate::utils::get_username_registry_token(®istry, token) +} diff --git a/lib/registry/src/queries.rs b/lib/registry/src/queries.rs new file mode 100644 index 000000000..994d408c9 --- /dev/null +++ b/lib/registry/src/queries.rs @@ -0,0 +1,62 @@ +//! Low-level GraphQL queries used by this crate. +//! +//! If possible, users should prefer the high-level functions exposed under +//! [`crate`]. +//! +//! This module is primarily used in combination with +//! [`crate::graphql::execute_query()`] as an "escape hatch" for accessing +//! information that may not be exposed via the high-level functions. +//! +//! # Backwards Compatibility +//! +//! Queries won't be deleted or have breaking changes to their inputs during +//! patch releases, however new fields may be added to the response types +//! generated by `graphql_client` at any time. +//! +//! Users should treat all response types as if they had the `#[non_exhaustive]` +//! attribute. + +use graphql_client::*; + +/// The GraphQL schema exposed by the WAPM backend. +pub const SCHEMA: &str = include_str!("../graphql/schema.graphql"); + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/queries/get_package_version.graphql", + response_derives = "Debug" +)] +pub struct GetPackageVersionQuery; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/queries/whoami.graphql", + response_derives = "Debug" +)] +pub struct WhoAmIQuery; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/queries/get_package_by_command.graphql", + response_derives = "Debug" +)] +pub struct GetPackageByCommandQuery; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/queries/test_if_registry_present.graphql", + response_derives = "Debug" +)] +pub struct TestIfRegistryPresent; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/queries/get_bindings.graphql", + response_derives = "Debug,Clone,PartialEq,Eq" +)] +pub struct GetBindingsQuery; diff --git a/lib/registry/src/utils.rs b/lib/registry/src/utils.rs new file mode 100644 index 000000000..e6185a326 --- /dev/null +++ b/lib/registry/src/utils.rs @@ -0,0 +1,27 @@ +use crate::{graphql::execute_query, PartialWapmConfig}; +use graphql_client::GraphQLQuery; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/queries/whoami.graphql", + response_derives = "Debug" +)] +struct WhoAmIQuery; + +pub fn get_username(#[cfg(test)] test_name: &str) -> anyhow::Result> { + #[cfg(test)] + let config = PartialWapmConfig::from_file(test_name).map_err(|e| anyhow::anyhow!("{e}"))?; + #[cfg(not(test))] + let config = PartialWapmConfig::from_file().map_err(|e| anyhow::anyhow!("{e}"))?; + let registry = &config.registry.get_current_registry(); + let q = WhoAmIQuery::build_query(who_am_i_query::Variables {}); + let response: who_am_i_query::ResponseData = execute_query(registry, "", &q)?; + Ok(response.viewer.map(|viewer| viewer.username)) +} + +pub fn get_username_registry_token(registry: &str, token: &str) -> anyhow::Result> { + let q = WhoAmIQuery::build_query(who_am_i_query::Variables {}); + let response: who_am_i_query::ResponseData = execute_query(registry, token, &q)?; + Ok(response.viewer.map(|viewer| viewer.username)) +} diff --git a/lib/types/Cargo.toml b/lib/types/Cargo.toml index d60a66cd9..0909c87ee 100644 --- a/lib/types/Cargo.toml +++ b/lib/types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-types" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Wasmer Common Types" categories = ["wasm", "no-std", "data-structures"] keywords = ["wasm", "webassembly", "types"] diff --git a/lib/types/src/compilation/function.rs b/lib/types/src/compilation/function.rs index 0569939a0..bd3402114 100644 --- a/lib/types/src/compilation/function.rs +++ b/lib/types/src/compilation/function.rs @@ -112,12 +112,12 @@ impl Dwarf { #[derive(Debug, PartialEq, Eq)] pub struct Compilation { /// Compiled code for the function bodies. - functions: Functions, + pub functions: Functions, /// Custom sections for the module. /// It will hold the data, for example, for constants used in a /// function, global variables, rodata_64, hot/cold function partitioning, ... - custom_sections: CustomSections, + pub custom_sections: CustomSections, /// Trampolines to call a function defined locally in the wasm via a /// provided `Vec` of values. @@ -128,7 +128,7 @@ pub struct Compilation { /// let func = instance.exports.get_function("my_func"); /// func.call(&[Value::I32(1)]); /// ``` - function_call_trampolines: PrimaryMap, + pub function_call_trampolines: PrimaryMap, /// Trampolines to call a dynamic function defined in /// a host, from a Wasm module. @@ -149,118 +149,8 @@ pub struct Compilation { /// ``` /// /// Note: Dynamic function trampolines are only compiled for imported function types. - dynamic_function_trampolines: PrimaryMap, + pub dynamic_function_trampolines: PrimaryMap, /// Section ids corresponding to the Dwarf debug info - debug: Option, -} - -impl Compilation { - /// Creates a compilation artifact from a contiguous function buffer and a set of ranges - pub fn new( - functions: Functions, - custom_sections: CustomSections, - function_call_trampolines: PrimaryMap, - dynamic_function_trampolines: PrimaryMap, - debug: Option, - ) -> Self { - Self { - functions, - custom_sections, - function_call_trampolines, - dynamic_function_trampolines, - debug, - } - } - - /// Gets the bytes of a single function - pub fn get(&self, func: LocalFunctionIndex) -> &CompiledFunction { - &self.functions[func] - } - - /// Gets the number of functions defined. - pub fn len(&self) -> usize { - self.functions.len() - } - - /// Returns whether there are no functions defined. - pub fn is_empty(&self) -> bool { - self.functions.is_empty() - } - - /// Gets functions relocations. - pub fn get_relocations(&self) -> PrimaryMap> { - self.functions - .iter() - .map(|(_, func)| func.relocations.clone()) - .collect::>() - } - - /// Gets functions bodies. - pub fn get_function_bodies(&self) -> PrimaryMap { - self.functions - .iter() - .map(|(_, func)| func.body.clone()) - .collect::>() - } - - /// Gets functions frame info. - pub fn get_frame_info(&self) -> PrimaryMap { - self.functions - .iter() - .map(|(_, func)| func.frame_info.clone()) - .collect::>() - } - - /// Gets function call trampolines. - pub fn get_function_call_trampolines(&self) -> PrimaryMap { - self.function_call_trampolines.clone() - } - - /// Gets function call trampolines. - pub fn get_dynamic_function_trampolines(&self) -> PrimaryMap { - self.dynamic_function_trampolines.clone() - } - - /// Gets custom section data. - pub fn get_custom_sections(&self) -> PrimaryMap { - self.custom_sections.clone() - } - - /// Gets relocations that apply to custom sections. - pub fn get_custom_section_relocations(&self) -> PrimaryMap> { - self.custom_sections - .iter() - .map(|(_, section)| section.relocations.clone()) - .collect::>() - } - - /// Returns the Dwarf info. - pub fn get_debug(&self) -> Option { - self.debug.clone() - } -} - -impl<'a> IntoIterator for &'a Compilation { - type IntoIter = Iter<'a>; - type Item = ::Item; - - fn into_iter(self) -> Self::IntoIter { - Iter { - iterator: self.functions.iter(), - } - } -} - -/// `Functions` iterator. -pub struct Iter<'a> { - iterator: <&'a Functions as IntoIterator>::IntoIter, -} - -impl<'a> Iterator for Iter<'a> { - type Item = &'a CompiledFunction; - - fn next(&mut self) -> Option { - self.iterator.next().map(|(_, b)| b) - } + pub debug: Option, } diff --git a/lib/types/src/features.rs b/lib/types/src/features.rs index 0f9f6c7fb..9b02f3608 100644 --- a/lib/types/src/features.rs +++ b/lib/types/src/features.rs @@ -45,7 +45,7 @@ impl Features { /// Create a new feature pub fn new() -> Self { Self { - threads: false, + threads: true, // Reference types should be on by default reference_types: true, // SIMD should be on by default @@ -253,7 +253,7 @@ mod test_features { assert_eq!( default, Features { - threads: false, + threads: true, reference_types: true, simd: true, bulk_memory: true, diff --git a/lib/types/src/libcalls.rs b/lib/types/src/libcalls.rs index 5beac58c0..6ea62d42e 100644 --- a/lib/types/src/libcalls.rs +++ b/lib/types/src/libcalls.rs @@ -109,6 +109,24 @@ pub enum LibCall { /// probe for stack overflow. These are emitted for functions which need /// when the `enable_probestack` setting is true. Probestack, + + /// memory.atomic.wait32 for local memories + Memory32AtomicWait32, + + /// memory.atomic.wait32 for imported memories + ImportedMemory32AtomicWait32, + + /// memory.atomic.wait64 for local memories + Memory32AtomicWait64, + + /// memory.atomic.wait64 for imported memories + ImportedMemory32AtomicWait64, + + /// memory.atomic.notify for local memories + Memory32AtomicNotify, + + /// memory.atomic.botify for imported memories + ImportedMemory32AtomicNotify, } impl LibCall { @@ -151,6 +169,12 @@ impl LibCall { Self::Probestack => "_wasmer_vm_probestack", #[cfg(not(target_vendor = "apple"))] Self::Probestack => "wasmer_vm_probestack", + Self::Memory32AtomicWait32 => "wasmer_vm_memory32_atomic_wait32", + Self::ImportedMemory32AtomicWait32 => "wasmer_vm_imported_memory32_atomic_wait32", + Self::Memory32AtomicWait64 => "wasmer_vm_memory32_atomic_wait64", + Self::ImportedMemory32AtomicWait64 => "wasmer_vm_imported_memory32_atomic_wait64", + Self::Memory32AtomicNotify => "wasmer_vm_memory32_atomic_notify", + Self::ImportedMemory32AtomicNotify => "wasmer_vm_imported_memory32_atomic_notify", } } } diff --git a/lib/types/src/vmoffsets.rs b/lib/types/src/vmoffsets.rs index 81cd0b042..729adc106 100644 --- a/lib/types/src/vmoffsets.rs +++ b/lib/types/src/vmoffsets.rs @@ -115,9 +115,33 @@ impl VMBuiltinFunctionIndex { pub const fn get_table_fill_index() -> Self { Self(23) } + /// Returns an index for wasm's local `memory.atomic.wait32` builtin function. + pub const fn get_memory_atomic_wait32_index() -> Self { + Self(24) + } + /// Returns an index for wasm's imported `memory.atomic.wait32` builtin function. + pub const fn get_imported_memory_atomic_wait32_index() -> Self { + Self(25) + } + /// Returns an index for wasm's local `memory.atomic.wait64` builtin function. + pub const fn get_memory_atomic_wait64_index() -> Self { + Self(26) + } + /// Returns an index for wasm's imported `memory.atomic.wait64` builtin function. + pub const fn get_imported_memory_atomic_wait64_index() -> Self { + Self(27) + } + /// Returns an index for wasm's local `memory.atomic.notify` builtin function. + pub const fn get_memory_atomic_notify_index() -> Self { + Self(28) + } + /// Returns an index for wasm's imported `memory.atomic.notify` builtin function. + pub const fn get_imported_memory_atomic_notify_index() -> Self { + Self(29) + } /// Returns the total number of builtin functions. pub const fn builtin_functions_total_number() -> u32 { - 24 + 30 } /// Return the index as an u32 number. @@ -136,6 +160,7 @@ fn cast_to_u32(sz: usize) -> u32 { } /// Align an offset used in this module to a specific byte-width by rounding up +#[inline] const fn align(offset: u32, width: u32) -> u32 { (offset + (width - 1)) / width * width } @@ -145,29 +170,44 @@ const fn align(offset: u32, width: u32) -> u32 { #[derive(Clone, Debug)] pub struct VMOffsets { /// The size in bytes of a pointer on the target. - pub pointer_size: u8, + pointer_size: u8, /// The number of signature declarations in the module. - pub num_signature_ids: u32, + num_signature_ids: u32, /// The number of imported functions in the module. - pub num_imported_functions: u32, + num_imported_functions: u32, /// The number of imported tables in the module. - pub num_imported_tables: u32, + num_imported_tables: u32, /// The number of imported memories in the module. - pub num_imported_memories: u32, + num_imported_memories: u32, /// The number of imported globals in the module. - pub num_imported_globals: u32, + num_imported_globals: u32, /// The number of defined tables in the module. - pub num_local_tables: u32, + num_local_tables: u32, /// The number of defined memories in the module. - pub num_local_memories: u32, + num_local_memories: u32, /// The number of defined globals in the module. - pub num_local_globals: u32, + num_local_globals: u32, + + vmctx_signature_ids_begin: u32, + vmctx_imported_functions_begin: u32, + vmctx_imported_tables_begin: u32, + vmctx_imported_memories_begin: u32, + vmctx_imported_globals_begin: u32, + vmctx_tables_begin: u32, + vmctx_memories_begin: u32, + vmctx_globals_begin: u32, + vmctx_builtin_functions_begin: u32, + vmctx_trap_handler_begin: u32, + vmctx_gas_limiter_pointer: u32, + vmctx_stack_limit_begin: u32, + vmctx_stack_limit_initial_begin: u32, + size_of_vmctx: u32, } impl VMOffsets { /// Return a new `VMOffsets` instance, for a given pointer size. pub fn new(pointer_size: u8, module: &ModuleInfo) -> Self { - Self { + let mut ret = Self { pointer_size, num_signature_ids: cast_to_u32(module.signatures.len()), num_imported_functions: cast_to_u32(module.num_imported_functions), @@ -177,7 +217,23 @@ impl VMOffsets { num_local_tables: cast_to_u32(module.tables.len()), num_local_memories: cast_to_u32(module.memories.len()), num_local_globals: cast_to_u32(module.globals.len()), - } + vmctx_signature_ids_begin: 0, + vmctx_imported_functions_begin: 0, + vmctx_imported_tables_begin: 0, + vmctx_imported_memories_begin: 0, + vmctx_imported_globals_begin: 0, + vmctx_tables_begin: 0, + vmctx_memories_begin: 0, + vmctx_globals_begin: 0, + vmctx_builtin_functions_begin: 0, + vmctx_trap_handler_begin: 0, + vmctx_gas_limiter_pointer: 0, + vmctx_stack_limit_begin: 0, + vmctx_stack_limit_initial_begin: 0, + size_of_vmctx: 0, + }; + ret.precompute(); + ret } /// Return a new `VMOffsets` instance, for a given pointer size @@ -195,8 +251,102 @@ impl VMOffsets { num_local_tables: 0, num_local_memories: 0, num_local_globals: 0, + vmctx_signature_ids_begin: 0, + vmctx_imported_functions_begin: 0, + vmctx_imported_tables_begin: 0, + vmctx_imported_memories_begin: 0, + vmctx_imported_globals_begin: 0, + vmctx_tables_begin: 0, + vmctx_memories_begin: 0, + vmctx_globals_begin: 0, + vmctx_builtin_functions_begin: 0, + vmctx_trap_handler_begin: 0, + vmctx_gas_limiter_pointer: 0, + vmctx_stack_limit_begin: 0, + vmctx_stack_limit_initial_begin: 0, + size_of_vmctx: 0, } } + + /// Number of local tables defined in the module + pub fn num_local_tables(&self) -> u32 { + self.num_local_tables + } + + /// Number of local memories defined in the module + pub fn num_local_memories(&self) -> u32 { + self.num_local_memories + } + + fn precompute(&mut self) { + /// Offset base by num_items items of size item_size, panicking on overflow + fn offset_by(base: u32, num_items: u32, item_size: u32) -> u32 { + base.checked_add(num_items.checked_mul(item_size).unwrap()) + .unwrap() + } + + self.vmctx_signature_ids_begin = 0; + self.vmctx_imported_functions_begin = offset_by( + self.vmctx_signature_ids_begin, + self.num_signature_ids, + u32::from(self.size_of_vmshared_signature_index()), + ); + self.vmctx_imported_tables_begin = offset_by( + self.vmctx_imported_functions_begin, + self.num_imported_functions, + u32::from(self.size_of_vmfunction_import()), + ); + self.vmctx_imported_memories_begin = offset_by( + self.vmctx_imported_tables_begin, + self.num_imported_tables, + u32::from(self.size_of_vmtable_import()), + ); + self.vmctx_imported_globals_begin = offset_by( + self.vmctx_imported_memories_begin, + self.num_imported_memories, + u32::from(self.size_of_vmmemory_import()), + ); + self.vmctx_tables_begin = offset_by( + self.vmctx_imported_globals_begin, + self.num_imported_globals, + u32::from(self.size_of_vmglobal_import()), + ); + self.vmctx_memories_begin = offset_by( + self.vmctx_tables_begin, + self.num_local_tables, + u32::from(self.size_of_vmtable_definition()), + ); + self.vmctx_globals_begin = align( + offset_by( + self.vmctx_memories_begin, + self.num_local_memories, + u32::from(self.size_of_vmmemory_definition()), + ), + 16, + ); + self.vmctx_builtin_functions_begin = offset_by( + self.vmctx_globals_begin, + self.num_local_globals, + u32::from(self.size_of_vmglobal_local()), + ); + self.vmctx_trap_handler_begin = offset_by( + self.vmctx_builtin_functions_begin, + VMBuiltinFunctionIndex::builtin_functions_total_number(), + u32::from(self.pointer_size), + ); + self.vmctx_gas_limiter_pointer = offset_by( + self.vmctx_trap_handler_begin, + 1, + u32::from(self.pointer_size), + ); + self.vmctx_stack_limit_begin = offset_by( + self.vmctx_gas_limiter_pointer, + 1, + u32::from(self.pointer_size), + ); + self.vmctx_stack_limit_initial_begin = self.vmctx_stack_limit_begin.checked_add(4).unwrap(); + self.size_of_vmctx = self.vmctx_stack_limit_begin.checked_add(4).unwrap(); + } } /// Offsets for `VMFunctionImport`. @@ -432,296 +582,172 @@ impl VMOffsets { impl VMOffsets { /// The offset of the `signature_ids` array. pub fn vmctx_signature_ids_begin(&self) -> u32 { - 0 + self.vmctx_signature_ids_begin } /// The offset of the `tables` array. #[allow(clippy::erasing_op)] pub fn vmctx_imported_functions_begin(&self) -> u32 { - self.vmctx_signature_ids_begin() - .checked_add( - self.num_signature_ids - .checked_mul(u32::from(self.size_of_vmshared_signature_index())) - .unwrap(), - ) - .unwrap() + self.vmctx_imported_functions_begin } /// The offset of the `tables` array. #[allow(clippy::identity_op)] pub fn vmctx_imported_tables_begin(&self) -> u32 { - self.vmctx_imported_functions_begin() - .checked_add( - self.num_imported_functions - .checked_mul(u32::from(self.size_of_vmfunction_import())) - .unwrap(), - ) - .unwrap() + self.vmctx_imported_tables_begin } /// The offset of the `memories` array. pub fn vmctx_imported_memories_begin(&self) -> u32 { - self.vmctx_imported_tables_begin() - .checked_add( - self.num_imported_tables - .checked_mul(u32::from(self.size_of_vmtable_import())) - .unwrap(), - ) - .unwrap() + self.vmctx_imported_memories_begin } /// The offset of the `globals` array. pub fn vmctx_imported_globals_begin(&self) -> u32 { - self.vmctx_imported_memories_begin() - .checked_add( - self.num_imported_memories - .checked_mul(u32::from(self.size_of_vmmemory_import())) - .unwrap(), - ) - .unwrap() + self.vmctx_imported_globals_begin } /// The offset of the `tables` array. pub fn vmctx_tables_begin(&self) -> u32 { - self.vmctx_imported_globals_begin() - .checked_add( - self.num_imported_globals - .checked_mul(u32::from(self.size_of_vmglobal_import())) - .unwrap(), - ) - .unwrap() + self.vmctx_tables_begin } /// The offset of the `memories` array. pub fn vmctx_memories_begin(&self) -> u32 { - self.vmctx_tables_begin() - .checked_add( - self.num_local_tables - .checked_mul(u32::from(self.size_of_vmtable_definition())) - .unwrap(), - ) - .unwrap() + self.vmctx_memories_begin } /// The offset of the `globals` array. pub fn vmctx_globals_begin(&self) -> u32 { - let offset = self - .vmctx_memories_begin() - .checked_add( - self.num_local_memories - .checked_mul(u32::from(self.size_of_vmmemory_definition())) - .unwrap(), - ) - .unwrap(); - align(offset, 16) + self.vmctx_globals_begin } /// The offset of the builtin functions array. pub fn vmctx_builtin_functions_begin(&self) -> u32 { - self.vmctx_globals_begin() - .checked_add( - self.num_local_globals - .checked_mul(u32::from(self.size_of_vmglobal_local())) - .unwrap(), - ) - .unwrap() + self.vmctx_builtin_functions_begin } /// Return the size of the `VMContext` allocation. pub fn size_of_vmctx(&self) -> u32 { - self.vmctx_builtin_functions_begin() - .checked_add( - VMBuiltinFunctionIndex::builtin_functions_total_number() - .checked_mul(u32::from(self.pointer_size)) - .unwrap(), - ) - .unwrap() + self.size_of_vmctx } /// Return the offset to `VMSharedSignatureIndex` index `index`. pub fn vmctx_vmshared_signature_id(&self, index: SignatureIndex) -> u32 { assert_lt!(index.as_u32(), self.num_signature_ids); - self.vmctx_signature_ids_begin() - .checked_add( - index - .as_u32() - .checked_mul(u32::from(self.size_of_vmshared_signature_index())) - .unwrap(), - ) - .unwrap() + self.vmctx_signature_ids_begin + + index.as_u32() * u32::from(self.size_of_vmshared_signature_index()) } /// Return the offset to `VMFunctionImport` index `index`. pub fn vmctx_vmfunction_import(&self, index: FunctionIndex) -> u32 { assert_lt!(index.as_u32(), self.num_imported_functions); - self.vmctx_imported_functions_begin() - .checked_add( - index - .as_u32() - .checked_mul(u32::from(self.size_of_vmfunction_import())) - .unwrap(), - ) - .unwrap() + self.vmctx_imported_functions_begin + + index.as_u32() * u32::from(self.size_of_vmfunction_import()) } /// Return the offset to `VMTableImport` index `index`. pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 { assert_lt!(index.as_u32(), self.num_imported_tables); - self.vmctx_imported_tables_begin() - .checked_add( - index - .as_u32() - .checked_mul(u32::from(self.size_of_vmtable_import())) - .unwrap(), - ) - .unwrap() + self.vmctx_imported_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_import()) } /// Return the offset to `VMMemoryImport` index `index`. pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 { assert_lt!(index.as_u32(), self.num_imported_memories); - self.vmctx_imported_memories_begin() - .checked_add( - index - .as_u32() - .checked_mul(u32::from(self.size_of_vmmemory_import())) - .unwrap(), - ) - .unwrap() + self.vmctx_imported_memories_begin + + index.as_u32() * u32::from(self.size_of_vmmemory_import()) } /// Return the offset to `VMGlobalImport` index `index`. pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 { assert_lt!(index.as_u32(), self.num_imported_globals); - self.vmctx_imported_globals_begin() - .checked_add( - index - .as_u32() - .checked_mul(u32::from(self.size_of_vmglobal_import())) - .unwrap(), - ) - .unwrap() + self.vmctx_imported_globals_begin + + index.as_u32() * u32::from(self.size_of_vmglobal_import()) } /// Return the offset to `VMTableDefinition` index `index`. pub fn vmctx_vmtable_definition(&self, index: LocalTableIndex) -> u32 { assert_lt!(index.as_u32(), self.num_local_tables); - self.vmctx_tables_begin() - .checked_add( - index - .as_u32() - .checked_mul(u32::from(self.size_of_vmtable_definition())) - .unwrap(), - ) - .unwrap() + self.vmctx_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_definition()) } /// Return the offset to `VMMemoryDefinition` index `index`. pub fn vmctx_vmmemory_definition(&self, index: LocalMemoryIndex) -> u32 { assert_lt!(index.as_u32(), self.num_local_memories); - self.vmctx_memories_begin() - .checked_add( - index - .as_u32() - .checked_mul(u32::from(self.size_of_vmmemory_definition())) - .unwrap(), - ) - .unwrap() + self.vmctx_memories_begin + index.as_u32() * u32::from(self.size_of_vmmemory_definition()) } /// Return the offset to the `VMGlobalDefinition` index `index`. pub fn vmctx_vmglobal_definition(&self, index: LocalGlobalIndex) -> u32 { assert_lt!(index.as_u32(), self.num_local_globals); - self.vmctx_globals_begin() - .checked_add( - index - .as_u32() - .checked_mul(u32::from(self.size_of_vmglobal_local())) - .unwrap(), - ) - .unwrap() + self.vmctx_globals_begin + index.as_u32() * u32::from(self.size_of_vmglobal_local()) } /// Return the offset to the `body` field in `*const VMFunctionBody` index `index`. + /// Remember updating precompute upon changes pub fn vmctx_vmfunction_import_body(&self, index: FunctionIndex) -> u32 { - self.vmctx_vmfunction_import(index) - .checked_add(u32::from(self.vmfunction_import_body())) - .unwrap() + self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_body()) } /// Return the offset to the `vmctx` field in `*const VMFunctionBody` index `index`. + /// Remember updating precompute upon changes pub fn vmctx_vmfunction_import_vmctx(&self, index: FunctionIndex) -> u32 { - self.vmctx_vmfunction_import(index) - .checked_add(u32::from(self.vmfunction_import_vmctx())) - .unwrap() + self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_vmctx()) } /// Return the offset to the `definition` field in `VMTableImport` index `index`. + /// Remember updating precompute upon changes pub fn vmctx_vmtable_import_definition(&self, index: TableIndex) -> u32 { - self.vmctx_vmtable_import(index) - .checked_add(u32::from(self.vmtable_import_definition())) - .unwrap() + self.vmctx_vmtable_import(index) + u32::from(self.vmtable_import_definition()) } /// Return the offset to the `base` field in `VMTableDefinition` index `index`. + /// Remember updating precompute upon changes pub fn vmctx_vmtable_definition_base(&self, index: LocalTableIndex) -> u32 { - self.vmctx_vmtable_definition(index) - .checked_add(u32::from(self.vmtable_definition_base())) - .unwrap() + self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_base()) } /// Return the offset to the `current_elements` field in `VMTableDefinition` index `index`. + /// Remember updating precompute upon changes pub fn vmctx_vmtable_definition_current_elements(&self, index: LocalTableIndex) -> u32 { - self.vmctx_vmtable_definition(index) - .checked_add(u32::from(self.vmtable_definition_current_elements())) - .unwrap() + self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_current_elements()) } /// Return the offset to the `from` field in `VMMemoryImport` index `index`. + /// Remember updating precompute upon changes pub fn vmctx_vmmemory_import_definition(&self, index: MemoryIndex) -> u32 { - self.vmctx_vmmemory_import(index) - .checked_add(u32::from(self.vmmemory_import_definition())) - .unwrap() + self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_definition()) } /// Return the offset to the `vmctx` field in `VMMemoryImport` index `index`. + /// Remember updating precompute upon changes pub fn vmctx_vmmemory_import_handle(&self, index: MemoryIndex) -> u32 { - self.vmctx_vmmemory_import(index) - .checked_add(u32::from(self.vmmemory_import_handle())) - .unwrap() + self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_handle()) } /// Return the offset to the `base` field in `VMMemoryDefinition` index `index`. + /// Remember updating precompute upon changes pub fn vmctx_vmmemory_definition_base(&self, index: LocalMemoryIndex) -> u32 { - self.vmctx_vmmemory_definition(index) - .checked_add(u32::from(self.vmmemory_definition_base())) - .unwrap() + self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_base()) } /// Return the offset to the `current_length` field in `VMMemoryDefinition` index `index`. + /// Remember updating precompute upon changes pub fn vmctx_vmmemory_definition_current_length(&self, index: LocalMemoryIndex) -> u32 { - self.vmctx_vmmemory_definition(index) - .checked_add(u32::from(self.vmmemory_definition_current_length())) - .unwrap() + self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_current_length()) } /// Return the offset to the `from` field in `VMGlobalImport` index `index`. + /// Remember updating precompute upon changes pub fn vmctx_vmglobal_import_definition(&self, index: GlobalIndex) -> u32 { - self.vmctx_vmglobal_import(index) - .checked_add(u32::from(self.vmglobal_import_definition())) - .unwrap() + self.vmctx_vmglobal_import(index) + u32::from(self.vmglobal_import_definition()) } /// Return the offset to builtin function in `VMBuiltinFunctionsArray` index `index`. + /// Remember updating precompute upon changes pub fn vmctx_builtin_function(&self, index: VMBuiltinFunctionIndex) -> u32 { - self.vmctx_builtin_functions_begin() - .checked_add( - index - .index() - .checked_mul(u32::from(self.pointer_size)) - .unwrap(), - ) - .unwrap() + self.vmctx_builtin_functions_begin + index.index() * u32::from(self.pointer_size) } } diff --git a/lib/vbus/Cargo.toml b/lib/vbus/Cargo.toml index 23f668245..21d8b3fca 100644 --- a/lib/vbus/Cargo.toml +++ b/lib/vbus/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-vbus" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Wasmer Virtual Bus" authors = ["Wasmer Engineering Team "] license = "MIT" @@ -14,7 +14,7 @@ tracing = { version = "0.1" } typetag = { version = "0.1", optional = true } slab = { version = "0.4", optional = true } wasmer = { path = "../api", version = "=3.0.0-rc.2", default-features = false } -wasmer-vfs = { path = "../vfs", version = "=3.0.0-rc.2", default-features = false } +wasmer-vfs = { path = "../vfs", version = "=3.0.2", default-features = false } wasmer-wasi-types = { path = "../wasi-types/", version = "3.0.0-rc.2" } [features] diff --git a/lib/vfs/Cargo.toml b/lib/vfs/Cargo.toml index fdf53ca51..972a3aaaa 100644 --- a/lib/vfs/Cargo.toml +++ b/lib/vfs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-vfs" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Wasmer Virtual FileSystem" authors = ["Wasmer Engineering Team "] license = "MIT" diff --git a/lib/vfs/src/webc_fs.rs b/lib/vfs/src/webc_fs.rs index bf5cee3e4..fa35e8315 100644 --- a/lib/vfs/src/webc_fs.rs +++ b/lib/vfs/src/webc_fs.rs @@ -25,7 +25,7 @@ where pub memory: Arc, } -impl<'a, T> WebcFileSystem +impl WebcFileSystem where T: std::fmt::Debug + Send + Sync + 'static, T: Deref>, @@ -56,7 +56,7 @@ where pub memory: Arc, } -impl<'a, T> FileOpener for WebCFileOpener +impl FileOpener for WebCFileOpener where T: std::fmt::Debug + Send + Sync + 'static, T: Deref>, diff --git a/lib/vm/Cargo.toml b/lib/vm/Cargo.toml index b52568e1e..729fba3f6 100644 --- a/lib/vm/Cargo.toml +++ b/lib/vm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-vm" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Runtime library support for Wasmer" categories = ["wasm"] keywords = ["wasm", "webassembly"] @@ -11,7 +11,7 @@ readme = "README.md" edition = "2018" [dependencies] -wasmer-types = { path = "../types", version = "=3.0.0-rc.2" } +wasmer-types = { path = "../types", version = "=3.0.2" } libc = { version = "^0.2", default-features = false } memoffset = "0.6" indexmap = { version = "1.6" } diff --git a/lib/vm/src/instance/allocator.rs b/lib/vm/src/instance/allocator.rs index 450c462cc..ae3f360e8 100644 --- a/lib/vm/src/instance/allocator.rs +++ b/lib/vm/src/instance/allocator.rs @@ -131,7 +131,7 @@ impl InstanceAllocator { /// memory, i.e. `Self.instance_ptr` must have been allocated by /// `Self::new`. unsafe fn memory_definition_locations(&self) -> Vec> { - let num_memories = self.offsets.num_local_memories; + let num_memories = self.offsets.num_local_memories(); let num_memories = usize::try_from(num_memories).unwrap(); let mut out = Vec::with_capacity(num_memories); @@ -165,7 +165,7 @@ impl InstanceAllocator { /// memory, i.e. `Self.instance_ptr` must have been allocated by /// `Self::new`. unsafe fn table_definition_locations(&self) -> Vec> { - let num_tables = self.offsets.num_local_tables; + let num_tables = self.offsets.num_local_tables(); let num_tables = usize::try_from(num_tables).unwrap(); let mut out = Vec::with_capacity(num_tables); diff --git a/lib/vm/src/instance/mod.rs b/lib/vm/src/instance/mod.rs index d6b6e2341..45224b64e 100644 --- a/lib/vm/src/instance/mod.rs +++ b/lib/vm/src/instance/mod.rs @@ -14,12 +14,13 @@ use crate::store::{InternalStoreHandle, StoreObjects}; use crate::table::TableElement; use crate::trap::{catch_traps, Trap, TrapCode}; use crate::vmcontext::{ - memory_copy, memory_fill, VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, - VMFunctionContext, VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport, + memory32_atomic_check32, memory32_atomic_check64, memory_copy, memory_fill, + VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionContext, + VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport, VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline, }; +use crate::LinearMemory; use crate::{FunctionBodyPtr, MaybeInstanceOwned, TrapHandlerFn, VMFunctionBody}; -use crate::{LinearMemory, VMMemoryDefinition}; use crate::{VMFuncRef, VMFunction, VMGlobal, VMMemory, VMTable}; pub use allocator::InstanceAllocator; use memoffset::offset_of; @@ -32,7 +33,8 @@ use std::fmt; use std::mem; use std::ptr::{self, NonNull}; use std::slice; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; +use std::thread::{current, park, park_timeout, Thread}; use wasmer_types::entity::{packed_option::ReservedValue, BoxedSlice, EntityRef, PrimaryMap}; use wasmer_types::{ DataIndex, DataInitializer, ElemIndex, ExportIndex, FunctionIndex, GlobalIndex, GlobalInit, @@ -40,6 +42,20 @@ use wasmer_types::{ MemoryIndex, ModuleInfo, Pages, SignatureIndex, TableIndex, TableInitializer, VMOffsets, }; +#[derive(Hash, Eq, PartialEq, Clone, Copy)] +struct NotifyLocation { + memory_index: u32, + address: u32, +} + +struct NotifyWaiter { + thread: Thread, + notified: bool, +} +struct NotifyMap { + map: HashMap>, +} + /// A WebAssembly instance. /// /// The type is dynamically-sized. Indeed, the `vmctx` field can @@ -47,6 +63,7 @@ use wasmer_types::{ /// to ensure that the `vmctx` field is last. See the documentation of /// the `vmctx` field to learn more. #[repr(C)] +#[allow(clippy::type_complexity)] pub(crate) struct Instance { /// The `ModuleInfo` this `Instance` was instantiated from. module: Arc, @@ -88,6 +105,9 @@ pub(crate) struct Instance { /// will point to elements here for functions imported by this instance. imported_funcrefs: BoxedSlice>, + /// The Hasmap with the Notify for the Notify/wait opcodes + conditions: Arc>, + /// Additional context used by compiled WebAssembly code. This /// field is last, and represents a dynamically-sized array that /// extends beyond the nominal end of the struct (similar to a @@ -776,6 +796,227 @@ impl Instance { self.imported_table(table_index).handle } } + + // To implement Wait / Notify, a HasMap, behind a mutex, will be used + // to track the address of waiter. The key of the hashmap is based on the memory + // and waiter threads are "park"'d (with or without timeout) + // Notify will wake the waiters by simply "unpark" the thread + // as the Thread info is stored on the HashMap + // once unparked, the waiter thread will remove it's mark on the HashMap + // timeout / awake is tracked with a boolean in the HashMap + // because `park_timeout` doesn't gives any information on why it returns + fn do_wait(&mut self, index: u32, dst: u32, timeout: i64) -> u32 { + // fetch the notifier + let key = NotifyLocation { + memory_index: index, + address: dst, + }; + let mut conds = self.conditions.lock().unwrap(); + let v = conds.map.entry(key).or_insert_with(Vec::new); + v.push(NotifyWaiter { + thread: current(), + notified: false, + }); + drop(conds); + if timeout < 0 { + park(); + } else { + park_timeout(std::time::Duration::from_nanos(timeout as u64)); + } + let mut conds = self.conditions.lock().unwrap(); + let v = conds.map.get_mut(&key).unwrap(); + let id = current().id(); + let mut ret = 0; + v.retain(|cond| { + if cond.thread.id() == id { + ret = if cond.notified { 0 } else { 2 }; + false + } else { + true + } + }); + if v.is_empty() { + conds.map.remove(&key); + } + if conds.map.len() > 1 << 32 { + ret = 0xffff; + } + ret + } + + /// Perform an Atomic.Wait32 + pub(crate) fn local_memory_wait32( + &mut self, + memory_index: LocalMemoryIndex, + dst: u32, + val: u32, + timeout: i64, + ) -> Result { + let memory = self.memory(memory_index); + //if ! memory.shared { + // We should trap according to spec, but official test rely on not trapping... + //} + + let ret = unsafe { memory32_atomic_check32(&memory, dst, val) }; + + if let Ok(mut ret) = ret { + if ret == 0 { + ret = self.do_wait(memory_index.as_u32(), dst, timeout); + } + if ret == 0xffff { + // ret is 0xffff if there is more than 2^32 waiter in queue + return Err(Trap::lib(TrapCode::TableAccessOutOfBounds)); + } + Ok(ret) + } else { + ret + } + } + + /// Perform an Atomic.Wait32 + pub(crate) fn imported_memory_wait32( + &mut self, + memory_index: MemoryIndex, + dst: u32, + val: u32, + timeout: i64, + ) -> Result { + let import = self.imported_memory(memory_index); + let memory = unsafe { import.definition.as_ref() }; + //if ! memory.shared { + // We should trap according to spec, but official test rely on not trapping... + //} + + let ret = unsafe { memory32_atomic_check32(memory, dst, val) }; + + if let Ok(mut ret) = ret { + if ret == 0 { + ret = self.do_wait(memory_index.as_u32(), dst, timeout); + } + if ret == 0xffff { + // ret is 0xffff if there is more than 2^32 waiter in queue + return Err(Trap::lib(TrapCode::TableAccessOutOfBounds)); + } + Ok(ret) + } else { + ret + } + } + + /// Perform an Atomic.Wait64 + pub(crate) fn local_memory_wait64( + &mut self, + memory_index: LocalMemoryIndex, + dst: u32, + val: u64, + timeout: i64, + ) -> Result { + let memory = self.memory(memory_index); + //if ! memory.shared { + // We should trap according to spec, but official test rely on not trapping... + //} + + let ret = unsafe { memory32_atomic_check64(&memory, dst, val) }; + + if let Ok(mut ret) = ret { + if ret == 0 { + ret = self.do_wait(memory_index.as_u32(), dst, timeout); + } + if ret == 0xffff { + // ret is 0xffff if there is more than 2^32 waiter in queue + return Err(Trap::lib(TrapCode::TableAccessOutOfBounds)); + } + Ok(ret) + } else { + ret + } + } + + /// Perform an Atomic.Wait64 + pub(crate) fn imported_memory_wait64( + &mut self, + memory_index: MemoryIndex, + dst: u32, + val: u64, + timeout: i64, + ) -> Result { + let import = self.imported_memory(memory_index); + let memory = unsafe { import.definition.as_ref() }; + //if ! memory.shared { + // We should trap according to spec, but official test rely on not trapping... + //} + + let ret = unsafe { memory32_atomic_check64(memory, dst, val) }; + + if let Ok(mut ret) = ret { + if ret == 0 { + ret = self.do_wait(memory_index.as_u32(), dst, timeout); + } + if ret == 0xffff { + // ret is 0xffff if there is more than 2^32 waiter in queue + return Err(Trap::lib(TrapCode::TableAccessOutOfBounds)); + } + Ok(ret) + } else { + ret + } + } + + fn do_notify(&mut self, key: NotifyLocation, count: u32) -> Result { + let mut conds = self.conditions.lock().unwrap(); + let mut cnt = 0u32; + if let Some(v) = conds.map.get_mut(&key) { + for waiter in v { + if cnt < count { + waiter.notified = true; // mark as was waiked up + waiter.thread.unpark(); // wakeup! + cnt += 1; + } + } + } + Ok(cnt) + } + + /// Perform an Atomic.Notify + pub(crate) fn local_memory_notify( + &mut self, + memory_index: LocalMemoryIndex, + dst: u32, + count: u32, + ) -> Result { + //let memory = self.memory(memory_index); + //if ! memory.shared { + // We should trap according to spec, but official test rely on not trapping... + //} + + // fetch the notifier + let key = NotifyLocation { + memory_index: memory_index.as_u32(), + address: dst, + }; + self.do_notify(key, count) + } + + /// Perform an Atomic.Notify + pub(crate) fn imported_memory_notify( + &mut self, + memory_index: MemoryIndex, + dst: u32, + count: u32, + ) -> Result { + //let import = self.imported_memory(memory_index); + //let memory = unsafe { import.definition.as_ref() }; + //if ! memory.shared { + // We should trap according to spec, but official test rely on not trapping... + //} + + // fetch the notifier + let key = NotifyLocation { + memory_index: memory_index.as_u32(), + address: dst, + }; + self.do_notify(key, count) + } } /// A handle holding an `Instance` of a WebAssembly module. @@ -868,6 +1109,9 @@ impl InstanceHandle { funcrefs, imported_funcrefs, vmctx: VMContext {}, + conditions: Arc::new(Mutex::new(NotifyMap { + map: HashMap::new(), + })), }; let mut instance_handle = allocator.write_instance(instance); diff --git a/lib/vm/src/libcalls.rs b/lib/vm/src/libcalls.rs index 9274237f1..67523a144 100644 --- a/lib/vm/src/libcalls.rs +++ b/lib/vm/src/libcalls.rs @@ -667,6 +667,154 @@ pub unsafe extern "C" fn wasmer_vm_raise_trap(trap_code: TrapCode) -> ! { #[no_mangle] pub static wasmer_vm_probestack: unsafe extern "C" fn() = PROBESTACK; +/// Implementation of memory.wait32 for locally-defined 32-bit memories. +/// +/// # Safety +/// +/// `vmctx` must be dereferenceable. +#[no_mangle] +pub unsafe extern "C" fn wasmer_vm_memory32_atomic_wait32( + vmctx: *mut VMContext, + memory_index: u32, + dst: u32, + val: u32, + timeout: i64, +) -> u32 { + let result = { + let instance = (*vmctx).instance_mut(); + let memory_index = LocalMemoryIndex::from_u32(memory_index); + + instance.local_memory_wait32(memory_index, dst, val, timeout) + }; + if let Err(trap) = result { + raise_lib_trap(trap); + } + result.unwrap() +} + +/// Implementation of memory.wait32 for imported 32-bit memories. +/// +/// # Safety +/// +/// `vmctx` must be dereferenceable. +#[no_mangle] +pub unsafe extern "C" fn wasmer_vm_imported_memory32_atomic_wait32( + vmctx: *mut VMContext, + memory_index: u32, + dst: u32, + val: u32, + timeout: i64, +) -> u32 { + let result = { + let instance = (*vmctx).instance_mut(); + let memory_index = MemoryIndex::from_u32(memory_index); + + instance.imported_memory_wait32(memory_index, dst, val, timeout) + }; + if let Err(trap) = result { + raise_lib_trap(trap); + } + result.unwrap() +} + +/// Implementation of memory.wait64 for locally-defined 32-bit memories. +/// +/// # Safety +/// +/// `vmctx` must be dereferenceable. +#[no_mangle] +pub unsafe extern "C" fn wasmer_vm_memory32_atomic_wait64( + vmctx: *mut VMContext, + memory_index: u32, + dst: u32, + val: u64, + timeout: i64, +) -> u32 { + let result = { + let instance = (*vmctx).instance_mut(); + let memory_index = LocalMemoryIndex::from_u32(memory_index); + + instance.local_memory_wait64(memory_index, dst, val, timeout) + }; + if let Err(trap) = result { + raise_lib_trap(trap); + } + result.unwrap() +} + +/// Implementation of memory.wait64 for imported 32-bit memories. +/// +/// # Safety +/// +/// `vmctx` must be dereferenceable. +#[no_mangle] +pub unsafe extern "C" fn wasmer_vm_imported_memory32_atomic_wait64( + vmctx: *mut VMContext, + memory_index: u32, + dst: u32, + val: u64, + timeout: i64, +) -> u32 { + let result = { + let instance = (*vmctx).instance_mut(); + let memory_index = MemoryIndex::from_u32(memory_index); + + instance.imported_memory_wait64(memory_index, dst, val, timeout) + }; + if let Err(trap) = result { + raise_lib_trap(trap); + } + result.unwrap() +} + +/// Implementation of memory.notfy for locally-defined 32-bit memories. +/// +/// # Safety +/// +/// `vmctx` must be dereferenceable. +#[no_mangle] +pub unsafe extern "C" fn wasmer_vm_memory32_atomic_notify( + vmctx: *mut VMContext, + memory_index: u32, + dst: u32, + cnt: u32, +) -> u32 { + let result = { + let instance = (*vmctx).instance_mut(); + let memory_index = LocalMemoryIndex::from_u32(memory_index); + + instance.local_memory_notify(memory_index, dst, cnt) + }; + if let Err(trap) = result { + raise_lib_trap(trap); + } + result.unwrap() +} + +/// Implementation of memory.notfy for imported 32-bit memories. +/// +/// # Safety +/// +/// `vmctx` must be dereferenceable. +#[no_mangle] +pub unsafe extern "C" fn wasmer_vm_imported_memory32_atomic_notify( + vmctx: *mut VMContext, + memory_index: u32, + dst: u32, + cnt: u32, +) -> u32 { + let result = { + let instance = (*vmctx).instance_mut(); + let memory_index = MemoryIndex::from_u32(memory_index); + + instance.imported_memory_notify(memory_index, dst, cnt) + }; + if let Err(trap) = result { + raise_lib_trap(trap); + } + result.unwrap() +} + /// The function pointer to a libcall pub fn function_pointer(libcall: LibCall) -> usize { match libcall { @@ -701,5 +849,11 @@ pub fn function_pointer(libcall: LibCall) -> usize { LibCall::DataDrop => wasmer_vm_data_drop as usize, LibCall::Probestack => wasmer_vm_probestack as usize, LibCall::RaiseTrap => wasmer_vm_raise_trap as usize, + LibCall::Memory32AtomicWait32 => wasmer_vm_memory32_atomic_wait32 as usize, + LibCall::ImportedMemory32AtomicWait32 => wasmer_vm_imported_memory32_atomic_wait32 as usize, + LibCall::Memory32AtomicWait64 => wasmer_vm_memory32_atomic_wait64 as usize, + LibCall::ImportedMemory32AtomicWait64 => wasmer_vm_imported_memory32_atomic_wait64 as usize, + LibCall::Memory32AtomicNotify => wasmer_vm_memory32_atomic_notify as usize, + LibCall::ImportedMemory32AtomicNotify => wasmer_vm_imported_memory32_atomic_notify as usize, } } diff --git a/lib/vm/src/memory.rs b/lib/vm/src/memory.rs index a4eeea0b7..9c8e02a11 100644 --- a/lib/vm/src/memory.rs +++ b/lib/vm/src/memory.rs @@ -178,6 +178,18 @@ pub struct VMOwnedMemory { unsafe impl Send for VMOwnedMemory {} unsafe impl Sync for VMOwnedMemory {} +/// A shared linear memory instance. +#[derive(Debug, Clone)] +pub struct VMSharedMemory { + // The underlying allocation. + mmap: Arc>, + // Configuration of this memory + config: VMMemoryConfig, +} + +unsafe impl Send for VMSharedMemory {} +unsafe impl Sync for VMSharedMemory {} + impl VMOwnedMemory { /// Create a new linear memory instance with specified minimum and maximum number of wasm pages. /// @@ -297,6 +309,16 @@ impl VMOwnedMemory { } } +impl VMOwnedMemory { + /// Converts this owned memory into shared memory + pub fn to_shared(self) -> VMSharedMemory { + VMSharedMemory { + mmap: Arc::new(RwLock::new(self.mmap)), + config: self.config, + } + } +} + impl LinearMemory for VMOwnedMemory { /// Returns the type for this memory. fn ty(&self) -> MemoryType { @@ -339,12 +361,85 @@ impl LinearMemory for VMOwnedMemory { } } +impl VMSharedMemory { + /// Create a new linear memory instance with specified minimum and maximum number of wasm pages. + /// + /// This creates a `Memory` with owned metadata: this can be used to create a memory + /// that will be imported into Wasm modules. + pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result { + Ok(VMOwnedMemory::new(memory, style)?.to_shared()) + } + + /// Create a new linear memory instance with specified minimum and maximum number of wasm pages. + /// + /// This creates a `Memory` with metadata owned by a VM, pointed to by + /// `vm_memory_location`: this can be used to create a local memory. + /// + /// # Safety + /// - `vm_memory_location` must point to a valid location in VM memory. + pub unsafe fn from_definition( + memory: &MemoryType, + style: &MemoryStyle, + vm_memory_location: NonNull, + ) -> Result { + Ok(VMOwnedMemory::from_definition(memory, style, vm_memory_location)?.to_shared()) + } +} + +impl LinearMemory for VMSharedMemory { + /// Returns the type for this memory. + fn ty(&self) -> MemoryType { + let minimum = { + let guard = self.mmap.read().unwrap(); + guard.size() + }; + self.config.ty(minimum) + } + + /// Returns the size of hte memory in pages + fn size(&self) -> Pages { + let guard = self.mmap.read().unwrap(); + guard.size() + } + + /// Returns the memory style for this memory. + fn style(&self) -> MemoryStyle { + self.config.style() + } + + /// Grow memory by the specified amount of wasm pages. + /// + /// Returns `None` if memory can't be grown by the specified amount + /// of wasm pages. + fn grow(&mut self, delta: Pages) -> Result { + let mut guard = self.mmap.write().unwrap(); + guard.grow(delta, self.config.clone()) + } + + /// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code. + fn vmmemory(&self) -> NonNull { + let guard = self.mmap.read().unwrap(); + guard.vm_memory_definition.as_ptr() + } + + /// Owned memory can not be cloned (this will always return None) + fn try_clone(&self) -> Option> { + None + } +} + impl From for VMMemory { fn from(mem: VMOwnedMemory) -> Self { Self(Box::new(mem)) } } +impl From for VMMemory { + fn from(mem: VMSharedMemory) -> Self { + Self(Box::new(mem)) + } +} + /// Represents linear memory that can be either owned or shared #[derive(Debug)] pub struct VMMemory(pub Box); @@ -407,7 +502,11 @@ impl VMMemory { /// This creates a `Memory` with owned metadata: this can be used to create a memory /// that will be imported into Wasm modules. pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result { - Ok(Self(Box::new(VMOwnedMemory::new(memory, style)?))) + Ok(if memory.shared { + Self(Box::new(VMSharedMemory::new(memory, style)?)) + } else { + Self(Box::new(VMOwnedMemory::new(memory, style)?)) + }) } /// Returns the number of pages in the allocated memory block @@ -446,9 +545,9 @@ impl VMMemory { /// are natively supported /// - VMOwnedMemory -> VMMemory /// - Box -> VMMemory - pub fn from_custom(memory: IntoVMMemory) -> Self + pub fn from_custom(memory: IntoVMMemory) -> VMMemory where - IntoVMMemory: Into, + IntoVMMemory: Into, { memory.into() } diff --git a/lib/vm/src/store.rs b/lib/vm/src/store.rs index 4648d0e5e..3eeecfb6d 100644 --- a/lib/vm/src/store.rs +++ b/lib/vm/src/store.rs @@ -289,8 +289,8 @@ impl MaybeInstanceOwned { /// Returns underlying pointer to the VM data. pub fn as_ptr(&self) -> NonNull { match self { - MaybeInstanceOwned::Host(p) => unsafe { NonNull::new_unchecked(p.get()) }, - MaybeInstanceOwned::Instance(p) => *p, + Self::Host(p) => unsafe { NonNull::new_unchecked(p.get()) }, + Self::Instance(p) => *p, } } } @@ -301,12 +301,12 @@ where { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - MaybeInstanceOwned::Host(p) => { + Self::Host(p) => { write!(f, "host(")?; p.as_ref().fmt(f)?; write!(f, ")") } - MaybeInstanceOwned::Instance(p) => { + Self::Instance(p) => { write!(f, "instance(")?; unsafe { p.as_ref().fmt(f)? }; write!(f, ")") diff --git a/lib/vm/src/trap/traphandlers.rs b/lib/vm/src/trap/traphandlers.rs index 2899b5d18..117833bd8 100644 --- a/lib/vm/src/trap/traphandlers.rs +++ b/lib/vm/src/trap/traphandlers.rs @@ -272,7 +272,7 @@ cfg_if::cfg_if! { ))] { pc = context.uc_mcontext.gregs[libc::REG_EIP as usize] as usize; sp = context.uc_mcontext.gregs[libc::REG_ESP as usize] as usize; - } else if #[cfg(all(target_os = "freebsd", target_arch = "x86"))] { + } else if #[cfg(all(target_os = "freebsd", any(target_arch = "x86", target_arch = "x86_64")))] { pc = context.uc_mcontext.mc_rip as usize; sp = context.uc_mcontext.mc_rsp as usize; } else if #[cfg(all(target_vendor = "apple", target_arch = "x86_64"))] { @@ -829,14 +829,14 @@ enum UnwindReason { impl UnwindReason { fn into_trap(self) -> Trap { match self { - UnwindReason::UserTrap(data) => Trap::User(data), - UnwindReason::LibTrap(trap) => trap, - UnwindReason::WasmTrap { + Self::UserTrap(data) => Trap::User(data), + Self::LibTrap(trap) => trap, + Self::WasmTrap { backtrace, pc, signal_trap, } => Trap::wasm(pc, backtrace, signal_trap), - UnwindReason::Panic(panic) => std::panic::resume_unwind(panic), + Self::Panic(panic) => std::panic::resume_unwind(panic), } } } diff --git a/lib/vm/src/vmcontext.rs b/lib/vm/src/vmcontext.rs index 766a8708d..f87df89c4 100644 --- a/lib/vm/src/vmcontext.rs +++ b/lib/vm/src/vmcontext.rs @@ -14,6 +14,7 @@ use crate::VMTable; use crate::{VMBuiltinFunctionIndex, VMFunction}; use std::convert::TryFrom; use std::ptr::{self, NonNull}; +use std::sync::atomic::{AtomicPtr, Ordering}; use std::u32; use wasmer_types::RawValue; @@ -376,6 +377,68 @@ pub(crate) unsafe fn memory_fill( Ok(()) } +/// Perform the `memory32.atomic.check32` operation for the memory. Return 0 if same, 1 if different +/// +/// # Errors +/// +/// Returns a `Trap` error if the memory range is out of bounds or 32bits unligned. +/// +/// # Safety +/// memory access is unsafe +pub(crate) unsafe fn memory32_atomic_check32( + mem: &VMMemoryDefinition, + dst: u32, + val: u32, +) -> Result { + if usize::try_from(dst).unwrap() > mem.current_length { + return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds)); + } + + let dst = isize::try_from(dst).unwrap(); + if dst & 0b11 != 0 { + return Err(Trap::lib(TrapCode::UnalignedAtomic)); + } + + // Bounds and casts are checked above, by this point we know that + // everything is safe. + let dst = mem.base.offset(dst) as *mut u32; + let atomic_dst = AtomicPtr::new(dst); + let read_val = *atomic_dst.load(Ordering::Acquire); + let ret = if read_val == val { 0 } else { 1 }; + Ok(ret) +} + +/// Perform the `memory32.atomic.check64` operation for the memory. Return 0 if same, 1 if different +/// +/// # Errors +/// +/// Returns a `Trap` error if the memory range is out of bounds or 64bits unaligned. +/// +/// # Safety +/// memory access is unsafe +pub(crate) unsafe fn memory32_atomic_check64( + mem: &VMMemoryDefinition, + dst: u32, + val: u64, +) -> Result { + if usize::try_from(dst).unwrap() > mem.current_length { + return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds)); + } + + let dst = isize::try_from(dst).unwrap(); + if dst & 0b111 != 0 { + return Err(Trap::lib(TrapCode::UnalignedAtomic)); + } + + // Bounds and casts are checked above, by this point we know that + // everything is safe. + let dst = mem.base.offset(dst) as *mut u64; + let atomic_dst = AtomicPtr::new(dst); + let read_val = *atomic_dst.load(Ordering::Acquire); + let ret = if read_val == val { 0 } else { 1 }; + Ok(ret) +} + /// The fields compiled code needs to access to utilize a WebAssembly table /// defined within the instance. #[derive(Debug, Clone, Copy)] @@ -634,6 +697,19 @@ impl VMBuiltinFunctionsArray { ptrs[VMBuiltinFunctionIndex::get_table_fill_index().index() as usize] = wasmer_vm_table_fill as usize; + ptrs[VMBuiltinFunctionIndex::get_memory_atomic_wait32_index().index() as usize] = + wasmer_vm_memory32_atomic_wait32 as usize; + ptrs[VMBuiltinFunctionIndex::get_imported_memory_atomic_wait32_index().index() as usize] = + wasmer_vm_imported_memory32_atomic_wait32 as usize; + ptrs[VMBuiltinFunctionIndex::get_memory_atomic_wait64_index().index() as usize] = + wasmer_vm_memory32_atomic_wait64 as usize; + ptrs[VMBuiltinFunctionIndex::get_imported_memory_atomic_wait64_index().index() as usize] = + wasmer_vm_imported_memory32_atomic_wait64 as usize; + ptrs[VMBuiltinFunctionIndex::get_memory_atomic_notify_index().index() as usize] = + wasmer_vm_memory32_atomic_notify as usize; + ptrs[VMBuiltinFunctionIndex::get_imported_memory_atomic_notify_index().index() as usize] = + wasmer_vm_imported_memory32_atomic_notify as usize; + debug_assert!(ptrs.iter().cloned().all(|p| p != 0)); Self { ptrs } diff --git a/lib/vnet/Cargo.toml b/lib/vnet/Cargo.toml index 2232850ba..a5dd2c9da 100644 --- a/lib/vnet/Cargo.toml +++ b/lib/vnet/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-vnet" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Wasmer Virtual Networking" authors = ["Wasmer Engineering Team "] license = "MIT" @@ -8,7 +8,7 @@ edition = "2018" [dependencies] thiserror = "1" -wasmer-vfs = { path = "../vfs", version = "=3.0.0-rc.2", default-features = false } +wasmer-vfs = { path = "../vfs", version = "=3.0.2", default-features = false } bytes = "1" async-trait = { version = "^0.1" } diff --git a/lib/wasi-experimental-io-devices/Cargo.toml b/lib/wasi-experimental-io-devices/Cargo.toml index 1e3326526..556ff0add 100644 --- a/lib/wasi-experimental-io-devices/Cargo.toml +++ b/lib/wasi-experimental-io-devices/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi-experimental-io-devices" -version = "3.0.0-rc.2" +version = "3.0.2" description = "An experimental non-standard WASI extension for graphics" categories = ["wasm"] keywords = ["wasm", "webassembly", "types"] @@ -14,7 +14,7 @@ edition = "2018" maintenance = { status = "experimental" } [dependencies] -wasmer-wasi = { version = "=3.0.0-rc.2", path = "../wasi", default-features=false } +wasmer-wasi = { version = "=3.0.2", path = "../wasi", default-features=false } tracing = "0.1" minifb = { version = "0.23", optional = true } nix = "0.25.0" diff --git a/lib/wasi-local-networking/Cargo.toml b/lib/wasi-local-networking/Cargo.toml index 8461359f2..9d204382f 100644 --- a/lib/wasi-local-networking/Cargo.toml +++ b/lib/wasi-local-networking/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi-local-networking" -version = "3.0.0-rc.2" +version = "3.0.2" description = "An WASIX extension for local networking" categories = ["wasm"] keywords = ["wasm", "webassembly", "types"] @@ -14,8 +14,8 @@ edition = "2018" maintenance = { status = "experimental" } [dependencies] -wasmer-vnet = { version = "=3.0.0-rc.2", path = "../vnet", default-features = false } -wasmer-vfs = { path = "../vfs", version = "=3.0.0-rc.2", default-features = false } +wasmer-vnet = { version = "=3.0.2", path = "../vnet", default-features = false } +wasmer-vfs = { path = "../vfs", version = "=3.0.2", default-features = false } tracing = "0.1" bytes = "1.1" tokio = { version = "1", features = [ "sync", "macros", "io-util", "signal" ], default_features = false } diff --git a/lib/wasi-types/Cargo.toml b/lib/wasi-types/Cargo.toml index 0c78c4c2e..9f30d5e0c 100644 --- a/lib/wasi-types/Cargo.toml +++ b/lib/wasi-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi-types" -version = "3.0.0-rc.2" +version = "3.0.2" description = "WASI types for Wasmer WebAssembly runtime" categories = ["wasm", "os"] keywords = ["wasm", "webassembly", "wasi", "sandbox", "ABI"] @@ -13,12 +13,12 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -#wai-bindgen-rust = { version = "0.2.0", optional = true } +wit-bindgen-rust = { package = "wasmer-wit-bindgen-rust", version = "0.1.1" } wit-bindgen-rust-wasm = { package = "wasmer-wit-bindgen-gen-rust-wasm", version = "0.1.1" } wit-bindgen-core = { package = "wasmer-wit-bindgen-gen-core", version = "0.1.1" } wit-parser = { package = "wasmer-wit-parser", version = "0.1.1" } -wasmer-types = { path = "../types", version = "=3.0.0-rc.2", default_features = false } -wasmer-derive = { path = "../derive", version = "=3.0.0-rc.2" } +wasmer-types = { path = "../types", version = "=3.0.2" } +wasmer-derive = { path = "../derive", version = "=3.0.2" } serde = { version = "1.0", features = ["derive"], optional = true } byteorder = "1.3" time = "0.2" diff --git a/lib/wasi-types/regenerate.sh b/lib/wasi-types/regenerate.sh index 7e34b9b64..b6d14be02 100755 --- a/lib/wasi-types/regenerate.sh +++ b/lib/wasi-types/regenerate.sh @@ -1,6 +1,4 @@ -#!/usr/bin/env bash - -set -Eeuxo pipefail +#!/bin/bash BASEDIR=$(dirname "$0") @@ -10,17 +8,10 @@ rm -f \ cat "$BASEDIR"/wit-clean/typenames.wit "$BASEDIR"/wit-clean/wasi_unstable.wit > "$BASEDIR"/wit-clean/output.wit -cd "$BASEDIR" - -if [ ! -d ./wit-bindgen/.git ]; then - git clone https://github.com/wasmerio/wai --branch force-generate-structs --single-branch wit-bindgen -fi -cd wit-bindgen +cargo install --force wai-bindgen git pull origin force-generate-structs -cargo build -cd .. -./wit-bindgen/target/debug/wit-bindgen rust-wasm \ +wai-bindgen rust-wasm \ --import "$BASEDIR"/wit-clean/output.wit \ --force-generate-structs \ --out-dir "$BASEDIR"/src/wasi \ @@ -31,7 +22,7 @@ cp src/wasi/bindings2.rs src/wasi/bindings.rs rm src/wasi/bindings2.rs cd ./wasi-types-generator-extra -cargo run +cargo build pwd `pwd`/target/debug/wasi-types-generator-extra cd .. diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index 90b33fcfd..4769afcdf 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi" -version = "3.0.0-rc.2" +version = "3.0.2" description = "WASI implementation library for Wasmer WebAssembly runtime" categories = ["wasm", "os"] keywords = ["wasm", "webassembly", "wasi", "sandbox", "ABI"] @@ -16,13 +16,13 @@ thiserror = "1" generational-arena = { version = "0.2" } tracing = "0.1" getrandom = "0.2" -wasmer-wasi-types = { path = "../wasi-types", version = "=3.0.0-rc.2" } -wasmer-types = { path = "../types", version = "=3.0.0-rc.2", default-features = false } -wasmer = { path = "../api", version = "=3.0.0-rc.2", default-features = false, features = ["wat", "js-serializable-module", "enable-rkyv"] } -wasmer-vfs = { path = "../vfs", version = "=3.0.0-rc.2", default-features = false, features = ["webc-fs"] } -wasmer-vbus = { path = "../vbus", version = "=3.0.0-rc.2", default-features = false } -wasmer-vnet = { path = "../vnet", version = "=3.0.0-rc.2", default-features = false } -wasmer-wasi-local-networking = { path = "../wasi-local-networking", version = "=3.0.0-rc.2", default-features = false, optional = true } +wasmer-wasi-types = { path = "../wasi-types", version = "=3.0.2" } +wasmer-types = { path = "../types", version = "=3.0.2", default-features = false } +wasmer = { path = "../api", version = "=3.0.2", default-features = false, features = ["wat", "js-serializable-module"] } +wasmer-vfs = { path = "../vfs", version = "=3.0.2", default-features = false, features = ["webc-fs"] } +wasmer-vbus = { path = "../vbus", version = "=3.0.2", default-features = false } +wasmer-vnet = { path = "../vnet", version = "=3.0.2", default-features = false } +wasmer-wasi-local-networking = { path = "../wasi-local-networking", version = "=3.0.2", default-features = false, optional = true } typetag = { version = "0.1", optional = true } serde = { version = "1.0", default-features = false, features = ["derive"] } bincode = { version = "1.3", optional = true } @@ -32,7 +32,7 @@ bytes = "1" webc = { version = "3.0.1", default-features = false, features = ["std", "mmap"] } serde_cbor = { version = "0.11.2", optional = true } anyhow = { version = "1.0.66" } -wasmer-emscripten = { path = "../emscripten", version = "=3.0.0-rc.2", optional = true } +wasmer-emscripten = { path = "../emscripten", version = "=3.0.2", optional = true } lazy_static = "1.4" sha2 = { version = "0.10" } waker-fn = { version = "1.1" } diff --git a/lib/wasi/README.md b/lib/wasi/README.md index 86edd2288..81a2985e4 100644 --- a/lib/wasi/README.md +++ b/lib/wasi/README.md @@ -12,6 +12,12 @@ varies based on the WASI version). A program compiled for the filesystem manipulation, memory management, time, string, environment variables, program startup etc. +Wasmer WASI is created with the aim to be fully sandboxed. +We are able to achieve that thanks to our Virtual Filesystem implementation (`wasmer-vfs`) +and by only allowing secure systemcalls back to the host. + +> Note: If you encounter any sandboxing issue please open an issue in the wasmer repo https://github.com/wasmerio/wasmer. + This crate provides the necessary API to create the imports to use WASI easily from the Wasmer runtime, through our `ImportObject` API. diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs new file mode 100644 index 000000000..e69de29bb diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index 861719434..162bafd9f 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -6,8 +6,16 @@ use std::convert::TryInto; /// types for use in the WASI filesystem #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; +#[cfg(all(unix, feature = "sys-poll"))] +use std::convert::TryInto; +use std::{ + collections::VecDeque, + io::{self, Read, Seek, Write}, + sync::{Arc, Mutex}, + time::Duration, +}; +use wasmer_wasi_types::wasi::{BusErrno, Errno}; use wasmer_vbus::VirtualBusError; -use wasmer_wasi_types::wasi::{BusErrno, Rights}; cfg_if! { if #[cfg(feature = "host-fs")] { @@ -38,7 +46,7 @@ pub fn vbus_error_into_bus_errno(bus_error: VirtualBusError) -> BusErrno { InvokeFailed => BusErrno::Invoke, AlreadyConsumed => BusErrno::Consumed, MemoryAccessViolation => BusErrno::Memviolation, - _ => BusErrno::Unknown, + UnknownError => BusErrno::Unknown, } } @@ -63,7 +71,7 @@ pub fn bus_errno_into_vbus_error(bus_error: BusErrno) -> VirtualBusError { BusErrno::Invoke => InvokeFailed, BusErrno::Consumed => AlreadyConsumed, BusErrno::Memviolation => MemoryAccessViolation, - _ => UnknownError, + BusErrno::Unknown => UnknownError, } } diff --git a/lib/wasi/src/utils/mod.rs b/lib/wasi/src/utils/mod.rs index 1f0179a2c..60a5b87e7 100644 --- a/lib/wasi/src/utils/mod.rs +++ b/lib/wasi/src/utils/mod.rs @@ -1,8 +1,9 @@ mod thread_parker; use std::collections::BTreeSet; - -use wasmer::Module; +#[cfg(not(feature = "js"))] +use wasmer::vm::VMSharedMemory; +use wasmer::{AsStoreMut, Imports, Memory, Module}; use wasmer_wasi_types::wasi::Errno; pub use self::thread_parker::WasiParkingLot; @@ -28,6 +29,44 @@ pub fn map_io_err(err: std::io::Error) -> Errno { From::::from(err) } +/// Imports (any) shared memory into the imports. +/// (if the module does not import memory then this function is ignored) +#[cfg(not(feature = "js"))] +pub fn wasi_import_shared_memory( + imports: &mut Imports, + module: &Module, + store: &mut impl AsStoreMut, +) { + // Determine if shared memory needs to be created and imported + let shared_memory = module + .imports() + .memories() + .next() + .map(|a| *a.ty()) + .map(|ty| { + let style = store.as_store_ref().tunables().memory_style(&ty); + VMSharedMemory::new(&ty, &style).unwrap() + }); + + if let Some(memory) = shared_memory { + // if the memory has already be defined, don't redefine it! + if !imports.exists("env", "memory") { + imports.define( + "env", + "memory", + Memory::new_from_existing(store, memory.into()), + ); + } + }; +} +#[cfg(feature = "js")] +pub fn wasi_import_shared_memory( + _imports: &mut Imports, + _module: &Module, + _store: &mut impl AsStoreMut, +) { +} + /// The version of WASI. This is determined by the imports namespace /// string. #[derive(Debug, Clone, Copy, Eq)] diff --git a/lib/wasi/tests/stdio.rs b/lib/wasi/tests/stdio.rs index 18f43214b..fb6cdfe57 100644 --- a/lib/wasi/tests/stdio.rs +++ b/lib/wasi/tests/stdio.rs @@ -77,7 +77,7 @@ async fn test_stdout() { // pipe.set_blocking(false); let mut wasi_env = WasiState::new("command-name") .args(&["Gordon"]) - .stdout(Box::new(pipe.clone())) + .stdout(Box::new(stdout.clone())) .finalize(&mut store) .unwrap(); diff --git a/scripts/make-release.py b/scripts/make-release.py new file mode 100644 index 000000000..c246b91a5 --- /dev/null +++ b/scripts/make-release.py @@ -0,0 +1,485 @@ +#! /usr/bin/env python3 + +import os +import signal +import time +import sys +import subprocess +import tempfile +import datetime +import re + +RELEASE_VERSION="" +DATE = datetime.date.today().strftime("%d/%m/%Y") +SIGNOFF_REVIEWER = "syrusakbary" + +if len(sys.argv) > 1: + RELEASE_VERSION = sys.argv[1] +else: + print("no release version as first argument") + sys.exit(1) + +RELEASE_VERSION_WITH_V = RELEASE_VERSION + +if not(RELEASE_VERSION.startswith("v")): + RELEASE_VERSION_WITH_V = "v" + RELEASE_VERSION +else: + RELEASE_VERSION = RELEASE_VERSION[1:] + +if os.system("git --version") != 0: + print("git not installed") + sys.exit(1) + +if os.system("gh --version") != 0: + print("gh not installed") + sys.exit(1) + +def get_file_string(file): + file_handle = open(file, 'r') + file_string = file_handle.read() + file_handle.close() + return file_string + +def write_file_string(file, file_string): + file_handle = open(file, 'w') + file_handle.write(file_string) + file_handle.close() + +def replace(file, pattern, subst): + file_string = get_file_string(file) + file_string = file_string.replace(pattern, subst,1) + write_file_string(file, file_string) + +def make_release(version): + gh_logged_in = os.system("gh auth status") == 0 + if not(gh_logged_in): + raise Exception("please log in") + + import tempfile + + temp_dir = tempfile.TemporaryDirectory() + print(temp_dir.name) + if os.system("git clone https://github.com/wasmerio/wasmer --branch master --depth 1 " + temp_dir.name) != 0: + raise Exception("could not clone github repo") + + # generate changelog + proc = subprocess.Popen(['gh', "search", "prs", "--repo", "wasmerio/wasmer", "--merged", "--limit", "100"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + if proc.returncode != 0: + print(proc.stdout) + raise Exception("could not run gh search prs") + + lines = [] + for line in proc.stdout: + line = line.decode("utf-8").rstrip() + if "Release" in line: + break + lines.append(line) + + changed = [] + added = [] + fixed = [] + release_notes_changed = [] + + for l in lines: + fields = l.split("\t") + pr_number = fields[1] + pr_text = fields[3] + l = " - [#" + pr_number + "](https://github.com/wasmerio/wasmer/pull/" + pr_number + ") " + pr_text + release_notes_changed.append(l) + if "add" in l.lower(): + added.append(l) + elif "fix" in l.lower(): + fixed.append(l) + else: + changed.append(l) + + changelog = [] + + changelog.append("## **Unreleased**") + changelog.append("") + changelog.append("## " + RELEASE_VERSION + " - " + DATE) + changelog.append("") + changelog.append("## Added") + changelog.append("") + for a in added: + changelog.append(a) + changelog.append("") + changelog.append("## Changed") + changelog.append("") + for c in changed: + changelog.append(c) + changelog.append("") + changelog.append("## Fixed") + changelog.append("") + for f in fixed: + changelog.append(f) + changelog.append("") + changelog.append("") + + for l in changelog: + print(" " + l) + + proc = subprocess.Popen(['gh','search', "prs", "--repo", "wasmerio/wasmer", "--merged"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + already_released_str = "" + for line in proc.stdout: + line = line.decode("utf-8").rstrip() + if RELEASE_VERSION + "\t" in line: + already_released_str = line + break + + already_released = already_released_str != "" + + proc = subprocess.Popen(['gh','pr', "list", "--repo", "wasmerio/wasmer"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + github_link_line = "" + for line in proc.stdout: + line = line.decode("utf-8").rstrip() + if "release-" + RELEASE_VERSION + "\t" in line: + github_link_line = line + break + + print("github link line" + github_link_line) + + if github_link_line != "": + proc = subprocess.Popen(['git','pull', "origin", "release-" + RELEASE_VERSION], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + proc = subprocess.Popen(['git','checkout', "-b", "release-" + RELEASE_VERSION], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + proc = subprocess.Popen(['git','pull', "origin", "release-" + RELEASE_VERSION], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + proc = subprocess.Popen(['git','log', "--oneline"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + for line in proc.stdout: + print(line.rstrip()) + + if github_link_line == "" and not(already_released): + + # git checkout -b release-3.0.0-rc.2 + proc = subprocess.Popen(['git','checkout', "-b", "release-" + RELEASE_VERSION], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + if proc.returncode != 0: + for line in proc.stdout: + print(line.rstrip()) + raise Exception("could not run git checkout -b release-" + RELEASE_VERSION) + + replace(temp_dir.name + "/CHANGELOG.md", "## **Unreleased**", "\r\n".join(changelog)) + + proc = subprocess.Popen(['git','commit', "-am", "Update CHANGELOG"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + if proc.returncode != 0: + for line in proc.stdout: + print(line.rstrip()) + raise Exception("could not commit CHANGELOG " + RELEASE_VERSION_WITH_V) + + # Update version numbers + update_version_py = get_file_string(temp_dir.name + "/scripts/update-version.py") + previous_version = re.search("NEXT_VERSION=\'(.*)\'", update_version_py).groups(1)[0] + next_version = RELEASE_VERSION + print("updating version " + previous_version + " -> " + next_version) + update_version_py = re.sub("PREVIOUS_VERSION=\'.*\'","PREVIOUS_VERSION='" + previous_version + "'", update_version_py) + update_version_py = re.sub("NEXT_VERSION=\'.*\'","NEXT_VERSION='" + next_version + "'", update_version_py) + write_file_string(temp_dir.name + "/scripts/update-version.py", update_version_py) + proc = subprocess.Popen(['python3', temp_dir.name + "/scripts/update-version.py"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + proc = subprocess.Popen(['git','commit', "-am", "Release " + RELEASE_VERSION], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + if proc.returncode != 0: + for line in proc.stdout: + print(line.rstrip()) + raise Exception("could not commit CHANGELOG " + RELEASE_VERSION_WITH_V) + + + proc = subprocess.Popen(['git','log', "--oneline"], stdout = subprocess.PIPE, cwd = temp_dir.name) + for line in proc.stdout: + line = line.decode("utf-8").rstrip() + print(line) + proc.wait() + + proc = subprocess.Popen(['git','push', "-f", "-u", "origin", "release-" + RELEASE_VERSION], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + proc = subprocess.Popen(['gh','pr', "create", "--head", "release-" + RELEASE_VERSION, "--title", "Release " + RELEASE_VERSION, "--body", "[bot] Release wasmer version " + RELEASE_VERSION, "--reviewer", SIGNOFF_REVIEWER], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + proc = subprocess.Popen(['gh','pr', "list", "--repo", "wasmerio/wasmer"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + for line in proc.stdout: + line = line.decode("utf-8").rstrip() + if "release-" + RELEASE_VERSION + "\t" in line: + github_link_line = line + break + + pr_number = "" + if (already_released): + pr_number = already_released_str.split("\t")[1] + print("already released in PR " + pr_number) + else: + pr_number = github_link_line.split("\t")[0] + print("releasing in PR " + pr_number) + + while not(already_released): + proc = subprocess.Popen(['gh','pr', "checks", pr_number], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + bors_failed = False + all_checks_have_passed = True + + if proc.stderr is not None: + for line in proc.stderr: + if "no checks reported" in line: + all_checks_have_passed = False + + if all_checks_have_passed: + for line in proc.stdout: + line = line.decode("utf-8").rstrip() + print("---- " + line) + if "no checks reported" in line: + all_checks_have_passed = False + if line.startswith("*"): + all_checks_have_passed = False + if "pending" in line and not("bors" in line): + all_checks_have_passed = False + if line.startswith("X"): + raise Exception("check failed") + if "fail" in line and "bors" in line: + bors_failed = True + if "pending" in line and "bors" in line: + bors_failed = True + if "fail" in line and not("bors" in line): + raise Exception("check failed") + + if all_checks_have_passed: + if proc.returncode != 0 and not(bors_failed): + raise Exception("failed to list checks with: gh pr checks " + pr_number) + break + else: + print("Waiting for checks to pass... PR " + pr_number + " https://github.com/wasmerio/wasmer/pull/" + pr_number) + time.sleep(30) + + if not(already_released): + # PR created, checks have passed, run python script and publish to crates.io + proc = subprocess.Popen(['gh','pr', "comment", pr_number, "--body", "[bot] Checks have passed. Publishing to crates.io..."], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + proc = subprocess.Popen(['python3',temp_dir.name + "/scripts/publish.py", "publish"], stdout = subprocess.PIPE, cwd = temp_dir.name) + while True: + line = proc.stdout.readline() + line = line.decode("utf-8").rstrip() + print(line.rstrip()) + if not line: break + + proc.wait() + + if proc.returncode != 0: + log = ["[bot] Failed to publish to crates.io"] + log.append("") + log.append("```") + for line in proc.stdout: + line = line.decode("utf-8").rstrip() + log.append("stdout: " + line) + log.append("```") + log.append("```") + if proc.stderr is not None: + for line in proc.stderr: + line = line.decode("utf-8").rstrip() + log.append("stderr: " + line) + log.append("```") + proc = subprocess.Popen(['gh','pr', "comment", pr_number, "--body", "\r\n".join(log)], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + raise Exception("Failed to publish to crates.io: " + "\r\n".join(log)) + else: + proc = subprocess.Popen(['gh','pr', "comment", pr_number, "--body", "[bot] Successfully published wasmer version " + RELEASE_VERSION + " to crates.io"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + last_commit = "" + proc = subprocess.Popen(['git','log'], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + if proc.returncode == 0: + for line in proc.stdout: + line = line.decode("utf-8").rstrip() + print(line.rstrip()) + last_commit = line + break + else: + raise Exception("could not git log branch " + RELEASE_VERSION_WITH_V) + + if last_commit == "": + raise Exception("could not get last info") + + proc = subprocess.Popen(['git','checkout', "master"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + if proc.returncode != 0: + for line in proc.stdout: + print(line.rstrip()) + raise Exception("could not commit checkout master " + RELEASE_VERSION_WITH_V) + + if not(already_released): + proc = subprocess.Popen(['gh','pr', "comment", pr_number, "--body", "bors r+"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + # wait for bors to merge PR + while not(already_released): + + print("git pull origin master...") + proc = subprocess.Popen(['git','pull', "origin", "master"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + if proc.returncode != 0: + for line in proc.stdout: + print(line.rstrip()) + raise Exception("could not pull origin ") + + proc = subprocess.Popen(['gh','search', "prs", "--repo", "wasmerio/wasmer", "--merged"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + github_link_line = "" + for line in proc.stdout: + line = line.decode("utf-8").rstrip() + if RELEASE_VERSION + "\t" in line: + github_link_line = line + break + + current_commit = "" + proc = subprocess.Popen(['git','log'], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + if proc.returncode == 0: + for line in proc.stdout: + line = line.decode("utf-8").rstrip() + print(line.rstrip()) + current_commit = line + break + else: + raise Exception("could not git log master") + + if current_commit == "": + raise Exception("could not get current info") + + if github_link_line != "": + print("ok: " + current_commit + " == " + last_commit) + print(github_link_line) + break + else: + time.sleep(20) + + # Select the correct merge commit to tag + correct_checkout = "" + proc = subprocess.Popen(['git','log', "--oneline"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + if proc.returncode == 0: + for line in proc.stdout: + line = line.decode("utf-8").rstrip() + if "Merge #" + pr_number in line: + correct_checkout = line + else: + raise Exception("could not git log branch " + RELEASE_VERSION_WITH_V) + + if correct_checkout == "": + raise Exception("could not get last info") + + print(correct_checkout) + checkout_hash = correct_checkout.split(" ")[0] + print("checking out hash " + checkout_hash) + + proc = subprocess.Popen(['git','tag', "-d", RELEASE_VERSION_WITH_V], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + proc = subprocess.Popen(['git','push', "-d", "origin", RELEASE_VERSION_WITH_V], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + proc = subprocess.Popen(['git','tag', RELEASE_VERSION_WITH_V, checkout_hash], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + proc = subprocess.Popen(['git','push', "-f", "origin", RELEASE_VERSION_WITH_V], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + # Make release and wait for it to finish + if not(already_released): + proc = subprocess.Popen(['gh','workflow', "run", "build.yml", "--field", "release=" + RELEASE_VERSION_WITH_V, "--ref", RELEASE_VERSION_WITH_V], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + time.sleep(5) + + while True: + # gh run list --workflow=build.yml + proc = subprocess.Popen(['gh','run', "list", "--workflow=build.yml"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + workflow_line = "" + if proc.returncode == 0: + for line in proc.stdout: + line = line.decode("utf-8").rstrip() + if RELEASE_VERSION_WITH_V in line: + workflow_line = line + break + + print("workflow line: " + workflow_line) + + if workflow_line.startswith("X"): + raise Exception("release workflow failed") + + proc = subprocess.Popen(['gh','release', "list"], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + release_line = "" + if proc.returncode == 0: + for line in proc.stdout: + line = line.decode("utf-8").rstrip() + if RELEASE_VERSION_WITH_V in line: + release_line = line + break + + if release_line != "": + break + else: + print("not released yet") + + time.sleep(30) + + # release done, update release + + release_notes = [ + "Install this version of wasmer:", + "", + "```sh", + "curl https://get.wasmer.io -sSfL | sh -s \"" + RELEASE_VERSION_WITH_V + "\"", + "```", + "", + ] + + if not(len(added) == 0) and not(len(changed) == 0): + release_notes.append("## What's Changed") + release_notes.append("") + + for a in added: + release_notes.append(a) + + for c in changed: + release_notes.append(c) + + hash = RELEASE_VERSION + "---" + DATE + hash = hash.replace(".", "") + hash = hash.replace("/", "") + + release_notes.append("") + release_notes.append("See full list of changes in the [CHANGELOG](https://github.com/wasmerio/wasmer/blob/master/CHANGELOG.md#" + hash + ")") + + proc = subprocess.Popen(['gh','release', "edit", RELEASE_VERSION_WITH_V, "--notes", "\r\n".join(release_notes)], stdout = subprocess.PIPE, cwd = temp_dir.name) + proc.wait() + + raise Exception("script done and merged") + +try: + make_release(RELEASE_VERSION) +except Exception as err: + while True: + print(str(err)) + if os.system("say " + str(err)) != 0: + sys.exit() \ No newline at end of file diff --git a/scripts/update-version.py b/scripts/update-version.py new file mode 100644 index 000000000..dcba7c62f --- /dev/null +++ b/scripts/update-version.py @@ -0,0 +1,51 @@ +#!/usr/bin/python + +PREVIOUS_VERSION='3.0.1' +NEXT_VERSION='3.0.2' + +import os +import re + +def replace(file, pattern, subst): + # Read contents from file as a single string + file_handle = open(file, 'r') + file_string = file_handle.read() + file_handle.close() + + # Use RE package to allow for replacement (also allowing for (multiline) REGEX) + file_string = (re.sub(pattern, subst, file_string)) + + # Write contents to file. + # Using mode 'w' truncates the file. + file_handle = open(file, 'w') + file_handle.write(file_string) + file_handle.close() + +def replace_version(path): + print(PREVIOUS_VERSION + " -> " + NEXT_VERSION + " (" + path + ")") + replace(path, "version = \"" + PREVIOUS_VERSION +"\"", "version = \"" + NEXT_VERSION +"\"") + replace(path, "version = \"=" + PREVIOUS_VERSION +"\"", "version = \"=" + NEXT_VERSION +"\"") + pass + +def replace_version_py(path): + print(PREVIOUS_VERSION + " -> " + NEXT_VERSION + " (" + path + ")") + replace(path, "target_version = \"" + PREVIOUS_VERSION +"\"", "target_version = \"" + NEXT_VERSION +"\"") + pass + +def replace_version_iss(path): + print(PREVIOUS_VERSION + " -> " + NEXT_VERSION + " (" + path + ")") + replace(path, "AppVersion=" + PREVIOUS_VERSION, "AppVersion=" + NEXT_VERSION) + pass + +for root, dirs, files in os.walk("."): + path = root.split(os.sep) + # print((len(path) - 1) * '---', os.path.basename(root)) + for file in files: + if "Cargo.toml" in file: + replace_version(root + "/" + file) + elif "wasmer.iss" in file: + replace_version_iss(root + "/" + file) + elif "publish.py" in file: + replace_version_py(root + "/" + file) + +os.system("cargo generate-lockfile") \ No newline at end of file diff --git a/scripts/update-version.sh b/scripts/update-version.sh deleted file mode 100755 index 0724b54d5..000000000 --- a/scripts/update-version.sh +++ /dev/null @@ -1,33 +0,0 @@ -#! /bin/sh - -# How to install `fd`: https://github.com/sharkdp/fd#installation -: "${FD:=fd}" - -# A script to update the version of all the crates at the same time -PREVIOUS_VERSION='3.0.0-rc.1' -NEXT_VERSION='3.0.0-rc.2' - -# quick hack -${FD} Cargo.toml --exec sed -i '{}' -e "s/version = \"$PREVIOUS_VERSION\"/version = \"$NEXT_VERSION\"/" -${FD} Cargo.toml --exec sed -i '{}' -e "s/version = \"=$PREVIOUS_VERSION\"/version = \"=$NEXT_VERSION\"/" -echo "manually check changes to Cargo.toml" - -${FD} wasmer.iss --exec sed -i '{}' -e "s/AppVersion=$PREVIOUS_VERSION/AppVersion=$NEXT_VERSION/" -echo "manually check changes to wasmer.iss" - -${FD} publish.py --exec sed -i '{}' -e "s/target_version = \"$PREVIOUS_VERSION\"/target_version = \"$NEXT_VERSION\"/" -echo "manually check changes to publish.py" - -# Re-generate lock files -cargo generate-lockfile - -# Order to upload packages in -## wasmer-types -## win-exception-handler -## compiler -## compiler-cranelift -## compiler-llvm -## compiler-singlepass -## emscripten -## wasi -## wasmer (api) diff --git a/scripts/windows-installer/wasmer.iss b/scripts/windows-installer/wasmer.iss index 93518ff1a..0c0286a80 100644 --- a/scripts/windows-installer/wasmer.iss +++ b/scripts/windows-installer/wasmer.iss @@ -1,6 +1,6 @@ [Setup] AppName=Wasmer -AppVersion=3.0.0-rc.2 +AppVersion=3.0.2 DefaultDirName={pf}\Wasmer DefaultGroupName=Wasmer Compression=lzma2 diff --git a/tests/compilers/config.rs b/tests/compilers/config.rs index 4a3e30d40..59f90b918 100644 --- a/tests/compilers/config.rs +++ b/tests/compilers/config.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use wasmer::{CompilerConfig, Features, ModuleMiddleware, Store}; use wasmer_compiler::Engine; -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum Compiler { LLVM, Cranelift, diff --git a/tests/compilers/traps.rs b/tests/compilers/traps.rs index 6bf18c27f..555b9a17f 100644 --- a/tests/compilers/traps.rs +++ b/tests/compilers/traps.rs @@ -34,8 +34,7 @@ fn test_trap_return(config: crate::Config) -> Result<()> { let e = run_func .call(&mut store, &[]) - .err() - .expect("error calling function"); + .expect_err("error calling function"); assert_eq!(e.message(), "test 123"); @@ -62,8 +61,7 @@ fn test_trap_trace(config: crate::Config) -> Result<()> { let e = run_func .call(&mut store, &[]) - .err() - .expect("error calling function"); + .expect_err("error calling function"); let trace = e.trace(); assert_eq!(trace.len(), 2); @@ -113,8 +111,7 @@ fn test_trap_trace_cb(config: crate::Config) -> Result<()> { let e = run_func .call(&mut store, &[]) - .err() - .expect("error calling function"); + .expect_err("error calling function"); let trace = e.trace(); println!("Trace {:?}", trace); @@ -148,8 +145,7 @@ fn test_trap_stack_overflow(config: crate::Config) -> Result<()> { let e = run_func .call(&mut store, &[]) - .err() - .expect("error calling function"); + .expect_err("error calling function"); // We specifically don't check the stack trace here: stack traces after // stack overflows are not generally possible due to unreliable unwinding @@ -181,8 +177,7 @@ fn trap_display_pretty(config: crate::Config) -> Result<()> { let e = run_func .call(&mut store, &[]) - .err() - .expect("error calling function"); + .expect_err("error calling function"); assert_eq!( e.to_string(), "\ @@ -236,8 +231,7 @@ fn trap_display_multi_module(config: crate::Config) -> Result<()> { let e = bar2 .call(&mut store, &[]) - .err() - .expect("error calling function"); + .expect_err("error calling function"); assert_eq!( e.to_string(), "\ @@ -262,7 +256,7 @@ fn trap_start_function_import(config: crate::Config) -> Result<()> { ) "#; - let module = Module::new(&store, binary)?; + let module = Module::new(&store, &binary)?; let sig = FunctionType::new(vec![], vec![]); let func = Function::new(&mut store, &sig, |_| Err(RuntimeError::new("user trap"))); let err = Instance::new( @@ -302,7 +296,7 @@ fn rust_panic_import(config: crate::Config) -> Result<()> { ) "#; - let module = Module::new(&store, binary)?; + let module = Module::new(&store, &binary)?; let sig = FunctionType::new(vec![], vec![]); let func = Function::new(&mut store, &sig, |_| panic!("this is a panic")); let f0 = Function::new_typed(&mut store, || panic!("this is another panic")); @@ -347,7 +341,7 @@ fn rust_panic_start_function(config: crate::Config) -> Result<()> { ) "#; - let module = Module::new(&store, binary)?; + let module = Module::new(&store, &binary)?; let sig = FunctionType::new(vec![], vec![]); let func = Function::new(&mut store, &sig, |_| panic!("this is a panic")); let err = panic::catch_unwind(AssertUnwindSafe(|| { @@ -393,7 +387,7 @@ fn mismatched_arguments(config: crate::Config) -> Result<()> { ) "#; - let module = Module::new(&store, binary)?; + let module = Module::new(&store, &binary)?; let instance = Instance::new(&mut store, &module, &imports! {})?; let func: &Function = instance.exports.get("foo")?; assert_eq!( @@ -434,8 +428,7 @@ fn call_signature_mismatch(config: crate::Config) -> Result<()> { let module = Module::new(&store, binary)?; let err = Instance::new(&mut store, &module, &imports! {}) - .err() - .expect("expected error"); + .expect_err("expected error"); assert_eq!( format!("{}", err), "\ @@ -461,9 +454,7 @@ fn start_trap_pretty(config: crate::Config) -> Result<()> { "#; let module = Module::new(&store, wat)?; - let err = Instance::new(&mut store, &module, &imports! {}) - .err() - .expect("expected error"); + let err = Instance::new(&mut store, &module, &imports! {}).expect_err("expected error"); assert_eq!( format!("{}", err), diff --git a/tests/compilers/typed_functions.rs b/tests/compilers/typed_functions.rs index e4b48af19..bdf40dd44 100644 --- a/tests/compilers/typed_functions.rs +++ b/tests/compilers/typed_functions.rs @@ -1,3 +1,5 @@ +#![allow(clippy::unnecessary_operation)] // We use x1 multiplies for clarity + use anyhow::Result; use std::convert::Infallible; use std::sync::{Arc, Mutex}; diff --git a/tests/compilers/wast.rs b/tests/compilers/wast.rs index 576e62e19..a27d24b56 100644 --- a/tests/compilers/wast.rs +++ b/tests/compilers/wast.rs @@ -22,12 +22,16 @@ pub fn run_wast(mut config: crate::Config, wast_path: &str) -> anyhow::Result<() let mut features = Features::default(); let is_bulkmemory = wast_path.contains("bulk-memory"); let is_simd = wast_path.contains("simd"); + let is_threads = wast_path.contains("threads"); if is_bulkmemory { features.bulk_memory(true); } if is_simd { features.simd(true); } + if is_threads { + features.threads(true); + } if config.compiler == crate::Compiler::Singlepass { features.multi_value(false); } @@ -53,6 +57,10 @@ pub fn run_wast(mut config: crate::Config, wast_path: &str) -> anyhow::Result<() "Validation error: Invalid var_u32", ]); } + if is_threads { + // We allow this, so tests can be run properly for `simd_const` test. + wast.allow_instantiation_failures(&["Validation error: multiple tables"]); + } if config.compiler == crate::Compiler::Singlepass { // We don't support multivalue yet in singlepass wast.allow_instantiation_failures(&[ diff --git a/tests/integration/cli/Cargo.toml b/tests/integration/cli/Cargo.toml index 71a71a1cf..1d1cd81cd 100644 --- a/tests/integration/cli/Cargo.toml +++ b/tests/integration/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-integration-tests-cli" -version = "3.0.0-rc.2" +version = "3.0.2" authors = ["Wasmer Engineering Team "] description = "CLI integration tests" repository = "https://github.com/wasmerio/wasmer" @@ -20,6 +20,7 @@ hex = "0.4.3" [dependencies] anyhow = "1" tempfile = "3" +target-lexicon = "0.12.5" [features] default = ["webc_runner"] diff --git a/tests/integration/cli/src/assets.rs b/tests/integration/cli/src/assets.rs index 53f15bd79..b341bbb69 100644 --- a/tests/integration/cli/src/assets.rs +++ b/tests/integration/cli/src/assets.rs @@ -63,21 +63,58 @@ pub fn get_wasmer_path() -> PathBuf { ret = PathBuf::from(format!("{}wasmer", WASMER_TARGET_PATH2)); } if !ret.exists() { - match get_repo_root_path() { + ret = match get_repo_root_path() { Some(s) => { #[cfg(target_os = "windows")] { - return s.join("target").join("release").join("wasmer.exe"); + s.join("target").join("release").join("wasmer.exe") } #[cfg(not(target_os = "windows"))] { - return s.join("target").join("release").join("wasmer"); + s.join("target").join("release").join("wasmer") } } None => { panic!("Could not find wasmer executable path! {:?}", ret); } + }; + } + + if !ret.exists() { + ret = match get_repo_root_path() { + Some(s) => { + #[cfg(target_os = "windows")] + { + s.join("target") + .join(target_lexicon::HOST.to_string()) + .join("release") + .join("wasmer.exe") + } + #[cfg(not(target_os = "windows"))] + { + s.join("target") + .join(target_lexicon::HOST.to_string()) + .join("release") + .join("wasmer") + } + } + None => { + panic!("Could not find wasmer executable path! {:?}", ret); + } + }; + } + + if !ret.exists() { + if let Some(root) = get_repo_root_path() { + use std::process::Stdio; + let _ = std::process::Command::new("ls") + .arg(root.join("target")) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .stdin(Stdio::null()) + .output(); } + panic!("cannot find wasmer / wasmer.exe for integration test!"); } ret } diff --git a/tests/integration/cli/tests/create_exe.rs b/tests/integration/cli/tests/create_exe.rs index 866bef6a5..45969f7c6 100644 --- a/tests/integration/cli/tests/create_exe.rs +++ b/tests/integration/cli/tests/create_exe.rs @@ -277,7 +277,7 @@ fn create_obj(args: Vec<&'static str>, keyword_needle: &str, keyword: &str) -> a let object_path = operating_dir.join("wasm.obj"); let output: Vec = WasmerCreateObj { - current_dir: operating_dir, + current_dir: operating_dir.clone(), wasm_path, output_object_path: object_path.clone(), compiler: Compiler::Cranelift, @@ -292,7 +292,7 @@ fn create_obj(args: Vec<&'static str>, keyword_needle: &str, keyword: &str) -> a "create-obj successfully completed but object output file `{}` missing", object_path.display() ); - let mut object_header_path = object_path; + let mut object_header_path = object_path.clone(); object_header_path.set_extension("h"); assert!( object_header_path.exists(), diff --git a/tests/integration/cli/tests/login.rs b/tests/integration/cli/tests/login.rs new file mode 100644 index 000000000..fdb1bea19 --- /dev/null +++ b/tests/integration/cli/tests/login.rs @@ -0,0 +1,48 @@ +use anyhow::bail; +use std::path::PathBuf; +use std::process::Command; +use wasmer_integration_tests_cli::{get_repo_root_path, get_wasmer_path, ASSET_PATH, C_ASSET_PATH}; + +#[test] +fn login_works() -> anyhow::Result<()> { + // running test locally: should always pass since + // developers don't have access to WAPM_DEV_TOKEN + if std::env::var("GITHUB_TOKEN").is_err() { + return Ok(()); + } + let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").expect("WAPM_DEV_TOKEN env var not set"); + let output = Command::new(get_wasmer_path()) + .arg("login") + .arg("--registry") + .arg("wapm.dev") + .arg(wapm_dev_token) + .output()?; + + let stdout = std::str::from_utf8(&output.stdout) + .expect("stdout is not utf8! need to handle arbitrary bytes"); + + let stderr = std::str::from_utf8(&output.stderr) + .expect("stderr is not utf8! need to handle arbitrary bytes"); + + if !output.status.success() { + bail!( + "wasmer login failed with: stdout: {}\n\nstderr: {}", + stdout, + stderr + ); + } + + let stdout_output = std::str::from_utf8(&output.stdout).unwrap(); + let expected = "Login for WAPM user \"ciuser\" saved\n"; + if stdout_output != expected { + println!("expected:"); + println!("{expected}"); + println!("got:"); + println!("{stdout}"); + println!("-----"); + println!("{stderr}"); + panic!("stdout incorrect"); + } + + Ok(()) +} diff --git a/tests/integration/cli/tests/run.rs b/tests/integration/cli/tests/run.rs index dafb0d3f9..8146e5578 100644 --- a/tests/integration/cli/tests/run.rs +++ b/tests/integration/cli/tests/run.rs @@ -1,24 +1,131 @@ //! Basic tests for the `run` subcommand -use anyhow::bail; -use std::path::PathBuf; +use anyhow::{bail, Context}; +use std::path::{Path, PathBuf}; use std::process::Command; use wasmer_integration_tests_cli::{get_repo_root_path, get_wasmer_path, ASSET_PATH, C_ASSET_PATH}; -fn wasi_test_python_path() -> String { - format!("{}/{}", C_ASSET_PATH, "python-0.1.0.wasmer") +fn wasi_test_python_path() -> PathBuf { + Path::new(C_ASSET_PATH).join("python-0.1.0.wasmer") } -fn wasi_test_wasm_path() -> String { - format!("{}/{}", C_ASSET_PATH, "qjs.wasm") +fn wasi_test_wasm_path() -> PathBuf { + Path::new(C_ASSET_PATH).join("qjs.wasm") } -fn test_no_imports_wat_path() -> String { - format!("{}/{}", ASSET_PATH, "fib.wat") +fn test_no_imports_wat_path() -> PathBuf { + Path::new(ASSET_PATH).join("fib.wat") } -fn test_no_start_wat_path() -> String { - format!("{}/{}", ASSET_PATH, "no_start.wat") +fn test_no_start_wat_path() -> PathBuf { + Path::new(ASSET_PATH).join("no_start.wat") +} + +#[cfg(any(target_os = "linux", target_os = "macos"))] +#[test] +fn test_cross_compile_python_windows() -> anyhow::Result<()> { + let temp_dir = tempfile::TempDir::new()?; + + let targets = &[ + "aarch64-darwin", + "x86_64-darwin", + "x86_64-linux-gnu", + "aarch64-linux-gnu", + "x86_64-windows-gnu", + ]; + + for t in targets { + let python_wasmer_path = temp_dir.path().join(format!("{t}-python")); + + let mut output = Command::new(get_wasmer_path()); + + output.arg("create-exe"); + output.arg(wasi_test_python_path()); + output.arg("--target"); + output.arg(t); + output.arg("-o"); + output.arg(python_wasmer_path.clone()); + let output = output.output()?; + + let stdout = std::str::from_utf8(&output.stdout) + .expect("stdout is not utf8! need to handle arbitrary bytes"); + + let stderr = std::str::from_utf8(&output.stderr) + .expect("stderr is not utf8! need to handle arbitrary bytes"); + + if !output.status.success() { + bail!("linking failed with: stdout: {stdout}\n\nstderr: {stderr}"); + } + + println!("stdout: {stdout}"); + println!("stderr: {stderr}"); + + if !python_wasmer_path.exists() { + let p = std::fs::read_dir(temp_dir.path()) + .unwrap() + .filter_map(|e| Some(e.ok()?.path())) + .collect::>(); + panic!( + "target {t} was not compiled correctly {stdout} {stderr}, tempdir: {:#?}", + p + ); + } + } + + Ok(()) +} + +#[test] +fn run_whoami_works() -> anyhow::Result<()> { + // running test locally: should always pass since + // developers don't have access to WAPM_DEV_TOKEN + if std::env::var("GITHUB_TOKEN").is_err() { + return Ok(()); + } + + let ciuser_token = std::env::var("WAPM_DEV_TOKEN").expect("no CIUSER / WAPM_DEV_TOKEN token"); + + let output = Command::new(get_wasmer_path()) + .arg("login") + .arg("--registry") + .arg("wapm.dev") + .arg(ciuser_token) + .output()?; + + if !output.status.success() { + bail!( + "wasmer login failed with: stdout: {}\n\nstderr: {}", + std::str::from_utf8(&output.stdout) + .expect("stdout is not utf8! need to handle arbitrary bytes"), + std::str::from_utf8(&output.stderr) + .expect("stderr is not utf8! need to handle arbitrary bytes") + ); + } + + let output = Command::new(get_wasmer_path()) + .arg("whoami") + .arg("--registry") + .arg("wapm.dev") + .output()?; + + let stdout = std::str::from_utf8(&output.stdout) + .expect("stdout is not utf8! need to handle arbitrary bytes"); + + if !output.status.success() { + bail!( + "linking failed with: stdout: {}\n\nstderr: {}", + stdout, + std::str::from_utf8(&output.stderr) + .expect("stderr is not utf8! need to handle arbitrary bytes") + ); + } + + assert_eq!( + stdout, + "logged into registry \"https://registry.wapm.dev/graphql\" as user \"ciuser\"\n" + ); + + Ok(()) } #[test] @@ -55,7 +162,9 @@ fn package_directory(in_dir: &PathBuf, out: &PathBuf) { let tar = File::create(out).unwrap(); let enc = GzEncoder::new(tar, Compression::none()); let mut a = tar::Builder::new(enc); - a.append_dir_all("", in_dir).unwrap(); + a.append_dir_all("bin", in_dir.join("bin")).unwrap(); + a.append_dir_all("lib", in_dir.join("lib")).unwrap(); + a.append_dir_all("include", in_dir.join("include")).unwrap(); a.finish().unwrap(); } @@ -73,75 +182,6 @@ fn test_wasmer_create_exe_pirita_works() -> anyhow::Result<()> { let native_target = target_lexicon::HOST; let root_path = get_repo_root_path().unwrap(); let package_path = root_path.join("package"); - if !package_path.exists() { - let current_dir = std::env::current_dir().unwrap(); - println!("running make && make build-capi && make package-capi && make package..."); - println!("current dir = {}", current_dir.display()); - println!("setting current dir = {}", root_path.display()); - // make && make build-capi && make package-capi && make package - let mut c1 = std::process::Command::new("make"); - c1.current_dir(&root_path); - let r = c1.output().unwrap(); - if !r.status.success() { - let stdout = String::from_utf8_lossy(&r.stdout); - let stderr = String::from_utf8_lossy(&r.stdout); - println!("make failed: (stdout = {stdout}, stderr = {stderr})"); - } - println!("make ok!"); - let mut c1 = std::process::Command::new("make"); - c1.arg("build-wasmer"); - c1.current_dir(&root_path); - let r = c1.output().unwrap(); - if !r.status.success() { - let stdout = String::from_utf8_lossy(&r.stdout); - let stderr = String::from_utf8_lossy(&r.stdout); - println!("make failed: (stdout = {stdout}, stderr = {stderr})"); - } - println!("make build-wasmer ok!"); - let mut c1 = std::process::Command::new("make"); - c1.arg("build-capi"); - c1.current_dir(&root_path); - let r = c1.output().unwrap(); - if !r.status.success() { - let stdout = String::from_utf8_lossy(&r.stdout); - let stderr = String::from_utf8_lossy(&r.stdout); - println!("make build-capi failed: (stdout = {stdout}, stderr = {stderr})"); - } - println!("make build-capi ok!"); - - let mut c1 = std::process::Command::new("make"); - c1.arg("build-wasmer"); - c1.current_dir(&root_path); - let r = c1.output().unwrap(); - if !r.status.success() { - let stdout = String::from_utf8_lossy(&r.stdout); - let stderr = String::from_utf8_lossy(&r.stdout); - println!("make build-wasmer failed: (stdout = {stdout}, stderr = {stderr})"); - } - println!("make build-wasmer ok!"); - - let mut c1 = std::process::Command::new("make"); - c1.arg("package-capi"); - c1.current_dir(&root_path); - let r = c1.output().unwrap(); - if !r.status.success() { - let stdout = String::from_utf8_lossy(&r.stdout); - let stderr = String::from_utf8_lossy(&r.stdout); - println!("make package-capi: (stdout = {stdout}, stderr = {stderr})"); - } - println!("make package-capi ok!"); - - let mut c1 = std::process::Command::new("make"); - c1.arg("package"); - c1.current_dir(&root_path); - let r = c1.output().unwrap(); - if !r.status.success() { - let stdout = String::from_utf8_lossy(&r.stdout); - let stderr = String::from_utf8_lossy(&r.stdout); - println!("make package failed: (stdout = {stdout}, stderr = {stderr})"); - } - println!("make package ok!"); - } if !package_path.exists() { panic!("package path {} does not exist", package_path.display()); } @@ -154,6 +194,11 @@ fn test_wasmer_create_exe_pirita_works() -> anyhow::Result<()> { ); package_directory(&package_path, &tmp_targz_path); println!("packaging done"); + println!( + "tmp tar gz path: {} - exists: {:?}", + tmp_targz_path.display(), + tmp_targz_path.exists() + ); let mut cmd = Command::new(get_wasmer_path()); cmd.arg("create-exe"); @@ -182,10 +227,24 @@ fn test_wasmer_create_exe_pirita_works() -> anyhow::Result<()> { ); } - let output = Command::new(&python_exe_output_path) - .arg("-c") - .arg("print(\"hello\")") - .output()?; + println!("compilation ok!"); + + if !python_exe_output_path.exists() { + return Err(anyhow::anyhow!( + "python_exe_output_path {} does not exist", + python_exe_output_path.display() + )); + } + + println!("invoking command..."); + + let mut command = Command::new(&python_exe_output_path); + command.arg("-c"); + command.arg("print(\"hello\")"); + + let output = command + .output() + .map_err(|e| anyhow::anyhow!("{e}: {command:?}"))?; let stdout = std::str::from_utf8(&output.stdout) .expect("stdout is not utf8! need to handle arbitrary bytes"); @@ -232,6 +291,32 @@ fn test_wasmer_run_pirita_works() -> anyhow::Result<()> { Ok(()) } +#[cfg(feature = "webc_runner")] +#[test] +fn test_wasmer_run_pirita_url_works() -> anyhow::Result<()> { + let output = Command::new(get_wasmer_path()) + .arg("run") + .arg("https://wapm.dev/syrusakbary/python") + .arg("--") + .arg("-c") + .arg("print(\"hello\")") + .output()?; + + let stdout = std::str::from_utf8(&output.stdout) + .expect("stdout is not utf8! need to handle arbitrary bytes"); + + if stdout != "hello\n" { + bail!( + "1 running python.wasmer failed with: stdout: {}\n\nstderr: {}", + stdout, + std::str::from_utf8(&output.stderr) + .expect("stderr is not utf8! need to handle arbitrary bytes") + ); + } + + Ok(()) +} + #[test] fn test_wasmer_run_works_with_dir() -> anyhow::Result<()> { let temp_dir = tempfile::TempDir::new()?; @@ -365,7 +450,7 @@ fn test_wasmer_run_works() -> anyhow::Result<()> { if stdout != "hello\n" { bail!( - "3 running python/python failed with: stdout: {}\n\nstderr: {}", + "4 running python/python failed with: stdout: {}\n\nstderr: {}", stdout, std::str::from_utf8(&output.stderr) .expect("stderr is not utf8! need to handle arbitrary bytes") @@ -457,3 +542,52 @@ fn run_no_start_wasm_report_error() -> anyhow::Result<()> { assert_eq!(result.contains("Can not find any export functions."), true); Ok(()) } + +// Test that wasmer can run a complex path +#[test] +fn test_wasmer_run_complex_url() -> anyhow::Result<()> { + let wasm_test_path = wasi_test_wasm_path(); + let wasm_test_path = wasm_test_path.canonicalize().unwrap_or(wasm_test_path); + let mut wasm_test_path = format!("{}", wasm_test_path.display()); + if wasm_test_path.starts_with(r#"\\?\"#) { + wasm_test_path = wasm_test_path.replacen(r#"\\?\"#, "", 1); + } + #[cfg(target_os = "windows")] + { + wasm_test_path = wasm_test_path.replace("D:\\", "D://"); + wasm_test_path = wasm_test_path.replace("C:\\", "C://"); + wasm_test_path = wasm_test_path.replace("c:\\", "c://"); + wasm_test_path = wasm_test_path.replace("\\", "/"); + // wasmer run used to fail on c:\Users\username\wapm_packages\ ... + assert!( + wasm_test_path.contains("://"), + "wasm_test_path path is not complex enough" + ); + } + + let mut cmd = Command::new(get_wasmer_path()); + cmd.arg("run"); + cmd.arg(wasm_test_path); + cmd.arg("--"); + cmd.arg("-q"); + + let cmd_str = format!("{cmd:?}"); + let output = cmd.output().with_context(|| { + anyhow::anyhow!( + "failed to run {cmd_str} with {}", + get_wasmer_path().display() + ) + })?; + + if !output.status.success() { + bail!( + "wasmer run qjs.wasm failed with: stdout: {}\n\nstderr: {}", + std::str::from_utf8(&output.stdout) + .expect("stdout is not utf8! need to handle arbitrary bytes"), + std::str::from_utf8(&output.stderr) + .expect("stderr is not utf8! need to handle arbitrary bytes") + ); + } + + Ok(()) +} diff --git a/tests/integration/ios/Cargo.toml b/tests/integration/ios/Cargo.toml index 2d3080413..3841cb519 100644 --- a/tests/integration/ios/Cargo.toml +++ b/tests/integration/ios/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-integration-tests-ios" -version = "3.0.0-rc.2" +version = "3.0.2" authors = ["Wasmer Engineering Team "] description = "iOS integration tests" repository = "https://github.com/wasmerio/wasmer" diff --git a/tests/integration/ios/tests/dylib.rs b/tests/integration/ios/tests/dylib.rs index db452fffb..7660a62e4 100644 --- a/tests/integration/ios/tests/dylib.rs +++ b/tests/integration/ios/tests/dylib.rs @@ -40,8 +40,9 @@ mod tests { */ let command_success = command.status.success(); let test_success = !stderr.contains("** TEST FAILED **"); + let success = command_success && test_success; - command_success && test_success + success } fn remove_existing_artificats() -> Output { diff --git a/tests/lib/wast/Cargo.toml b/tests/lib/wast/Cargo.toml index 55df4864d..019c94017 100644 --- a/tests/lib/wast/Cargo.toml +++ b/tests/lib/wast/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wast" -version = "3.0.0-rc.2" +version = "3.0.2" authors = ["Wasmer Engineering Team "] description = "wast testing support for wasmer" license = "MIT OR Apache-2.0 WITH LLVM-exception" @@ -12,9 +12,9 @@ edition = "2018" [dependencies] anyhow = "1.0" -wasmer = { path = "../../../lib/api", version = "=3.0.0-rc.2", default-features = false } -wasmer-wasi = { path = "../../../lib/wasi", version = "=3.0.0-rc.2", default_features = false } -wasmer-vfs = { path = "../../../lib/vfs", version = "=3.0.0-rc.2", default_features = false } +wasmer = { path = "../../../lib/api", version = "=3.0.2", default-features = false } +wasmer-wasi = { path = "../../../lib/wasi", version = "=3.0.2" } +wasmer-vfs = { path = "../../../lib/vfs", version = "=3.0.2" } wast = "38.0" serde = "1" tempfile = "3" diff --git a/tests/lib/wast/src/spectest.rs b/tests/lib/wast/src/spectest.rs index 9c2433ecd..b4d449384 100644 --- a/tests/lib/wast/src/spectest.rs +++ b/tests/lib/wast/src/spectest.rs @@ -28,6 +28,9 @@ pub fn spectest_importobject(store: &mut Store) -> Imports { let ty = MemoryType::new(1, Some(2), false); let memory = Memory::new(store, ty).unwrap(); + let ty = MemoryType::new(1, Some(2), true); + let shared_memory = Memory::new(store, ty).unwrap(); + imports! { "spectest" => { "print" => print, @@ -43,6 +46,7 @@ pub fn spectest_importobject(store: &mut Store) -> Imports { "global_f64" => global_f64, "table" => table, "memory" => memory, + "shared_memory" => shared_memory, }, } } diff --git a/tests/wasi-wast/Cargo.toml b/tests/wasi-wast/Cargo.toml index c8a27a0b1..349eba41d 100644 --- a/tests/wasi-wast/Cargo.toml +++ b/tests/wasi-wast/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasi-test-generator" -version = "3.0.0-rc.2" +version = "3.0.2" description = "Tests for our WASI implementation" license = "MIT" authors = ["Wasmer Engineering Team "] diff --git a/tests/wast/spec/proposals/threads/imports.wast b/tests/wast/spec/proposals/threads/imports.wast index 51dfbceaa..4567171c7 100644 --- a/tests/wast/spec/proposals/threads/imports.wast +++ b/tests/wast/spec/proposals/threads/imports.wast @@ -305,19 +305,19 @@ (assert_trap (invoke "call" (i32.const 3)) "uninitialized element") (assert_trap (invoke "call" (i32.const 100)) "undefined element") - -(assert_invalid - (module (import "" "" (table 10 funcref)) (import "" "" (table 10 funcref))) - "multiple tables" -) -(assert_invalid - (module (import "" "" (table 10 funcref)) (table 10 funcref)) - "multiple tables" -) -(assert_invalid - (module (table 10 funcref) (table 10 funcref)) - "multiple tables" -) +;; No multiple table yet. +;;(assert_invalid +;; (module (import "" "" (table 10 funcref)) (import "" "" (table 10 funcref))) +;; "multiple tables" +;;) +;;(assert_invalid +;; (module (import "" "" (table 10 funcref)) (table 10 funcref)) +;; "multiple tables" +;;) +;;(assert_invalid +;; (module (table 10 funcref) (table 10 funcref)) +;; "multiple tables" +;;) (module (import "test" "table-10-inf" (table 10 funcref))) (module (import "test" "table-10-inf" (table 5 funcref))) diff --git a/tests/wast/wasmer/README.md b/tests/wast/wasmer/README.md index 60c933dfb..17d398c6a 100644 --- a/tests/wast/wasmer/README.md +++ b/tests/wast/wasmer/README.md @@ -31,4 +31,8 @@ front, not once in each call. ## Divide by Zero: `divide.wast` -This is a simple test to check that a divide by zero is correctly trapped \ No newline at end of file +This is a simple test to check that a divide by zero is correctly trapped + +## Atomic Load: `atomic_load.wast` + +This is a simple test to check that load an atomic "to far" in memory trigger a OutOfBound trap diff --git a/tests/wast/wasmer/atomic_load.wast b/tests/wast/wasmer/atomic_load.wast new file mode 100755 index 000000000..932b39a1d --- /dev/null +++ b/tests/wast/wasmer/atomic_load.wast @@ -0,0 +1,9 @@ +(module + (memory 1) + (func (export "atomic_load") + i32.const 0xffff_fff0 + i32.atomic.load offset=16 + drop + ) +) +(assert_trap (invoke "atomic_load") "out of bound")