mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-05 02:20:19 +00:00
Merge branch 'master' into doc-runtime-c-api-exports-1
This commit is contained in:
commit
6403159b57
@ -18,24 +18,22 @@ environment:
|
||||
cache:
|
||||
- 'C:\Users\appveyor\.cargo'
|
||||
- target
|
||||
- wapm-cli-target
|
||||
|
||||
install:
|
||||
# # Install LLVM
|
||||
# - mkdir C:\projects\deps
|
||||
# - cd C:\projects\deps
|
||||
# - appveyor DownloadFile http://prereleases.llvm.org/win-snapshots/LLVM-7.0.0-r336178-win64.exe -FileName llvm.exe
|
||||
# - 7z x llvm.exe -oC:\projects\deps\llvm
|
||||
# # - set "PATH=%PATH%;C:\projects\deps\llvm\bin"
|
||||
# - set "LLD_LINK=C:\projects\deps\llvm\bin\lld-link.exe"
|
||||
# - set "LLVM_SYS_70_PREFIX=C:\projects\deps\llvm"
|
||||
# - cd "%APPVEYOR_BUILD_FOLDER%"
|
||||
# Install LLVM
|
||||
- mkdir C:\projects\deps
|
||||
- cd C:\projects\deps
|
||||
- appveyor DownloadFile https://github.com/wasmerio/windows-llvm-build/releases/download/v8.0.0/llvm-8.0.0-install.zip -FileName llvm-8.0.0-install.zip
|
||||
- 7z x llvm-8.0.0-install.zip
|
||||
- C:\projects\deps\llvm-8.0.0-install\bin\llvm-config.exe --version
|
||||
- set "LLVM_SYS_80_PREFIX=C:\projects\deps\llvm-8.0.0-install"
|
||||
- cd "%APPVEYOR_BUILD_FOLDER%"
|
||||
|
||||
# Install Rust
|
||||
# uncomment these lines if the cache is cleared, or if we must re-install rust for some reason
|
||||
# - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
||||
# - rustup-init.exe -yv --default-host %target%
|
||||
- set PATH=%PATH%;C:\\Libraries\\llvm-5.0.0\\bin;%USERPROFILE%\.cargo\bin
|
||||
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
||||
- rustup-init.exe -yv --default-host %target%
|
||||
- set PATH=%PATH%;%USERPROFILE%\.cargo\bin
|
||||
- rustup default stable-%target%
|
||||
- rustup update
|
||||
- rustc -vV
|
||||
@ -49,25 +47,17 @@ install:
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
|
||||
build_script:
|
||||
- cargo build --release --verbose
|
||||
- git submodule init
|
||||
- git submodule update
|
||||
# Cache wapm cli target in dir above to prevent breaking git submodule on windows
|
||||
- if not exist wapm-cli-target mkdir wapm-cli-target
|
||||
- move wapm-cli-target wapm-cli
|
||||
- cd wapm-cli
|
||||
- rename wapm-cli-target target
|
||||
- cd ..
|
||||
- cargo build --release --manifest-path wapm-cli/Cargo.toml --features telemetry
|
||||
- cd wapm-cli
|
||||
- cd ..
|
||||
- xcopy wapm-cli\target wapm-cli-target\ /i /y
|
||||
- cargo build --release --verbose --features backend-llvm
|
||||
- cargo build --release --manifest-path lib/runtime-c-api/Cargo.toml
|
||||
|
||||
test_script:
|
||||
- cargo test --manifest-path lib/spectests/Cargo.toml --features clif
|
||||
- cargo test --manifest-path lib/spectests/Cargo.toml --release --features clif -- --nocapture
|
||||
|
||||
before_deploy:
|
||||
- appveyor PushArtifact target\release\wasmer_runtime_c_api.dll
|
||||
- git submodule init
|
||||
- git submodule update
|
||||
- cargo build --release --manifest-path wapm-cli/Cargo.toml --features "telemetry update-notifications"
|
||||
- cd ./src/installer
|
||||
- iscc wasmer.iss
|
||||
- copy /y .\WasmerInstaller.exe ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
||||
|
@ -1,14 +1,14 @@
|
||||
run_with_build_env_vars: &run_with_build_env_vars
|
||||
environment:
|
||||
LLVM_SYS_70_PREFIX: /home/circleci/project/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/
|
||||
LLVM_SYS_80_PREFIX: /home/circleci/project/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/
|
||||
|
||||
run_install_dependencies: &run_install_dependencies
|
||||
run:
|
||||
name: install dependencies
|
||||
command: |
|
||||
sudo apt-get install -y cmake
|
||||
curl -O https://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||
tar xf clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||
curl -O https://releases.llvm.org/8.0.0/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||
tar xf clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||
|
||||
version: 2
|
||||
jobs:
|
||||
@ -75,9 +75,6 @@ jobs:
|
||||
make cranelift
|
||||
make llvm
|
||||
make test-rest
|
||||
- run:
|
||||
name: Release
|
||||
command: make release-fast
|
||||
- run:
|
||||
name: Integration Tests
|
||||
command: make integration-tests
|
||||
@ -115,9 +112,9 @@ jobs:
|
||||
name: Check
|
||||
command: |
|
||||
make check
|
||||
- run:
|
||||
name: Release
|
||||
command: make release-fast
|
||||
make compile-bench-singlepass
|
||||
make compile-bench-llvm
|
||||
# TODO: add compile-bench-clif when it works
|
||||
- run:
|
||||
name: Integration Tests
|
||||
command: make integration-tests
|
||||
@ -129,6 +126,26 @@ jobs:
|
||||
- target/release/deps
|
||||
key: v8-test-cargo-cache-linux-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
|
||||
test-rust-example:
|
||||
docker:
|
||||
- image: circleci/rust:latest
|
||||
<<: *run_with_build_env_vars
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Check Wasmer Rust example"
|
||||
command: |
|
||||
git clone https://github.com/wasmerio/wasmer-rust-example
|
||||
rustup default stable
|
||||
rustup target add wasm32-unknown-unknown
|
||||
cd wasmer-rust-example
|
||||
cd wasm-sample-app
|
||||
cargo build --release
|
||||
cd ..
|
||||
sed -i 's/wasmer-runtime.*/wasmer-runtime = \{ path = "..\/lib\/runtime" \}/g' Cargo.toml
|
||||
cargo run
|
||||
cargo test
|
||||
|
||||
test-macos:
|
||||
macos:
|
||||
xcode: "9.0"
|
||||
@ -149,8 +166,8 @@ jobs:
|
||||
tar xf cmake-3.4.1-Darwin-x86_64.tar.gz
|
||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||
# Installing LLVM outside of brew
|
||||
curl -O https://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz
|
||||
tar xf clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz
|
||||
curl -O https://releases.llvm.org/8.0.0/clang+llvm-8.0.0-x86_64-apple-darwin.tar.xz
|
||||
tar xf clang+llvm-8.0.0-x86_64-apple-darwin.tar.xz
|
||||
- run:
|
||||
name: Install Rust
|
||||
command: |
|
||||
@ -162,7 +179,7 @@ jobs:
|
||||
command: |
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/"
|
||||
export LLVM_SYS_80_PREFIX="`pwd`/clang+llvm-8.0.0-x86_64-apple-darwin/"
|
||||
# We increase the ulimit for fixing cargo unclosed files in mac
|
||||
ulimit -n 8000
|
||||
sudo sysctl -w kern.maxfiles=655360 kern.maxfilesperproc=327680
|
||||
@ -171,18 +188,14 @@ jobs:
|
||||
name: Check
|
||||
command: |
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
export LLVM_SYS_80_PREFIX="`pwd`/clang+llvm-8.0.0-x86_64-apple-darwin/"
|
||||
make check
|
||||
- run:
|
||||
name: Release
|
||||
command: |
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
make release-fast
|
||||
- run:
|
||||
name: Integration Tests
|
||||
command: |
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/"
|
||||
export LLVM_SYS_80_PREFIX="`pwd`/clang+llvm-8.0.0-x86_64-apple-darwin/"
|
||||
make integration-tests
|
||||
- save_cache:
|
||||
paths:
|
||||
@ -213,27 +226,27 @@ jobs:
|
||||
name: Install dependencies
|
||||
command: |
|
||||
sudo apt-get install -y cmake
|
||||
curl -O https://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||
tar xf clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||
curl -O https://releases.llvm.org/8.0.0/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||
tar xf clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||
- run: rustup default nightly-2019-06-10
|
||||
- run:
|
||||
name: Tests
|
||||
command: |
|
||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||
export LLVM_SYS_80_PREFIX="`pwd`/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||
make test
|
||||
- run:
|
||||
name: Release Build
|
||||
command: |
|
||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||
export LLVM_SYS_80_PREFIX="`pwd`/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||
make release
|
||||
cargo build --release --manifest-path wapm-cli/Cargo.toml --features telemetry
|
||||
cargo build --release --manifest-path wapm-cli/Cargo.toml --features "telemetry update-notifications"
|
||||
mkdir -p artifacts
|
||||
VERSION=$(cargo pkgid | cut -d# -f2 | cut -d: -f2)
|
||||
# GIT_VERSION=$(git describe --exact-match --tags)
|
||||
echo "${VERSION}" >> artifacts/version
|
||||
echo "${CIRCLE_TAG}" >> artifacts/git_version
|
||||
make build-install
|
||||
cp ./wasmer.tar.gz ./artifacts/$(./binary-name.sh)
|
||||
cp ./wasmer.tar.gz ./artifacts/$(./scripts/binary-name.sh)
|
||||
- run:
|
||||
name: Dynamic library
|
||||
command: |
|
||||
@ -275,8 +288,8 @@ jobs:
|
||||
tar xf cmake-3.4.1-Darwin-x86_64.tar.gz
|
||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||
# Installing LLVM outside of brew
|
||||
curl -O https://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz
|
||||
tar xf clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz
|
||||
curl -O https://releases.llvm.org/8.0.0/clang+llvm-8.0.0-x86_64-apple-darwin.tar.xz
|
||||
tar xf clang+llvm-8.0.0-x86_64-apple-darwin.tar.xz
|
||||
- run:
|
||||
name: Install Rust
|
||||
command: |
|
||||
@ -288,7 +301,7 @@ jobs:
|
||||
command: |
|
||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/"
|
||||
export LLVM_SYS_80_PREFIX="`pwd`/clang+llvm-8.0.0-x86_64-apple-darwin/"
|
||||
# We increase the ulimit for fixing cargo unclosed files in mac
|
||||
ulimit -n 8000
|
||||
sudo sysctl -w kern.maxfiles=655360 kern.maxfilesperproc=327680
|
||||
@ -299,12 +312,12 @@ jobs:
|
||||
command: |
|
||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/"
|
||||
export LLVM_SYS_80_PREFIX="`pwd`/clang+llvm-8.0.0-x86_64-apple-darwin/"
|
||||
make release
|
||||
cargo build --release --manifest-path wapm-cli/Cargo.toml --features telemetry
|
||||
cargo build --release --manifest-path wapm-cli/Cargo.toml --features "telemetry update-notifications"
|
||||
mkdir -p artifacts
|
||||
make build-install
|
||||
cp ./wasmer.tar.gz ./artifacts/$(./binary-name.sh)
|
||||
cp ./wasmer.tar.gz ./artifacts/$(./scripts/binary-name.sh)
|
||||
# VERSION=$(cargo pkgid | cut -d# -f2 | cut -d: -f2)
|
||||
# echo "${VERSION}" >> artifacts/version
|
||||
- run:
|
||||
@ -344,6 +357,8 @@ jobs:
|
||||
VERSION=$(cat ./artifacts/version)
|
||||
# VERSION_TAG=${CIRCLE_TAG}
|
||||
VERSION_TAG=$(cat ./artifacts/git_version)
|
||||
LATEST_VERSION_PUBLISHED_ON_CRATES=$(curl -s https://raw.githubusercontent.com/rust-lang/crates.io-index/master/wa/sm/wasmer-runtime | tail -n 1 | sed 's/.*"vers":"\([^"]*\)".*/\1/')
|
||||
if ( [ $VERSION_TAG -ne $LATEST_VERSION_PUBLISHED_ON_CRATES ] ) then { echo "Could not detect version published to crates.io; make sure we've published the crates before publishing the Wasmer binary"; exit 1; } else { true; } fi
|
||||
rm ./artifacts/version
|
||||
rm ./artifacts/git_version
|
||||
# VERSION_TAG=$(git describe --exact-match --tags)
|
||||
@ -382,6 +397,12 @@ workflows:
|
||||
only:
|
||||
- trying
|
||||
- staging
|
||||
- test-rust-example:
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- trying
|
||||
- staging
|
||||
- test-macos:
|
||||
filters:
|
||||
branches:
|
||||
|
39
.github/CODEOWNERS
vendored
Normal file
39
.github/CODEOWNERS
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
#
|
||||
src/ @syrusakbary @MarkMcCaskey
|
||||
|
||||
# Backends
|
||||
lib/singlepass-backend @losfair @nlewycky
|
||||
lib/clif-backend @nlewycky @bjfish
|
||||
lib/llvm-backend @nlewycky @losfair
|
||||
|
||||
# Runtime
|
||||
lib/runtime-core @Hywan @bjfish
|
||||
lib/runtime-abi @MarkMcCaskey
|
||||
lib/runtime @MarkMcCaskey @Hywan @bjfish
|
||||
lib/runtime-c-api @bjfish @Hywan
|
||||
lib/win-exception-handler @bjfish @losfair
|
||||
lib/middleware-common @bjfish @losfair
|
||||
|
||||
# Frontend integrations
|
||||
|
||||
## Emscripten
|
||||
lib/emscripten @MarkMcCaskey @syrusakbary
|
||||
lib/emscripten-tests @MarkMcCaskey @syrusakbary
|
||||
|
||||
## WASI
|
||||
lib/wasi @MarkMcCaskey
|
||||
lib/wasi-tests @MarkMcCaskey
|
||||
|
||||
## Spectests
|
||||
lib/spectests @syrusakbary @MarkMcCaskey @nlewycky
|
||||
|
||||
# Kernel
|
||||
lib/kernel-loader @losfair
|
||||
lib/kernel-net @losfair
|
||||
|
||||
# Examples
|
||||
examples @syrusakbary
|
||||
|
||||
# Documentation
|
||||
docs @syrusakbary
|
||||
|
46
CHANGELOG.md
46
CHANGELOG.md
@ -6,26 +6,64 @@ Blocks of changes will separated by version increments.
|
||||
|
||||
## **[Unreleased]**
|
||||
|
||||
## 0.5.6
|
||||
Special thanks to @YaronWittenstein @penberg for their contributions.
|
||||
|
||||
- [#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
|
||||
|
||||
## 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
|
||||
## 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
|
||||
## 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`
|
||||
|
33
CONTRIBUTING.md
Normal file
33
CONTRIBUTING.md
Normal file
@ -0,0 +1,33 @@
|
||||
# How to Contribute to Wasmer
|
||||
|
||||
Thank you for your interest in contributing to Wasmer. This document outlines some recommendations on how to contribute.
|
||||
|
||||
## Issues & Feature Requests
|
||||
Please use the issue template and provide a failing example if possible to help us recreate the issue.
|
||||
|
||||
## Pull Requests
|
||||
For large changes, please try reaching the Wasmer using Github Issues or Spectrum Chat to ensure we can accept the change once it is ready.
|
||||
|
||||
We recommend trying the following commands before sending a pull request to ensure code quality:
|
||||
- `cargo fmt --all` Ensures all code is correctly formatted.
|
||||
- Run `cargo test` in the crates that you are modifying.
|
||||
- Run `cargo build --all` (nightly) or `cargo build --all --exclude wasmer-singlepass-backend`
|
||||
|
||||
A comprehensive CI test suite will be run by a Wasmer team member after the PR has been created.
|
||||
|
||||
### Common Build Issues
|
||||
|
||||
**LLVM Dependency**
|
||||
|
||||
The LLVM backend requires LLVM to be installed to compile.
|
||||
|
||||
So, you may run into the following error:
|
||||
```
|
||||
Didn't find usable system-wide LLVM.
|
||||
No suitable version of LLVM was found system-wide or pointed
|
||||
```
|
||||
|
||||
**Singlepass Nightly Only**
|
||||
|
||||
The singlepass crate depends on nightly so you may need to add the `+nightly` cargo flag to compile this crate.
|
||||
`error[E0554]: #![feature] may not be used on the stable release channel`
|
1153
Cargo.lock
generated
1153
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
34
Cargo.toml
34
Cargo.toml
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer"
|
||||
version = "0.5.6"
|
||||
version = "0.6.0"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
edition = "2018"
|
||||
repository = "https://github.com/wasmerio/wasmer"
|
||||
@ -19,11 +19,10 @@ include = [
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.3.1"
|
||||
byteorder = "1.3.2"
|
||||
errno = "0.2.4"
|
||||
structopt = "0.2.11"
|
||||
wabt = "0.7.2"
|
||||
hashbrown = "0.1.8"
|
||||
structopt = "0.2.18"
|
||||
wabt = "0.9.1"
|
||||
wasmer-clif-backend = { path = "lib/clif-backend" }
|
||||
wasmer-singlepass-backend = { path = "lib/singlepass-backend", optional = true }
|
||||
wasmer-middleware-common = { path = "lib/middleware-common" }
|
||||
@ -61,20 +60,35 @@ members = [
|
||||
]
|
||||
|
||||
[build-dependencies]
|
||||
wabt = "0.7.2"
|
||||
glob = "0.2.11"
|
||||
wabt = "0.9.1"
|
||||
glob = "0.3.0"
|
||||
rustc_version = "0.2.3"
|
||||
|
||||
[features]
|
||||
default = ["fast-tests", "wasi"]
|
||||
default = ["fast-tests", "wasi", "backend-cranelift"]
|
||||
"loader-kernel" = ["wasmer-kernel-loader"]
|
||||
debug = ["wasmer-runtime-core/debug"]
|
||||
trace = ["wasmer-runtime-core/trace"]
|
||||
extra-debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
||||
# This feature will allow cargo test to run much faster
|
||||
fast-tests = []
|
||||
"backend-llvm" = ["wasmer-llvm-backend", "wasmer-runtime-core/backend-llvm"]
|
||||
"backend-singlepass" = ["wasmer-singlepass-backend", "wasmer-runtime-core/backend-singlepass"]
|
||||
backend-cranelift = [
|
||||
"wasmer-runtime-core/backend-cranelift",
|
||||
"wasmer-runtime/cranelift",
|
||||
"wasmer-middleware-common/clif"
|
||||
]
|
||||
backend-llvm = [
|
||||
"wasmer-llvm-backend",
|
||||
"wasmer-runtime-core/backend-llvm",
|
||||
"wasmer-runtime/llvm",
|
||||
"wasmer-middleware-common/llvm"
|
||||
]
|
||||
backend-singlepass = [
|
||||
"wasmer-singlepass-backend",
|
||||
"wasmer-runtime-core/backend-singlepass",
|
||||
"wasmer-runtime/singlepass",
|
||||
"wasmer-middleware-common/singlepass"
|
||||
]
|
||||
wasi = ["wasmer-wasi"]
|
||||
# vfs = ["wasmer-runtime-abi"]
|
||||
|
||||
|
@ -3,9 +3,9 @@ RUN sudo apt-get update && \
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
cmake \
|
||||
&& sudo rm -rf /var/lib/apt/lists/*
|
||||
RUN curl -SL https://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz \
|
||||
RUN curl -SL https://releases.llvm.org/8.0.0/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz \
|
||||
| tar -xJC /home/circleci
|
||||
ENV LLVM_SYS_70_PREFIX /home/circleci/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/
|
||||
ENV LLVM_SYS_80_PREFIX /home/circleci/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/
|
||||
|
||||
FROM wasmer-build-env AS wasmer-debug-env
|
||||
RUN sudo apt-get update && \
|
||||
|
13
Dockerfile.build
Normal file
13
Dockerfile.build
Normal file
@ -0,0 +1,13 @@
|
||||
FROM ubuntu:19.04
|
||||
|
||||
ARG RUST_TOOLCHAIN="nightly"
|
||||
|
||||
ENV CARGO_HOME=/usr/local/rust
|
||||
ENV RUSTUP_HOME=/usr/local/rust
|
||||
ENV PATH="$PATH:$CARGO_HOME/bin"
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get -y install sudo strace curl cmake pkg-config python libssl-dev llvm-dev libz-dev gnuplot-nox \
|
||||
&& echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \
|
||||
&& echo '%wheel ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \
|
||||
&& curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN"
|
48
Makefile
48
Makefile
@ -7,21 +7,27 @@ generate-spectests:
|
||||
generate-emtests:
|
||||
WASM_EMSCRIPTEN_GENERATE_EMTESTS=1 cargo build -p wasmer-emscripten-tests --release
|
||||
|
||||
generate-wasitests:
|
||||
WASM_WASI_GENERATE_WASITESTS=1 cargo build -p wasmer-wasi-tests --release -vv
|
||||
generate-wasitests: wasitests-setup
|
||||
WASM_WASI_GENERATE_WASITESTS=1 cargo build -p wasmer-wasi-tests --release -vv \
|
||||
&& echo "formatting" \
|
||||
&& cargo fmt
|
||||
|
||||
spectests-generate: generate-spectests
|
||||
emtests-generate: generate-emtests
|
||||
wasitests-generate: generate-wasitests
|
||||
|
||||
generate: generate-spectests generate-emtests generate-wasitests
|
||||
|
||||
|
||||
# Spectests
|
||||
spectests-singlepass:
|
||||
cargo test --manifest-path lib/spectests/Cargo.toml --release --features singlepass
|
||||
cargo test --manifest-path lib/spectests/Cargo.toml --release --features singlepass -- --nocapture
|
||||
|
||||
spectests-cranelift:
|
||||
cargo test --manifest-path lib/spectests/Cargo.toml --release --features clif
|
||||
cargo test --manifest-path lib/spectests/Cargo.toml --release --features clif -- --nocapture
|
||||
|
||||
spectests-llvm:
|
||||
cargo test --manifest-path lib/spectests/Cargo.toml --release --features llvm
|
||||
cargo test --manifest-path lib/spectests/Cargo.toml --release --features llvm -- --nocapture
|
||||
|
||||
spectests: spectests-singlepass spectests-cranelift spectests-llvm
|
||||
|
||||
@ -56,13 +62,17 @@ middleware: middleware-singlepass middleware-cranelift middleware-llvm
|
||||
|
||||
|
||||
# Wasitests
|
||||
wasitests-singlepass:
|
||||
wasitests-setup:
|
||||
rm -rf lib/wasi-tests/wasitests/test_fs/temp
|
||||
mkdir -p lib/wasi-tests/wasitests/test_fs/temp
|
||||
|
||||
wasitests-singlepass: wasitests-setup
|
||||
cargo test --manifest-path lib/wasi-tests/Cargo.toml --release --features singlepass -- --test-threads=1
|
||||
|
||||
wasitests-cranelift:
|
||||
wasitests-cranelift: wasitests-setup
|
||||
cargo test --manifest-path lib/wasi-tests/Cargo.toml --release --features clif -- --test-threads=1
|
||||
|
||||
wasitests-llvm:
|
||||
wasitests-llvm: wasitests-setup
|
||||
cargo test --manifest-path lib/wasi-tests/Cargo.toml --release --features llvm -- --test-threads=1
|
||||
|
||||
wasitests-unit:
|
||||
@ -78,7 +88,7 @@ singlepass: spectests-singlepass emtests-singlepass middleware-singlepass wasite
|
||||
cranelift: spectests-cranelift emtests-cranelift middleware-cranelift wasitests-cranelift
|
||||
cargo test -p wasmer-clif-backend --release
|
||||
|
||||
llvm: spectests-llvm emtests-llvm middleware-llvm wasitests-llvm
|
||||
llvm: spectests-llvm emtests-llvm wasitests-llvm
|
||||
cargo test -p wasmer-llvm-backend --release
|
||||
|
||||
|
||||
@ -98,7 +108,7 @@ test: spectests emtests middleware wasitests circleci-clean test-rest
|
||||
|
||||
|
||||
# Integration tests
|
||||
integration-tests: release-fast
|
||||
integration-tests: release-clif
|
||||
echo "Running Integration Tests"
|
||||
./integration_tests/lua/test.sh
|
||||
./integration_tests/nginx/test.sh
|
||||
@ -124,7 +134,7 @@ release:
|
||||
cargo build --release --features backend-singlepass,backend-llvm,loader-kernel
|
||||
|
||||
# Only one backend (cranelift)
|
||||
release-fast:
|
||||
release-clif:
|
||||
# If you are in OS-X, you will need mingw-w64 for cross compiling to windows
|
||||
# brew install mingw-w64
|
||||
cargo build --release
|
||||
@ -135,8 +145,20 @@ release-singlepass:
|
||||
release-llvm:
|
||||
cargo build --release --features backend-llvm
|
||||
|
||||
bench:
|
||||
cargo bench --all
|
||||
bench-singlepass:
|
||||
cargo bench --all --no-default-features --features "backend-singlepass"
|
||||
bench-clif:
|
||||
cargo bench --all --no-default-features --features "backend-cranelift"
|
||||
bench-llvm:
|
||||
cargo bench --all --no-default-features --features "backend-llvm"
|
||||
|
||||
# compile but don't run the benchmarks
|
||||
compile-bench-singlepass:
|
||||
cargo bench --all --no-run --no-default-features --features "backend-singlepass"
|
||||
compile-bench-clif:
|
||||
cargo bench --all --no-run --no-default-features --features "backend-cranelift"
|
||||
compile-bench-llvm:
|
||||
cargo bench --all --no-run --no-default-features --features "backend-llvm"
|
||||
|
||||
|
||||
# Build utils
|
||||
|
83
README.md
83
README.md
@ -1,6 +1,6 @@
|
||||
<p align="center">
|
||||
<a href="https://wasmer.io" target="_blank" rel="noopener noreferrer">
|
||||
<img width="400" src="https://raw.githubusercontent.com/wasmerio/wasmer/master/logo.png" alt="Wasmer logo">
|
||||
<img width="300" src="https://raw.githubusercontent.com/wasmerio/wasmer/master/logo.png" alt="Wasmer logo">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@ -14,6 +14,9 @@
|
||||
<a href="https://spectrum.chat/wasmer">
|
||||
<img src="https://withspectrum.github.io/badge/badge.svg" alt="Join the Wasmer Community">
|
||||
</a>
|
||||
<a href="https://twitter.com/wasmerio">
|
||||
<img alt="Follow @wasmerio on Twitter" src="https://img.shields.io/twitter/follow/wasmerio?label=%40wasmerio&style=social">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Introduction
|
||||
@ -26,10 +29,13 @@ Install Wasmer with:
|
||||
curl https://get.wasmer.io -sSfL | sh
|
||||
```
|
||||
|
||||
> Note: *Wasmer is also available on Windows. Download the [`WasmerInstaller.exe` from the Github Releases](https://github.com/wasmerio/wasmer/releases) page.*
|
||||
|
||||
Wasmer runtime can also be embedded in different languages, so you can use WebAssembly anywhere ✨:
|
||||
|
||||
* [🦀 **Rust**](https://github.com/wasmerio/wasmer-rust-example)
|
||||
* [**C/C++**](https://github.com/wasmerio/wasmer-c-api)
|
||||
* [**🦀 Rust**](https://github.com/wasmerio/wasmer-rust-example)
|
||||
* [**🔗 C/C++**](https://github.com/wasmerio/wasmer-c-api)
|
||||
* [**#️⃣ C#**](https://github.com/migueldeicaza/WasmerSharp)
|
||||
* [**🐘 PHP**](https://github.com/wasmerio/php-ext-wasm)
|
||||
* [**🐍 Python**](https://github.com/wasmerio/python-ext-wasm)
|
||||
* [**💎 Ruby**](https://github.com/wasmerio/ruby-ext-wasm)
|
||||
@ -45,21 +51,14 @@ Once installed, you will be able to run any WebAssembly files (_including Lua, P
|
||||
```sh
|
||||
# Run Lua
|
||||
wasmer run examples/lua.wasm
|
||||
|
||||
# Run PHP
|
||||
wasmer run examples/php.wasm
|
||||
|
||||
# Run SQLite
|
||||
wasmer run examples/sqlite.wasm
|
||||
|
||||
# Run nginx
|
||||
wasmer run examples/nginx/nginx.wasm -- -p examples/nginx -c nginx.conf
|
||||
```
|
||||
|
||||
*You can find more `wasm/wat` examples in the [examples](./examples) directory.*
|
||||
|
||||
#### With WAPM
|
||||
|
||||
Installing Wasmer through `wasmer.io` includes
|
||||
[wapm](https://github.com/wasmerio/wapm-cli), the WebAssembly package manager.
|
||||
[`wapm`](https://github.com/wasmerio/wapm-cli), the [WebAssembly Package Manager](https://wapm.io/).
|
||||
|
||||
Wapm allows you to easily download, run, and distribute WebAssembly binaries.
|
||||
|
||||
@ -86,7 +85,7 @@ Wasmer is structured into different directories:
|
||||
|
||||
Building Wasmer requires [rustup](https://rustup.rs/).
|
||||
|
||||
To build on Windows, download and run [`rustup-init.exe`](https://win.rustup.rs/)
|
||||
To build Wasmer on Windows, download and run [`rustup-init.exe`](https://win.rustup.rs/)
|
||||
then follow the onscreen instructions.
|
||||
|
||||
To build on other systems, run:
|
||||
@ -99,10 +98,9 @@ curl https://sh.rustup.rs -sSf | sh
|
||||
|
||||
Please select your operating system:
|
||||
|
||||
- [macOS](#macos)
|
||||
- [Debian-based Linuxes](#debian-based-linuxes)
|
||||
- [FreeBSD](#freebsd)
|
||||
- [Microsoft Windows](#windows-msvc)
|
||||
<details>
|
||||
<summary><b>macOS</b></summary>
|
||||
<p>
|
||||
|
||||
#### macOS
|
||||
|
||||
@ -118,22 +116,41 @@ Or, in case you have [MacPorts](https://www.macports.org/install.php):
|
||||
sudo port install cmake
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Debian-based Linuxes</b></summary>
|
||||
<p>
|
||||
|
||||
#### Debian-based Linuxes
|
||||
|
||||
```sh
|
||||
sudo apt install cmake pkg-config libssl-dev
|
||||
```
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>FreeBSD</b></summary>
|
||||
<p>
|
||||
|
||||
#### FreeBSD
|
||||
|
||||
```sh
|
||||
pkg install cmake
|
||||
```
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Windows</b></summary>
|
||||
<p>
|
||||
|
||||
#### Windows (MSVC)
|
||||
|
||||
Windows support is _highly experimental_. Only simple Wasm programs may be run, and no syscalls are allowed. This means
|
||||
nginx and Lua do not work on Windows. See [this issue](https://github.com/wasmerio/wasmer/issues/176) regarding Emscripten syscall polyfills for Windows.
|
||||
Windows support is _experimental_. WASI is fully supported, but Emscripten support is on the works (this means
|
||||
nginx and Lua do not work on Windows - you can track the progress on [this issue](https://github.com/wasmerio/wasmer/issues/176)).
|
||||
|
||||
1. Install [Visual Studio](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community&rel=15)
|
||||
|
||||
@ -147,7 +164,9 @@ nginx and Lua do not work on Windows. See [this issue](https://github.com/wasmer
|
||||
|
||||
5. Install [CMake](https://cmake.org/download/). Ensure CMake is in your PATH.
|
||||
|
||||
6. Install [LLVM 7.0](https://prereleases.llvm.org/win-snapshots/LLVM-7.0.0-r336178-win64.exe)
|
||||
6. Install [LLVM 8.0](https://prereleases.llvm.org/win-snapshots/LLVM-8.0.0-r351033-win64.exe)
|
||||
</p>
|
||||
</details>
|
||||
|
||||
## Building
|
||||
|
||||
@ -165,8 +184,14 @@ git clone https://github.com/wasmerio/wasmer.git
|
||||
cd wasmer
|
||||
|
||||
# install tools
|
||||
# make sure that `python` is accessible.
|
||||
make install
|
||||
make release-clif # To build with cranelift (default)
|
||||
|
||||
make release-llvm # To build with llvm support
|
||||
|
||||
make release-singlepass # To build with singlepass support
|
||||
|
||||
# or
|
||||
make release # To build with singlepass, cranelift and llvm support
|
||||
```
|
||||
|
||||
## Testing
|
||||
@ -204,7 +229,10 @@ Each integration can be tested separately:
|
||||
Benchmarks can be run with:
|
||||
|
||||
```sh
|
||||
make bench
|
||||
make bench-[backend]
|
||||
|
||||
# for example
|
||||
make bench-singlepass
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
@ -216,13 +244,12 @@ Below are some of the goals of this project (in order of priority):
|
||||
- [x] It should be 100% compatible with the [WebAssembly spec tests](https://github.com/wasmerio/wasmer/tree/master/lib/spectests/spectests)
|
||||
- [x] It should be fast _(partially achieved)_
|
||||
- [x] Support WASI - released in [0.3.0](https://github.com/wasmerio/wasmer/releases/tag/0.3.0)
|
||||
- [ ] Support Emscripten calls _(in the works)_
|
||||
- [ ] Support Rust ABI calls
|
||||
- [ ] Support Go ABI calls
|
||||
- [x] Support Emscripten calls _(in the works)_
|
||||
- [ ] Support Go js ABI calls
|
||||
|
||||
## Architecture
|
||||
|
||||
If you would like to know how Wasmer works under the hood, please see [ARCHITECTURE.md](./ARCHITECTURE.md).
|
||||
If you would like to know how Wasmer works under the hood, please see [docs/architecture.md](./docs/architecture.md).
|
||||
|
||||
## License
|
||||
|
||||
|
@ -3,8 +3,9 @@ status = [
|
||||
"ci/circleci: test",
|
||||
"ci/circleci: test-macos",
|
||||
"ci/circleci: test-stable",
|
||||
"ci/circleci: test-rust-example",
|
||||
"continuous-integration/appveyor/branch"
|
||||
]
|
||||
required_approvals = 1
|
||||
timeout_sec = 900
|
||||
timeout_sec = 7200
|
||||
delete_merged_branches = true
|
||||
|
79
build
Executable file
79
build
Executable file
@ -0,0 +1,79 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Wasmer build tool
|
||||
#
|
||||
# This is a script to build Wasmer in a Docker sandbox.
|
||||
#
|
||||
# To use the script, first make sure Docker is installed. Then build the
|
||||
# sandbox image with:
|
||||
#
|
||||
# docker build --file Dockerfile.build --tag wasmer-build .
|
||||
#
|
||||
# After the sandbox image is built successfully, you can run commands in it
|
||||
# with this script.
|
||||
#
|
||||
# For example, to build Wasmer, run:
|
||||
#
|
||||
# ./build make
|
||||
#
|
||||
# To test Wasmer, run:
|
||||
#
|
||||
# ./build make test
|
||||
#
|
||||
# and so on.
|
||||
|
||||
docker_hostname="wasmer-build"
|
||||
|
||||
docker_img="wasmer-build"
|
||||
|
||||
docker_workdir="/wasmer"
|
||||
|
||||
docker_args=(
|
||||
#
|
||||
# General config.
|
||||
#
|
||||
--hostname=${docker_hostname}
|
||||
--interactive
|
||||
--network=host
|
||||
--rm
|
||||
--tty
|
||||
|
||||
#
|
||||
# User and group config.
|
||||
#
|
||||
# Use the same user and group permissions as host to make integration
|
||||
# between host and container simple.
|
||||
#
|
||||
--user "$(id --user):$(id --group)"
|
||||
--volume "/etc/group:/etc/group:ro"
|
||||
--volume "/etc/passwd:/etc/passwd:ro"
|
||||
--volume "/etc/shadow:/etc/shadow:ro"
|
||||
|
||||
#
|
||||
# Time zone config.
|
||||
#
|
||||
# Use the same time zone as the host.
|
||||
#
|
||||
--volume "/etc/localtime:/etc/localtime:ro"
|
||||
|
||||
#
|
||||
# Linux capabilities.
|
||||
#
|
||||
# Add SYS_PTRACE capability to the container so that people can run
|
||||
# `strace'.
|
||||
#
|
||||
--cap-add SYS_PTRACE
|
||||
|
||||
#
|
||||
# Source directory.
|
||||
#
|
||||
--workdir=${docker_workdir}
|
||||
--volume "$(pwd):${docker_workdir}:z"
|
||||
|
||||
#
|
||||
# Environment variables.
|
||||
#
|
||||
--env "CARGO_HOME=${docker_workdir}/.cargo"
|
||||
)
|
||||
|
||||
docker run ${docker_args[@]} ${docker_img} $*
|
11
examples/no_abi_simple_plugin.rs
Normal file
11
examples/no_abi_simple_plugin.rs
Normal file
@ -0,0 +1,11 @@
|
||||
extern "C" {
|
||||
fn it_works() -> i32;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn plugin_entrypoint(n: i32) -> i32 {
|
||||
let result = unsafe { it_works() };
|
||||
result + n
|
||||
}
|
||||
|
||||
fn main() {}
|
BIN
examples/no_abi_simple_plugin.wasm
Executable file
BIN
examples/no_abi_simple_plugin.wasm
Executable file
Binary file not shown.
BIN
examples/particle-repel-simd.wasm
Executable file
BIN
examples/particle-repel-simd.wasm
Executable file
Binary file not shown.
BIN
examples/particle-repel.wasm
Executable file
BIN
examples/particle-repel.wasm
Executable file
Binary file not shown.
Binary file not shown.
@ -1,6 +1,10 @@
|
||||
use wasmer_runtime::{func, imports, instantiate};
|
||||
use wasmer_runtime_core::vm::Ctx;
|
||||
use wasmer_wasi::generate_import_object;
|
||||
use wasmer_wasi::{
|
||||
generate_import_object,
|
||||
state::{self, WasiFile},
|
||||
types,
|
||||
};
|
||||
|
||||
static PLUGIN_LOCATION: &'static str = "examples/plugin-for-example.wasm";
|
||||
|
||||
@ -9,6 +13,107 @@ fn it_works(_ctx: &mut Ctx) -> i32 {
|
||||
5
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LoggingWrapper {
|
||||
pub wasm_module_name: String,
|
||||
}
|
||||
|
||||
// std io trait boiler plate so we can implement WasiFile
|
||||
// LoggingWrapper is a write-only type so we just want to immediately
|
||||
// fail when reading or Seeking
|
||||
impl std::io::Read for LoggingWrapper {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"can not read from logging wrapper",
|
||||
))
|
||||
}
|
||||
fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> std::io::Result<usize> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"can not read from logging wrapper",
|
||||
))
|
||||
}
|
||||
fn read_to_string(&mut self, _buf: &mut String) -> std::io::Result<usize> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"can not read from logging wrapper",
|
||||
))
|
||||
}
|
||||
fn read_exact(&mut self, _buf: &mut [u8]) -> std::io::Result<()> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"can not read from logging wrapper",
|
||||
))
|
||||
}
|
||||
}
|
||||
impl std::io::Seek for LoggingWrapper {
|
||||
fn seek(&mut self, _pos: std::io::SeekFrom) -> std::io::Result<u64> {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"can not seek logging wrapper",
|
||||
))
|
||||
}
|
||||
}
|
||||
impl std::io::Write for LoggingWrapper {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
let stdout = std::io::stdout();
|
||||
let mut out = stdout.lock();
|
||||
out.write(b"[")?;
|
||||
out.write(self.wasm_module_name.as_bytes())?;
|
||||
out.write(b"]: ")?;
|
||||
out.write(buf)
|
||||
}
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
std::io::stdout().flush()
|
||||
}
|
||||
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
|
||||
let stdout = std::io::stdout();
|
||||
let mut out = stdout.lock();
|
||||
out.write(b"[")?;
|
||||
out.write(self.wasm_module_name.as_bytes())?;
|
||||
out.write(b"]: ")?;
|
||||
out.write_all(buf)
|
||||
}
|
||||
fn write_fmt(&mut self, fmt: std::fmt::Arguments) -> std::io::Result<()> {
|
||||
let stdout = std::io::stdout();
|
||||
let mut out = stdout.lock();
|
||||
out.write(b"[")?;
|
||||
out.write(self.wasm_module_name.as_bytes())?;
|
||||
out.write(b"]: ")?;
|
||||
out.write_fmt(fmt)
|
||||
}
|
||||
}
|
||||
|
||||
// the WasiFile methods aren't relevant for a write-only Stdout-like implementation
|
||||
impl WasiFile for LoggingWrapper {
|
||||
fn last_accessed(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
fn last_modified(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
fn created_time(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
fn size(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// Called by the program when it wants to set itself up
|
||||
fn initialize(ctx: &mut Ctx) {
|
||||
let state = unsafe { state::get_wasi_state(ctx) };
|
||||
let wasi_file_inner = LoggingWrapper {
|
||||
wasm_module_name: "example module name".to_string(),
|
||||
};
|
||||
// swap stdout with our new wasifile
|
||||
let _old_stdout = state
|
||||
.fs
|
||||
.swap_file(types::__WASI_STDOUT_FILENO, Box::new(wasi_file_inner))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Load the plugin data
|
||||
let wasm_bytes = std::fs::read(PLUGIN_LOCATION).expect(&format!(
|
||||
@ -27,8 +132,10 @@ fn main() {
|
||||
// The WASI imports object contains all required import functions for a WASI module to run.
|
||||
// Extend this imports with our custom imports containing "it_works" function so that our custom wasm code may run.
|
||||
base_imports.extend(custom_imports);
|
||||
let instance =
|
||||
let mut instance =
|
||||
instantiate(&wasm_bytes[..], &base_imports).expect("failed to instantiate wasm module");
|
||||
// set up logging by replacing stdout
|
||||
initialize(instance.context_mut());
|
||||
|
||||
// get a reference to the function "plugin_entrypoint" which takes an i32 and returns an i32
|
||||
let entry_point = instance.func::<(i32), i32>("plugin_entrypoint").unwrap();
|
||||
|
@ -33,6 +33,19 @@ INFO: seed corpus: files: 8 min: 1b max: 1b total: 8b rss: 133Mb
|
||||
```
|
||||
It will continue to generate random inputs forever, until it finds a bug or is terminated. The testcases for bugs it finds go into `fuzz/artifacts/simple_instantiate` and you can rerun the fuzzer on a single input by passing it on the command line `cargo fuzz run simple_instantiate my_testcase.wasm`.
|
||||
|
||||
## Seeding the corpus, optional
|
||||
|
||||
The fuzzer works best when it has examples of small Wasm files to start with. Using `wast2json` from [wabt](https://github.com/WebAssembly/wabt), we can easily produce `.wasm` files out of the WebAssembly spec tests.
|
||||
|
||||
```sh
|
||||
mkdir spec-test-corpus
|
||||
for i in lib/spectests/spectests/*.wast; do wast2json $i -o spec-test-corpus/$(basename $i).json; done
|
||||
mv spec-test-corpus/*.wasm fuzz/corpus/simple_instantiate/
|
||||
rm -r spec-test-corpus
|
||||
```
|
||||
|
||||
The corpus directory is created on the first run of the fuzzer. If it doesn't exist, run it first and then seed the corpus. The fuzzer will pick up new files added to the corpus while it is running.
|
||||
|
||||
## Trophy case
|
||||
|
||||
- [x] https://github.com/wasmerio/wasmer/issues/558
|
||||
|
92
install.sh
92
install.sh
@ -35,6 +35,11 @@ dim="\e[2m"
|
||||
# Warning: Remove this on the public repo
|
||||
RELEASES_URL="https://github.com/wasmerio/wasmer/releases"
|
||||
|
||||
WASMER_VERBOSE="verbose"
|
||||
if [ -z "$WASMER_INSTALL_LOG" ]; then
|
||||
WASMER_INSTALL_LOG="$WASMER_VERBOSE"
|
||||
fi
|
||||
|
||||
wasmer_download_json() {
|
||||
url="$2"
|
||||
|
||||
@ -66,9 +71,19 @@ wasmer_download_file() {
|
||||
|
||||
# echo "Fetching $url.."
|
||||
if test -x "$(command -v curl)"; then
|
||||
code=$(curl --progress-bar -w '%{http_code}' -L "$url" -o "$destination")
|
||||
if [ "$WASMER_INSTALL_LOG" == "$WASMER_VERBOSE" ]; then
|
||||
code=$(curl --progress-bar -w '%{http_code}' -L "$url" -o "$destination")
|
||||
printf "\033[K\n\033[1A"
|
||||
else
|
||||
code=$(curl -s -w '%{http_code}' -L "$url" -o "$destination")
|
||||
fi
|
||||
elif test -x "$(command -v wget)"; then
|
||||
code=$(wget --show-progress --progress=bar:force:noscroll -q -O "$destination" --server-response "$url" 2>&1 | awk '/^ HTTP/{print $2}' | tail -1)
|
||||
if [ "$WASMER_INSTALL_LOG" == "$WASMER_VERBOSE" ]; then
|
||||
code=$(wget --show-progress --progress=bar:force:noscroll -q -O "$destination" --server-response "$url" 2>&1 | awk '/^ HTTP/{print $2}' | tail -1)
|
||||
printf "\033[K\n\033[1A";
|
||||
else
|
||||
code=$(wget --quiet -O "$destination" --server-response "$url" 2>&1 | awk '/^ HTTP/{print $2}' | tail -1)
|
||||
fi
|
||||
else
|
||||
printf "$red> Neither curl nor wget was available to perform http requests.$reset\n"
|
||||
exit 1
|
||||
@ -130,7 +145,7 @@ wasmer_detect_profile() {
|
||||
wasmer_link() {
|
||||
printf "$cyan> Adding to bash profile...$reset\n"
|
||||
WASMER_PROFILE="$(wasmer_detect_profile)"
|
||||
LOAD_STR="\n# Wasmer\nexport WASMER_DIR=\"$INSTALL_DIRECTORY\"\n[ -s \"\$WASMER_DIR/wasmer.sh\" ] && source \"\$WASMER_DIR/wasmer.sh\" # This loads wasmer\n"
|
||||
LOAD_STR="\n# Wasmer\nexport WASMER_DIR=\"$INSTALL_DIRECTORY\"\n[ -s \"\$WASMER_DIR/wasmer.sh\" ] && source \"\$WASMER_DIR/wasmer.sh\"\n"
|
||||
SOURCE_STR="# Wasmer config\nexport WASMER_DIR=\"$INSTALL_DIRECTORY\"\nexport WASMER_CACHE_DIR=\"\$WASMER_DIR/cache\"\nexport PATH=\"\$WASMER_DIR/bin:\$WASMER_DIR/globals/wapm_packages/.bin:\$PATH\"\n"
|
||||
|
||||
# We create the wasmer.sh file
|
||||
@ -152,19 +167,22 @@ wasmer_link() {
|
||||
# fi
|
||||
fi
|
||||
printf "\033[1A$cyan> Adding to bash profile... ✓$reset\n"
|
||||
printf "${dim}Note: We've added the following to your $WASMER_PROFILE\n"
|
||||
echo "If this isn't the profile of your current shell then please add the following to your correct profile:"
|
||||
printf "$LOAD_STR$reset\n"
|
||||
if [ "$WASMER_INSTALL_LOG" == "$WASMER_VERBOSE" ]; then
|
||||
printf "${dim}Note: We've added the following to your $WASMER_PROFILE\n"
|
||||
echo "If you have a different profile please add the following:"
|
||||
printf "$LOAD_STR$reset\n"
|
||||
fi
|
||||
|
||||
version=`$INSTALL_DIRECTORY/bin/wasmer --version` || (
|
||||
printf "$red> wasmer was installed, but doesn't seem to be working :($reset\n"
|
||||
exit 1;
|
||||
)
|
||||
|
||||
printf "$green> Successfully installed $version!\n\n${reset}If you want to have the command available now please execute:\nsource $INSTALL_DIRECTORY/wasmer.sh$reset\n"
|
||||
printf "\nOtherwise, wasmer and wapm will be available the next time you open the terminal.\n"
|
||||
echo "Note: during the alpha release of wapm, telemetry is enabled by default; if you would like to opt out, run \`wapm config set telemetry.enabled false\`."
|
||||
echo "If you notice anything wrong or have any issues, please file a bug at https://github.com/wasmerio/wapm-cli :)"
|
||||
printf "$green> Successfully installed $version!\n"
|
||||
if [ "$WASMER_INSTALL_LOG" == "$WASMER_VERBOSE" ]; then
|
||||
printf "${reset}${dim}wasmer & wapm will be available the next time you open the terminal.\n"
|
||||
printf "${reset}${dim}If you want to have the commands available now please execute:\n${reset}source $INSTALL_DIRECTORY/wasmer.sh$reset\n"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@ -230,33 +248,36 @@ initOS() {
|
||||
|
||||
wasmer_install() {
|
||||
magenta1="${reset}\033[34;1m"
|
||||
magenta2="${reset}\033[34m"
|
||||
magenta3="${reset}\033[34;2m"
|
||||
magenta2=""
|
||||
magenta3=""
|
||||
|
||||
if which wasmer >/dev/null; then
|
||||
printf "${reset}Updating wasmer$reset\n"
|
||||
printf "${reset}Updating Wasmer and WAPM$reset\n"
|
||||
else
|
||||
printf "${reset}Installing Wasmer!$reset\n"
|
||||
printf "
|
||||
${magenta1} ${magenta2} ${magenta3}###${reset}
|
||||
${magenta1} ${magenta2} ${magenta3}#####${reset}
|
||||
${magenta1} ${magenta2}### ${magenta3}######${reset}
|
||||
${magenta1} ${magenta2}###### ${magenta3}#############${reset}
|
||||
${magenta1}# ${magenta2}####### ${magenta3}##############${reset}
|
||||
${magenta1}##### ${magenta2}#############${magenta3}#########${reset}
|
||||
${magenta1}######${magenta2}###############${magenta3}#######${reset}
|
||||
${magenta1}############${magenta2}#########${magenta3}#######${reset}
|
||||
${magenta1}##############${magenta2}#######${magenta3}#######${reset}
|
||||
${magenta1}##############${magenta2}#######${magenta3}#######${reset}
|
||||
${magenta1}##############${magenta2}#######${magenta3}#######${reset}
|
||||
${magenta1}##############${magenta2}#######${magenta3} ###${reset}
|
||||
${magenta1}##############${magenta2}#######
|
||||
${magenta1}###########${magenta2} ###
|
||||
${magenta1}########${magenta2}
|
||||
${magenta1}####${reset}
|
||||
|
||||
printf "${reset}Installing Wasmer and WAPM!$reset\n"
|
||||
if [ "$WASMER_INSTALL_LOG" == "$WASMER_VERBOSE" ]; then
|
||||
printf "
|
||||
${magenta1} ww
|
||||
${magenta1} wwwww
|
||||
${magenta1} ww wwwwww w
|
||||
${magenta1} wwwww wwwwwwwww
|
||||
${magenta1}ww wwwwww w wwwwwww
|
||||
${magenta1}wwwww wwwwwwwwww wwwww
|
||||
${magenta1}wwwwww w wwwwwww wwwww
|
||||
${magenta1}wwwwwwwwwwwwww wwwww wwwww
|
||||
${magenta1}wwwwwwwwwwwwwww wwwww wwwww
|
||||
${magenta1}wwwwwwwwwwwwwww wwwww wwwww
|
||||
${magenta1}wwwwwwwwwwwwwww wwwww wwwww
|
||||
${magenta1}wwwwwwwwwwwwwww wwwww wwww
|
||||
${magenta1}wwwwwwwwwwwwwww wwwww
|
||||
${magenta1} wwwwwwwwwwww wwww
|
||||
${magenta1} wwwwwwww
|
||||
${magenta1} wwww
|
||||
${reset}
|
||||
"
|
||||
fi
|
||||
fi
|
||||
|
||||
# if [ -d "$INSTALL_DIRECTORY" ]; then
|
||||
# if which wasmer; then
|
||||
# local latest_url
|
||||
@ -419,7 +440,7 @@ wasmer_download() {
|
||||
printf "$cyan> Downloading $WASMER_RELEASE_TAG release...$reset\n"
|
||||
wasmer_download_file "$BINARY_URL" "$DOWNLOAD_FILE"
|
||||
# echo -en "\b\b"
|
||||
printf "\033[2A$cyan> Downloading $WASMER_RELEASE_TAG release... ✓$reset\033[K\n"
|
||||
printf "\033[1A$cyan> Downloading $WASMER_RELEASE_TAG release... ✓$reset\n"
|
||||
printf "\033[K\n\033[1A"
|
||||
# printf "\033[1A$cyan> Downloaded$reset\033[K\n"
|
||||
# echo "Setting executable permissions."
|
||||
@ -431,9 +452,12 @@ wasmer_download() {
|
||||
|
||||
# echo "Moving executable to $INSTALL_DIRECTORY/$INSTALL_NAME"
|
||||
|
||||
printf "$cyan> Unpacking contents...$reset\n"
|
||||
|
||||
mkdir -p $INSTALL_DIRECTORY
|
||||
# Untar the wasmer contents in the install directory
|
||||
tar -C $INSTALL_DIRECTORY -zxvf $DOWNLOAD_FILE
|
||||
tar -C $INSTALL_DIRECTORY -zxf $DOWNLOAD_FILE
|
||||
printf "\033[1A$cyan> Unpacking contents... ✓$reset\n"
|
||||
}
|
||||
|
||||
wasmer_verify_or_quit() {
|
||||
|
@ -1,40 +1,41 @@
|
||||
[package]
|
||||
name = "wasmer-clif-backend"
|
||||
version = "0.5.6"
|
||||
version = "0.6.0"
|
||||
description = "Wasmer runtime Cranelift compiler backend"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
repository = "https://github.com/wasmerio/wasmer"
|
||||
edition = "2018"
|
||||
readme = "README.md"
|
||||
|
||||
[dependencies]
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.5.6" }
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
||||
cranelift-native = { version = "0.31" }
|
||||
cranelift-codegen = { version = "0.31" }
|
||||
cranelift-entity = { version = "0.31" }
|
||||
cranelift-frontend = { package = "wasmer-clif-fork-frontend", version = "0.31" }
|
||||
cranelift-wasm = { package = "wasmer-clif-fork-wasm", version = "0.31" }
|
||||
hashbrown = "0.1"
|
||||
cranelift-frontend = { package = "wasmer-clif-fork-frontend", version = "0.33" }
|
||||
cranelift-wasm = { package = "wasmer-clif-fork-wasm", version = "0.33" }
|
||||
target-lexicon = "0.4.0"
|
||||
wasmparser = "0.32.1"
|
||||
byteorder = "1"
|
||||
nix = "0.14.0"
|
||||
libc = "0.2.49"
|
||||
rayon = "1.0"
|
||||
wasmparser = "0.35.1"
|
||||
byteorder = "1.3.2"
|
||||
nix = "0.15.0"
|
||||
libc = "0.2.60"
|
||||
rayon = "1.1.0"
|
||||
|
||||
# Dependencies for caching.
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
version = "1.0.99"
|
||||
features = ["rc"]
|
||||
[dependencies.serde_derive]
|
||||
version = "1.0"
|
||||
version = "1.0.98"
|
||||
[dependencies.serde_bytes]
|
||||
version = "0.10"
|
||||
version = "0.11.2"
|
||||
[dependencies.serde-bench]
|
||||
version = "0.0.7"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
||||
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.5.6" }
|
||||
winapi = { version = "0.3.7", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
||||
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.6.0" }
|
||||
|
||||
[features]
|
||||
debug = ["wasmer-runtime-core/debug"]
|
||||
|
@ -28,4 +28,26 @@ Wasmer is a standalone JIT WebAssembly runtime, aiming to be fully
|
||||
compatible with Emscripten, Rust and Go. [Learn
|
||||
more](https://github.com/wasmerio/wasmer).
|
||||
|
||||
This crate represents the Cranelift backend.
|
||||
This crate represents the Cranelift backend integration for Wasmer.
|
||||
|
||||
## Usage
|
||||
|
||||
### Usage in Wasmer Standalone
|
||||
|
||||
If you are using the `wasmer` CLI, you can specify the backend with:
|
||||
|
||||
```bash
|
||||
wasmer run program.wasm --backend=cranelift
|
||||
```
|
||||
|
||||
### Usage in Wasmer Embedded
|
||||
|
||||
If you are using Wasmer Embedded, you can specify
|
||||
the Cranelift backend to the [`compile_with` function](https://docs.rs/wasmer-runtime-core/*/wasmer_runtime_core/fn.compile_with.html):
|
||||
|
||||
```rust
|
||||
use wasmer_clif_backend::CraneliftCompiler;
|
||||
|
||||
// ...
|
||||
let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &CraneliftCompiler::new());
|
||||
```
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::relocation::{ExternalRelocation, TrapSink};
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use wasmer_runtime_core::{
|
||||
backend::{sys::Memory, CacheGen},
|
||||
|
@ -33,7 +33,7 @@ use wasmer_runtime_core::{
|
||||
use wasmparser::Type as WpType;
|
||||
|
||||
pub struct CraneliftModuleCodeGenerator {
|
||||
isa: Box<isa::TargetIsa>,
|
||||
isa: Box<dyn isa::TargetIsa>,
|
||||
signatures: Option<Arc<Map<SigIndex, FuncSig>>>,
|
||||
pub clif_signatures: Map<SigIndex, ir::Signature>,
|
||||
function_signatures: Option<Arc<Map<FuncIndex, SigIndex>>>,
|
||||
@ -89,10 +89,12 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
|
||||
func,
|
||||
func_translator,
|
||||
next_local: 0,
|
||||
clif_signatures: self.clif_signatures.clone(),
|
||||
module_info: Arc::clone(&module_info),
|
||||
target_config: self.isa.frontend_config().clone(),
|
||||
position: Position::default(),
|
||||
func_env: FunctionEnvironment {
|
||||
module_info: Arc::clone(&module_info),
|
||||
target_config: self.isa.frontend_config().clone(),
|
||||
clif_signatures: self.clif_signatures.clone(),
|
||||
},
|
||||
};
|
||||
|
||||
debug_assert_eq!(func_env.func.dfg.num_ebbs(), 0, "Function must be empty");
|
||||
@ -304,8 +306,15 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
|
||||
|
||||
let trampolines = Arc::new(Trampolines::new(&*self.isa, module_info));
|
||||
|
||||
let signatures_empty = Map::new();
|
||||
let signatures = if self.signatures.is_some() {
|
||||
&self.signatures.as_ref().unwrap()
|
||||
} else {
|
||||
&signatures_empty
|
||||
};
|
||||
|
||||
let (func_resolver, backend_cache) = func_resolver_builder.finalize(
|
||||
&self.signatures.as_ref().unwrap(),
|
||||
signatures,
|
||||
Arc::clone(&trampolines),
|
||||
handler_data.clone(),
|
||||
)?;
|
||||
@ -384,10 +393,8 @@ pub struct CraneliftFunctionCodeGenerator {
|
||||
func: Function,
|
||||
func_translator: FuncTranslator,
|
||||
next_local: usize,
|
||||
pub clif_signatures: Map<SigIndex, ir::Signature>,
|
||||
module_info: Arc<RwLock<ModuleInfo>>,
|
||||
target_config: isa::TargetFrontendConfig,
|
||||
position: Position,
|
||||
func_env: FunctionEnvironment,
|
||||
}
|
||||
|
||||
pub struct FunctionEnvironment {
|
||||
@ -1131,11 +1138,6 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
|
||||
//let builder = self.builder.as_mut().unwrap();
|
||||
//let func_environment = FuncEnv::new();
|
||||
//let state = TranslationState::new();
|
||||
let mut function_environment = FunctionEnvironment {
|
||||
module_info: Arc::clone(&self.module_info),
|
||||
target_config: self.target_config.clone(),
|
||||
clif_signatures: self.clif_signatures.clone(),
|
||||
};
|
||||
|
||||
if self.func_translator.state.control_stack.is_empty() {
|
||||
return Ok(());
|
||||
@ -1147,7 +1149,7 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
|
||||
&mut self.position,
|
||||
);
|
||||
let state = &mut self.func_translator.state;
|
||||
translate_operator(op, &mut builder, state, &mut function_environment)?;
|
||||
translate_operator(op, &mut builder, state, &mut self.func_env)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,12 @@
|
||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||
|
||||
#![deny(
|
||||
dead_code,
|
||||
nonstandard_style,
|
||||
unused_imports,
|
||||
unused_mut,
|
||||
unused_variables,
|
||||
unused_unsafe,
|
||||
unreachable_patterns
|
||||
)]
|
||||
mod cache;
|
||||
mod code;
|
||||
mod libcalls;
|
||||
@ -21,7 +28,7 @@ extern crate serde_derive;
|
||||
extern crate rayon;
|
||||
extern crate serde;
|
||||
|
||||
fn get_isa() -> Box<isa::TargetIsa> {
|
||||
fn get_isa() -> Box<dyn isa::TargetIsa> {
|
||||
let flags = {
|
||||
let mut builder = settings::builder();
|
||||
builder.set("opt_level", "best").unwrap();
|
||||
|
@ -76,8 +76,7 @@ pub extern "C" fn nearbyintf64(x: f64) -> f64 {
|
||||
}
|
||||
}
|
||||
|
||||
/// A declaration for the stack probe function in Rust's standard library, for
|
||||
/// catching callstack overflow.
|
||||
extern "C" {
|
||||
pub fn __rust_probestack();
|
||||
}
|
||||
// FIXME: Is there a replacement on AArch64?
|
||||
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_probestack() {}
|
||||
|
@ -107,7 +107,8 @@ impl From<Converter<ir::Type>> for Type {
|
||||
ir::types::I64 => Type::I64,
|
||||
ir::types::F32 => Type::F32,
|
||||
ir::types::F64 => Type::F64,
|
||||
_ => panic!("unsupported wasm type"),
|
||||
ir::types::I32X4 => Type::V128,
|
||||
_ => unimplemented!("unsupported wasm type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -119,6 +120,7 @@ impl From<Converter<Type>> for ir::Type {
|
||||
Type::I64 => ir::types::I64,
|
||||
Type::F32 => ir::types::F32,
|
||||
Type::F64 => ir::types::F64,
|
||||
Type::V128 => ir::types::I32X4,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -130,6 +132,7 @@ impl From<Converter<Type>> for ir::AbiParam {
|
||||
Type::I64 => ir::AbiParam::new(ir::types::I64),
|
||||
Type::F32 => ir::AbiParam::new(ir::types::F32),
|
||||
Type::F64 => ir::AbiParam::new(ir::types::F64),
|
||||
Type::V128 => ir::AbiParam::new(ir::types::I32X4),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ impl FuncResolverBuilder {
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
isa: &isa::TargetIsa,
|
||||
isa: &dyn isa::TargetIsa,
|
||||
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
||||
info: &ModuleInfo,
|
||||
) -> CompileResult<(Self, HandlerData)> {
|
||||
|
@ -138,6 +138,14 @@ pub unsafe fn do_unwind(signum: i32, siginfo: *const c_void, ucontext: *const c_
|
||||
longjmp(jmp_buf as *mut ::nix::libc::c_void, signum)
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
|
||||
unsafe fn get_faulting_addr_and_ip(
|
||||
_siginfo: *const c_void,
|
||||
_ucontext: *const c_void,
|
||||
) -> (*const c_void, *const c_void) {
|
||||
(::std::ptr::null(), ::std::ptr::null())
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
||||
unsafe fn get_faulting_addr_and_ip(
|
||||
siginfo: *const c_void,
|
||||
@ -230,5 +238,6 @@ unsafe fn get_faulting_addr_and_ip(
|
||||
#[cfg(not(any(
|
||||
all(target_os = "macos", target_arch = "x86_64"),
|
||||
all(target_os = "linux", target_arch = "x86_64"),
|
||||
all(target_os = "linux", target_arch = "aarch64"),
|
||||
)))]
|
||||
compile_error!("This crate doesn't yet support compiling on operating systems other than linux and macos and architectures other than x86_64");
|
||||
|
@ -5,7 +5,7 @@ use cranelift_codegen::{
|
||||
ir::{self, InstBuilder},
|
||||
isa, Context,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use std::collections::HashMap;
|
||||
use std::{iter, mem, ptr::NonNull};
|
||||
use wasmer_runtime_core::{
|
||||
backend::sys::{Memory, Protect},
|
||||
@ -66,7 +66,7 @@ impl Trampolines {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(isa: &isa::TargetIsa, module: &ModuleInfo) -> Self {
|
||||
pub fn new(isa: &dyn isa::TargetIsa, module: &ModuleInfo) -> Self {
|
||||
let func_index_iter = module
|
||||
.exports
|
||||
.values()
|
||||
@ -204,6 +204,7 @@ fn wasm_ty_to_clif(ty: Type) -> ir::types::Type {
|
||||
Type::I64 => ir::types::I64,
|
||||
Type::F32 => ir::types::F32,
|
||||
Type::F64 => ir::types::F64,
|
||||
Type::V128 => ir::types::I32X4,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-dev-utils"
|
||||
version = "0.5.6"
|
||||
version = "0.6.0"
|
||||
description = "Wasmer runtime core library"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -8,4 +8,4 @@ edition = "2018"
|
||||
repository = "https://github.com/wasmerio/wasmer"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.49"
|
||||
libc = "0.2.60"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-emscripten-tests"
|
||||
version = "0.5.6"
|
||||
version = "0.6.0"
|
||||
description = "Tests for our Emscripten implementation"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -9,18 +9,18 @@ publish = false
|
||||
build = "build/mod.rs"
|
||||
|
||||
[dependencies]
|
||||
wasmer-emscripten = { path = "../emscripten", version = "0.5.6" }
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.5.6" }
|
||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.5.6" }
|
||||
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.5.6", optional = true }
|
||||
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.5.6", optional = true }
|
||||
wasmer-emscripten = { path = "../emscripten", version = "0.6.0" }
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.6.0" }
|
||||
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.6.0", optional = true }
|
||||
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.6.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
wabt = "0.7.2"
|
||||
wasmer-dev-utils = { path = "../dev-utils", version = "0.5.6"}
|
||||
wabt = "0.9.1"
|
||||
wasmer-dev-utils = { path = "../dev-utils", version = "0.6.0"}
|
||||
|
||||
[build-dependencies]
|
||||
glob = "0.2.11"
|
||||
glob = "0.3.0"
|
||||
|
||||
[features]
|
||||
clif = []
|
||||
|
@ -42,7 +42,7 @@ macro_rules! assert_emscripten_output {
|
||||
|
||||
// let module = compile(&wasm_bytes[..])
|
||||
// .map_err(|err| format!("Can't create the WebAssembly module: {}", err)).unwrap(); // NOTE: Need to figure what the unwrap is for ??
|
||||
let mut emscripten_globals = EmscriptenGlobals::new(&module);
|
||||
let mut emscripten_globals = EmscriptenGlobals::new(&module).expect("globals are valid");
|
||||
let import_object = generate_emscripten_env(&mut emscripten_globals);
|
||||
|
||||
let mut instance = module.instantiate(&import_object)
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-emscripten"
|
||||
version = "0.5.6"
|
||||
version = "0.6.0"
|
||||
description = "Wasmer runtime emscripten implementation library"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -8,15 +8,14 @@ repository = "https://github.com/wasmerio/wasmer"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1"
|
||||
hashbrown = "0.1"
|
||||
lazy_static = "1.2.0"
|
||||
libc = "0.2.49"
|
||||
time = "0.1.41"
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.5.6" }
|
||||
byteorder = "1.3.2"
|
||||
lazy_static = "1.3.0"
|
||||
libc = "0.2.60"
|
||||
time = "0.1.42"
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
rand = "0.6"
|
||||
rand = "0.7.0"
|
||||
|
||||
[features]
|
||||
debug = ["wasmer-runtime-core/debug"]
|
||||
|
1
lib/emscripten/src/env/mod.rs
vendored
1
lib/emscripten/src/env/mod.rs
vendored
@ -30,6 +30,7 @@ pub fn call_malloc(ctx: &mut Ctx, size: u32) -> u32 {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[warn(dead_code)]
|
||||
pub fn call_malloc_with_cast<T: Copy, Ty>(ctx: &mut Ctx, size: u32) -> WasmPtr<T, Ty> {
|
||||
WasmPtr::new(call_malloc(ctx, size))
|
||||
}
|
||||
|
25
lib/emscripten/src/env/unix/mod.rs
vendored
25
lib/emscripten/src/env/unix/mod.rs
vendored
@ -159,7 +159,7 @@ pub fn _gai_strerror(ctx: &mut Ctx, ecode: i32) -> i32 {
|
||||
.unwrap()
|
||||
};
|
||||
for (i, byte) in bytes.iter().enumerate() {
|
||||
writer[i].set(*byte as i8);
|
||||
writer[i].set(*byte as _);
|
||||
}
|
||||
|
||||
string_on_guest.offset() as _
|
||||
@ -196,18 +196,15 @@ pub fn _getaddrinfo(
|
||||
|
||||
let hints = hints_ptr.deref(memory).map(|hints_memory| {
|
||||
let hints_guest = hints_memory.get();
|
||||
unsafe {
|
||||
let mut hints_native: addrinfo = std::mem::uninitialized();
|
||||
hints_native.ai_flags = hints_guest.ai_flags;
|
||||
hints_native.ai_family = hints_guest.ai_family;
|
||||
hints_native.ai_socktype = hints_guest.ai_socktype;
|
||||
hints_native.ai_protocol = hints_guest.ai_protocol;
|
||||
hints_native.ai_addrlen = 0;
|
||||
hints_native.ai_addr = std::ptr::null_mut();
|
||||
hints_native.ai_canonname = std::ptr::null_mut();
|
||||
hints_native.ai_next = std::ptr::null_mut();
|
||||
|
||||
hints_native
|
||||
addrinfo {
|
||||
ai_flags: hints_guest.ai_flags,
|
||||
ai_family: hints_guest.ai_family,
|
||||
ai_socktype: hints_guest.ai_socktype,
|
||||
ai_protocol: hints_guest.ai_protocol,
|
||||
ai_addrlen: 0,
|
||||
ai_addr: std::ptr::null_mut(),
|
||||
ai_canonname: std::ptr::null_mut(),
|
||||
ai_next: std::ptr::null_mut(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -286,7 +283,7 @@ pub fn _getaddrinfo(
|
||||
.deref(ctx.memory(0), 0, str_size as _)
|
||||
.unwrap();
|
||||
for (i, b) in canonname_bytes.into_iter().enumerate() {
|
||||
guest_canonname_writer[i].set(*b as i8)
|
||||
guest_canonname_writer[i].set(*b as _)
|
||||
}
|
||||
|
||||
guest_canonname
|
||||
|
@ -37,7 +37,7 @@ pub fn execvp(ctx: &mut Ctx, command_name_offset: u32, argv_offset: u32) -> i32
|
||||
// construct raw pointers and hand them to `execvp`
|
||||
let command_pointer = command_name_string.as_ptr() as *const i8;
|
||||
let args_pointer = argv.as_ptr();
|
||||
unsafe { libc_execvp(command_pointer, args_pointer) }
|
||||
unsafe { libc_execvp(command_pointer as *const _, args_pointer as *const *const _) }
|
||||
}
|
||||
|
||||
/// execl
|
||||
|
@ -23,7 +23,7 @@ pub fn printf(ctx: &mut Ctx, memory_offset: i32, extra: i32) -> i32 {
|
||||
pub fn chroot(ctx: &mut Ctx, name_ptr: i32) -> i32 {
|
||||
debug!("emscripten::chroot");
|
||||
let name = emscripten_memory_pointer!(ctx.memory(0), name_ptr) as *const i8;
|
||||
unsafe { _chroot(name) }
|
||||
unsafe { _chroot(name as *const _) }
|
||||
}
|
||||
|
||||
/// getpwuid
|
||||
|
@ -1,15 +1,22 @@
|
||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||
|
||||
#![deny(
|
||||
dead_code,
|
||||
nonstandard_style,
|
||||
unused_imports,
|
||||
unused_mut,
|
||||
unused_variables,
|
||||
unused_unsafe,
|
||||
unreachable_patterns
|
||||
)]
|
||||
#[macro_use]
|
||||
extern crate wasmer_runtime_core;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use lazy_static::lazy_static;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::{f64, ffi::c_void};
|
||||
use wasmer_runtime_core::{
|
||||
error::CallResult,
|
||||
error::{CallError, CallResult, ResolveError},
|
||||
export::Export,
|
||||
func,
|
||||
global::Global,
|
||||
@ -25,11 +32,11 @@ use wasmer_runtime_core::{
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
use ::libc::DIR as libcDIR;
|
||||
use ::libc::DIR as LibcDir;
|
||||
|
||||
// We use a placeholder for windows
|
||||
#[cfg(not(unix))]
|
||||
type libcDIR = u8;
|
||||
type LibcDir = u8;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
@ -93,7 +100,7 @@ pub struct EmscriptenData<'a> {
|
||||
pub memset: Option<Func<'a, (u32, u32, u32), u32>>,
|
||||
pub stack_alloc: Option<Func<'a, u32, u32>>,
|
||||
pub jumps: Vec<UnsafeCell<[u32; 27]>>,
|
||||
pub opened_dirs: HashMap<i32, Box<*mut libcDIR>>,
|
||||
pub opened_dirs: HashMap<i32, Box<*mut LibcDir>>,
|
||||
|
||||
pub dyn_call_i: Option<Func<'a, i32, i32>>,
|
||||
pub dyn_call_ii: Option<Func<'a, (i32, i32), i32>>,
|
||||
@ -366,10 +373,11 @@ pub fn run_emscripten_instance(
|
||||
0 => {
|
||||
instance.call(func_name, &[])?;
|
||||
}
|
||||
_ => panic!(
|
||||
"The emscripten main function has received an incorrect number of params {}",
|
||||
num_params
|
||||
),
|
||||
_ => {
|
||||
return Err(CallError::Resolve(ResolveError::ExportWrongType {
|
||||
name: "main".to_string(),
|
||||
}))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -397,11 +405,18 @@ fn store_module_arguments(ctx: &mut Ctx, args: Vec<&str>) -> (u32, u32) {
|
||||
(argc as u32 - 1, argv_offset)
|
||||
}
|
||||
|
||||
pub fn emscripten_set_up_memory(memory: &Memory, globals: &EmscriptenGlobalsData) {
|
||||
pub fn emscripten_set_up_memory(
|
||||
memory: &Memory,
|
||||
globals: &EmscriptenGlobalsData,
|
||||
) -> Result<(), String> {
|
||||
let dynamictop_ptr = globals.dynamictop_ptr;
|
||||
let dynamic_base = globals.dynamic_base;
|
||||
|
||||
if (dynamictop_ptr / 4) as usize >= memory.view::<u32>().len() {
|
||||
return Err("dynamictop_ptr beyond memory len".to_string());
|
||||
}
|
||||
memory.view::<u32>()[(dynamictop_ptr / 4) as usize].set(dynamic_base);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct EmscriptenGlobalsData {
|
||||
@ -429,7 +444,7 @@ pub struct EmscriptenGlobals {
|
||||
}
|
||||
|
||||
impl EmscriptenGlobals {
|
||||
pub fn new(module: &Module /*, static_bump: u32 */) -> Self {
|
||||
pub fn new(module: &Module /*, static_bump: u32 */) -> Result<Self, String> {
|
||||
let mut use_old_abort_on_cannot_grow_memory = false;
|
||||
for (
|
||||
index,
|
||||
@ -451,8 +466,8 @@ impl EmscriptenGlobals {
|
||||
}
|
||||
}
|
||||
|
||||
let (table_min, table_max) = get_emscripten_table_size(&module);
|
||||
let (memory_min, memory_max, shared) = get_emscripten_memory_size(&module);
|
||||
let (table_min, table_max) = get_emscripten_table_size(&module)?;
|
||||
let (memory_min, memory_max, shared) = get_emscripten_memory_size(&module)?;
|
||||
|
||||
// Memory initialization
|
||||
let memory_type = MemoryDescriptor {
|
||||
@ -481,7 +496,7 @@ impl EmscriptenGlobals {
|
||||
static_top += 16;
|
||||
|
||||
let (dynamic_base, dynamictop_ptr) =
|
||||
get_emscripten_metadata(&module).unwrap_or_else(|| {
|
||||
get_emscripten_metadata(&module)?.unwrap_or_else(|| {
|
||||
let dynamictop_ptr = static_alloc(&mut static_top, 4);
|
||||
(
|
||||
align_memory(align_memory(static_top) + TOTAL_STACK),
|
||||
@ -505,7 +520,7 @@ impl EmscriptenGlobals {
|
||||
}
|
||||
};
|
||||
|
||||
emscripten_set_up_memory(&memory, &data);
|
||||
emscripten_set_up_memory(&memory, &data)?;
|
||||
|
||||
let mut null_func_names = vec![];
|
||||
for (
|
||||
@ -523,14 +538,14 @@ impl EmscriptenGlobals {
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
Ok(Self {
|
||||
data,
|
||||
memory,
|
||||
table,
|
||||
memory_min,
|
||||
memory_max,
|
||||
null_func_names,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ pub fn killpg(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
|
||||
pub fn pathconf(ctx: &mut Ctx, path_ptr: i32, name: i32) -> i32 {
|
||||
debug!("emscripten::pathconf");
|
||||
let path = emscripten_memory_pointer!(ctx.memory(0), path_ptr) as *const i8;
|
||||
unsafe { libc::pathconf(path, name).try_into().unwrap() }
|
||||
unsafe { libc::pathconf(path as *const _, name).try_into().unwrap() }
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
|
@ -71,7 +71,7 @@ pub fn sbrk(ctx: &mut Ctx, increment: i32) -> i32 {
|
||||
debug!("emscripten::sbrk");
|
||||
// let old_dynamic_top = 0;
|
||||
// let new_dynamic_top = 0;
|
||||
let mut globals = get_emscripten_data(ctx).globals;
|
||||
let globals = get_emscripten_data(ctx).globals;
|
||||
let dynamictop_ptr = (globals.dynamictop_ptr) as usize;
|
||||
let old_dynamic_top = ctx.memory(0).view::<u32>()[dynamictop_ptr].get() as i32;
|
||||
let new_dynamic_top: i32 = old_dynamic_top + increment;
|
||||
|
@ -97,7 +97,7 @@ pub fn ___syscall6(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
|
||||
pub fn ___syscall12(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
|
||||
debug!("emscripten::___syscall12 (chdir) {}", _which);
|
||||
let path_ptr = varargs.get_str(ctx);
|
||||
let real_path_owned = get_cstr_path(ctx, path_ptr);
|
||||
let real_path_owned = get_cstr_path(ctx, path_ptr as *const _);
|
||||
let real_path = if let Some(ref rp) = real_path_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
@ -168,13 +168,13 @@ pub fn ___syscall38(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
|
||||
debug!("emscripten::___syscall38 (rename)");
|
||||
let old_path = varargs.get_str(ctx);
|
||||
let new_path = varargs.get_str(ctx);
|
||||
let real_old_path_owned = get_cstr_path(ctx, old_path);
|
||||
let real_old_path_owned = get_cstr_path(ctx, old_path as *const _);
|
||||
let real_old_path = if let Some(ref rp) = real_old_path_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
old_path
|
||||
};
|
||||
let real_new_path_owned = get_cstr_path(ctx, new_path);
|
||||
let real_new_path_owned = get_cstr_path(ctx, new_path as *const _);
|
||||
let real_new_path = if let Some(ref rp) = real_new_path_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
@ -194,7 +194,7 @@ pub fn ___syscall38(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
|
||||
pub fn ___syscall40(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
|
||||
debug!("emscripten::___syscall40 (rmdir)");
|
||||
let pathname_addr = varargs.get_str(ctx);
|
||||
let real_path_owned = get_cstr_path(ctx, pathname_addr);
|
||||
let real_path_owned = get_cstr_path(ctx, pathname_addr as *const _);
|
||||
let real_path = if let Some(ref rp) = real_path_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
@ -359,7 +359,7 @@ pub fn ___syscall183(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32
|
||||
|
||||
let buf_writer = buf_offset.deref(ctx.memory(0), 0, len as u32 + 1).unwrap();
|
||||
for (i, byte) in path_string.bytes().enumerate() {
|
||||
buf_writer[i].set(byte as i8);
|
||||
buf_writer[i].set(byte as _);
|
||||
}
|
||||
buf_writer[len].set(0);
|
||||
buf_offset.offset() as i32
|
||||
@ -535,7 +535,7 @@ pub fn ___syscall195(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
let pathname_addr = varargs.get_str(ctx);
|
||||
let buf: u32 = varargs.get(ctx);
|
||||
|
||||
let real_path_owned = get_cstr_path(ctx, pathname_addr);
|
||||
let real_path_owned = get_cstr_path(ctx, pathname_addr as *const _);
|
||||
let real_path = if let Some(ref rp) = real_path_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
|
@ -146,7 +146,7 @@ pub fn ___syscall5(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
|
||||
let pathname_addr = varargs.get_str(ctx);
|
||||
let flags: i32 = varargs.get(ctx);
|
||||
let mode: u32 = varargs.get(ctx);
|
||||
let real_path_owned = utils::get_cstr_path(ctx, pathname_addr);
|
||||
let real_path_owned = utils::get_cstr_path(ctx, pathname_addr as *const _);
|
||||
let real_path = if let Some(ref rp) = real_path_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
@ -198,13 +198,13 @@ pub fn ___syscall83(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
|
||||
|
||||
let path1 = varargs.get_str(ctx);
|
||||
let path2 = varargs.get_str(ctx);
|
||||
let real_path1_owned = utils::get_cstr_path(ctx, path1);
|
||||
let real_path1_owned = utils::get_cstr_path(ctx, path1 as *const _);
|
||||
let real_path1 = if let Some(ref rp) = real_path1_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
path1
|
||||
};
|
||||
let real_path2_owned = utils::get_cstr_path(ctx, path2);
|
||||
let real_path2_owned = utils::get_cstr_path(ctx, path2 as *const _);
|
||||
let real_path2 = if let Some(ref rp) = real_path2_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
@ -227,7 +227,7 @@ pub fn ___syscall85(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
|
||||
let buf = varargs.get_str(ctx);
|
||||
// let buf_addr: i32 = varargs.get(ctx);
|
||||
let buf_size: i32 = varargs.get(ctx);
|
||||
let real_path_owned = get_cstr_path(ctx, pathname_addr);
|
||||
let real_path_owned = get_cstr_path(ctx, pathname_addr as *const _);
|
||||
let real_path = if let Some(ref rp) = real_path_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
@ -266,7 +266,7 @@ pub fn ___syscall194(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
pub fn ___syscall198(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
|
||||
debug!("emscripten::___syscall198 (lchown) {}", _which);
|
||||
let path_ptr = varargs.get_str(ctx);
|
||||
let real_path_owned = utils::get_cstr_path(ctx, path_ptr);
|
||||
let real_path_owned = utils::get_cstr_path(ctx, path_ptr as *const _);
|
||||
let real_path = if let Some(ref rp) = real_path_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
@ -307,7 +307,7 @@ pub fn ___syscall212(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
debug!("emscripten::___syscall212 (chown) {}", _which);
|
||||
|
||||
let pathname_addr = varargs.get_str(ctx);
|
||||
let real_path_owned = utils::get_cstr_path(ctx, pathname_addr);
|
||||
let real_path_owned = utils::get_cstr_path(ctx, pathname_addr as *const _);
|
||||
let real_path = if let Some(ref rp) = real_path_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
@ -336,7 +336,7 @@ pub fn ___syscall219(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
pub fn ___syscall33(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
|
||||
debug!("emscripten::___syscall33 (access) {}", _which);
|
||||
let path = varargs.get_str(ctx);
|
||||
let real_path_owned = utils::get_cstr_path(ctx, path);
|
||||
let real_path_owned = utils::get_cstr_path(ctx, path as *const _);
|
||||
let real_path = if let Some(ref rp) = real_path_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
@ -364,7 +364,7 @@ pub fn ___syscall34(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
|
||||
pub fn ___syscall39(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
|
||||
debug!("emscripten::___syscall39 (mkdir) {}", _which);
|
||||
let pathname_addr = varargs.get_str(ctx);
|
||||
let real_path_owned = utils::get_cstr_path(ctx, pathname_addr);
|
||||
let real_path_owned = utils::get_cstr_path(ctx, pathname_addr as *const _);
|
||||
let real_path = if let Some(ref rp) = real_path_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
@ -617,13 +617,13 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
unsafe { address_len.deref_mut(ctx.memory(0)).unwrap().get_mut() };
|
||||
// let mut address_len_addr: socklen_t = 0;
|
||||
|
||||
let (fd, host_address) = unsafe {
|
||||
let mut host_address: sockaddr = std::mem::uninitialized();
|
||||
let fd = accept(socket, &mut host_address, address_len_addr);
|
||||
|
||||
(fd, host_address)
|
||||
let mut host_address: sockaddr = sockaddr {
|
||||
sa_family: Default::default(),
|
||||
sa_data: Default::default(),
|
||||
#[cfg(target_os = "macos")]
|
||||
sa_len: Default::default(),
|
||||
};
|
||||
|
||||
let fd = unsafe { accept(socket, &mut host_address, address_len_addr) };
|
||||
let address_addr = unsafe { address.deref_mut(ctx.memory(0)).unwrap().get_mut() };
|
||||
|
||||
address_addr.sa_family = host_address.sa_family as _;
|
||||
@ -651,15 +651,18 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
let address_len_addr =
|
||||
unsafe { address_len.deref_mut(ctx.memory(0)).unwrap().get_mut() };
|
||||
|
||||
let (ret, sock_addr_host) = unsafe {
|
||||
// read host data into new var
|
||||
let mut address: sockaddr = std::mem::uninitialized();
|
||||
let ret = getsockname(
|
||||
let mut sock_addr_host: sockaddr = sockaddr {
|
||||
sa_family: Default::default(),
|
||||
sa_data: Default::default(),
|
||||
#[cfg(target_os = "macos")]
|
||||
sa_len: Default::default(),
|
||||
};
|
||||
let ret = unsafe {
|
||||
getsockname(
|
||||
socket,
|
||||
&mut address as *mut sockaddr,
|
||||
&mut sock_addr_host as *mut sockaddr,
|
||||
address_len_addr as *mut u32,
|
||||
);
|
||||
(ret, address)
|
||||
)
|
||||
};
|
||||
// translate from host data into emscripten data
|
||||
let mut address_mut = unsafe { address.deref_mut(ctx.memory(0)).unwrap().get_mut() };
|
||||
@ -983,7 +986,7 @@ pub fn ___syscall122(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
pub fn ___syscall196(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
|
||||
debug!("emscripten::___syscall196 (lstat64) {}", _which);
|
||||
let path = varargs.get_str(ctx);
|
||||
let real_path_owned = utils::get_cstr_path(ctx, path);
|
||||
let real_path_owned = utils::get_cstr_path(ctx, path as *const _);
|
||||
let real_path = if let Some(ref rp) = real_path_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
@ -1060,7 +1063,7 @@ pub fn ___syscall220(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
|
||||
let upper_bound = std::cmp::min((*dirent).d_reclen, 255) as usize;
|
||||
let mut i = 0;
|
||||
while i < upper_bound {
|
||||
*(dirp.add(pos + 11 + i) as *mut i8) = (*dirent).d_name[i];
|
||||
*(dirp.add(pos + 11 + i) as *mut i8) = (*dirent).d_name[i] as _;
|
||||
i += 1;
|
||||
}
|
||||
// We set the termination string char
|
||||
|
@ -33,29 +33,43 @@ pub fn is_emscripten_module(module: &Module) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn get_emscripten_table_size(module: &Module) -> (u32, Option<u32>) {
|
||||
pub fn get_emscripten_table_size(module: &Module) -> Result<(u32, Option<u32>), String> {
|
||||
if module.info().imported_tables.len() == 0 {
|
||||
return Err("Emscripten requires at least one imported table".to_string());
|
||||
}
|
||||
let (_, table) = &module.info().imported_tables[ImportedTableIndex::new(0)];
|
||||
(table.minimum, table.maximum)
|
||||
Ok((table.minimum, table.maximum))
|
||||
}
|
||||
|
||||
pub fn get_emscripten_memory_size(module: &Module) -> (Pages, Option<Pages>, bool) {
|
||||
pub fn get_emscripten_memory_size(module: &Module) -> Result<(Pages, Option<Pages>, bool), String> {
|
||||
if module.info().imported_memories.len() == 0 {
|
||||
return Err("Emscripten requires at least one imported memory".to_string());
|
||||
}
|
||||
let (_, memory) = &module.info().imported_memories[ImportedMemoryIndex::new(0)];
|
||||
(memory.minimum, memory.maximum, memory.shared)
|
||||
Ok((memory.minimum, memory.maximum, memory.shared))
|
||||
}
|
||||
|
||||
/// Reads values written by `-s EMIT_EMSCRIPTEN_METADATA=1`
|
||||
/// Assumes values start from the end in this order:
|
||||
/// Last export: Dynamic Base
|
||||
/// Second-to-Last export: Dynamic top pointer
|
||||
pub fn get_emscripten_metadata(module: &Module) -> Option<(u32, u32)> {
|
||||
let max_idx = &module.info().globals.iter().map(|(k, _)| k).max()?;
|
||||
let snd_max_idx = &module
|
||||
pub fn get_emscripten_metadata(module: &Module) -> Result<Option<(u32, u32)>, String> {
|
||||
let max_idx = match module.info().globals.iter().map(|(k, _)| k).max() {
|
||||
Some(x) => x,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
let snd_max_idx = match module
|
||||
.info()
|
||||
.globals
|
||||
.iter()
|
||||
.map(|(k, _)| k)
|
||||
.filter(|k| k != max_idx)
|
||||
.max()?;
|
||||
.filter(|k| *k != max_idx)
|
||||
.max()
|
||||
{
|
||||
Some(x) => x,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
use wasmer_runtime_core::types::{GlobalInit, Initializer::Const, Value::I32};
|
||||
if let (
|
||||
@ -68,15 +82,23 @@ pub fn get_emscripten_metadata(module: &Module) -> Option<(u32, u32)> {
|
||||
..
|
||||
},
|
||||
) = (
|
||||
&module.info().globals[*max_idx],
|
||||
&module.info().globals[*snd_max_idx],
|
||||
&module.info().globals[max_idx],
|
||||
&module.info().globals[snd_max_idx],
|
||||
) {
|
||||
Some((
|
||||
align_memory(*dynamic_base as u32 - 32),
|
||||
align_memory(*dynamictop_ptr as u32 - 32),
|
||||
))
|
||||
let dynamic_base = (*dynamic_base as u32).checked_sub(32).ok_or(format!(
|
||||
"emscripten unexpected dynamic_base {}",
|
||||
*dynamic_base as u32
|
||||
))?;
|
||||
let dynamictop_ptr = (*dynamictop_ptr as u32).checked_sub(32).ok_or(format!(
|
||||
"emscripten unexpected dynamictop_ptr {}",
|
||||
*dynamictop_ptr as u32
|
||||
))?;
|
||||
Ok(Some((
|
||||
align_memory(dynamic_base),
|
||||
align_memory(dynamictop_ptr),
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,7 +236,8 @@ pub fn read_string_from_wasm(memory: &Memory, offset: u32) -> String {
|
||||
pub fn get_cstr_path(ctx: &mut Ctx, path: *const i8) -> Option<std::ffi::CString> {
|
||||
use std::collections::VecDeque;
|
||||
|
||||
let path_str = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }.to_string();
|
||||
let path_str =
|
||||
unsafe { std::ffi::CStr::from_ptr(path as *const _).to_str().unwrap() }.to_string();
|
||||
let data = get_emscripten_data(ctx);
|
||||
let path = PathBuf::from(path_str);
|
||||
let mut prefix_added = false;
|
||||
|
@ -5,5 +5,5 @@ authors = ["Heyang Zhou <zhy20000919@hotmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.49"
|
||||
libc = "0.2.60"
|
||||
wasmer-runtime-core = { path = "../runtime-core" }
|
||||
|
@ -75,7 +75,7 @@ impl Loader for KernelLoader {
|
||||
if module.imported_globals.len() > 0 {
|
||||
return Err("imported globals are not supported".into());
|
||||
}
|
||||
let globals: Vec<u64> = unsafe {
|
||||
let globals: Vec<u128> = unsafe {
|
||||
let globals: &[*mut LocalGlobal] =
|
||||
::std::slice::from_raw_parts(ctx.globals, module.globals.len());
|
||||
globals.iter().map(|x| (**x).data).collect()
|
||||
@ -138,11 +138,11 @@ pub struct KernelInstance {
|
||||
|
||||
impl Instance for KernelInstance {
|
||||
type Error = String;
|
||||
fn call(&mut self, id: usize, args: &[Value]) -> Result<u64, String> {
|
||||
fn call(&mut self, id: usize, args: &[Value]) -> Result<u128, String> {
|
||||
if args.len() != self.param_counts[id] {
|
||||
return Err("param count mismatch".into());
|
||||
}
|
||||
let args: Vec<u64> = args.iter().map(|x| x.to_u64()).collect();
|
||||
let args: Vec<u128> = args.iter().map(|x| x.to_u128()).collect();
|
||||
|
||||
let ret = self
|
||||
.context
|
||||
|
@ -54,7 +54,7 @@ struct LoadCodeRequest {
|
||||
memory_max: u32,
|
||||
table: *const TableEntryRequest,
|
||||
table_count: u32,
|
||||
globals: *const u64,
|
||||
globals: *const u128,
|
||||
global_count: u32,
|
||||
|
||||
imported_funcs: *const ImportRequest,
|
||||
@ -67,7 +67,7 @@ struct LoadCodeRequest {
|
||||
#[repr(C)]
|
||||
struct RunCodeRequest {
|
||||
entry_offset: u32,
|
||||
params: *const u64,
|
||||
params: *const u128,
|
||||
param_count: u32,
|
||||
result: *mut RunCodeResult,
|
||||
}
|
||||
@ -75,7 +75,7 @@ struct RunCodeRequest {
|
||||
#[repr(C)]
|
||||
struct RunCodeResult {
|
||||
success: u32,
|
||||
retval: u64,
|
||||
retval: u128,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@ -108,7 +108,7 @@ pub struct LoadProfile<'a> {
|
||||
pub code: &'a [u8],
|
||||
pub memory: Option<&'a [u8]>,
|
||||
pub memory_max: usize,
|
||||
pub globals: &'a [u64],
|
||||
pub globals: &'a [u128],
|
||||
pub imports: &'a [ImportInfo],
|
||||
pub dynamic_sigindices: &'a [u32],
|
||||
pub table: Option<&'a [TableEntryRequest]>,
|
||||
@ -121,7 +121,7 @@ pub struct ImportInfo {
|
||||
|
||||
pub struct RunProfile<'a> {
|
||||
pub entry_offset: u32,
|
||||
pub params: &'a [u64],
|
||||
pub params: &'a [u128],
|
||||
}
|
||||
|
||||
pub struct ServiceContext {
|
||||
@ -181,7 +181,7 @@ impl ServiceContext {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_code(&mut self, run: RunProfile) -> ServiceResult<u64> {
|
||||
pub fn run_code(&mut self, run: RunProfile) -> ServiceResult<u128> {
|
||||
let mut result: RunCodeResult = unsafe { ::std::mem::zeroed() };
|
||||
let mut req = RunCodeRequest {
|
||||
entry_offset: run.entry_offset,
|
||||
|
@ -219,7 +219,7 @@ fn __get_async_io_payload<
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Default, Copy, Clone)]
|
||||
struct SockaddrIn {
|
||||
sin_family: u16, // e.g. AF_INET
|
||||
sin_port: u16, // e.g. htons(3490)
|
||||
@ -315,7 +315,7 @@ impl Tcp4Listener {
|
||||
self.fd,
|
||||
EpollDirection::In,
|
||||
move |fd| -> Result<Arc<TcpStream>, i32> {
|
||||
let mut incoming_sa: SockaddrIn = unsafe { ::std::mem::uninitialized() };
|
||||
let mut incoming_sa: SockaddrIn = SockaddrIn::default();
|
||||
let mut real_len: usize = ::std::mem::size_of::<SockaddrIn>();
|
||||
let conn = unsafe { _accept4(fd, &mut incoming_sa, &mut real_len, O_NONBLOCK) };
|
||||
if conn >= 0 {
|
||||
|
@ -1,29 +1,39 @@
|
||||
[package]
|
||||
name = "wasmer-llvm-backend"
|
||||
version = "0.5.6"
|
||||
authors = ["Lachlan Sneff <lachlan.sneff@gmail.com>"]
|
||||
version = "0.6.0"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
edition = "2018"
|
||||
readme = "README.md"
|
||||
|
||||
[dependencies]
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.5.6" }
|
||||
inkwell = { git = "https://github.com/wasmerio/inkwell", branch = "llvm7-0" }
|
||||
wasmparser = "0.32.1"
|
||||
hashbrown = "0.1.8"
|
||||
smallvec = "0.6.8"
|
||||
goblin = "0.0.20"
|
||||
libc = "0.2.49"
|
||||
nix = "0.14.0"
|
||||
capstone = { version = "0.5.0", optional = true }
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
|
||||
wasmparser = "0.35.1"
|
||||
smallvec = "0.6.10"
|
||||
goblin = "0.0.24"
|
||||
libc = "0.2.60"
|
||||
capstone = { version = "0.6.0", optional = true }
|
||||
|
||||
[dependencies.inkwell]
|
||||
git = "https://github.com/wasmerio/inkwell"
|
||||
branch = "llvm8-0"
|
||||
default-features = false
|
||||
features = ["llvm8-0", "target-x86"]
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
nix = "0.15.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3.7", features = ["memoryapi"] }
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
lazy_static = "1.2.0"
|
||||
regex = "1.1.0"
|
||||
lazy_static = "1.3.0"
|
||||
regex = "1.2.1"
|
||||
semver = "0.9"
|
||||
rustc_version = "0.2.3"
|
||||
|
||||
[dev-dependencies]
|
||||
wabt = "0.7.4"
|
||||
wabt = "0.9.1"
|
||||
|
||||
[features]
|
||||
debug = ["wasmer-runtime-core/debug"]
|
||||
|
@ -28,4 +28,26 @@ Wasmer is a standalone JIT WebAssembly runtime, aiming to be fully
|
||||
compatible with Emscripten, Rust and Go. [Learn
|
||||
more](https://github.com/wasmerio/wasmer).
|
||||
|
||||
This crate represents the LLVM backend.
|
||||
This crate represents the LLVM backend integration for Wasmer.
|
||||
|
||||
## Usage
|
||||
|
||||
### Usage in Wasmer Standalone
|
||||
|
||||
If you are using the `wasmer` CLI, you can specify the backend with:
|
||||
|
||||
```bash
|
||||
wasmer run program.wasm --backend=llvm
|
||||
```
|
||||
|
||||
### Usage in Wasmer Embedded
|
||||
|
||||
If you are using Wasmer Embedded, you can specify
|
||||
the LLVM backend to the [`compile_with` function](https://docs.rs/wasmer-runtime-core/*/wasmer_runtime_core/fn.compile_with.html):
|
||||
|
||||
```rust
|
||||
use wasmer_llvm_backend::LLVMCompiler;
|
||||
|
||||
// ...
|
||||
let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &LLVMCompiler::new());
|
||||
```
|
||||
|
@ -1,5 +1,5 @@
|
||||
//! This file was mostly taken from the llvm-sys crate.
|
||||
//! (https://bitbucket.org/tari/llvm-sys.rs/src/21ab524ec4df1450035df895209c3f8fbeb8775f/build.rs?at=default&fileviewer=file-view-default)
|
||||
//! (https://bitbucket.org/tari/llvm-sys.rs/raw/94361c1083a88f439b9d24c59b2d2831517413d7/build.rs)
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
@ -10,23 +10,54 @@ use std::io::{self, ErrorKind};
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
// Version of the llvm-sys crate that we (through inkwell) depend on.
|
||||
const LLVM_SYS_MAJOR_VERSION: &str = "80";
|
||||
const LLVM_SYS_MINOR_VERSION: &str = "0";
|
||||
|
||||
// Environment variables that can guide compilation
|
||||
//
|
||||
// When adding new ones, they should also be added to main() to force a
|
||||
// rebuild if they are changed.
|
||||
lazy_static! {
|
||||
|
||||
/// A single path to search for LLVM in (containing bin/llvm-config)
|
||||
static ref ENV_LLVM_PREFIX: String =
|
||||
format!("LLVM_SYS_{}_PREFIX", LLVM_SYS_MAJOR_VERSION);
|
||||
|
||||
/// If exactly "YES", ignore the version blacklist
|
||||
static ref ENV_IGNORE_BLACKLIST: String =
|
||||
format!("LLVM_SYS_{}_IGNORE_BLACKLIST", LLVM_SYS_MAJOR_VERSION);
|
||||
|
||||
/// If set, enforce precise correspondence between crate and binary versions.
|
||||
static ref ENV_STRICT_VERSIONING: String =
|
||||
format!("LLVM_SYS_{}_STRICT_VERSIONING", LLVM_SYS_MAJOR_VERSION);
|
||||
|
||||
/// If set, do not attempt to strip irrelevant options for llvm-config --cflags
|
||||
static ref ENV_NO_CLEAN_CXXFLAGS: String =
|
||||
format!("LLVM_SYS_{}_NO_CLEAN_CXXFLAGS", LLVM_SYS_MAJOR_VERSION);
|
||||
|
||||
/// If set and targeting MSVC, force the debug runtime library
|
||||
static ref ENV_USE_DEBUG_MSVCRT: String =
|
||||
format!("LLVM_SYS_{}_USE_DEBUG_MSVCRT", LLVM_SYS_MAJOR_VERSION);
|
||||
|
||||
/// If set, always link against libffi
|
||||
static ref ENV_FORCE_FFI: String =
|
||||
format!("LLVM_SYS_{}_FFI_WORKAROUND", LLVM_SYS_MAJOR_VERSION);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// LLVM version used by this version of the crate.
|
||||
static ref CRATE_VERSION: Version = {
|
||||
let crate_version = Version::parse(env!("CARGO_PKG_VERSION"))
|
||||
.expect("Crate version is somehow not valid semver");
|
||||
Version {
|
||||
major: crate_version.major / 10,
|
||||
minor: crate_version.major % 10,
|
||||
.. crate_version
|
||||
}
|
||||
Version::new(LLVM_SYS_MAJOR_VERSION.parse::<u64>().unwrap() / 10,
|
||||
LLVM_SYS_MINOR_VERSION.parse::<u64>().unwrap() % 10,
|
||||
0)
|
||||
};
|
||||
|
||||
static ref LLVM_CONFIG_BINARY_NAMES: Vec<String> = {
|
||||
vec![
|
||||
"llvm-config".into(),
|
||||
// format!("llvm-config-{}", CRATE_VERSION.major),
|
||||
// format!("llvm-config-{}.{}", CRATE_VERSION.major, CRATE_VERSION.minor),
|
||||
format!("llvm-config-{}", CRATE_VERSION.major),
|
||||
format!("llvm-config-{}.{}", CRATE_VERSION.major, CRATE_VERSION.minor),
|
||||
]
|
||||
};
|
||||
|
||||
@ -41,21 +72,7 @@ lazy_static! {
|
||||
|
||||
// Did the user give us a binary path to use? If yes, try
|
||||
// to use that and fail if it doesn't work.
|
||||
let binary_prefix_var = "LLVM_SYS_70_PREFIX";
|
||||
|
||||
let path = if let Some(path) = env::var_os(&binary_prefix_var) {
|
||||
Some(path.to_str().unwrap().to_owned())
|
||||
} else if let Ok(mut file) = std::fs::File::open(".llvmenv") {
|
||||
use std::io::Read;
|
||||
let mut s = String::new();
|
||||
file.read_to_string(&mut s).unwrap();
|
||||
s.truncate(s.len() - 4);
|
||||
Some(s)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(path) = path {
|
||||
if let Some(path) = env::var_os(&*ENV_LLVM_PREFIX) {
|
||||
for binary_name in LLVM_CONFIG_BINARY_NAMES.iter() {
|
||||
let mut pb: PathBuf = path.clone().into();
|
||||
pb.push("bin");
|
||||
@ -67,7 +84,7 @@ lazy_static! {
|
||||
return pb;
|
||||
} else {
|
||||
println!("LLVM binaries specified by {} are the wrong version.
|
||||
(Found {}, need {}.)", binary_prefix_var, ver, *CRATE_VERSION);
|
||||
(Found {}, need {}.)", *ENV_LLVM_PREFIX, ver, *CRATE_VERSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -79,7 +96,7 @@ lazy_static! {
|
||||
refer to the llvm-sys documentation for more information.
|
||||
|
||||
llvm-sys: https://crates.io/crates/llvm-sys
|
||||
llvmenv: https://crates.io/crates/llvmenv", binary_prefix_var);
|
||||
llvmenv: https://crates.io/crates/llvmenv", *ENV_LLVM_PREFIX);
|
||||
panic!("Could not find a compatible version of LLVM");
|
||||
};
|
||||
}
|
||||
@ -115,15 +132,55 @@ fn locate_system_llvm_config() -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Check whether the given version of LLVM is blacklisted,
|
||||
/// returning `Some(reason)` if it is.
|
||||
fn is_blacklisted_llvm(llvm_version: &Version) -> Option<&'static str> {
|
||||
static BLACKLIST: &'static [(u64, u64, u64, &'static str)] = &[];
|
||||
|
||||
if let Some(x) = env::var_os(&*ENV_IGNORE_BLACKLIST) {
|
||||
if &x == "YES" {
|
||||
println!(
|
||||
"cargo:warning=Ignoring blacklist entry for LLVM {}",
|
||||
llvm_version
|
||||
);
|
||||
return None;
|
||||
} else {
|
||||
println!(
|
||||
"cargo:warning={} is set but not exactly \"YES\"; blacklist is still honored.",
|
||||
*ENV_IGNORE_BLACKLIST
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for &(major, minor, patch, reason) in BLACKLIST.iter() {
|
||||
let bad_version = Version {
|
||||
major: major,
|
||||
minor: minor,
|
||||
patch: patch,
|
||||
pre: vec![],
|
||||
build: vec![],
|
||||
};
|
||||
|
||||
if &bad_version == llvm_version {
|
||||
return Some(reason);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Check whether the given LLVM version is compatible with this version of
|
||||
/// the crate.
|
||||
fn is_compatible_llvm(llvm_version: &Version) -> bool {
|
||||
let strict = env::var_os(format!(
|
||||
"LLVM_SYS_{}_STRICT_VERSIONING",
|
||||
env!("CARGO_PKG_VERSION_MAJOR")
|
||||
))
|
||||
.is_some()
|
||||
|| cfg!(feature = "strict-versioning");
|
||||
if let Some(reason) = is_blacklisted_llvm(llvm_version) {
|
||||
println!(
|
||||
"Found LLVM {}, which is blacklisted: {}",
|
||||
llvm_version, reason
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
let strict =
|
||||
env::var_os(&*ENV_STRICT_VERSIONING).is_some() || cfg!(feature = "strict-versioning");
|
||||
if strict {
|
||||
llvm_version.major == CRATE_VERSION.major && llvm_version.minor == CRATE_VERSION.minor
|
||||
} else {
|
||||
@ -184,11 +241,7 @@ fn get_llvm_cxxflags() -> String {
|
||||
// include flags that aren't understood by the default compiler we're
|
||||
// using. Unless requested otherwise, clean CFLAGS of options that are
|
||||
// known to be possibly-harmful.
|
||||
let no_clean = env::var_os(format!(
|
||||
"LLVM_SYS_{}_NO_CLEAN_CFLAGS",
|
||||
env!("CARGO_PKG_VERSION_MAJOR")
|
||||
))
|
||||
.is_some();
|
||||
let no_clean = env::var_os(&*ENV_NO_CLEAN_CXXFLAGS).is_some();
|
||||
if no_clean || cfg!(target_env = "msvc") {
|
||||
// MSVC doesn't accept -W... options, so don't try to strip them and
|
||||
// possibly strip something that should be retained. Also do nothing if
|
||||
@ -204,20 +257,43 @@ fn get_llvm_cxxflags() -> String {
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
fn is_llvm_debug() -> bool {
|
||||
// Has to be either Debug or Release
|
||||
llvm_config("--build-mode").contains("Debug")
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rustc-link-lib=static=llvm-backend");
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=cpp/object_loader.cpp");
|
||||
println!("cargo:rerun-if-changed=cpp/object_loader.hh");
|
||||
println!("cargo:rerun-if-env-changed={}", &*ENV_LLVM_PREFIX);
|
||||
println!("cargo:rerun-if-env-changed={}", &*ENV_IGNORE_BLACKLIST);
|
||||
println!("cargo:rerun-if-env-changed={}", &*ENV_STRICT_VERSIONING);
|
||||
println!("cargo:rerun-if-env-changed={}", &*ENV_NO_CLEAN_CXXFLAGS);
|
||||
println!("cargo:rerun-if-env-changed={}", &*ENV_USE_DEBUG_MSVCRT);
|
||||
println!("cargo:rerun-if-env-changed={}", &*ENV_FORCE_FFI);
|
||||
|
||||
std::env::set_var("CXXFLAGS", get_llvm_cxxflags());
|
||||
cc::Build::new()
|
||||
.cpp(true)
|
||||
.file("cpp/object_loader.cpp")
|
||||
.compile("llvm-backend");
|
||||
|
||||
println!("cargo:rustc-link-lib=static=llvm-backend");
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=cpp/object_loader.cpp");
|
||||
println!("cargo:rerun-if-changed=cpp/object_loader.hh");
|
||||
|
||||
// Enable "nightly" cfg if the current compiler is nightly.
|
||||
if rustc_version::version_meta().unwrap().channel == rustc_version::Channel::Nightly {
|
||||
println!("cargo:rustc-cfg=nightly");
|
||||
}
|
||||
|
||||
let use_debug_msvcrt = env::var_os(&*ENV_USE_DEBUG_MSVCRT).is_some();
|
||||
if cfg!(target_env = "msvc") && (use_debug_msvcrt || is_llvm_debug()) {
|
||||
println!("cargo:rustc-link-lib={}", "msvcrtd");
|
||||
}
|
||||
|
||||
// Link libffi if the user requested this workaround.
|
||||
// See https://bitbucket.org/tari/llvm-sys.rs/issues/12/
|
||||
let force_ffi = env::var_os(&*ENV_FORCE_FFI).is_some();
|
||||
if force_ffi {
|
||||
println!("cargo:rustc-link-lib=dylib={}", "ffi");
|
||||
}
|
||||
}
|
||||
|
@ -7,198 +7,214 @@ extern "C" void __deregister_frame(uint8_t *);
|
||||
|
||||
struct MemoryManager : llvm::RuntimeDyld::MemoryManager {
|
||||
public:
|
||||
MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {}
|
||||
MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {}
|
||||
|
||||
virtual ~MemoryManager() override {
|
||||
deregisterEHFrames();
|
||||
// Deallocate all of the allocated memory.
|
||||
callbacks.dealloc_memory(code_section.base, code_section.size);
|
||||
callbacks.dealloc_memory(read_section.base, read_section.size);
|
||||
callbacks.dealloc_memory(readwrite_section.base, readwrite_section.size);
|
||||
virtual ~MemoryManager() override {
|
||||
deregisterEHFrames();
|
||||
// Deallocate all of the allocated memory.
|
||||
callbacks.dealloc_memory(code_section.base, code_section.size);
|
||||
callbacks.dealloc_memory(read_section.base, read_section.size);
|
||||
callbacks.dealloc_memory(readwrite_section.base, readwrite_section.size);
|
||||
}
|
||||
|
||||
virtual uint8_t *allocateCodeSection(uintptr_t size, unsigned alignment,
|
||||
unsigned section_id,
|
||||
llvm::StringRef section_name) override {
|
||||
return allocate_bump(code_section, code_bump_ptr, size, alignment);
|
||||
}
|
||||
|
||||
virtual uint8_t *allocateDataSection(uintptr_t size, unsigned alignment,
|
||||
unsigned section_id,
|
||||
llvm::StringRef section_name,
|
||||
bool read_only) override {
|
||||
// Allocate from the read-only section or the read-write section, depending
|
||||
// on if this allocation should be read-only or not.
|
||||
if (read_only) {
|
||||
return allocate_bump(read_section, read_bump_ptr, size, alignment);
|
||||
} else {
|
||||
return allocate_bump(readwrite_section, readwrite_bump_ptr, size,
|
||||
alignment);
|
||||
}
|
||||
}
|
||||
|
||||
virtual uint8_t* allocateCodeSection(uintptr_t size, unsigned alignment, unsigned section_id, llvm::StringRef section_name) override {
|
||||
return allocate_bump(code_section, code_bump_ptr, size, alignment);
|
||||
}
|
||||
|
||||
virtual uint8_t* allocateDataSection(uintptr_t size, unsigned alignment, unsigned section_id, llvm::StringRef section_name, bool read_only) override {
|
||||
// Allocate from the read-only section or the read-write section, depending on if this allocation
|
||||
// should be read-only or not.
|
||||
if (read_only) {
|
||||
return allocate_bump(read_section, read_bump_ptr, size, alignment);
|
||||
} else {
|
||||
return allocate_bump(readwrite_section, readwrite_bump_ptr, size, alignment);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void reserveAllocationSpace(
|
||||
uintptr_t code_size,
|
||||
uint32_t code_align,
|
||||
uintptr_t read_data_size,
|
||||
uint32_t read_data_align,
|
||||
uintptr_t read_write_data_size,
|
||||
uint32_t read_write_data_align
|
||||
) override {
|
||||
auto aligner = [](uintptr_t ptr, size_t align) {
|
||||
if (ptr == 0) {
|
||||
return align;
|
||||
}
|
||||
return (ptr + align - 1) & ~(align - 1);
|
||||
};
|
||||
|
||||
|
||||
uint8_t *code_ptr_out = nullptr;
|
||||
size_t code_size_out = 0;
|
||||
auto code_result = callbacks.alloc_memory(aligner(code_size, 4096), PROTECT_READ_WRITE, &code_ptr_out, &code_size_out);
|
||||
assert(code_result == RESULT_OK);
|
||||
code_section = Section { code_ptr_out, code_size_out };
|
||||
code_bump_ptr = (uintptr_t)code_ptr_out;
|
||||
|
||||
uint8_t *read_ptr_out = nullptr;
|
||||
size_t read_size_out = 0;
|
||||
auto read_result = callbacks.alloc_memory(aligner(read_data_size, 4096), PROTECT_READ_WRITE, &read_ptr_out, &read_size_out);
|
||||
assert(read_result == RESULT_OK);
|
||||
read_section = Section { read_ptr_out, read_size_out };
|
||||
read_bump_ptr = (uintptr_t)read_ptr_out;
|
||||
|
||||
uint8_t *readwrite_ptr_out = nullptr;
|
||||
size_t readwrite_size_out = 0;
|
||||
auto readwrite_result = callbacks.alloc_memory(aligner(read_write_data_size, 4096), PROTECT_READ_WRITE, &readwrite_ptr_out, &readwrite_size_out);
|
||||
assert(readwrite_result == RESULT_OK);
|
||||
readwrite_section = Section { readwrite_ptr_out, readwrite_size_out };
|
||||
readwrite_bump_ptr = (uintptr_t)readwrite_ptr_out;
|
||||
}
|
||||
|
||||
/* Turn on the `reserveAllocationSpace` callback. */
|
||||
virtual bool needsToReserveAllocationSpace() override {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void registerEHFrames(uint8_t* addr, uint64_t LoadAddr, size_t size) override {
|
||||
eh_frame_ptr = addr;
|
||||
eh_frame_size = size;
|
||||
eh_frames_registered = true;
|
||||
callbacks.visit_fde(addr, size, __register_frame);
|
||||
}
|
||||
|
||||
virtual void deregisterEHFrames() override {
|
||||
if (eh_frames_registered) {
|
||||
callbacks.visit_fde(eh_frame_ptr, eh_frame_size, __deregister_frame);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override {
|
||||
auto code_result = callbacks.protect_memory(code_section.base, code_section.size, mem_protect_t::PROTECT_READ_EXECUTE);
|
||||
if (code_result != RESULT_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto read_result = callbacks.protect_memory(read_section.base, read_section.size, mem_protect_t::PROTECT_READ);
|
||||
if (read_result != RESULT_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The readwrite section is already mapped as read-write.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void notifyObjectLoaded(llvm::RuntimeDyld &RTDyld, const llvm::object::ObjectFile &Obj) override {}
|
||||
private:
|
||||
struct Section {
|
||||
uint8_t* base;
|
||||
size_t size;
|
||||
virtual void reserveAllocationSpace(uintptr_t code_size, uint32_t code_align,
|
||||
uintptr_t read_data_size,
|
||||
uint32_t read_data_align,
|
||||
uintptr_t read_write_data_size,
|
||||
uint32_t read_write_data_align) override {
|
||||
auto aligner = [](uintptr_t ptr, size_t align) {
|
||||
if (ptr == 0) {
|
||||
return align;
|
||||
}
|
||||
return (ptr + align - 1) & ~(align - 1);
|
||||
};
|
||||
|
||||
uint8_t* allocate_bump(Section& section, uintptr_t& bump_ptr, size_t size, size_t align) {
|
||||
auto aligner = [](uintptr_t& ptr, size_t align) {
|
||||
ptr = (ptr + align - 1) & ~(align - 1);
|
||||
};
|
||||
uint8_t *code_ptr_out = nullptr;
|
||||
size_t code_size_out = 0;
|
||||
auto code_result =
|
||||
callbacks.alloc_memory(aligner(code_size, 4096), PROTECT_READ_WRITE,
|
||||
&code_ptr_out, &code_size_out);
|
||||
assert(code_result == RESULT_OK);
|
||||
code_section = Section{code_ptr_out, code_size_out};
|
||||
code_bump_ptr = (uintptr_t)code_ptr_out;
|
||||
|
||||
// Align the bump pointer to the requires alignment.
|
||||
aligner(bump_ptr, align);
|
||||
uint8_t *read_ptr_out = nullptr;
|
||||
size_t read_size_out = 0;
|
||||
auto read_result = callbacks.alloc_memory(aligner(read_data_size, 4096),
|
||||
PROTECT_READ_WRITE, &read_ptr_out,
|
||||
&read_size_out);
|
||||
assert(read_result == RESULT_OK);
|
||||
read_section = Section{read_ptr_out, read_size_out};
|
||||
read_bump_ptr = (uintptr_t)read_ptr_out;
|
||||
|
||||
auto ret_ptr = bump_ptr;
|
||||
bump_ptr += size;
|
||||
uint8_t *readwrite_ptr_out = nullptr;
|
||||
size_t readwrite_size_out = 0;
|
||||
auto readwrite_result = callbacks.alloc_memory(
|
||||
aligner(read_write_data_size, 4096), PROTECT_READ_WRITE,
|
||||
&readwrite_ptr_out, &readwrite_size_out);
|
||||
assert(readwrite_result == RESULT_OK);
|
||||
readwrite_section = Section{readwrite_ptr_out, readwrite_size_out};
|
||||
readwrite_bump_ptr = (uintptr_t)readwrite_ptr_out;
|
||||
}
|
||||
|
||||
assert(bump_ptr <= (uintptr_t)section.base + section.size);
|
||||
/* Turn on the `reserveAllocationSpace` callback. */
|
||||
virtual bool needsToReserveAllocationSpace() override { return true; }
|
||||
|
||||
return (uint8_t*)ret_ptr;
|
||||
virtual void registerEHFrames(uint8_t *addr, uint64_t LoadAddr,
|
||||
size_t size) override {
|
||||
// We don't know yet how to do this on Windows, so we hide this on compilation
|
||||
// so we can compile and pass spectests on unix systems
|
||||
#ifndef _WIN32
|
||||
eh_frame_ptr = addr;
|
||||
eh_frame_size = size;
|
||||
eh_frames_registered = true;
|
||||
callbacks.visit_fde(addr, size, __register_frame);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void deregisterEHFrames() override {
|
||||
// We don't know yet how to do this on Windows, so we hide this on compilation
|
||||
// so we can compile and pass spectests on unix systems
|
||||
#ifndef _WIN32
|
||||
if (eh_frames_registered) {
|
||||
callbacks.visit_fde(eh_frame_ptr, eh_frame_size, __deregister_frame);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override {
|
||||
auto code_result =
|
||||
callbacks.protect_memory(code_section.base, code_section.size,
|
||||
mem_protect_t::PROTECT_READ_EXECUTE);
|
||||
if (code_result != RESULT_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Section code_section, read_section, readwrite_section;
|
||||
uintptr_t code_bump_ptr, read_bump_ptr, readwrite_bump_ptr;
|
||||
uint8_t* eh_frame_ptr;
|
||||
size_t eh_frame_size;
|
||||
bool eh_frames_registered = false;
|
||||
auto read_result = callbacks.protect_memory(
|
||||
read_section.base, read_section.size, mem_protect_t::PROTECT_READ);
|
||||
if (read_result != RESULT_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
callbacks_t callbacks;
|
||||
// The readwrite section is already mapped as read-write.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void
|
||||
notifyObjectLoaded(llvm::RuntimeDyld &RTDyld,
|
||||
const llvm::object::ObjectFile &Obj) override {}
|
||||
|
||||
private:
|
||||
struct Section {
|
||||
uint8_t *base;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
uint8_t *allocate_bump(Section §ion, uintptr_t &bump_ptr, size_t size,
|
||||
size_t align) {
|
||||
auto aligner = [](uintptr_t &ptr, size_t align) {
|
||||
ptr = (ptr + align - 1) & ~(align - 1);
|
||||
};
|
||||
|
||||
// Align the bump pointer to the requires alignment.
|
||||
aligner(bump_ptr, align);
|
||||
|
||||
auto ret_ptr = bump_ptr;
|
||||
bump_ptr += size;
|
||||
|
||||
assert(bump_ptr <= (uintptr_t)section.base + section.size);
|
||||
|
||||
return (uint8_t *)ret_ptr;
|
||||
}
|
||||
|
||||
Section code_section, read_section, readwrite_section;
|
||||
uintptr_t code_bump_ptr, read_bump_ptr, readwrite_bump_ptr;
|
||||
uint8_t *eh_frame_ptr;
|
||||
size_t eh_frame_size;
|
||||
bool eh_frames_registered = false;
|
||||
|
||||
callbacks_t callbacks;
|
||||
};
|
||||
|
||||
struct SymbolLookup : llvm::JITSymbolResolver {
|
||||
public:
|
||||
SymbolLookup(callbacks_t callbacks) : callbacks(callbacks) {}
|
||||
SymbolLookup(callbacks_t callbacks) : callbacks(callbacks) {}
|
||||
|
||||
virtual llvm::Expected<LookupResult> lookup(const LookupSet& symbols) override {
|
||||
LookupResult result;
|
||||
void lookup(const LookupSet &symbols, OnResolvedFunction OnResolved) {
|
||||
LookupResult result;
|
||||
|
||||
for (auto symbol : symbols) {
|
||||
result.emplace(symbol, symbol_lookup(symbol));
|
||||
}
|
||||
|
||||
return result;
|
||||
for (auto symbol : symbols) {
|
||||
result.emplace(symbol, symbol_lookup(symbol));
|
||||
}
|
||||
|
||||
virtual llvm::Expected<LookupFlagsResult> lookupFlags(const LookupSet& symbols) override {
|
||||
LookupFlagsResult result;
|
||||
OnResolved(result);
|
||||
}
|
||||
|
||||
for (auto symbol : symbols) {
|
||||
result.emplace(symbol, symbol_lookup(symbol).getFlags());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
llvm::Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) {
|
||||
const std::set<llvm::StringRef> empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::JITEvaluatedSymbol symbol_lookup(llvm::StringRef name) {
|
||||
uint64_t addr = callbacks.lookup_vm_symbol(name.data(), name.size());
|
||||
llvm::JITEvaluatedSymbol symbol_lookup(llvm::StringRef name) {
|
||||
uint64_t addr = callbacks.lookup_vm_symbol(name.data(), name.size());
|
||||
|
||||
return llvm::JITEvaluatedSymbol(addr, llvm::JITSymbolFlags::None);
|
||||
}
|
||||
return llvm::JITEvaluatedSymbol(addr, llvm::JITSymbolFlags::None);
|
||||
}
|
||||
|
||||
callbacks_t callbacks;
|
||||
callbacks_t callbacks;
|
||||
};
|
||||
|
||||
WasmModule::WasmModule(
|
||||
const uint8_t *object_start,
|
||||
size_t object_size,
|
||||
callbacks_t callbacks
|
||||
) : memory_manager(std::unique_ptr<MemoryManager>(new MemoryManager(callbacks)))
|
||||
{
|
||||
|
||||
WasmModule::WasmModule(const uint8_t *object_start, size_t object_size,
|
||||
callbacks_t callbacks)
|
||||
: memory_manager(
|
||||
std::unique_ptr<MemoryManager>(new MemoryManager(callbacks))) {
|
||||
|
||||
if (auto created_object_file = llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef(
|
||||
llvm::StringRef((const char *)object_start, object_size), "object"
|
||||
))) {
|
||||
object_file = cantFail(std::move(created_object_file));
|
||||
SymbolLookup symbol_resolver(callbacks);
|
||||
runtime_dyld = std::unique_ptr<llvm::RuntimeDyld>(new llvm::RuntimeDyld(*memory_manager, symbol_resolver));
|
||||
if (auto created_object_file =
|
||||
llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef(
|
||||
llvm::StringRef((const char *)object_start, object_size),
|
||||
"object"))) {
|
||||
object_file = cantFail(std::move(created_object_file));
|
||||
SymbolLookup symbol_resolver(callbacks);
|
||||
runtime_dyld = std::unique_ptr<llvm::RuntimeDyld>(
|
||||
new llvm::RuntimeDyld(*memory_manager, symbol_resolver));
|
||||
|
||||
runtime_dyld->setProcessAllSections(true);
|
||||
runtime_dyld->setProcessAllSections(true);
|
||||
|
||||
runtime_dyld->loadObject(*object_file);
|
||||
runtime_dyld->finalizeWithMemoryManagerLocking();
|
||||
runtime_dyld->loadObject(*object_file);
|
||||
runtime_dyld->finalizeWithMemoryManagerLocking();
|
||||
|
||||
if (runtime_dyld->hasError()) {
|
||||
_init_failed = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
_init_failed = true;
|
||||
if (runtime_dyld->hasError()) {
|
||||
_init_failed = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
_init_failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void* WasmModule::get_func(llvm::StringRef name) const {
|
||||
auto symbol = runtime_dyld->getSymbol(name);
|
||||
return (void*)symbol.getAddress();
|
||||
}
|
||||
void *WasmModule::get_func(llvm::StringRef name) const {
|
||||
auto symbol = runtime_dyld->getSymbol(name);
|
||||
return (void *)symbol.getAddress();
|
||||
}
|
||||
|
@ -1,236 +1,220 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <llvm/ExecutionEngine/RuntimeDyld.h>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <exception>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PROTECT_NONE,
|
||||
PROTECT_READ,
|
||||
PROTECT_READ_WRITE,
|
||||
PROTECT_READ_EXECUTE,
|
||||
#include <llvm/ExecutionEngine/RuntimeDyld.h>
|
||||
|
||||
typedef enum {
|
||||
PROTECT_NONE,
|
||||
PROTECT_READ,
|
||||
PROTECT_READ_WRITE,
|
||||
PROTECT_READ_EXECUTE,
|
||||
} mem_protect_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RESULT_OK,
|
||||
RESULT_ALLOCATE_FAILURE,
|
||||
RESULT_PROTECT_FAILURE,
|
||||
RESULT_DEALLOC_FAILURE,
|
||||
RESULT_OBJECT_LOAD_FAILURE,
|
||||
typedef enum {
|
||||
RESULT_OK,
|
||||
RESULT_ALLOCATE_FAILURE,
|
||||
RESULT_PROTECT_FAILURE,
|
||||
RESULT_DEALLOC_FAILURE,
|
||||
RESULT_OBJECT_LOAD_FAILURE,
|
||||
} result_t;
|
||||
|
||||
typedef result_t (*alloc_memory_t)(size_t size, mem_protect_t protect, uint8_t **ptr_out, size_t *size_out);
|
||||
typedef result_t (*protect_memory_t)(uint8_t *ptr, size_t size, mem_protect_t protect);
|
||||
typedef result_t (*alloc_memory_t)(size_t size, mem_protect_t protect,
|
||||
uint8_t **ptr_out, size_t *size_out);
|
||||
typedef result_t (*protect_memory_t)(uint8_t *ptr, size_t size,
|
||||
mem_protect_t protect);
|
||||
typedef result_t (*dealloc_memory_t)(uint8_t *ptr, size_t size);
|
||||
typedef uintptr_t (*lookup_vm_symbol_t)(const char *name_ptr, size_t length);
|
||||
typedef void (*fde_visitor_t)(uint8_t *fde);
|
||||
typedef result_t (*visit_fde_t)(uint8_t *fde, size_t size, fde_visitor_t visitor);
|
||||
typedef result_t (*visit_fde_t)(uint8_t *fde, size_t size,
|
||||
fde_visitor_t visitor);
|
||||
|
||||
typedef void (*trampoline_t)(void *, void *, void *, void *);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Memory management. */
|
||||
alloc_memory_t alloc_memory;
|
||||
protect_memory_t protect_memory;
|
||||
dealloc_memory_t dealloc_memory;
|
||||
typedef struct {
|
||||
/* Memory management. */
|
||||
alloc_memory_t alloc_memory;
|
||||
protect_memory_t protect_memory;
|
||||
dealloc_memory_t dealloc_memory;
|
||||
|
||||
lookup_vm_symbol_t lookup_vm_symbol;
|
||||
lookup_vm_symbol_t lookup_vm_symbol;
|
||||
|
||||
visit_fde_t visit_fde;
|
||||
visit_fde_t visit_fde;
|
||||
} callbacks_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t data, vtable;
|
||||
typedef struct {
|
||||
size_t data, vtable;
|
||||
} box_any_t;
|
||||
|
||||
struct WasmException
|
||||
{
|
||||
public:
|
||||
virtual std::string description() const noexcept = 0;
|
||||
struct WasmException {
|
||||
public:
|
||||
virtual std::string description() const noexcept = 0;
|
||||
};
|
||||
|
||||
struct UncatchableException : WasmException
|
||||
{
|
||||
public:
|
||||
virtual std::string description() const noexcept override
|
||||
{
|
||||
return "Uncatchable exception";
|
||||
}
|
||||
struct UncatchableException : WasmException {
|
||||
public:
|
||||
virtual std::string description() const noexcept override {
|
||||
return "Uncatchable exception";
|
||||
}
|
||||
};
|
||||
|
||||
struct UserException : UncatchableException
|
||||
{
|
||||
public:
|
||||
UserException(size_t data, size_t vtable) : error_data({ data, vtable }) {}
|
||||
struct UserException : UncatchableException {
|
||||
public:
|
||||
UserException(size_t data, size_t vtable) : error_data({data, vtable}) {}
|
||||
|
||||
virtual std::string description() const noexcept override
|
||||
{
|
||||
return "user exception";
|
||||
}
|
||||
virtual std::string description() const noexcept override {
|
||||
return "user exception";
|
||||
}
|
||||
|
||||
// The parts of a `Box<dyn Any>`.
|
||||
box_any_t error_data;
|
||||
// The parts of a `Box<dyn Any>`.
|
||||
box_any_t error_data;
|
||||
};
|
||||
|
||||
struct WasmTrap : UncatchableException
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
Unreachable = 0,
|
||||
IncorrectCallIndirectSignature = 1,
|
||||
MemoryOutOfBounds = 2,
|
||||
CallIndirectOOB = 3,
|
||||
IllegalArithmetic = 4,
|
||||
Unknown,
|
||||
};
|
||||
struct BreakpointException : UncatchableException {
|
||||
public:
|
||||
BreakpointException(uintptr_t callback) : callback(callback) {}
|
||||
|
||||
WasmTrap(Type type) : type(type) {}
|
||||
virtual std::string description() const noexcept override {
|
||||
return "breakpoint exception";
|
||||
}
|
||||
|
||||
virtual std::string description() const noexcept override
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss
|
||||
<< "WebAssembly trap:" << '\n'
|
||||
<< " - type: " << type << '\n';
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
Type type;
|
||||
|
||||
private:
|
||||
friend std::ostream &operator<<(std::ostream &out, const Type &ty)
|
||||
{
|
||||
switch (ty)
|
||||
{
|
||||
case Type::Unreachable:
|
||||
out << "unreachable";
|
||||
break;
|
||||
case Type::IncorrectCallIndirectSignature:
|
||||
out << "incorrect call_indirect signature";
|
||||
break;
|
||||
case Type::MemoryOutOfBounds:
|
||||
out << "memory access out-of-bounds";
|
||||
break;
|
||||
case Type::CallIndirectOOB:
|
||||
out << "call_indirect out-of-bounds";
|
||||
break;
|
||||
case Type::IllegalArithmetic:
|
||||
out << "illegal arithmetic operation";
|
||||
break;
|
||||
case Type::Unknown:
|
||||
default:
|
||||
out << "unknown";
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
uintptr_t callback;
|
||||
};
|
||||
|
||||
struct CatchableException : WasmException
|
||||
{
|
||||
public:
|
||||
CatchableException(uint32_t type_id, uint32_t value_num) : type_id(type_id), value_num(value_num) {}
|
||||
struct WasmTrap : UncatchableException {
|
||||
public:
|
||||
enum Type {
|
||||
Unreachable = 0,
|
||||
IncorrectCallIndirectSignature = 1,
|
||||
MemoryOutOfBounds = 2,
|
||||
CallIndirectOOB = 3,
|
||||
IllegalArithmetic = 4,
|
||||
Unknown,
|
||||
};
|
||||
|
||||
virtual std::string description() const noexcept override
|
||||
{
|
||||
return "catchable exception";
|
||||
WasmTrap(Type type) : type(type) {}
|
||||
|
||||
virtual std::string description() const noexcept override {
|
||||
std::ostringstream ss;
|
||||
ss << "WebAssembly trap:" << '\n' << " - type: " << type << '\n';
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
Type type;
|
||||
|
||||
private:
|
||||
friend std::ostream &operator<<(std::ostream &out, const Type &ty) {
|
||||
switch (ty) {
|
||||
case Type::Unreachable:
|
||||
out << "unreachable";
|
||||
break;
|
||||
case Type::IncorrectCallIndirectSignature:
|
||||
out << "incorrect call_indirect signature";
|
||||
break;
|
||||
case Type::MemoryOutOfBounds:
|
||||
out << "memory access out-of-bounds";
|
||||
break;
|
||||
case Type::CallIndirectOOB:
|
||||
out << "call_indirect out-of-bounds";
|
||||
break;
|
||||
case Type::IllegalArithmetic:
|
||||
out << "illegal arithmetic operation";
|
||||
break;
|
||||
case Type::Unknown:
|
||||
default:
|
||||
out << "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t type_id, value_num;
|
||||
uint64_t values[1];
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
struct WasmModule
|
||||
{
|
||||
public:
|
||||
WasmModule(
|
||||
const uint8_t *object_start,
|
||||
size_t object_size,
|
||||
callbacks_t callbacks);
|
||||
struct CatchableException : WasmException {
|
||||
public:
|
||||
CatchableException(uint32_t type_id, uint32_t value_num)
|
||||
: type_id(type_id), value_num(value_num) {}
|
||||
|
||||
void *get_func(llvm::StringRef name) const;
|
||||
virtual std::string description() const noexcept override {
|
||||
return "catchable exception";
|
||||
}
|
||||
|
||||
bool _init_failed = false;
|
||||
private:
|
||||
std::unique_ptr<llvm::RuntimeDyld::MemoryManager> memory_manager;
|
||||
std::unique_ptr<llvm::object::ObjectFile> object_file;
|
||||
std::unique_ptr<llvm::RuntimeDyld> runtime_dyld;
|
||||
uint32_t type_id, value_num;
|
||||
uint64_t values[1];
|
||||
};
|
||||
|
||||
extern "C"
|
||||
{
|
||||
result_t module_load(const uint8_t *mem_ptr, size_t mem_size, callbacks_t callbacks, WasmModule **module_out)
|
||||
{
|
||||
*module_out = new WasmModule(mem_ptr, mem_size, callbacks);
|
||||
struct WasmModule {
|
||||
public:
|
||||
WasmModule(const uint8_t *object_start, size_t object_size,
|
||||
callbacks_t callbacks);
|
||||
|
||||
if ((*module_out)->_init_failed) {
|
||||
return RESULT_OBJECT_LOAD_FAILURE;
|
||||
}
|
||||
void *get_func(llvm::StringRef name) const;
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
bool _init_failed = false;
|
||||
|
||||
[[noreturn]] void throw_trap(WasmTrap::Type ty) {
|
||||
throw WasmTrap(ty);
|
||||
}
|
||||
private:
|
||||
std::unique_ptr<llvm::RuntimeDyld::MemoryManager> memory_manager;
|
||||
std::unique_ptr<llvm::object::ObjectFile> object_file;
|
||||
std::unique_ptr<llvm::RuntimeDyld> runtime_dyld;
|
||||
};
|
||||
|
||||
void module_delete(WasmModule *module)
|
||||
{
|
||||
delete module;
|
||||
}
|
||||
extern "C" {
|
||||
void callback_trampoline(void *, void *);
|
||||
|
||||
// Throw a fat pointer that's assumed to be `*mut dyn Any` on the rust
|
||||
// side.
|
||||
[[noreturn]] void throw_any(size_t data, size_t vtable) {
|
||||
throw UserException(data, vtable);
|
||||
}
|
||||
result_t module_load(const uint8_t *mem_ptr, size_t mem_size,
|
||||
callbacks_t callbacks, WasmModule **module_out) {
|
||||
*module_out = new WasmModule(mem_ptr, mem_size, callbacks);
|
||||
|
||||
bool invoke_trampoline(
|
||||
trampoline_t trampoline,
|
||||
void *ctx,
|
||||
void *func,
|
||||
void *params,
|
||||
void *results,
|
||||
WasmTrap::Type *trap_out,
|
||||
box_any_t *user_error,
|
||||
void *invoke_env) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
trampoline(ctx, func, params, results);
|
||||
return true;
|
||||
}
|
||||
catch (const WasmTrap &e)
|
||||
{
|
||||
*trap_out = e.type;
|
||||
return false;
|
||||
}
|
||||
catch (const UserException &e)
|
||||
{
|
||||
*user_error = e.error_data;
|
||||
return false;
|
||||
}
|
||||
catch (const WasmException &e)
|
||||
{
|
||||
*trap_out = WasmTrap::Type::Unknown;
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
*trap_out = WasmTrap::Type::Unknown;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((*module_out)->_init_failed) {
|
||||
return RESULT_OBJECT_LOAD_FAILURE;
|
||||
}
|
||||
|
||||
void *get_func_symbol(WasmModule *module, const char *name)
|
||||
{
|
||||
return module->get_func(llvm::StringRef(name));
|
||||
}
|
||||
}
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
[[noreturn]] void throw_trap(WasmTrap::Type ty) { throw WasmTrap(ty); }
|
||||
|
||||
void module_delete(WasmModule *module) { delete module; }
|
||||
|
||||
// Throw a fat pointer that's assumed to be `*mut dyn Any` on the rust
|
||||
// side.
|
||||
[[noreturn]] void throw_any(size_t data, size_t vtable) {
|
||||
throw UserException(data, vtable);
|
||||
}
|
||||
|
||||
// Throw a pointer that's assumed to be codegen::BreakpointHandler on the
|
||||
// rust side.
|
||||
[[noreturn]] void throw_breakpoint(uintptr_t callback) {
|
||||
throw BreakpointException(callback);
|
||||
}
|
||||
|
||||
bool invoke_trampoline(trampoline_t trampoline, void *ctx, void *func,
|
||||
void *params, void *results, WasmTrap::Type *trap_out,
|
||||
box_any_t *user_error, void *invoke_env) noexcept {
|
||||
try {
|
||||
trampoline(ctx, func, params, results);
|
||||
return true;
|
||||
} catch (const WasmTrap &e) {
|
||||
*trap_out = e.type;
|
||||
return false;
|
||||
} catch (const UserException &e) {
|
||||
*user_error = e.error_data;
|
||||
return false;
|
||||
} catch (const BreakpointException &e) {
|
||||
callback_trampoline(user_error, (void *)e.callback);
|
||||
return false;
|
||||
} catch (const WasmException &e) {
|
||||
*trap_out = WasmTrap::Type::Unknown;
|
||||
return false;
|
||||
} catch (...) {
|
||||
*trap_out = WasmTrap::Type::Unknown;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void *get_func_symbol(WasmModule *module, const char *name) {
|
||||
return module->get_func(llvm::StringRef(name));
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
use crate::intrinsics::Intrinsics;
|
||||
use crate::structs::{Callbacks, LLVMModule, LLVMResult, MemProtect};
|
||||
use inkwell::{
|
||||
memory_buffer::MemoryBuffer,
|
||||
module::Module,
|
||||
targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine},
|
||||
OptimizationLevel,
|
||||
};
|
||||
use libc::{
|
||||
c_char, mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE, PROT_READ,
|
||||
PROT_WRITE,
|
||||
};
|
||||
use libc::c_char;
|
||||
use std::{
|
||||
any::Any,
|
||||
ffi::{c_void, CString},
|
||||
fs::File,
|
||||
io::Write,
|
||||
mem,
|
||||
ops::Deref,
|
||||
ptr::{self, NonNull},
|
||||
@ -31,42 +31,6 @@ use wasmer_runtime_core::{
|
||||
vm, vmcalls,
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
struct LLVMModule {
|
||||
_private: [u8; 0],
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
enum MemProtect {
|
||||
NONE,
|
||||
READ,
|
||||
READ_WRITE,
|
||||
READ_EXECUTE,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
enum LLVMResult {
|
||||
OK,
|
||||
ALLOCATE_FAILURE,
|
||||
PROTECT_FAILURE,
|
||||
DEALLOC_FAILURE,
|
||||
OBJECT_LOAD_FAILURE,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Callbacks {
|
||||
alloc_memory: extern "C" fn(usize, MemProtect, &mut *mut u8, &mut usize) -> LLVMResult,
|
||||
protect_memory: extern "C" fn(*mut u8, usize, MemProtect) -> LLVMResult,
|
||||
dealloc_memory: extern "C" fn(*mut u8, usize) -> LLVMResult,
|
||||
|
||||
lookup_vm_symbol: extern "C" fn(*const c_char, usize) -> *const vm::Func,
|
||||
visit_fde: extern "C" fn(*mut u8, usize, extern "C" fn(*mut u8)),
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn module_load(
|
||||
mem_ptr: *const u8,
|
||||
@ -77,7 +41,8 @@ extern "C" {
|
||||
fn module_delete(module: *mut LLVMModule);
|
||||
fn get_func_symbol(module: *mut LLVMModule, name: *const c_char) -> *const vm::Func;
|
||||
|
||||
fn throw_trap(ty: i32);
|
||||
fn throw_trap(ty: i32) -> !;
|
||||
fn throw_breakpoint(ty: i64) -> !;
|
||||
|
||||
/// This should be the same as spliting up the fat pointer into two arguments,
|
||||
/// but this is cleaner, I think?
|
||||
@ -99,69 +64,21 @@ extern "C" {
|
||||
}
|
||||
|
||||
fn get_callbacks() -> Callbacks {
|
||||
fn round_up_to_page_size(size: usize) -> usize {
|
||||
(size + (4096 - 1)) & !(4096 - 1)
|
||||
}
|
||||
|
||||
extern "C" fn alloc_memory(
|
||||
size: usize,
|
||||
protect: MemProtect,
|
||||
ptr_out: &mut *mut u8,
|
||||
size_out: &mut usize,
|
||||
) -> LLVMResult {
|
||||
let size = round_up_to_page_size(size);
|
||||
let ptr = unsafe {
|
||||
mmap(
|
||||
ptr::null_mut(),
|
||||
size,
|
||||
match protect {
|
||||
MemProtect::NONE => PROT_NONE,
|
||||
MemProtect::READ => PROT_READ,
|
||||
MemProtect::READ_WRITE => PROT_READ | PROT_WRITE,
|
||||
MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC,
|
||||
},
|
||||
MAP_PRIVATE | MAP_ANON,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
};
|
||||
if ptr as isize == -1 {
|
||||
return LLVMResult::ALLOCATE_FAILURE;
|
||||
}
|
||||
*ptr_out = ptr as _;
|
||||
*size_out = size;
|
||||
LLVMResult::OK
|
||||
unsafe { crate::platform::alloc_memory(size, protect, ptr_out, size_out) }
|
||||
}
|
||||
|
||||
extern "C" fn protect_memory(ptr: *mut u8, size: usize, protect: MemProtect) -> LLVMResult {
|
||||
let res = unsafe {
|
||||
mprotect(
|
||||
ptr as _,
|
||||
round_up_to_page_size(size),
|
||||
match protect {
|
||||
MemProtect::NONE => PROT_NONE,
|
||||
MemProtect::READ => PROT_READ,
|
||||
MemProtect::READ_WRITE => PROT_READ | PROT_WRITE,
|
||||
MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC,
|
||||
},
|
||||
)
|
||||
};
|
||||
|
||||
if res == 0 {
|
||||
LLVMResult::OK
|
||||
} else {
|
||||
LLVMResult::PROTECT_FAILURE
|
||||
}
|
||||
unsafe { crate::platform::protect_memory(ptr, size, protect) }
|
||||
}
|
||||
|
||||
extern "C" fn dealloc_memory(ptr: *mut u8, size: usize) -> LLVMResult {
|
||||
let res = unsafe { munmap(ptr as _, round_up_to_page_size(size)) };
|
||||
|
||||
if res == 0 {
|
||||
LLVMResult::OK
|
||||
} else {
|
||||
LLVMResult::DEALLOC_FAILURE
|
||||
}
|
||||
unsafe { crate::platform::dealloc_memory(ptr, size) }
|
||||
}
|
||||
|
||||
extern "C" fn lookup_vm_symbol(name_ptr: *const c_char, length: usize) -> *const vm::Func {
|
||||
@ -188,7 +105,13 @@ fn get_callbacks() -> Callbacks {
|
||||
fn_name!("vm.memory.grow.static.local") => vmcalls::local_static_memory_grow as _,
|
||||
fn_name!("vm.memory.size.static.local") => vmcalls::local_static_memory_size as _,
|
||||
|
||||
fn_name!("vm.memory.grow.dynamic.import") => vmcalls::imported_dynamic_memory_grow as _,
|
||||
fn_name!("vm.memory.size.dynamic.import") => vmcalls::imported_dynamic_memory_size as _,
|
||||
fn_name!("vm.memory.grow.static.import") => vmcalls::imported_static_memory_grow as _,
|
||||
fn_name!("vm.memory.size.static.import") => vmcalls::imported_static_memory_size as _,
|
||||
|
||||
fn_name!("vm.exception.trap") => throw_trap as _,
|
||||
fn_name!("vm.breakpoint") => throw_breakpoint as _,
|
||||
|
||||
_ => ptr::null(),
|
||||
}
|
||||
@ -261,6 +184,14 @@ impl LLVMBackend {
|
||||
.unwrap();
|
||||
let mem_buf_slice = memory_buffer.as_slice();
|
||||
|
||||
if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.obj_file } {
|
||||
let mut file = File::create(path).unwrap();
|
||||
let mut pos = 0;
|
||||
while pos < mem_buf_slice.len() {
|
||||
pos += file.write(&mem_buf_slice[pos..]).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
let callbacks = get_callbacks();
|
||||
let mut module: *mut LLVMModule = ptr::null_mut();
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,15 @@
|
||||
use hashbrown::HashMap;
|
||||
use inkwell::{
|
||||
attributes::{Attribute, AttributeLoc},
|
||||
builder::Builder,
|
||||
context::Context,
|
||||
module::Module,
|
||||
types::{BasicType, FloatType, FunctionType, IntType, PointerType, StructType, VoidType},
|
||||
types::{
|
||||
BasicType, FloatType, FunctionType, IntType, PointerType, StructType, VectorType, VoidType,
|
||||
},
|
||||
values::{BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue},
|
||||
AddressSpace,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::marker::PhantomData;
|
||||
use wasmer_runtime_core::{
|
||||
memory::MemoryType,
|
||||
@ -16,7 +19,7 @@ use wasmer_runtime_core::{
|
||||
GlobalIndex, ImportedFuncIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex,
|
||||
TableIndex, Type,
|
||||
},
|
||||
vm::Ctx,
|
||||
vm::{Ctx, INTERNALS_SIZE},
|
||||
};
|
||||
|
||||
fn type_to_llvm_ptr(intrinsics: &Intrinsics, ty: Type) -> PointerType {
|
||||
@ -25,6 +28,7 @@ fn type_to_llvm_ptr(intrinsics: &Intrinsics, ty: Type) -> PointerType {
|
||||
Type::I64 => intrinsics.i64_ptr_ty,
|
||||
Type::F32 => intrinsics.f32_ptr_ty,
|
||||
Type::F64 => intrinsics.f64_ptr_ty,
|
||||
Type::V128 => intrinsics.i128_ptr_ty,
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,12 +44,18 @@ pub struct Intrinsics {
|
||||
|
||||
pub sqrt_f32: FunctionValue,
|
||||
pub sqrt_f64: FunctionValue,
|
||||
pub sqrt_f32x4: FunctionValue,
|
||||
pub sqrt_f64x2: FunctionValue,
|
||||
|
||||
pub minimum_f32: FunctionValue,
|
||||
pub minimum_f64: FunctionValue,
|
||||
pub minimum_f32x4: FunctionValue,
|
||||
pub minimum_f64x2: FunctionValue,
|
||||
|
||||
pub maximum_f32: FunctionValue,
|
||||
pub maximum_f64: FunctionValue,
|
||||
pub maximum_f32x4: FunctionValue,
|
||||
pub maximum_f64x2: FunctionValue,
|
||||
|
||||
pub ceil_f32: FunctionValue,
|
||||
pub ceil_f64: FunctionValue,
|
||||
@ -61,10 +71,22 @@ pub struct Intrinsics {
|
||||
|
||||
pub fabs_f32: FunctionValue,
|
||||
pub fabs_f64: FunctionValue,
|
||||
pub fabs_f32x4: FunctionValue,
|
||||
pub fabs_f64x2: FunctionValue,
|
||||
|
||||
pub copysign_f32: FunctionValue,
|
||||
pub copysign_f64: FunctionValue,
|
||||
|
||||
pub sadd_sat_i8x16: FunctionValue,
|
||||
pub sadd_sat_i16x8: FunctionValue,
|
||||
pub uadd_sat_i8x16: FunctionValue,
|
||||
pub uadd_sat_i16x8: FunctionValue,
|
||||
|
||||
pub ssub_sat_i8x16: FunctionValue,
|
||||
pub ssub_sat_i16x8: FunctionValue,
|
||||
pub usub_sat_i8x16: FunctionValue,
|
||||
pub usub_sat_i16x8: FunctionValue,
|
||||
|
||||
pub expect_i1: FunctionValue,
|
||||
pub trap: FunctionValue,
|
||||
|
||||
@ -74,21 +96,33 @@ pub struct Intrinsics {
|
||||
pub i16_ty: IntType,
|
||||
pub i32_ty: IntType,
|
||||
pub i64_ty: IntType,
|
||||
pub i128_ty: IntType,
|
||||
pub f32_ty: FloatType,
|
||||
pub f64_ty: FloatType,
|
||||
|
||||
pub i1x128_ty: VectorType,
|
||||
pub i8x16_ty: VectorType,
|
||||
pub i16x8_ty: VectorType,
|
||||
pub i32x4_ty: VectorType,
|
||||
pub i64x2_ty: VectorType,
|
||||
pub f32x4_ty: VectorType,
|
||||
pub f64x2_ty: VectorType,
|
||||
|
||||
pub i8_ptr_ty: PointerType,
|
||||
pub i16_ptr_ty: PointerType,
|
||||
pub i32_ptr_ty: PointerType,
|
||||
pub i64_ptr_ty: PointerType,
|
||||
pub i128_ptr_ty: PointerType,
|
||||
pub f32_ptr_ty: PointerType,
|
||||
pub f64_ptr_ty: PointerType,
|
||||
|
||||
pub anyfunc_ty: StructType,
|
||||
|
||||
pub i1_zero: IntValue,
|
||||
pub i8_zero: IntValue,
|
||||
pub i32_zero: IntValue,
|
||||
pub i64_zero: IntValue,
|
||||
pub i128_zero: IntValue,
|
||||
pub f32_zero: FloatValue,
|
||||
pub f64_zero: FloatValue,
|
||||
|
||||
@ -97,6 +131,7 @@ pub struct Intrinsics {
|
||||
pub trap_call_indirect_oob: BasicValueEnum,
|
||||
pub trap_memory_oob: BasicValueEnum,
|
||||
pub trap_illegal_arithmetic: BasicValueEnum,
|
||||
pub trap_misaligned_atomic: BasicValueEnum,
|
||||
|
||||
// VM intrinsics.
|
||||
pub memory_grow_dynamic_local: FunctionValue,
|
||||
@ -114,6 +149,7 @@ pub struct Intrinsics {
|
||||
pub memory_size_shared_import: FunctionValue,
|
||||
|
||||
pub throw_trap: FunctionValue,
|
||||
pub throw_breakpoint: FunctionValue,
|
||||
|
||||
pub ctx_ptr_ty: PointerType,
|
||||
}
|
||||
@ -126,19 +162,31 @@ impl Intrinsics {
|
||||
let i16_ty = context.i16_type();
|
||||
let i32_ty = context.i32_type();
|
||||
let i64_ty = context.i64_type();
|
||||
let i128_ty = context.i128_type();
|
||||
let f32_ty = context.f32_type();
|
||||
let f64_ty = context.f64_type();
|
||||
|
||||
let i1x128_ty = i1_ty.vec_type(128);
|
||||
let i8x16_ty = i8_ty.vec_type(16);
|
||||
let i16x8_ty = i16_ty.vec_type(8);
|
||||
let i32x4_ty = i32_ty.vec_type(4);
|
||||
let i64x2_ty = i64_ty.vec_type(2);
|
||||
let f32x4_ty = f32_ty.vec_type(4);
|
||||
let f64x2_ty = f64_ty.vec_type(2);
|
||||
|
||||
let i8_ptr_ty = i8_ty.ptr_type(AddressSpace::Generic);
|
||||
let i16_ptr_ty = i16_ty.ptr_type(AddressSpace::Generic);
|
||||
let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::Generic);
|
||||
let i64_ptr_ty = i64_ty.ptr_type(AddressSpace::Generic);
|
||||
let i128_ptr_ty = i128_ty.ptr_type(AddressSpace::Generic);
|
||||
let f32_ptr_ty = f32_ty.ptr_type(AddressSpace::Generic);
|
||||
let f64_ptr_ty = f64_ty.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let i1_zero = i1_ty.const_int(0, false);
|
||||
let i8_zero = i8_ty.const_int(0, false);
|
||||
let i32_zero = i32_ty.const_int(0, false);
|
||||
let i64_zero = i64_ty.const_int(0, false);
|
||||
let i128_zero = i128_ty.const_int(0, false);
|
||||
let f32_zero = f32_ty.const_float(0.0);
|
||||
let f64_zero = f64_ty.const_float(0.0);
|
||||
|
||||
@ -147,6 +195,10 @@ impl Intrinsics {
|
||||
let i64_ty_basic = i64_ty.as_basic_type_enum();
|
||||
let f32_ty_basic = f32_ty.as_basic_type_enum();
|
||||
let f64_ty_basic = f64_ty.as_basic_type_enum();
|
||||
let i8x16_ty_basic = i8x16_ty.as_basic_type_enum();
|
||||
let i16x8_ty_basic = i16x8_ty.as_basic_type_enum();
|
||||
let f32x4_ty_basic = f32x4_ty.as_basic_type_enum();
|
||||
let f64x2_ty_basic = f64x2_ty.as_basic_type_enum();
|
||||
let i8_ptr_ty_basic = i8_ptr_ty.as_basic_type_enum();
|
||||
|
||||
let ctx_ty = context.opaque_struct_type("ctx");
|
||||
@ -233,6 +285,9 @@ impl Intrinsics {
|
||||
false,
|
||||
);
|
||||
|
||||
let ret_i8x16_take_i8x16_i8x16 = i8x16_ty.fn_type(&[i8x16_ty_basic, i8x16_ty_basic], false);
|
||||
let ret_i16x8_take_i16x8_i16x8 = i16x8_ty.fn_type(&[i16x8_ty_basic, i16x8_ty_basic], false);
|
||||
|
||||
let ret_i32_take_i32_i1 = i32_ty.fn_type(&[i32_ty_basic, i1_ty_basic], false);
|
||||
let ret_i64_take_i64_i1 = i64_ty.fn_type(&[i64_ty_basic, i1_ty_basic], false);
|
||||
|
||||
@ -241,9 +296,13 @@ impl Intrinsics {
|
||||
|
||||
let ret_f32_take_f32 = f32_ty.fn_type(&[f32_ty_basic], false);
|
||||
let ret_f64_take_f64 = f64_ty.fn_type(&[f64_ty_basic], false);
|
||||
let ret_f32x4_take_f32x4 = f32x4_ty.fn_type(&[f32x4_ty_basic], false);
|
||||
let ret_f64x2_take_f64x2 = f64x2_ty.fn_type(&[f64x2_ty_basic], false);
|
||||
|
||||
let ret_f32_take_f32_f32 = f32_ty.fn_type(&[f32_ty_basic, f32_ty_basic], false);
|
||||
let ret_f64_take_f64_f64 = f64_ty.fn_type(&[f64_ty_basic, f64_ty_basic], false);
|
||||
let ret_f32x4_take_f32x4_f32x4 = f32x4_ty.fn_type(&[f32x4_ty_basic, f32x4_ty_basic], false);
|
||||
let ret_f64x2_take_f64x2_f64x2 = f64x2_ty.fn_type(&[f64x2_ty_basic, f64x2_ty_basic], false);
|
||||
|
||||
let ret_i32_take_ctx_i32_i32 = i32_ty.fn_type(
|
||||
&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic],
|
||||
@ -253,8 +312,7 @@ impl Intrinsics {
|
||||
i32_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false);
|
||||
|
||||
let ret_i1_take_i1_i1 = i1_ty.fn_type(&[i1_ty_basic, i1_ty_basic], false);
|
||||
|
||||
Self {
|
||||
let intrinsics = Self {
|
||||
ctlz_i32: module.add_function("llvm.ctlz.i32", ret_i32_take_i32_i1, None),
|
||||
ctlz_i64: module.add_function("llvm.ctlz.i64", ret_i64_take_i64_i1, None),
|
||||
|
||||
@ -266,12 +324,34 @@ impl Intrinsics {
|
||||
|
||||
sqrt_f32: module.add_function("llvm.sqrt.f32", ret_f32_take_f32, None),
|
||||
sqrt_f64: module.add_function("llvm.sqrt.f64", ret_f64_take_f64, None),
|
||||
sqrt_f32x4: module.add_function("llvm.sqrt.v4f32", ret_f32x4_take_f32x4, None),
|
||||
sqrt_f64x2: module.add_function("llvm.sqrt.v2f64", ret_f64x2_take_f64x2, None),
|
||||
|
||||
minimum_f32: module.add_function("llvm.minnum.f32", ret_f32_take_f32_f32, None),
|
||||
minimum_f64: module.add_function("llvm.minnum.f64", ret_f64_take_f64_f64, None),
|
||||
minimum_f32x4: module.add_function(
|
||||
"llvm.minnum.v4f32",
|
||||
ret_f32x4_take_f32x4_f32x4,
|
||||
None,
|
||||
),
|
||||
minimum_f64x2: module.add_function(
|
||||
"llvm.minnum.v2f64",
|
||||
ret_f64x2_take_f64x2_f64x2,
|
||||
None,
|
||||
),
|
||||
|
||||
maximum_f32: module.add_function("llvm.maxnum.f32", ret_f32_take_f32_f32, None),
|
||||
maximum_f64: module.add_function("llvm.maxnum.f64", ret_f64_take_f64_f64, None),
|
||||
maximum_f32x4: module.add_function(
|
||||
"llvm.maxnum.v4f32",
|
||||
ret_f32x4_take_f32x4_f32x4,
|
||||
None,
|
||||
),
|
||||
maximum_f64x2: module.add_function(
|
||||
"llvm.maxnum.v2f64",
|
||||
ret_f64x2_take_f64x2_f64x2,
|
||||
None,
|
||||
),
|
||||
|
||||
ceil_f32: module.add_function("llvm.ceil.f32", ret_f32_take_f32, None),
|
||||
ceil_f64: module.add_function("llvm.ceil.f64", ret_f64_take_f64, None),
|
||||
@ -287,10 +367,54 @@ impl Intrinsics {
|
||||
|
||||
fabs_f32: module.add_function("llvm.fabs.f32", ret_f32_take_f32, None),
|
||||
fabs_f64: module.add_function("llvm.fabs.f64", ret_f64_take_f64, None),
|
||||
fabs_f32x4: module.add_function("llvm.fabs.v4f32", ret_f32x4_take_f32x4, None),
|
||||
fabs_f64x2: module.add_function("llvm.fabs.v2f64", ret_f64x2_take_f64x2, None),
|
||||
|
||||
copysign_f32: module.add_function("llvm.copysign.f32", ret_f32_take_f32_f32, None),
|
||||
copysign_f64: module.add_function("llvm.copysign.f64", ret_f64_take_f64_f64, None),
|
||||
|
||||
sadd_sat_i8x16: module.add_function(
|
||||
"llvm.sadd.sat.v16i8",
|
||||
ret_i8x16_take_i8x16_i8x16,
|
||||
None,
|
||||
),
|
||||
sadd_sat_i16x8: module.add_function(
|
||||
"llvm.sadd.sat.v8i16",
|
||||
ret_i16x8_take_i16x8_i16x8,
|
||||
None,
|
||||
),
|
||||
uadd_sat_i8x16: module.add_function(
|
||||
"llvm.uadd.sat.v16i8",
|
||||
ret_i8x16_take_i8x16_i8x16,
|
||||
None,
|
||||
),
|
||||
uadd_sat_i16x8: module.add_function(
|
||||
"llvm.uadd.sat.v8i16",
|
||||
ret_i16x8_take_i16x8_i16x8,
|
||||
None,
|
||||
),
|
||||
|
||||
ssub_sat_i8x16: module.add_function(
|
||||
"llvm.ssub.sat.v16i8",
|
||||
ret_i8x16_take_i8x16_i8x16,
|
||||
None,
|
||||
),
|
||||
ssub_sat_i16x8: module.add_function(
|
||||
"llvm.ssub.sat.v8i16",
|
||||
ret_i16x8_take_i16x8_i16x8,
|
||||
None,
|
||||
),
|
||||
usub_sat_i8x16: module.add_function(
|
||||
"llvm.usub.sat.v16i8",
|
||||
ret_i8x16_take_i8x16_i8x16,
|
||||
None,
|
||||
),
|
||||
usub_sat_i16x8: module.add_function(
|
||||
"llvm.usub.sat.v8i16",
|
||||
ret_i16x8_take_i16x8_i16x8,
|
||||
None,
|
||||
),
|
||||
|
||||
expect_i1: module.add_function("llvm.expect.i1", ret_i1_take_i1_i1, None),
|
||||
trap: module.add_function("llvm.trap", void_ty.fn_type(&[], false), None),
|
||||
|
||||
@ -300,21 +424,33 @@ impl Intrinsics {
|
||||
i16_ty,
|
||||
i32_ty,
|
||||
i64_ty,
|
||||
i128_ty,
|
||||
f32_ty,
|
||||
f64_ty,
|
||||
|
||||
i1x128_ty,
|
||||
i8x16_ty,
|
||||
i16x8_ty,
|
||||
i32x4_ty,
|
||||
i64x2_ty,
|
||||
f32x4_ty,
|
||||
f64x2_ty,
|
||||
|
||||
i8_ptr_ty,
|
||||
i16_ptr_ty,
|
||||
i32_ptr_ty,
|
||||
i64_ptr_ty,
|
||||
i128_ptr_ty,
|
||||
f32_ptr_ty,
|
||||
f64_ptr_ty,
|
||||
|
||||
anyfunc_ty,
|
||||
|
||||
i1_zero,
|
||||
i8_zero,
|
||||
i32_zero,
|
||||
i64_zero,
|
||||
i128_zero,
|
||||
f32_zero,
|
||||
f64_zero,
|
||||
|
||||
@ -323,6 +459,7 @@ impl Intrinsics {
|
||||
trap_call_indirect_oob: i32_ty.const_int(3, false).as_basic_value_enum(),
|
||||
trap_memory_oob: i32_ty.const_int(2, false).as_basic_value_enum(),
|
||||
trap_illegal_arithmetic: i32_ty.const_int(4, false).as_basic_value_enum(),
|
||||
trap_misaligned_atomic: i32_ty.const_int(5, false).as_basic_value_enum(),
|
||||
|
||||
// VM intrinsics.
|
||||
memory_grow_dynamic_local: module.add_function(
|
||||
@ -391,8 +528,45 @@ impl Intrinsics {
|
||||
void_ty.fn_type(&[i32_ty_basic], false),
|
||||
None,
|
||||
),
|
||||
throw_breakpoint: module.add_function(
|
||||
"vm.breakpoint",
|
||||
void_ty.fn_type(&[i64_ty_basic], false),
|
||||
None,
|
||||
),
|
||||
ctx_ptr_ty,
|
||||
}
|
||||
};
|
||||
|
||||
let readonly =
|
||||
context.create_enum_attribute(Attribute::get_named_enum_kind_id("readonly"), 0);
|
||||
intrinsics
|
||||
.memory_size_dynamic_local
|
||||
.add_attribute(AttributeLoc::Function, readonly);
|
||||
intrinsics
|
||||
.memory_size_static_local
|
||||
.add_attribute(AttributeLoc::Function, readonly);
|
||||
intrinsics
|
||||
.memory_size_shared_local
|
||||
.add_attribute(AttributeLoc::Function, readonly);
|
||||
intrinsics
|
||||
.memory_size_dynamic_import
|
||||
.add_attribute(AttributeLoc::Function, readonly);
|
||||
intrinsics
|
||||
.memory_size_static_import
|
||||
.add_attribute(AttributeLoc::Function, readonly);
|
||||
intrinsics
|
||||
.memory_size_shared_import
|
||||
.add_attribute(AttributeLoc::Function, readonly);
|
||||
|
||||
let noreturn =
|
||||
context.create_enum_attribute(Attribute::get_named_enum_kind_id("noreturn"), 0);
|
||||
intrinsics
|
||||
.throw_trap
|
||||
.add_attribute(AttributeLoc::Function, noreturn);
|
||||
intrinsics
|
||||
.throw_breakpoint
|
||||
.add_attribute(AttributeLoc::Function, noreturn);
|
||||
|
||||
intrinsics
|
||||
}
|
||||
}
|
||||
|
||||
@ -808,4 +982,31 @@ impl<'a> CtxType<'a> {
|
||||
|
||||
(imported_func_cache.func_ptr, imported_func_cache.ctx_ptr)
|
||||
}
|
||||
|
||||
pub fn internal_field(
|
||||
&mut self,
|
||||
index: usize,
|
||||
intrinsics: &Intrinsics,
|
||||
builder: &Builder,
|
||||
) -> PointerValue {
|
||||
assert!(index < INTERNALS_SIZE);
|
||||
|
||||
let local_internals_ptr_ptr = unsafe {
|
||||
builder.build_struct_gep(
|
||||
self.ctx_ptr_value,
|
||||
offset_to_index(Ctx::offset_internals()),
|
||||
"local_internals_ptr_ptr",
|
||||
)
|
||||
};
|
||||
let local_internals_ptr = builder
|
||||
.build_load(local_internals_ptr_ptr, "local_internals_ptr")
|
||||
.into_pointer_value();
|
||||
unsafe {
|
||||
builder.build_in_bounds_gep(
|
||||
local_internals_ptr,
|
||||
&[intrinsics.i32_ty.const_int(index as u64, false)],
|
||||
"local_internal_field_ptr",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,12 @@
|
||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||
#![deny(
|
||||
dead_code,
|
||||
nonstandard_style,
|
||||
unused_imports,
|
||||
unused_mut,
|
||||
unused_variables,
|
||||
unused_unsafe,
|
||||
unreachable_patterns
|
||||
)]
|
||||
#![cfg_attr(nightly, feature(unwind_attributes))]
|
||||
|
||||
mod backend;
|
||||
@ -7,8 +15,14 @@ mod intrinsics;
|
||||
mod platform;
|
||||
mod read_info;
|
||||
mod state;
|
||||
mod structs;
|
||||
mod trampolines;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub use code::LLVMFunctionCodeGenerator as FunctionCodeGenerator;
|
||||
pub use code::LLVMModuleCodeGenerator as ModuleCodeGenerator;
|
||||
|
||||
use wasmer_runtime_core::codegen::SimpleStreamingCompilerGen;
|
||||
|
||||
pub type LLVMCompiler = SimpleStreamingCompilerGen<
|
||||
@ -17,3 +31,22 @@ pub type LLVMCompiler = SimpleStreamingCompilerGen<
|
||||
backend::LLVMBackend,
|
||||
code::CodegenError,
|
||||
>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// LLVM backend flags.
|
||||
pub struct LLVMOptions {
|
||||
/// Emit LLVM IR before optimization pipeline.
|
||||
pub pre_opt_ir: Option<PathBuf>,
|
||||
|
||||
/// Emit LLVM IR after optimization pipeline.
|
||||
pub post_opt_ir: Option<PathBuf>,
|
||||
|
||||
/// Emit LLVM generated native code object file.
|
||||
pub obj_file: Option<PathBuf>,
|
||||
}
|
||||
|
||||
pub static mut GLOBAL_OPTIONS: LLVMOptions = LLVMOptions {
|
||||
pre_opt_ir: None,
|
||||
post_opt_ir: None,
|
||||
obj_file: None,
|
||||
};
|
||||
|
3
lib/llvm-backend/src/platform/common.rs
Normal file
3
lib/llvm-backend/src/platform/common.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub fn round_up_to_page_size(size: usize) -> usize {
|
||||
(size + (4096 - 1)) & !(4096 - 1)
|
||||
}
|
@ -1,7 +1,14 @@
|
||||
mod common;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod unix;
|
||||
#[cfg(unix)]
|
||||
pub use self::unix::*;
|
||||
|
||||
#[cfg(target_family = "windows")]
|
||||
compile_error!("windows not yet supported for the llvm-based compiler backend");
|
||||
mod win;
|
||||
#[cfg(target_family = "windows")]
|
||||
pub use self::win::*;
|
||||
|
||||
#[cfg(not(any(unix, target_family = "windows")))]
|
||||
compile_error!("Your system is not yet supported for the llvm-based compiler backend");
|
||||
|
@ -1,5 +1,11 @@
|
||||
use libc::{c_void, siginfo_t};
|
||||
use super::common::round_up_to_page_size;
|
||||
use crate::structs::{LLVMResult, MemProtect};
|
||||
use libc::{
|
||||
c_void, mmap, mprotect, munmap, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE,
|
||||
PROT_READ, PROT_WRITE,
|
||||
};
|
||||
use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGSEGV};
|
||||
use std::ptr;
|
||||
|
||||
/// `__register_frame` and `__deregister_frame` on macos take a single fde as an
|
||||
/// argument, so we need to parse the fde table here.
|
||||
@ -68,3 +74,60 @@ extern "C" fn signal_trap_handler(
|
||||
throw_trap(2);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn alloc_memory(
|
||||
size: usize,
|
||||
protect: MemProtect,
|
||||
ptr_out: &mut *mut u8,
|
||||
size_out: &mut usize,
|
||||
) -> LLVMResult {
|
||||
let size = round_up_to_page_size(size);
|
||||
let ptr = mmap(
|
||||
ptr::null_mut(),
|
||||
size,
|
||||
match protect {
|
||||
MemProtect::NONE => PROT_NONE,
|
||||
MemProtect::READ => PROT_READ,
|
||||
MemProtect::READ_WRITE => PROT_READ | PROT_WRITE,
|
||||
MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC,
|
||||
},
|
||||
MAP_PRIVATE | MAP_ANON,
|
||||
-1,
|
||||
0,
|
||||
);
|
||||
if ptr as isize == -1 {
|
||||
return LLVMResult::ALLOCATE_FAILURE;
|
||||
}
|
||||
*ptr_out = ptr as _;
|
||||
*size_out = size;
|
||||
LLVMResult::OK
|
||||
}
|
||||
|
||||
pub unsafe fn protect_memory(ptr: *mut u8, size: usize, protect: MemProtect) -> LLVMResult {
|
||||
let res = mprotect(
|
||||
ptr as _,
|
||||
round_up_to_page_size(size),
|
||||
match protect {
|
||||
MemProtect::NONE => PROT_NONE,
|
||||
MemProtect::READ => PROT_READ,
|
||||
MemProtect::READ_WRITE => PROT_READ | PROT_WRITE,
|
||||
MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC,
|
||||
},
|
||||
);
|
||||
|
||||
if res == 0 {
|
||||
LLVMResult::OK
|
||||
} else {
|
||||
LLVMResult::PROTECT_FAILURE
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dealloc_memory(ptr: *mut u8, size: usize) -> LLVMResult {
|
||||
let res = munmap(ptr as _, round_up_to_page_size(size));
|
||||
|
||||
if res == 0 {
|
||||
LLVMResult::OK
|
||||
} else {
|
||||
LLVMResult::DEALLOC_FAILURE
|
||||
}
|
||||
}
|
||||
|
80
lib/llvm-backend/src/platform/win.rs
Normal file
80
lib/llvm-backend/src/platform/win.rs
Normal file
@ -0,0 +1,80 @@
|
||||
use super::common::round_up_to_page_size;
|
||||
use crate::structs::{LLVMResult, MemProtect};
|
||||
use std::ptr;
|
||||
|
||||
use winapi::um::memoryapi::{VirtualAlloc, VirtualFree};
|
||||
use winapi::um::winnt::{
|
||||
MEM_COMMIT, MEM_DECOMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_NOACCESS, PAGE_READONLY,
|
||||
PAGE_READWRITE,
|
||||
};
|
||||
|
||||
pub unsafe fn visit_fde(_addr: *mut u8, _size: usize, _visitor: extern "C" fn(*mut u8)) {
|
||||
// Do nothing on Windows
|
||||
}
|
||||
|
||||
pub unsafe fn install_signal_handler() {
|
||||
// Do nothing on Windows
|
||||
}
|
||||
|
||||
pub unsafe fn alloc_memory(
|
||||
size: usize,
|
||||
protect: MemProtect,
|
||||
ptr_out: &mut *mut u8,
|
||||
size_out: &mut usize,
|
||||
) -> LLVMResult {
|
||||
let size = round_up_to_page_size(size);
|
||||
let flags = if protect == MemProtect::NONE {
|
||||
MEM_RESERVE
|
||||
} else {
|
||||
MEM_RESERVE | MEM_COMMIT
|
||||
};
|
||||
let ptr = VirtualAlloc(
|
||||
ptr::null_mut(),
|
||||
size,
|
||||
flags,
|
||||
memprotect_to_protect_const(protect),
|
||||
);
|
||||
|
||||
if ptr.is_null() {
|
||||
return LLVMResult::ALLOCATE_FAILURE;
|
||||
}
|
||||
|
||||
*ptr_out = ptr as _;
|
||||
*size_out = size;
|
||||
LLVMResult::OK
|
||||
}
|
||||
|
||||
pub unsafe fn protect_memory(ptr: *mut u8, size: usize, protect: MemProtect) -> LLVMResult {
|
||||
let size = round_up_to_page_size(size);
|
||||
let ptr = VirtualAlloc(
|
||||
ptr as _,
|
||||
size,
|
||||
MEM_COMMIT,
|
||||
memprotect_to_protect_const(protect),
|
||||
);
|
||||
|
||||
if ptr.is_null() {
|
||||
LLVMResult::PROTECT_FAILURE
|
||||
} else {
|
||||
LLVMResult::OK
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dealloc_memory(ptr: *mut u8, size: usize) -> LLVMResult {
|
||||
let success = VirtualFree(ptr as _, size, MEM_DECOMMIT);
|
||||
// If the function succeeds, the return value is nonzero.
|
||||
if success == 1 {
|
||||
LLVMResult::OK
|
||||
} else {
|
||||
LLVMResult::DEALLOC_FAILURE
|
||||
}
|
||||
}
|
||||
|
||||
fn memprotect_to_protect_const(protect: MemProtect) -> u32 {
|
||||
match protect {
|
||||
MemProtect::NONE => PAGE_NOACCESS,
|
||||
MemProtect::READ => PAGE_READONLY,
|
||||
MemProtect::READ_WRITE => PAGE_READWRITE,
|
||||
MemProtect::READ_EXECUTE => PAGE_EXECUTE_READ,
|
||||
}
|
||||
}
|
@ -7,12 +7,7 @@ pub fn type_to_type(ty: WpType) -> Result<Type, BinaryReaderError> {
|
||||
WpType::I64 => Type::I64,
|
||||
WpType::F32 => Type::F32,
|
||||
WpType::F64 => Type::F64,
|
||||
WpType::V128 => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "the wasmer llvm backend does not yet support the simd extension",
|
||||
offset: -1isize as usize,
|
||||
});
|
||||
}
|
||||
WpType::V128 => Type::V128,
|
||||
_ => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "that type is not supported as a wasmer type",
|
||||
|
39
lib/llvm-backend/src/structs.rs
Normal file
39
lib/llvm-backend/src/structs.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use libc::c_char;
|
||||
|
||||
use wasmer_runtime_core::vm;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct LLVMModule {
|
||||
_private: [u8; 0],
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub enum MemProtect {
|
||||
NONE,
|
||||
READ,
|
||||
READ_WRITE,
|
||||
READ_EXECUTE,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub enum LLVMResult {
|
||||
OK,
|
||||
ALLOCATE_FAILURE,
|
||||
PROTECT_FAILURE,
|
||||
DEALLOC_FAILURE,
|
||||
OBJECT_LOAD_FAILURE,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Callbacks {
|
||||
pub alloc_memory: extern "C" fn(usize, MemProtect, &mut *mut u8, &mut usize) -> LLVMResult,
|
||||
pub protect_memory: extern "C" fn(*mut u8, usize, MemProtect) -> LLVMResult,
|
||||
pub dealloc_memory: extern "C" fn(*mut u8, usize) -> LLVMResult,
|
||||
|
||||
pub lookup_vm_symbol: extern "C" fn(*const c_char, usize) -> *const vm::Func,
|
||||
pub visit_fde: extern "C" fn(*mut u8, usize, extern "C" fn(*mut u8)),
|
||||
}
|
@ -72,12 +72,14 @@ fn generate_trampoline(
|
||||
Type::I64 => intrinsics.i64_ptr_ty,
|
||||
Type::F32 => intrinsics.f32_ptr_ty,
|
||||
Type::F64 => intrinsics.f64_ptr_ty,
|
||||
Type::V128 => intrinsics.i128_ptr_ty,
|
||||
};
|
||||
|
||||
let mut args_vec = Vec::with_capacity(func_sig.params().len() + 1);
|
||||
args_vec.push(vmctx_ptr);
|
||||
|
||||
for (i, param_ty) in func_sig.params().iter().enumerate() {
|
||||
let mut i = 0;
|
||||
for param_ty in func_sig.params().iter() {
|
||||
let index = intrinsics.i32_ty.const_int(i as _, false);
|
||||
let item_pointer = unsafe { builder.build_in_bounds_gep(args_ptr, &[index], "arg_ptr") };
|
||||
|
||||
@ -88,6 +90,10 @@ fn generate_trampoline(
|
||||
|
||||
let arg = builder.build_load(typed_item_pointer, "arg");
|
||||
args_vec.push(arg);
|
||||
i = i + 1;
|
||||
if *param_ty == Type::V128 {
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
let call_site = builder.build_call(func_ptr, &args_vec, "call");
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-middleware-common"
|
||||
version = "0.5.6"
|
||||
version = "0.6.0"
|
||||
repository = "https://github.com/wasmerio/wasmer"
|
||||
description = "Wasmer runtime common middlewares"
|
||||
license = "MIT"
|
||||
@ -9,12 +9,12 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasmer-runtime-core = { path = "../runtime-core" }
|
||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.5.6" }
|
||||
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.5.6", optional = true }
|
||||
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.5.6", optional = true }
|
||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.6.0" }
|
||||
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.6.0", optional = true }
|
||||
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.6.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
wabt = "0.7.4"
|
||||
wabt = "0.9.1"
|
||||
criterion = "0.2"
|
||||
|
||||
[features]
|
||||
|
@ -135,16 +135,15 @@ static WAT_GAS: &'static str = r#"
|
||||
|
||||
#[cfg(feature = "llvm")]
|
||||
fn get_compiler(limit: u64, metering: bool) -> impl Compiler {
|
||||
use wasmer_llvm_backend::code::LLVMModuleCodeGenerator;
|
||||
use wasmer_llvm_backend::ModuleCodeGenerator;
|
||||
use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler};
|
||||
let c: StreamingCompiler<LLVMModuleCodeGenerator, _, _, _, _> =
|
||||
StreamingCompiler::new(move || {
|
||||
let mut chain = MiddlewareChain::new();
|
||||
if metering {
|
||||
chain.push(Metering::new(limit));
|
||||
}
|
||||
chain
|
||||
});
|
||||
let c: StreamingCompiler<ModuleCodeGenerator, _, _, _, _> = StreamingCompiler::new(move || {
|
||||
let mut chain = MiddlewareChain::new();
|
||||
if metering {
|
||||
chain.push(Metering::new(limit));
|
||||
}
|
||||
chain
|
||||
});
|
||||
|
||||
c
|
||||
}
|
||||
@ -164,15 +163,11 @@ fn get_compiler(limit: u64, metering: bool) -> impl Compiler {
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))]
|
||||
fn get_compiler(_limit: u64, metering: bool) -> impl Compiler {
|
||||
panic!("compiler not specified, activate a compiler via features");
|
||||
use wasmer_clif_backend::CraneliftCompiler;
|
||||
CraneliftCompiler::new()
|
||||
}
|
||||
compile_error!("compiler not specified, activate a compiler via features");
|
||||
|
||||
#[cfg(feature = "clif")]
|
||||
fn get_compiler(_limit: u64, metering: bool) -> impl Compiler {
|
||||
panic!("cranelift does not implement metering");
|
||||
compile_error!("cranelift does not implement metering");
|
||||
use wasmer_clif_backend::CraneliftCompiler;
|
||||
CraneliftCompiler::new()
|
||||
}
|
||||
|
@ -1,4 +1,11 @@
|
||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||
|
||||
#![deny(
|
||||
dead_code,
|
||||
nonstandard_style,
|
||||
unused_imports,
|
||||
unused_mut,
|
||||
unused_variables,
|
||||
unused_unsafe,
|
||||
unreachable_patterns
|
||||
)]
|
||||
pub mod call_trace;
|
||||
pub mod metering;
|
||||
|
@ -129,29 +129,27 @@ pub fn set_points_used_ctx(ctx: &mut Ctx, value: u64) {
|
||||
ctx.set_internal(&INTERNAL_FIELD, value);
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "singlepass"))]
|
||||
#[cfg(all(test, any(feature = "singlepass", feature = "llvm")))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use wabt::wat2wasm;
|
||||
|
||||
use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler};
|
||||
use wasmer_runtime_core::{backend::Compiler, compile_with, imports, Func};
|
||||
|
||||
#[cfg(feature = "llvm")]
|
||||
fn get_compiler(limit: u64) -> impl Compiler {
|
||||
use wasmer_llvm_backend::code::LLVMModuleCodeGenerator;
|
||||
use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler};
|
||||
let c: StreamingCompiler<LLVMModuleCodeGenerator, _, _, _, _> =
|
||||
StreamingCompiler::new(move || {
|
||||
let mut chain = MiddlewareChain::new();
|
||||
chain.push(Metering::new(limit));
|
||||
chain
|
||||
});
|
||||
use wasmer_llvm_backend::ModuleCodeGenerator as LLVMMCG;
|
||||
let c: StreamingCompiler<LLVMMCG, _, _, _, _> = StreamingCompiler::new(move || {
|
||||
let mut chain = MiddlewareChain::new();
|
||||
chain.push(Metering::new(limit));
|
||||
chain
|
||||
});
|
||||
c
|
||||
}
|
||||
|
||||
#[cfg(feature = "singlepass")]
|
||||
fn get_compiler(limit: u64) -> impl Compiler {
|
||||
use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler};
|
||||
use wasmer_singlepass_backend::ModuleCodeGenerator as SinglePassMCG;
|
||||
let c: StreamingCompiler<SinglePassMCG, _, _, _, _> = StreamingCompiler::new(move || {
|
||||
let mut chain = MiddlewareChain::new();
|
||||
@ -162,15 +160,11 @@ mod tests {
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))]
|
||||
fn get_compiler(_limit: u64) -> impl Compiler {
|
||||
panic!("compiler not specified, activate a compiler via features");
|
||||
use wasmer_clif_backend::CraneliftCompiler;
|
||||
CraneliftCompiler::new()
|
||||
}
|
||||
compile_error!("compiler not specified, activate a compiler via features");
|
||||
|
||||
#[cfg(feature = "clif")]
|
||||
fn get_compiler(_limit: u64) -> impl Compiler {
|
||||
panic!("cranelift does not implement metering");
|
||||
compile_error!("cranelift does not implement metering");
|
||||
use wasmer_clif_backend::CraneliftCompiler;
|
||||
CraneliftCompiler::new()
|
||||
}
|
||||
@ -253,7 +247,7 @@ mod tests {
|
||||
// verify it returns the correct value
|
||||
assert_eq!(value, 7);
|
||||
|
||||
// verify is uses the correct number of points
|
||||
// verify it used the correct number of points
|
||||
assert_eq!(get_points_used(&instance), 74);
|
||||
}
|
||||
|
||||
@ -282,7 +276,7 @@ mod tests {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
// verify is uses the correct number of points
|
||||
// verify it used the correct number of points
|
||||
assert_eq!(get_points_used(&instance), 109); // Used points will be slightly more than `limit` because of the way we do gas checking.
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-runtime-abi"
|
||||
version = "0.5.6"
|
||||
version = "0.6.0"
|
||||
description = "Wasmer runtime core library"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -8,12 +8,11 @@ repository = "https://github.com/wasmerio/wasmer"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.50"
|
||||
libc = "0.2.60"
|
||||
wasmer-runtime-core = { path = "../runtime-core" }
|
||||
hashbrown = "0.1"
|
||||
failure = "0.1"
|
||||
tar = "0.4"
|
||||
wasmparser = "0.32.1"
|
||||
wasmparser = "0.35.1"
|
||||
zstd = "0.4"
|
||||
|
||||
# [target.'cfg(unix)'.dependencies.zbox]
|
||||
|
@ -1,5 +1,4 @@
|
||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||
|
||||
#![deny(dead_code, unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
#[macro_use]
|
||||
extern crate failure;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::vfs::file_like::FileLike;
|
||||
use crate::vfs::vfs_header::{header_from_bytes, ArchiveType, CompressionType};
|
||||
use crate::vfs::virtual_file::VirtualFile;
|
||||
use hashbrown::HashMap;
|
||||
use std::collections::HashMap;
|
||||
use std::cell::RefCell;
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-runtime-c-api"
|
||||
version = "0.5.6"
|
||||
version = "0.6.0"
|
||||
description = "Wasmer C API library"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -12,19 +12,19 @@ readme = "README.md"
|
||||
crate-type = ["cdylib", "rlib", "staticlib"]
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
libc = "0.2.60"
|
||||
|
||||
[dependencies.wasmer-runtime]
|
||||
path = "../runtime"
|
||||
version = "0.5.6"
|
||||
version = "0.6.0"
|
||||
|
||||
[dependencies.wasmer-runtime-core]
|
||||
path = "../runtime-core"
|
||||
version = "0.5.6"
|
||||
version = "0.6.0"
|
||||
|
||||
[features]
|
||||
debug = ["wasmer-runtime/debug"]
|
||||
llvm = ["wasmer-runtime/llvm"]
|
||||
|
||||
[build-dependencies]
|
||||
cbindgen = "0.8"
|
||||
cbindgen = "0.9.0"
|
||||
|
@ -8,17 +8,17 @@ use std::ptr;
|
||||
use std::slice;
|
||||
|
||||
thread_local! {
|
||||
static LAST_ERROR: RefCell<Option<Box<Error>>> = RefCell::new(None);
|
||||
static LAST_ERROR: RefCell<Option<Box<dyn Error>>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
pub(crate) fn update_last_error<E: Error + 'static>(err: E) {
|
||||
pub fn update_last_error<E: Error + 'static>(err: E) {
|
||||
LAST_ERROR.with(|prev| {
|
||||
*prev.borrow_mut() = Some(Box::new(err));
|
||||
});
|
||||
}
|
||||
|
||||
/// Retrieve the most recent error, clearing it in the process.
|
||||
pub(crate) fn take_last_error() -> Option<Box<Error>> {
|
||||
pub(crate) fn take_last_error() -> Option<Box<dyn Error>> {
|
||||
LAST_ERROR.with(|prev| prev.borrow_mut().take())
|
||||
}
|
||||
|
||||
@ -89,8 +89,8 @@ pub unsafe extern "C" fn wasmer_last_error_message(buffer: *mut c_char, length:
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CApiError {
|
||||
pub(crate) msg: String,
|
||||
pub struct CApiError {
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
impl Display for CApiError {
|
||||
|
@ -436,6 +436,7 @@ pub unsafe extern "C" fn wasmer_export_func_call(
|
||||
tag: wasmer_value_tag::WASM_F64,
|
||||
value: wasmer_value { F64: x },
|
||||
},
|
||||
Value::V128(_) => unimplemented!("returning V128 type"),
|
||||
};
|
||||
results[0] = ret;
|
||||
}
|
||||
|
@ -10,9 +10,10 @@ use crate::{
|
||||
};
|
||||
use libc::c_uint;
|
||||
use std::{ffi::c_void, ptr, slice, sync::Arc};
|
||||
use wasmer_runtime::Module;
|
||||
use wasmer_runtime::{Global, Memory, Module, Table};
|
||||
use wasmer_runtime_core::{
|
||||
export::{Context, Export, FuncPointer},
|
||||
import::ImportObject,
|
||||
module::ImportName,
|
||||
types::{FuncSig, Type},
|
||||
};
|
||||
@ -25,6 +26,9 @@ pub struct wasmer_import_t {
|
||||
pub value: wasmer_import_export_value,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct wasmer_import_object_t;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct wasmer_import_func_t;
|
||||
@ -37,6 +41,83 @@ pub struct wasmer_import_descriptor_t;
|
||||
#[derive(Clone)]
|
||||
pub struct wasmer_import_descriptors_t;
|
||||
|
||||
/// Creates a new empty import object.
|
||||
/// See also `wasmer_import_object_append`
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object_t {
|
||||
let import_object = Box::new(ImportObject::new());
|
||||
|
||||
Box::into_raw(import_object) as *mut wasmer_import_object_t
|
||||
}
|
||||
|
||||
/// Extends an existing import object with new imports
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_import_object_extend(
|
||||
import_object: *mut wasmer_import_object_t,
|
||||
imports: *mut wasmer_import_t,
|
||||
imports_len: c_uint,
|
||||
) -> wasmer_result_t {
|
||||
let import_object: &mut ImportObject = &mut *(import_object as *mut ImportObject);
|
||||
|
||||
let mut extensions: Vec<(String, String, Export)> = Vec::new();
|
||||
|
||||
let imports: &[wasmer_import_t] = slice::from_raw_parts(imports, imports_len as usize);
|
||||
for import in imports {
|
||||
let module_name = slice::from_raw_parts(
|
||||
import.module_name.bytes,
|
||||
import.module_name.bytes_len as usize,
|
||||
);
|
||||
let module_name = if let Ok(s) = std::str::from_utf8(module_name) {
|
||||
s
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "error converting module name to string".to_string(),
|
||||
});
|
||||
return wasmer_result_t::WASMER_ERROR;
|
||||
};
|
||||
let import_name = slice::from_raw_parts(
|
||||
import.import_name.bytes,
|
||||
import.import_name.bytes_len as usize,
|
||||
);
|
||||
let import_name = if let Ok(s) = std::str::from_utf8(import_name) {
|
||||
s
|
||||
} else {
|
||||
update_last_error(CApiError {
|
||||
msg: "error converting import_name to string".to_string(),
|
||||
});
|
||||
return wasmer_result_t::WASMER_ERROR;
|
||||
};
|
||||
|
||||
let export = match import.tag {
|
||||
wasmer_import_export_kind::WASM_MEMORY => {
|
||||
let mem = import.value.memory as *mut Memory;
|
||||
Export::Memory((&*mem).clone())
|
||||
}
|
||||
wasmer_import_export_kind::WASM_FUNCTION => {
|
||||
let func_export = import.value.func as *mut Export;
|
||||
(&*func_export).clone()
|
||||
}
|
||||
wasmer_import_export_kind::WASM_GLOBAL => {
|
||||
let global = import.value.global as *mut Global;
|
||||
Export::Global((&*global).clone())
|
||||
}
|
||||
wasmer_import_export_kind::WASM_TABLE => {
|
||||
let table = import.value.table as *mut Table;
|
||||
Export::Table((&*table).clone())
|
||||
}
|
||||
};
|
||||
|
||||
let extension = (module_name.to_string(), import_name.to_string(), export);
|
||||
extensions.push(extension)
|
||||
}
|
||||
|
||||
import_object.extend(extensions);
|
||||
|
||||
return wasmer_result_t::WASMER_OK;
|
||||
}
|
||||
|
||||
/// Gets import descriptors for the given module
|
||||
///
|
||||
/// The caller owns the object and should call `wasmer_import_descriptors_destroy` to free it.
|
||||
@ -352,6 +433,14 @@ pub extern "C" fn wasmer_import_func_destroy(func: *mut wasmer_import_func_t) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Frees memory of the given ImportObject
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import_object_t) {
|
||||
if !import_object.is_null() {
|
||||
unsafe { Box::from_raw(import_object as *mut ImportObject) };
|
||||
}
|
||||
}
|
||||
|
||||
struct NamedImportDescriptor {
|
||||
module: String,
|
||||
name: String,
|
||||
|
@ -3,15 +3,19 @@
|
||||
use crate::{
|
||||
error::{update_last_error, CApiError},
|
||||
export::{wasmer_exports_t, wasmer_import_export_kind, NamedExport, NamedExports},
|
||||
import::wasmer_import_t,
|
||||
import::{wasmer_import_object_t, wasmer_import_t},
|
||||
memory::wasmer_memory_t,
|
||||
module::wasmer_module_t,
|
||||
value::{wasmer_value, wasmer_value_t, wasmer_value_tag},
|
||||
wasmer_result_t,
|
||||
};
|
||||
use libc::{c_char, c_int, c_void};
|
||||
use std::{collections::HashMap, ffi::CStr, slice};
|
||||
use wasmer_runtime::{Ctx, Global, ImportObject, Instance, Memory, Table, Value};
|
||||
use wasmer_runtime_core::{export::Export, import::Namespace};
|
||||
use wasmer_runtime::{Ctx, Global, Instance, Memory, Module, Table, Value};
|
||||
use wasmer_runtime_core::{
|
||||
export::Export,
|
||||
import::{ImportObject, Namespace},
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct wasmer_instance_t;
|
||||
@ -108,6 +112,45 @@ pub unsafe extern "C" fn wasmer_instantiate(
|
||||
wasmer_result_t::WASMER_OK
|
||||
}
|
||||
|
||||
/// Given:
|
||||
/// * A prepared `wasmer` import-object
|
||||
/// * A compiled wasmer module
|
||||
///
|
||||
/// Instantiates a wasmer instance
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_module_import_instantiate(
|
||||
instance: *mut *mut wasmer_instance_t,
|
||||
module: *const wasmer_module_t,
|
||||
import_object: *const wasmer_import_object_t,
|
||||
) -> wasmer_result_t {
|
||||
let import_object: &ImportObject = &*(import_object as *const ImportObject);
|
||||
let module: &Module = &*(module as *const Module);
|
||||
|
||||
let new_instance: Instance = match module.instantiate(import_object) {
|
||||
Ok(instance) => instance,
|
||||
Err(error) => {
|
||||
update_last_error(error);
|
||||
return wasmer_result_t::WASMER_ERROR;
|
||||
}
|
||||
};
|
||||
*instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t;
|
||||
|
||||
return wasmer_result_t::WASMER_OK;
|
||||
}
|
||||
|
||||
/// Extracts the instance's context and returns it.
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_instance_context_get(
|
||||
instance: *mut wasmer_instance_t,
|
||||
) -> *const wasmer_instance_context_t {
|
||||
let instance_ref = &*(instance as *const Instance);
|
||||
|
||||
let ctx: *const Ctx = instance_ref.context() as *const _;
|
||||
|
||||
ctx as *const wasmer_instance_context_t
|
||||
}
|
||||
|
||||
/// Calls an instances exported function by `name` with the provided parameters.
|
||||
/// Results are set using the provided `results` pointer.
|
||||
///
|
||||
@ -173,6 +216,7 @@ pub unsafe extern "C" fn wasmer_instance_call(
|
||||
tag: wasmer_value_tag::WASM_F64,
|
||||
value: wasmer_value { F64: x },
|
||||
},
|
||||
Value::V128(_) => unimplemented!("calling function with V128 parameter"),
|
||||
};
|
||||
results[0] = ret;
|
||||
}
|
||||
|
@ -80,8 +80,13 @@
|
||||
//!
|
||||
//! [wasmer_h]: ./wasmer.h
|
||||
//! [wasmer_hh]: ./wasmer.hh
|
||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||
|
||||
#![deny(
|
||||
dead_code,
|
||||
unused_imports,
|
||||
unused_variables,
|
||||
unused_unsafe,
|
||||
unreachable_patterns
|
||||
)]
|
||||
extern crate wasmer_runtime;
|
||||
extern crate wasmer_runtime_core;
|
||||
|
||||
@ -118,6 +123,6 @@ pub struct wasmer_limit_option_t {
|
||||
|
||||
#[repr(C)]
|
||||
pub struct wasmer_byte_array {
|
||||
bytes: *const u8,
|
||||
bytes_len: u32,
|
||||
pub bytes: *const u8,
|
||||
pub bytes_len: u32,
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ impl From<wasmer_value_t> for Value {
|
||||
tag: wasmer_value_tag::WASM_F64,
|
||||
value: wasmer_value { F64 },
|
||||
} => Value::F64(F64),
|
||||
_ => panic!("not implemented"),
|
||||
_ => unreachable!("unknown WASM type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -76,6 +76,7 @@ impl From<Value> for wasmer_value_t {
|
||||
tag: wasmer_value_tag::WASM_F64,
|
||||
value: wasmer_value { F64: x },
|
||||
},
|
||||
Value::V128(_) => unimplemented!("V128 not supported in C API"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -88,7 +89,7 @@ impl From<Type> for wasmer_value_tag {
|
||||
Type::I64 => wasmer_value_tag::WASM_I64,
|
||||
Type::F32 => wasmer_value_tag::WASM_F32,
|
||||
Type::F64 => wasmer_value_tag::WASM_F64,
|
||||
_ => panic!("not implemented"),
|
||||
Type::V128 => unreachable!("V128 not supported in C API"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -101,7 +102,7 @@ impl From<wasmer_value_tag> for Type {
|
||||
wasmer_value_tag::WASM_I64 => Type::I64,
|
||||
wasmer_value_tag::WASM_F32 => Type::F32,
|
||||
wasmer_value_tag::WASM_F64 => Type::F64,
|
||||
_ => panic!("not implemented"),
|
||||
_ => unreachable!("unknown WASM type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -113,6 +114,7 @@ impl From<&wasmer_runtime::wasm::Type> for wasmer_value_tag {
|
||||
Type::I64 => wasmer_value_tag::WASM_I64,
|
||||
Type::F32 => wasmer_value_tag::WASM_F32,
|
||||
Type::F64 => wasmer_value_tag::WASM_F64,
|
||||
Type::V128 => unimplemented!("V128 not supported in C API"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
4
lib/runtime-c-api/tests/.gitignore
vendored
4
lib/runtime-c-api/tests/.gitignore
vendored
@ -22,4 +22,6 @@ test-module-exports
|
||||
test-module-imports
|
||||
test-module-serialize
|
||||
test-tables
|
||||
test-validate
|
||||
test-validate
|
||||
test-context
|
||||
test-module-import-instantiate
|
||||
|
@ -14,6 +14,8 @@ add_executable(test-module-imports test-module-imports.c)
|
||||
add_executable(test-module-serialize test-module-serialize.c)
|
||||
add_executable(test-tables test-tables.c)
|
||||
add_executable(test-validate test-validate.c)
|
||||
add_executable(test-context test-context.c)
|
||||
add_executable(test-module-import-instantiate test-module-import-instantiate.c)
|
||||
|
||||
find_library(
|
||||
WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so libwasmer_runtime_c_api.dll
|
||||
@ -87,3 +89,11 @@ add_test(test-tables test-tables)
|
||||
target_link_libraries(test-validate general ${WASMER_LIB})
|
||||
target_compile_options(test-validate PRIVATE ${COMPILER_OPTIONS})
|
||||
add_test(test-validate test-validate)
|
||||
|
||||
target_link_libraries(test-context general ${WASMER_LIB})
|
||||
target_compile_options(test-context PRIVATE ${COMPILER_OPTIONS})
|
||||
add_test(test-context test-context)
|
||||
|
||||
target_link_libraries(test-module-import-instantiate general ${WASMER_LIB})
|
||||
target_compile_options(test-module-import-instantiate PRIVATE ${COMPILER_OPTIONS})
|
||||
add_test(test-module-import-instantiate test-module-import-instantiate)
|
||||
|
BIN
lib/runtime-c-api/tests/assets/inc.wasm
Normal file
BIN
lib/runtime-c-api/tests/assets/inc.wasm
Normal file
Binary file not shown.
12
lib/runtime-c-api/tests/assets/inc.wast
Normal file
12
lib/runtime-c-api/tests/assets/inc.wast
Normal file
@ -0,0 +1,12 @@
|
||||
(module
|
||||
(func $inc (import "env" "inc"))
|
||||
(func $mul (import "env" "mul"))
|
||||
(func $get (import "env" "get") (result i32))
|
||||
|
||||
(func (export "inc_and_get") (result i32)
|
||||
call $inc
|
||||
call $get)
|
||||
|
||||
(func (export "mul_and_get") (result i32)
|
||||
call $mul
|
||||
call $get))
|
@ -4,19 +4,17 @@ use std::process::Command;
|
||||
fn test_c_api() {
|
||||
let project_tests_dir = concat!(env!("CARGO_MANIFEST_DIR"), "/tests");
|
||||
|
||||
run_command("cmake", project_tests_dir, Some("."));
|
||||
run_command("make", project_tests_dir, Some("-Wdev -Werror=dev"));
|
||||
run_command("make", project_tests_dir, Some("test"));
|
||||
run_command("cmake", project_tests_dir, vec!["."]);
|
||||
run_command("make", project_tests_dir, vec!["-Wdev", "-Werror=dev"]);
|
||||
run_command("make", project_tests_dir, vec!["test", "ARGS=\"-V\""]);
|
||||
}
|
||||
|
||||
fn run_command(command_str: &str, dir: &str, arg: Option<&str>) {
|
||||
println!("Running command: `{}` arg: {:?}", command_str, arg);
|
||||
fn run_command(command_str: &str, dir: &str, args: Vec<&str>) {
|
||||
println!("Running command: `{}` args: {:?}", command_str, args);
|
||||
|
||||
let mut command = Command::new(command_str);
|
||||
|
||||
if let Some(a) = arg {
|
||||
command.arg(a);
|
||||
}
|
||||
command.args(&args);
|
||||
|
||||
command.current_dir(dir);
|
||||
|
||||
|
137
lib/runtime-c-api/tests/test-context.c
Normal file
137
lib/runtime-c-api/tests/test-context.c
Normal file
@ -0,0 +1,137 @@
|
||||
#include <stdio.h>
|
||||
#include "../wasmer.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
int32_t amount;
|
||||
int32_t value;
|
||||
} counter_data;
|
||||
|
||||
typedef struct {
|
||||
uint8_t* bytes;
|
||||
long bytes_len;
|
||||
} wasm_file_t;
|
||||
|
||||
wasm_file_t read_wasm_file(const char* file_name) {
|
||||
wasm_file_t wasm_file;
|
||||
|
||||
FILE *file = fopen(file_name, "r");
|
||||
fseek(file, 0, SEEK_END);
|
||||
wasm_file.bytes_len = ftell(file);
|
||||
|
||||
wasm_file.bytes = malloc(wasm_file.bytes_len);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(wasm_file.bytes, 1, wasm_file.bytes_len, file);
|
||||
fclose(file);
|
||||
|
||||
return wasm_file;
|
||||
}
|
||||
|
||||
void inc_counter(wasmer_instance_context_t *ctx) {
|
||||
counter_data* data = (counter_data*)wasmer_instance_context_data_get(ctx);
|
||||
data->value = data->value + data->amount;
|
||||
}
|
||||
|
||||
void mul_counter(wasmer_instance_context_t *ctx) {
|
||||
counter_data* data = (counter_data*)wasmer_instance_context_data_get(ctx);
|
||||
data->value = data->value * data->amount;
|
||||
}
|
||||
|
||||
int32_t get_counter(wasmer_instance_context_t *ctx) {
|
||||
counter_data* data = (counter_data*)wasmer_instance_context_data_get(ctx);
|
||||
return data->value;
|
||||
}
|
||||
|
||||
counter_data *init_counter(int32_t value, int32_t amount) {
|
||||
counter_data* counter = malloc(sizeof(counter_data));
|
||||
counter->value = value;
|
||||
counter->amount = amount;
|
||||
return counter;
|
||||
}
|
||||
|
||||
void assert_counter(wasmer_instance_t *instance, int32_t expected) {
|
||||
wasmer_value_t result_one;
|
||||
wasmer_value_t params[] = {};
|
||||
wasmer_value_t results[] = {result_one};
|
||||
|
||||
wasmer_result_t call1_result = wasmer_instance_call(instance, "inc_and_get", params, 0, results, 1);
|
||||
printf("Call result: %d\n", call1_result);
|
||||
printf("Result: %d\n", results[0].value.I32);
|
||||
assert(results[0].value.I32 == expected);
|
||||
assert(call1_result == WASMER_OK);
|
||||
|
||||
const wasmer_instance_context_t *ctx = wasmer_instance_context_get(instance);
|
||||
counter_data *cd = (counter_data*)wasmer_instance_context_data_get(ctx);
|
||||
assert(cd->value == expected);
|
||||
}
|
||||
|
||||
wasmer_import_t create_import(char* module_name, char* import_name, wasmer_import_func_t *func) {
|
||||
wasmer_import_t import;
|
||||
wasmer_byte_array module_name_bytes;
|
||||
wasmer_byte_array import_name_bytes;
|
||||
|
||||
module_name_bytes.bytes = (const uint8_t *) module_name;
|
||||
module_name_bytes.bytes_len = strlen(module_name);
|
||||
|
||||
import_name_bytes.bytes = (const uint8_t *) import_name;
|
||||
import_name_bytes.bytes_len = strlen(import_name);
|
||||
|
||||
import.module_name = module_name_bytes;
|
||||
import.import_name = import_name_bytes;
|
||||
|
||||
import.tag = WASM_FUNCTION;
|
||||
import.value.func = func;
|
||||
|
||||
return import;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Prepare Imports
|
||||
wasmer_value_tag inc_params_sig[] = {};
|
||||
wasmer_value_tag inc_returns_sig[] = {};
|
||||
wasmer_import_func_t *inc_func = wasmer_import_func_new((void (*)(void *)) inc_counter, inc_params_sig, 0, inc_returns_sig, 0);
|
||||
wasmer_import_t inc_import = create_import("env", "inc", inc_func);
|
||||
|
||||
wasmer_value_tag mul_params_sig[] = {};
|
||||
wasmer_value_tag mul_returns_sig[] = {};
|
||||
wasmer_import_func_t *mul_func = wasmer_import_func_new((void (*)(void *)) mul_counter, mul_params_sig, 0, mul_returns_sig, 0);
|
||||
wasmer_import_t mul_import = create_import("env", "mul", mul_func);
|
||||
|
||||
wasmer_value_tag get_params_sig[] = {};
|
||||
wasmer_value_tag get_returns_sig[] = {WASM_I32};
|
||||
wasmer_import_func_t *get_func = wasmer_import_func_new((void (*)(void *)) get_counter, get_params_sig, 0, get_returns_sig, 1);
|
||||
wasmer_import_t get_import = create_import("env", "get", get_func);
|
||||
|
||||
wasmer_import_t imports[] = {inc_import, mul_import, get_import};
|
||||
|
||||
// Read the wasm file
|
||||
wasm_file_t wasm_file = read_wasm_file("assets/inc.wasm");
|
||||
|
||||
// Instantiate instance
|
||||
printf("Instantiating\n");
|
||||
wasmer_instance_t *instance = NULL;
|
||||
wasmer_result_t instantiate_res = wasmer_instantiate(&instance, wasm_file.bytes, wasm_file.bytes_len, imports, 3);
|
||||
printf("Compile result: %d\n", instantiate_res);
|
||||
assert(instantiate_res == WASMER_OK);
|
||||
|
||||
// Init counter
|
||||
counter_data *counter = init_counter(2, 5);
|
||||
wasmer_instance_context_data_set(instance, counter);
|
||||
|
||||
// Run `instance.inc_and_get` and assert
|
||||
assert_counter(instance, 7);
|
||||
assert_counter(instance, 12);
|
||||
assert_counter(instance, 17);
|
||||
|
||||
// Clear resources
|
||||
wasmer_import_func_destroy(inc_func);
|
||||
wasmer_import_func_destroy(get_func);
|
||||
wasmer_instance_destroy(instance);
|
||||
free(counter);
|
||||
free(wasm_file.bytes);
|
||||
|
||||
return 0;
|
||||
}
|
@ -42,8 +42,9 @@ int main()
|
||||
assert(export_length == 5);
|
||||
|
||||
// Get the `memory` export.
|
||||
wasmer_export_t *export = wasmer_exports_get(exports, 1);
|
||||
wasmer_export_t *export = wasmer_exports_get(exports, 0);
|
||||
wasmer_import_export_kind kind = wasmer_export_kind(export);
|
||||
printf("Wasmer import export kind: %d (Memory is %d)\n", kind, WASM_MEMORY);
|
||||
assert(kind == WASM_MEMORY);
|
||||
|
||||
wasmer_byte_array export_name = wasmer_export_name(export);
|
||||
|
149
lib/runtime-c-api/tests/test-module-import-instantiate.c
Normal file
149
lib/runtime-c-api/tests/test-module-import-instantiate.c
Normal file
@ -0,0 +1,149 @@
|
||||
#include <stdio.h>
|
||||
#include "../wasmer.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
int32_t amount;
|
||||
int32_t value;
|
||||
} counter_data;
|
||||
|
||||
typedef struct {
|
||||
uint8_t* bytes;
|
||||
long bytes_len;
|
||||
} wasm_file_t;
|
||||
|
||||
wasm_file_t read_wasm_file(const char* file_name) {
|
||||
wasm_file_t wasm_file;
|
||||
|
||||
FILE *file = fopen(file_name, "r");
|
||||
fseek(file, 0, SEEK_END);
|
||||
wasm_file.bytes_len = ftell(file);
|
||||
|
||||
wasm_file.bytes = malloc(wasm_file.bytes_len);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(wasm_file.bytes, 1, wasm_file.bytes_len, file);
|
||||
fclose(file);
|
||||
|
||||
return wasm_file;
|
||||
}
|
||||
|
||||
void inc_counter(wasmer_instance_context_t *ctx) {
|
||||
counter_data* data = (counter_data*)wasmer_instance_context_data_get(ctx);
|
||||
data->value = data->value + data->amount;
|
||||
}
|
||||
|
||||
void mul_counter(wasmer_instance_context_t *ctx) {
|
||||
counter_data* data = (counter_data*)wasmer_instance_context_data_get(ctx);
|
||||
data->value = data->value * data->amount;
|
||||
}
|
||||
|
||||
int32_t get_counter(wasmer_instance_context_t *ctx) {
|
||||
counter_data* data = (counter_data*)wasmer_instance_context_data_get(ctx);
|
||||
return data->value;
|
||||
}
|
||||
|
||||
counter_data *init_counter(int32_t value, int32_t amount) {
|
||||
counter_data* counter = malloc(sizeof(counter_data));
|
||||
counter->value = value;
|
||||
counter->amount = amount;
|
||||
return counter;
|
||||
}
|
||||
|
||||
wasmer_import_t create_import(char* module_name, char* import_name, wasmer_import_func_t *func) {
|
||||
wasmer_import_t import;
|
||||
wasmer_byte_array module_name_bytes;
|
||||
wasmer_byte_array import_name_bytes;
|
||||
|
||||
module_name_bytes.bytes = (const uint8_t *) module_name;
|
||||
module_name_bytes.bytes_len = strlen(module_name);
|
||||
|
||||
import_name_bytes.bytes = (const uint8_t *) import_name;
|
||||
import_name_bytes.bytes_len = strlen(import_name);
|
||||
|
||||
import.module_name = module_name_bytes;
|
||||
import.import_name = import_name_bytes;
|
||||
|
||||
import.tag = WASM_FUNCTION;
|
||||
import.value.func = func;
|
||||
|
||||
return import;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Prepare Imports
|
||||
wasmer_value_tag inc_params_sig[] = {};
|
||||
wasmer_value_tag inc_returns_sig[] = {};
|
||||
wasmer_import_func_t *inc_func = wasmer_import_func_new((void (*)(void *)) inc_counter, inc_params_sig, 0, inc_returns_sig, 0);
|
||||
wasmer_import_t inc_import = create_import("env", "inc", inc_func);
|
||||
|
||||
wasmer_value_tag mul_params_sig[] = {};
|
||||
wasmer_value_tag mul_returns_sig[] = {};
|
||||
wasmer_import_func_t *mul_func = wasmer_import_func_new((void (*)(void *)) mul_counter, mul_params_sig, 0, mul_returns_sig, 0);
|
||||
wasmer_import_t mul_import = create_import("env", "mul", mul_func);
|
||||
|
||||
wasmer_value_tag get_params_sig[] = {};
|
||||
wasmer_value_tag get_returns_sig[] = {WASM_I32};
|
||||
wasmer_import_func_t *get_func = wasmer_import_func_new((void (*)(void *)) get_counter, get_params_sig, 0, get_returns_sig, 1);
|
||||
wasmer_import_t get_import = create_import("env", "get", get_func);
|
||||
|
||||
// Read the wasm file
|
||||
wasm_file_t wasm_file = read_wasm_file("assets/inc.wasm");
|
||||
|
||||
// Compile module
|
||||
wasmer_module_t *module = NULL;
|
||||
wasmer_result_t compile_res = wasmer_compile(&module, wasm_file.bytes, wasm_file.bytes_len);
|
||||
assert(compile_res == WASMER_OK);
|
||||
|
||||
// Prepare Import Object
|
||||
wasmer_import_object_t *import_object = wasmer_import_object_new();
|
||||
|
||||
// First, we import `inc_counter` and `mul_counter`
|
||||
wasmer_import_t imports[] = {inc_import, mul_import};
|
||||
wasmer_result_t extend_res = wasmer_import_object_extend(import_object, imports, 2);
|
||||
assert(extend_res == WASMER_OK);
|
||||
|
||||
// Now, we'll import `inc_counter` and `mul_counter`
|
||||
wasmer_import_t more_imports[] = {get_import};
|
||||
wasmer_result_t extend_res2 = wasmer_import_object_extend(import_object, more_imports, 1);
|
||||
assert(extend_res2 == WASMER_OK);
|
||||
|
||||
// Same `wasmer_import_object_extend` as the first, doesn't affect anything
|
||||
wasmer_result_t extend_res3 = wasmer_import_object_extend(import_object, imports, 2);
|
||||
assert(extend_res3 == WASMER_OK);
|
||||
|
||||
// Instantiate instance
|
||||
printf("Instantiating\n");
|
||||
wasmer_instance_t *instance = NULL;
|
||||
wasmer_result_t instantiate_res = wasmer_module_import_instantiate(&instance, module, import_object);
|
||||
printf("Compile result: %d\n", instantiate_res);
|
||||
assert(instantiate_res == WASMER_OK);
|
||||
|
||||
// Init counter
|
||||
counter_data *counter = init_counter(2, 5);
|
||||
wasmer_instance_context_data_set(instance, counter);
|
||||
|
||||
wasmer_value_t result_one;
|
||||
wasmer_value_t params[] = {};
|
||||
wasmer_value_t results[] = {result_one};
|
||||
|
||||
wasmer_result_t call1_result = wasmer_instance_call(instance, "inc_and_get", params, 0, results, 1);
|
||||
printf("Call result: %d\n", call1_result);
|
||||
printf("Result: %d\n", results[0].value.I32);
|
||||
|
||||
wasmer_result_t call2_result = wasmer_instance_call(instance, "mul_and_get", params, 0, results, 1);
|
||||
printf("Call result: %d\n", call2_result);
|
||||
printf("Result: %d\n", results[0].value.I32);
|
||||
|
||||
// Clear resources
|
||||
wasmer_import_func_destroy(inc_func);
|
||||
wasmer_import_func_destroy(mul_func);
|
||||
wasmer_import_func_destroy(get_func);
|
||||
wasmer_instance_destroy(instance);
|
||||
free(counter);
|
||||
free(wasm_file.bytes);
|
||||
|
||||
return 0;
|
||||
}
|
@ -95,11 +95,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_instance_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_instance_context_t;
|
||||
} wasmer_import_object_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@ -119,6 +115,14 @@ typedef struct {
|
||||
wasmer_import_export_value value;
|
||||
} wasmer_import_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_instance_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wasmer_instance_context_t;
|
||||
|
||||
typedef struct {
|
||||
bool has_some;
|
||||
uint32_t some;
|
||||
@ -392,6 +396,24 @@ wasmer_result_t wasmer_import_func_returns(const wasmer_import_func_t *func,
|
||||
wasmer_result_t wasmer_import_func_returns_arity(const wasmer_import_func_t *func,
|
||||
uint32_t *result);
|
||||
|
||||
/**
|
||||
* Frees memory of the given ImportObject
|
||||
*/
|
||||
void wasmer_import_object_destroy(wasmer_import_object_t *import_object);
|
||||
|
||||
/**
|
||||
* Extends an existing import object with new imports
|
||||
*/
|
||||
wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_object,
|
||||
wasmer_import_t *imports,
|
||||
unsigned int imports_len);
|
||||
|
||||
/**
|
||||
* Creates a new empty import object.
|
||||
* See also `wasmer_import_object_append`
|
||||
*/
|
||||
wasmer_import_object_t *wasmer_import_object_new(void);
|
||||
|
||||
/**
|
||||
* Calls an instances exported function by `name` with the provided parameters.
|
||||
* Results are set using the provided `results` pointer.
|
||||
@ -417,6 +439,11 @@ void *wasmer_instance_context_data_get(const wasmer_instance_context_t *ctx);
|
||||
*/
|
||||
void wasmer_instance_context_data_set(wasmer_instance_t *instance, void *data_ptr);
|
||||
|
||||
/**
|
||||
* Extracts the instance's context and returns it.
|
||||
*/
|
||||
const wasmer_instance_context_t *wasmer_instance_context_get(wasmer_instance_t *instance);
|
||||
|
||||
/**
|
||||
* Gets the memory within the context at the index `memory_idx`.
|
||||
* The index is always 0 until multiple memories are supported.
|
||||
@ -526,6 +553,16 @@ wasmer_result_t wasmer_module_deserialize(wasmer_module_t **module,
|
||||
*/
|
||||
void wasmer_module_destroy(wasmer_module_t *module);
|
||||
|
||||
/**
|
||||
* Given:
|
||||
* A prepared `wasmer` import-object
|
||||
* A compiled wasmer module
|
||||
* Instantiates a wasmer instance
|
||||
*/
|
||||
wasmer_result_t wasmer_module_import_instantiate(wasmer_instance_t **instance,
|
||||
const wasmer_module_t *module,
|
||||
const wasmer_import_object_t *import_object);
|
||||
|
||||
/**
|
||||
* Creates a new Instance from the given module and imports.
|
||||
* Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
|
@ -91,11 +91,7 @@ struct wasmer_import_func_t {
|
||||
|
||||
};
|
||||
|
||||
struct wasmer_instance_t {
|
||||
|
||||
};
|
||||
|
||||
struct wasmer_instance_context_t {
|
||||
struct wasmer_import_object_t {
|
||||
|
||||
};
|
||||
|
||||
@ -117,6 +113,14 @@ struct wasmer_import_t {
|
||||
wasmer_import_export_value value;
|
||||
};
|
||||
|
||||
struct wasmer_instance_t {
|
||||
|
||||
};
|
||||
|
||||
struct wasmer_instance_context_t {
|
||||
|
||||
};
|
||||
|
||||
struct wasmer_limit_option_t {
|
||||
bool has_some;
|
||||
uint32_t some;
|
||||
@ -318,6 +322,18 @@ wasmer_result_t wasmer_import_func_returns(const wasmer_import_func_t *func,
|
||||
wasmer_result_t wasmer_import_func_returns_arity(const wasmer_import_func_t *func,
|
||||
uint32_t *result);
|
||||
|
||||
/// Frees memory of the given ImportObject
|
||||
void wasmer_import_object_destroy(wasmer_import_object_t *import_object);
|
||||
|
||||
/// Extends an existing import object with new imports
|
||||
wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_object,
|
||||
wasmer_import_t *imports,
|
||||
unsigned int imports_len);
|
||||
|
||||
/// Creates a new empty import object.
|
||||
/// See also `wasmer_import_object_append`
|
||||
wasmer_import_object_t *wasmer_import_object_new();
|
||||
|
||||
/// Calls an instances exported function by `name` with the provided parameters.
|
||||
/// Results are set using the provided `results` pointer.
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
@ -337,6 +353,9 @@ void *wasmer_instance_context_data_get(const wasmer_instance_context_t *ctx);
|
||||
/// passed to all imported function for instance.
|
||||
void wasmer_instance_context_data_set(wasmer_instance_t *instance, void *data_ptr);
|
||||
|
||||
/// Extracts the instance's context and returns it.
|
||||
const wasmer_instance_context_t *wasmer_instance_context_get(wasmer_instance_t *instance);
|
||||
|
||||
/// Gets the memory within the context at the index `memory_idx`.
|
||||
/// The index is always 0 until multiple memories are supported.
|
||||
const wasmer_memory_t *wasmer_instance_context_memory(const wasmer_instance_context_t *ctx,
|
||||
@ -418,6 +437,14 @@ wasmer_result_t wasmer_module_deserialize(wasmer_module_t **module,
|
||||
/// Frees memory for the given Module
|
||||
void wasmer_module_destroy(wasmer_module_t *module);
|
||||
|
||||
/// Given:
|
||||
/// A prepared `wasmer` import-object
|
||||
/// A compiled wasmer module
|
||||
/// Instantiates a wasmer instance
|
||||
wasmer_result_t wasmer_module_import_instantiate(wasmer_instance_t **instance,
|
||||
const wasmer_module_t *module,
|
||||
const wasmer_import_object_t *import_object);
|
||||
|
||||
/// Creates a new Instance from the given module and imports.
|
||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-runtime-core"
|
||||
version = "0.5.6"
|
||||
version = "0.6.0"
|
||||
description = "Wasmer runtime core library"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -8,46 +8,46 @@ repository = "https://github.com/wasmerio/wasmer"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nix = "0.14.0"
|
||||
nix = "0.15.0"
|
||||
page_size = "0.4.1"
|
||||
wasmparser = "0.32.1"
|
||||
parking_lot = "0.7.1"
|
||||
lazy_static = "1.2.0"
|
||||
indexmap = "1.0.2"
|
||||
wasmparser = "0.35.1"
|
||||
parking_lot = "0.9.0"
|
||||
lazy_static = "1.3.0"
|
||||
errno = "0.2.4"
|
||||
libc = "0.2.49"
|
||||
libc = "0.2.60"
|
||||
hex = "0.3.2"
|
||||
smallvec = "0.6.9"
|
||||
smallvec = "0.6.10"
|
||||
bincode = "1.1"
|
||||
colored = "1.8"
|
||||
|
||||
[dependencies.indexmap]
|
||||
version = "1.0.2"
|
||||
features = ["serde-1"]
|
||||
|
||||
# Dependencies for caching.
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
version = "1.0.99"
|
||||
# This feature is required for serde to support serializing/deserializing reference counted pointers (e.g. Rc and Arc).
|
||||
features = ["rc"]
|
||||
[dependencies.serde_derive]
|
||||
version = "1.0"
|
||||
version = "1.0.98"
|
||||
[dependencies.serde_bytes]
|
||||
version = "0.10"
|
||||
version = "0.11.2"
|
||||
[dependencies.serde-bench]
|
||||
version = "0.0.7"
|
||||
[dependencies.blake2b_simd]
|
||||
version = "0.4.1"
|
||||
version = "0.5.6"
|
||||
[dependencies.digest]
|
||||
version = "0.8.0"
|
||||
[dependencies.hashbrown]
|
||||
version = "0.1"
|
||||
features = ["serde"]
|
||||
version = "0.8.1"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3", features = ["memoryapi"] }
|
||||
winapi = { version = "0.3.7", features = ["memoryapi"] }
|
||||
|
||||
[dev-dependencies]
|
||||
field-offset = "0.1.1"
|
||||
|
||||
[build-dependencies]
|
||||
blake2b_simd = "0.4.1"
|
||||
blake2b_simd = "0.5.6"
|
||||
rustc_version = "0.2.3"
|
||||
cc = "1.0"
|
||||
|
||||
@ -55,5 +55,6 @@ cc = "1.0"
|
||||
debug = []
|
||||
trace = ["debug"]
|
||||
# backend flags used in conditional compilation of Backend::variants
|
||||
"backend-cranelift" = []
|
||||
"backend-singlepass" = []
|
||||
"backend-llvm" = []
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
};
|
||||
use std::{any::Any, ptr::NonNull};
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub mod sys {
|
||||
pub use crate::sys::*;
|
||||
@ -32,6 +32,7 @@ pub enum Backend {
|
||||
impl Backend {
|
||||
pub fn variants() -> &'static [&'static str] {
|
||||
&[
|
||||
#[cfg(feature = "backend-cranelift")]
|
||||
"cranelift",
|
||||
#[cfg(feature = "backend-singlepass")]
|
||||
"singlepass",
|
||||
@ -110,14 +111,21 @@ impl Default for MemoryBoundCheckMode {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Features {
|
||||
pub simd: bool,
|
||||
pub threads: bool,
|
||||
}
|
||||
|
||||
/// Configuration data for the compiler
|
||||
#[derive(Default)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct CompilerConfig {
|
||||
/// Symbol information generated from emscripten; used for more detailed debug messages
|
||||
pub symbol_map: Option<HashMap<u32, String>>,
|
||||
pub memory_bound_check_mode: MemoryBoundCheckMode,
|
||||
pub enforce_stack_check: bool,
|
||||
pub track_state: bool,
|
||||
pub features: Features,
|
||||
}
|
||||
|
||||
pub trait Compiler {
|
||||
|
@ -55,11 +55,19 @@ pub struct LocalBacking {
|
||||
}
|
||||
|
||||
impl LocalBacking {
|
||||
pub(crate) fn new(module: &ModuleInner, imports: &ImportBacking, vmctx: *mut vm::Ctx) -> Self {
|
||||
pub(crate) fn new(
|
||||
module: &ModuleInner,
|
||||
imports: &ImportBacking,
|
||||
vmctx: *mut vm::Ctx,
|
||||
) -> LinkResult<Self> {
|
||||
let mut memories = Self::generate_memories(module);
|
||||
let mut tables = Self::generate_tables(module);
|
||||
let mut globals = Self::generate_globals(module, imports);
|
||||
|
||||
// Ensure all initializers are valid before running finalizers
|
||||
Self::validate_memories(module, imports)?;
|
||||
Self::validate_tables(module, imports, &mut tables)?;
|
||||
|
||||
let vm_memories = Self::finalize_memories(module, imports, &mut memories);
|
||||
let vm_tables = Self::finalize_tables(module, imports, &mut tables, vmctx);
|
||||
let vm_globals = Self::finalize_globals(&mut globals);
|
||||
@ -67,7 +75,7 @@ impl LocalBacking {
|
||||
let dynamic_sigindices = Self::generate_sigindices(&module.info);
|
||||
let local_functions = Self::generate_local_functions(module);
|
||||
|
||||
Self {
|
||||
Ok(Self {
|
||||
memories,
|
||||
tables,
|
||||
globals,
|
||||
@ -80,7 +88,7 @@ impl LocalBacking {
|
||||
local_functions,
|
||||
|
||||
internals: Internals([0; INTERNALS_SIZE]),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_local_functions(module: &ModuleInner) -> BoxedMap<LocalFuncIndex, *const vm::Func> {
|
||||
@ -117,6 +125,51 @@ impl LocalBacking {
|
||||
memories.into_boxed_map()
|
||||
}
|
||||
|
||||
/// Validate each locally-defined memory in the Module.
|
||||
///
|
||||
/// This involves copying in the data initializers.
|
||||
fn validate_memories(module: &ModuleInner, imports: &ImportBacking) -> LinkResult<()> {
|
||||
// Validate data size fits
|
||||
for init in module.info.data_initializers.iter() {
|
||||
let init_base = match init.base {
|
||||
Initializer::Const(Value::I32(offset)) => offset as u32,
|
||||
Initializer::Const(_) => panic!("a const initializer must be the i32 type"),
|
||||
Initializer::GetGlobal(import_global_index) => {
|
||||
if let Value::I32(x) = imports.globals[import_global_index].get() {
|
||||
x as u32
|
||||
} else {
|
||||
panic!("unsupported global type for initializer")
|
||||
}
|
||||
}
|
||||
} as usize;
|
||||
|
||||
// Validate data size fits
|
||||
match init.memory_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_memory_index) => {
|
||||
let memory_desc = module.info.memories[local_memory_index];
|
||||
let data_top = init_base + init.data.len();
|
||||
if memory_desc.minimum.bytes().0 < data_top || data_top < init_base {
|
||||
return Err(vec![LinkError::Generic {
|
||||
message: "data segment does not fit".to_string(),
|
||||
}]);
|
||||
}
|
||||
}
|
||||
LocalOrImport::Import(imported_memory_index) => {
|
||||
// Write the initialization data to the memory that
|
||||
// we think the imported memory is.
|
||||
let local_memory = unsafe { &*imports.vm_memories[imported_memory_index] };
|
||||
let data_top = init_base + init.data.len();
|
||||
if local_memory.bound < data_top || data_top < init_base {
|
||||
return Err(vec![LinkError::Generic {
|
||||
message: "data segment does not fit".to_string(),
|
||||
}]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Initialize each locally-defined memory in the Module.
|
||||
///
|
||||
/// This involves copying in the data initializers.
|
||||
@ -126,12 +179,8 @@ impl LocalBacking {
|
||||
memories: &mut SliceMap<LocalMemoryIndex, Memory>,
|
||||
) -> BoxedMap<LocalMemoryIndex, *mut vm::LocalMemory> {
|
||||
// For each init that has some data...
|
||||
for init in module
|
||||
.info
|
||||
.data_initializers
|
||||
.iter()
|
||||
.filter(|init| init.data.len() > 0)
|
||||
{
|
||||
// Initialize data
|
||||
for init in module.info.data_initializers.iter() {
|
||||
let init_base = match init.base {
|
||||
Initializer::Const(Value::I32(offset)) => offset as u32,
|
||||
Initializer::Const(_) => panic!("a const initializer must be the i32 type"),
|
||||
@ -146,10 +195,6 @@ impl LocalBacking {
|
||||
|
||||
match init.memory_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_memory_index) => {
|
||||
let memory_desc = module.info.memories[local_memory_index];
|
||||
let data_top = init_base + init.data.len();
|
||||
assert!(memory_desc.minimum.bytes().0 >= data_top);
|
||||
|
||||
let mem = &memories[local_memory_index];
|
||||
for (mem_byte, data_byte) in mem.view()[init_base..init_base + init.data.len()]
|
||||
.iter()
|
||||
@ -161,15 +206,13 @@ impl LocalBacking {
|
||||
LocalOrImport::Import(imported_memory_index) => {
|
||||
// Write the initialization data to the memory that
|
||||
// we think the imported memory is.
|
||||
unsafe {
|
||||
let memory_slice = unsafe {
|
||||
let local_memory = &*imports.vm_memories[imported_memory_index];
|
||||
let memory_slice =
|
||||
slice::from_raw_parts_mut(local_memory.base, local_memory.bound);
|
||||
slice::from_raw_parts_mut(local_memory.base, local_memory.bound)
|
||||
};
|
||||
|
||||
let mem_init_view =
|
||||
&mut memory_slice[init_base..init_base + init.data.len()];
|
||||
mem_init_view.copy_from_slice(&init.data);
|
||||
}
|
||||
let mem_init_view = &mut memory_slice[init_base..init_base + init.data.len()];
|
||||
mem_init_view.copy_from_slice(&init.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -192,6 +235,50 @@ impl LocalBacking {
|
||||
tables.into_boxed_map()
|
||||
}
|
||||
|
||||
/// This validates all of the locally-defined tables in the Module.
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
fn validate_tables(
|
||||
module: &ModuleInner,
|
||||
imports: &ImportBacking,
|
||||
tables: &mut SliceMap<LocalTableIndex, Table>,
|
||||
) -> LinkResult<()> {
|
||||
for init in &module.info.elem_initializers {
|
||||
let init_base = match init.base {
|
||||
Initializer::Const(Value::I32(offset)) => offset as u32,
|
||||
Initializer::Const(_) => panic!("a const initializer must be the i32 type"),
|
||||
Initializer::GetGlobal(import_global_index) => {
|
||||
if let Value::I32(x) = imports.globals[import_global_index].get() {
|
||||
x as u32
|
||||
} else {
|
||||
panic!("unsupported global type for initializer")
|
||||
}
|
||||
}
|
||||
} as usize;
|
||||
|
||||
match init.table_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_table_index) => {
|
||||
let table = &tables[local_table_index];
|
||||
|
||||
if (table.size() as usize) < init_base + init.elements.len() {
|
||||
return Err(vec![LinkError::Generic {
|
||||
message: "elements segment does not fit".to_string(),
|
||||
}]);
|
||||
}
|
||||
}
|
||||
LocalOrImport::Import(import_table_index) => {
|
||||
let table = &imports.tables[import_table_index];
|
||||
|
||||
if (table.size() as usize) < init_base + init.elements.len() {
|
||||
return Err(vec![LinkError::Generic {
|
||||
message: "elements segment does not fit".to_string(),
|
||||
}]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This initializes all of the locally-defined tables in the Module, e.g.
|
||||
/// putting all the table elements (function pointers)
|
||||
/// in the right places.
|
||||
@ -218,13 +305,6 @@ impl LocalBacking {
|
||||
match init.table_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_table_index) => {
|
||||
let table = &tables[local_table_index];
|
||||
|
||||
if (table.size() as usize) < init_base + init.elements.len() {
|
||||
let delta = (init_base + init.elements.len()) - table.size() as usize;
|
||||
// Grow the table if it's too small.
|
||||
table.grow(delta as u32).expect("couldn't grow table");
|
||||
}
|
||||
|
||||
table.anyfunc_direct_access_mut(|elements| {
|
||||
for (i, &func_index) in init.elements.iter().enumerate() {
|
||||
let sig_index = module.info.func_assoc[func_index];
|
||||
@ -258,12 +338,6 @@ impl LocalBacking {
|
||||
LocalOrImport::Import(import_table_index) => {
|
||||
let table = &imports.tables[import_table_index];
|
||||
|
||||
if (table.size() as usize) < init_base + init.elements.len() {
|
||||
let delta = (init_base + init.elements.len()) - table.size() as usize;
|
||||
// Grow the table if it's too small.
|
||||
table.grow(delta as u32).expect("couldn't grow table");
|
||||
}
|
||||
|
||||
table.anyfunc_direct_access_mut(|elements| {
|
||||
for (i, &func_index) in init.elements.iter().enumerate() {
|
||||
let sig_index = module.info.func_assoc[func_index];
|
||||
|
@ -20,6 +20,7 @@ pub enum Error {
|
||||
Unknown(String),
|
||||
InvalidFile(InvalidFileType),
|
||||
InvalidatedCache,
|
||||
UnsupportedBackend(Backend),
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
backend::RunnableModule,
|
||||
backend::{Backend, CacheGen, Compiler, CompilerConfig, Token},
|
||||
backend::{Backend, CacheGen, Compiler, CompilerConfig, Features, Token},
|
||||
cache::{Artifact, Error as CacheError},
|
||||
error::{CompileError, CompileResult},
|
||||
module::{ModuleInfo, ModuleInner},
|
||||
@ -18,7 +18,7 @@ use wasmparser::{self, WasmDecoder};
|
||||
use wasmparser::{Operator, Type as WpType};
|
||||
|
||||
pub type BreakpointHandler =
|
||||
Box<Fn(BreakpointInfo) -> Result<(), Box<dyn Any>> + Send + Sync + 'static>;
|
||||
Box<dyn Fn(BreakpointInfo) -> Result<(), Box<dyn Any>> + Send + Sync + 'static>;
|
||||
pub type BreakpointMap = Arc<HashMap<usize, BreakpointHandler>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -137,8 +137,22 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
fn validate(bytes: &[u8]) -> CompileResult<()> {
|
||||
let mut parser = wasmparser::ValidatingParser::new(bytes, None);
|
||||
pub fn validating_parser_config(features: &Features) -> wasmparser::ValidatingParserConfig {
|
||||
wasmparser::ValidatingParserConfig {
|
||||
operator_config: wasmparser::OperatorValidatorConfig {
|
||||
enable_threads: features.threads,
|
||||
enable_reference_types: false,
|
||||
enable_simd: features.simd,
|
||||
enable_bulk_memory: false,
|
||||
enable_multi_value: false,
|
||||
},
|
||||
mutable_global_imports: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_with_features(bytes: &[u8], features: &Features) -> CompileResult<()> {
|
||||
let mut parser =
|
||||
wasmparser::ValidatingParser::new(bytes, Some(validating_parser_config(features)));
|
||||
loop {
|
||||
let state = parser.read();
|
||||
match *state {
|
||||
@ -166,7 +180,7 @@ impl<
|
||||
_: Token,
|
||||
) -> CompileResult<ModuleInner> {
|
||||
if requires_pre_validation(MCG::backend_id()) {
|
||||
validate(wasm)?;
|
||||
validate_with_features(wasm, &compiler_config.features)?;
|
||||
}
|
||||
|
||||
let mut mcg = MCG::new();
|
||||
@ -218,7 +232,7 @@ impl<'a, 'b> EventSink<'a, 'b> {
|
||||
}
|
||||
|
||||
pub struct MiddlewareChain {
|
||||
chain: Vec<Box<GenericFunctionMiddleware>>,
|
||||
chain: Vec<Box<dyn GenericFunctionMiddleware>>,
|
||||
}
|
||||
|
||||
impl MiddlewareChain {
|
||||
|
@ -80,6 +80,9 @@ pub enum LinkError {
|
||||
expected: GlobalDescriptor,
|
||||
found: GlobalDescriptor,
|
||||
},
|
||||
Generic {
|
||||
message: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl PartialEq for LinkError {
|
||||
@ -107,6 +110,9 @@ impl std::fmt::Display for LinkError {
|
||||
LinkError::IncorrectTableDescriptor{namespace, name,expected,found} => {
|
||||
write!(f, "Incorrect table descriptor, namespace: {}, name: {}, expected table descriptor: {:?}, found table descriptor: {:?}", namespace, name, expected, found)
|
||||
},
|
||||
LinkError::Generic { message } => {
|
||||
write!(f, "{}", message)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -134,7 +140,7 @@ impl std::fmt::Display for RuntimeError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
RuntimeError::Trap { ref msg } => {
|
||||
write!(f, "WebAssembly trap occured during runtime: {}", msg)
|
||||
write!(f, "WebAssembly trap occurred during runtime: {}", msg)
|
||||
}
|
||||
RuntimeError::Error { data } => {
|
||||
if let Some(s) = data.downcast_ref::<String>() {
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
global::Global, instance::InstanceInner, memory::Memory, module::ExportIndex,
|
||||
module::ModuleInner, table::Table, types::FuncSig, vm,
|
||||
};
|
||||
use hashbrown::hash_map;
|
||||
use indexmap::map::Iter as IndexMapIter;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
@ -41,7 +41,7 @@ impl FuncPointer {
|
||||
|
||||
pub struct ExportIter<'a> {
|
||||
inner: &'a InstanceInner,
|
||||
iter: hash_map::Iter<'a, String, ExportIndex>,
|
||||
iter: IndexMapIter<'a, String, ExportIndex>,
|
||||
module: &'a ModuleInner,
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ type SetJmpBuffer = [i32; SETJMP_BUFFER_LEN];
|
||||
struct UnwindInfo {
|
||||
jmpbuf: SetJmpBuffer, // in
|
||||
breakpoints: Option<BreakpointMap>,
|
||||
payload: Option<Box<Any>>, // out
|
||||
payload: Option<Box<dyn Any>>, // out
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
@ -89,7 +89,7 @@ pub unsafe fn clear_wasm_interrupt() {
|
||||
pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
|
||||
f: F,
|
||||
breakpoints: Option<BreakpointMap>,
|
||||
) -> Result<R, Box<Any>> {
|
||||
) -> Result<R, Box<dyn Any>> {
|
||||
let unwind = UNWIND.with(|x| x.get());
|
||||
let old = (*unwind).take();
|
||||
*unwind = Some(UnwindInfo {
|
||||
@ -111,7 +111,7 @@ pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn begin_unsafe_unwind(e: Box<Any>) -> ! {
|
||||
pub unsafe fn begin_unsafe_unwind(e: Box<dyn Any>) -> ! {
|
||||
let unwind = UNWIND.with(|x| x.get());
|
||||
let inner = (*unwind)
|
||||
.as_mut()
|
||||
|
@ -46,10 +46,11 @@ impl Global {
|
||||
|
||||
let local_global = vm::LocalGlobal {
|
||||
data: match value {
|
||||
Value::I32(x) => x as u64,
|
||||
Value::I64(x) => x as u64,
|
||||
Value::F32(x) => x.to_bits() as u64,
|
||||
Value::F64(x) => x.to_bits(),
|
||||
Value::I32(x) => x as u128,
|
||||
Value::I64(x) => x as u128,
|
||||
Value::F32(x) => x.to_bits() as u128,
|
||||
Value::F64(x) => x.to_bits() as u128,
|
||||
Value::V128(x) => x,
|
||||
},
|
||||
};
|
||||
|
||||
@ -75,10 +76,11 @@ impl Global {
|
||||
if self.desc.ty == value.ty() {
|
||||
let local_global = vm::LocalGlobal {
|
||||
data: match value {
|
||||
Value::I32(x) => x as u64,
|
||||
Value::I64(x) => x as u64,
|
||||
Value::F32(x) => x.to_bits() as u64,
|
||||
Value::F64(x) => x.to_bits(),
|
||||
Value::I32(x) => x as u128,
|
||||
Value::I64(x) => x as u128,
|
||||
Value::F32(x) => x.to_bits() as u128,
|
||||
Value::F64(x) => x.to_bits() as u128,
|
||||
Value::V128(x) => x,
|
||||
},
|
||||
};
|
||||
*self.storage.borrow_mut() = local_global;
|
||||
@ -98,7 +100,8 @@ impl Global {
|
||||
Type::I32 => Value::I32(data as i32),
|
||||
Type::I64 => Value::I64(data as i64),
|
||||
Type::F32 => Value::F32(f32::from_bits(data as u32)),
|
||||
Type::F64 => Value::F64(f64::from_bits(data)),
|
||||
Type::F64 => Value::F64(f64::from_bits(data as u64)),
|
||||
Type::V128 => Value::V128(data),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::export::Export;
|
||||
use hashbrown::{hash_map::Entry, HashMap};
|
||||
use std::collections::VecDeque;
|
||||
use std::collections::{hash_map::Entry, HashMap};
|
||||
use std::{
|
||||
cell::{Ref, RefCell},
|
||||
ffi::c_void,
|
||||
@ -46,12 +46,12 @@ impl IsExport for Export {
|
||||
/// ```
|
||||
pub struct ImportObject {
|
||||
map: Rc<RefCell<HashMap<String, Box<dyn LikeNamespace>>>>,
|
||||
pub(crate) state_creator: Option<Rc<Fn() -> (*mut c_void, fn(*mut c_void))>>,
|
||||
pub(crate) state_creator: Option<Rc<dyn Fn() -> (*mut c_void, fn(*mut c_void))>>,
|
||||
pub allow_missing_functions: bool,
|
||||
}
|
||||
|
||||
impl ImportObject {
|
||||
/// Create a new `ImportObject`.
|
||||
/// Create a new `ImportObject`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
map: Rc::new(RefCell::new(HashMap::new())),
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user