mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-12 22:05:33 +00:00
Merge remote-tracking branch 'origin/master' into command/dash
This commit is contained in:
commit
c827a6a993
@ -35,13 +35,14 @@ jobs:
|
|||||||
name: Install lint deps
|
name: Install lint deps
|
||||||
command: |
|
command: |
|
||||||
git config --global --unset url."ssh://git@github.com".insteadOf || true
|
git config --global --unset url."ssh://git@github.com".insteadOf || true
|
||||||
rustup toolchain install nightly-2019-05-20
|
# rustup toolchain install nightly-2019-06-10
|
||||||
|
# rustup default nightly-2019-06-10
|
||||||
rustup component add rustfmt
|
rustup component add rustfmt
|
||||||
rustup component add clippy --toolchain=nightly-2019-05-20 || cargo +nightly-2019-05-20 install --git https://github.com/rust-lang/rust-clippy/ --force clippy
|
rustup component add clippy || cargo install --git https://github.com/rust-lang/rust-clippy/ --force clippy
|
||||||
- run:
|
- run:
|
||||||
name: Execute lints
|
name: Execute lints
|
||||||
command: |
|
command: |
|
||||||
make lint
|
cargo fmt --all -- --check
|
||||||
- save_cache:
|
- save_cache:
|
||||||
paths:
|
paths:
|
||||||
- /usr/local/cargo/registry
|
- /usr/local/cargo/registry
|
||||||
@ -50,7 +51,7 @@ jobs:
|
|||||||
- target/debug/deps
|
- target/debug/deps
|
||||||
key: v8-lint-{{ arch }}-{{ checksum "Cargo.lock" }}
|
key: v8-lint-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||||
|
|
||||||
test:
|
test-stable:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/rust:latest
|
- image: circleci/rust:latest
|
||||||
<<: *run_with_build_env_vars
|
<<: *run_with_build_env_vars
|
||||||
@ -61,24 +62,57 @@ jobs:
|
|||||||
- v8-test-cargo-cache-linux-stable-{{ arch }}-{{ checksum "Cargo.lock" }}
|
- v8-test-cargo-cache-linux-stable-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||||
- <<: *run_install_dependencies
|
- <<: *run_install_dependencies
|
||||||
- run:
|
- run:
|
||||||
name: Tests
|
name: Test everything (except singlepass)
|
||||||
command: make test
|
|
||||||
- run:
|
|
||||||
name: Emscripten Tests
|
|
||||||
command: |
|
command: |
|
||||||
make test-emscripten-clif
|
make cranelift
|
||||||
make test-emscripten-llvm
|
make llvm
|
||||||
|
make test-rest
|
||||||
|
- run:
|
||||||
|
name: Release
|
||||||
|
command: make release-fast
|
||||||
- run:
|
- run:
|
||||||
name: Integration Tests
|
name: Integration Tests
|
||||||
command: make integration-tests
|
command: make integration-tests
|
||||||
- save_cache:
|
- save_cache:
|
||||||
paths:
|
paths:
|
||||||
- /usr/local/cargo/registry
|
- /usr/local/cargo/registry
|
||||||
- target/debug/.fingerprint
|
- target/release/.fingerprint
|
||||||
- target/debug/build
|
- target/release/build
|
||||||
- target/debug/deps
|
- target/release/deps
|
||||||
key: v8-test-cargo-cache-linux-stable-{{ arch }}-{{ checksum "Cargo.lock" }}
|
key: v8-test-cargo-cache-linux-stable-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||||
|
|
||||||
|
test:
|
||||||
|
docker:
|
||||||
|
- image: circleci/rust:latest
|
||||||
|
<<: *run_with_build_env_vars
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- v8-test-cargo-cache-linux-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||||
|
- <<: *run_install_dependencies
|
||||||
|
- run: rustup default nightly-2019-06-10
|
||||||
|
- run:
|
||||||
|
name: Tests
|
||||||
|
command: make test
|
||||||
|
- run:
|
||||||
|
name: Debug flag checked
|
||||||
|
command: |
|
||||||
|
cargo check --features "debug" --release
|
||||||
|
- run:
|
||||||
|
name: Release
|
||||||
|
command: make release-fast
|
||||||
|
- run:
|
||||||
|
name: Integration Tests
|
||||||
|
command: make integration-tests
|
||||||
|
- save_cache:
|
||||||
|
paths:
|
||||||
|
- /usr/local/cargo/registry
|
||||||
|
- target/release/.fingerprint
|
||||||
|
- target/release/build
|
||||||
|
- target/release/deps
|
||||||
|
key: v8-test-cargo-cache-linux-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||||
|
|
||||||
test-macos:
|
test-macos:
|
||||||
macos:
|
macos:
|
||||||
xcode: "9.0"
|
xcode: "9.0"
|
||||||
@ -86,7 +120,7 @@ jobs:
|
|||||||
- checkout
|
- checkout
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- v8-cargo-cache-darwin-stable-{{ arch }}-{{ checksum "Cargo.lock" }}
|
- v8-cargo-cache-darwin-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||||
- run:
|
- run:
|
||||||
name: Install crate dependencies
|
name: Install crate dependencies
|
||||||
command: |
|
command: |
|
||||||
@ -100,7 +134,7 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: Install Rust
|
name: Install Rust
|
||||||
command: |
|
command: |
|
||||||
curl -sSf https://sh.rustup.rs | sh -s -- -y
|
curl -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly-2019-06-10
|
||||||
export PATH="$HOME/.cargo/bin:$PATH"
|
export PATH="$HOME/.cargo/bin:$PATH"
|
||||||
cargo --version
|
cargo --version
|
||||||
- run:
|
- run:
|
||||||
@ -114,16 +148,10 @@ jobs:
|
|||||||
sudo sysctl -w kern.maxfiles=655360 kern.maxfilesperproc=327680
|
sudo sysctl -w kern.maxfiles=655360 kern.maxfilesperproc=327680
|
||||||
make test
|
make test
|
||||||
- run:
|
- run:
|
||||||
name: Emscripten Tests
|
name: Release
|
||||||
command: |
|
command: |
|
||||||
export PATH="$HOME/.cargo/bin:$PATH"
|
export PATH="$HOME/.cargo/bin:$PATH"
|
||||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
make release-fast
|
||||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.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
|
|
||||||
make test-emscripten-clif
|
|
||||||
make test-emscripten-llvm
|
|
||||||
- run:
|
- run:
|
||||||
name: Integration Tests
|
name: Integration Tests
|
||||||
command: |
|
command: |
|
||||||
@ -134,13 +162,10 @@ jobs:
|
|||||||
- save_cache:
|
- save_cache:
|
||||||
paths:
|
paths:
|
||||||
- ~/.cargo/registry/
|
- ~/.cargo/registry/
|
||||||
- target/debug/.fingerprint
|
|
||||||
- target/debug/build
|
|
||||||
- target/debug/deps
|
|
||||||
- target/release/.fingerprint
|
- target/release/.fingerprint
|
||||||
- target/release/build
|
- target/release/build
|
||||||
- target/release/deps
|
- target/release/deps
|
||||||
key: v8-cargo-cache-darwin-stable-{{ arch }}-{{ checksum "Cargo.lock" }}
|
key: v8-cargo-cache-darwin-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||||
|
|
||||||
test-and-build:
|
test-and-build:
|
||||||
docker:
|
docker:
|
||||||
@ -161,28 +186,17 @@ jobs:
|
|||||||
sudo apt-get install -y cmake
|
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
|
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
|
tar xf clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||||
# Use rust nightly (for singlepass, for now)
|
- run: rustup default nightly-2019-06-10
|
||||||
- run: rustup default nightly-2019-04-11
|
|
||||||
- run:
|
- run:
|
||||||
name: Tests
|
name: Tests
|
||||||
command: |
|
command: |
|
||||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||||
make test
|
make test
|
||||||
- run:
|
|
||||||
name: Emscripten Tests
|
|
||||||
command: |
|
|
||||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
|
||||||
make test-emscripten-clif
|
|
||||||
make test-emscripten-llvm
|
|
||||||
- run:
|
|
||||||
name: Debug flag checked
|
|
||||||
command: |
|
|
||||||
cargo check --features "debug"
|
|
||||||
- run:
|
- run:
|
||||||
name: Release Build
|
name: Release Build
|
||||||
command: |
|
command: |
|
||||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||||
make production-release
|
make release
|
||||||
cargo build --release --manifest-path wapm-cli/Cargo.toml --features telemetry
|
cargo build --release --manifest-path wapm-cli/Cargo.toml --features telemetry
|
||||||
mkdir -p artifacts
|
mkdir -p artifacts
|
||||||
VERSION=$(cargo pkgid | cut -d# -f2 | cut -d: -f2)
|
VERSION=$(cargo pkgid | cut -d# -f2 | cut -d: -f2)
|
||||||
@ -203,9 +217,6 @@ jobs:
|
|||||||
- save_cache:
|
- save_cache:
|
||||||
paths:
|
paths:
|
||||||
- /usr/local/cargo/registry
|
- /usr/local/cargo/registry
|
||||||
- target/debug/.fingerprint
|
|
||||||
- target/debug/build
|
|
||||||
- target/debug/deps
|
|
||||||
- target/release/.fingerprint
|
- target/release/.fingerprint
|
||||||
- target/release/build
|
- target/release/build
|
||||||
- target/release/deps
|
- target/release/deps
|
||||||
@ -240,15 +251,9 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: Install Rust
|
name: Install Rust
|
||||||
command: |
|
command: |
|
||||||
curl -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly
|
curl -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly-2019-06-10
|
||||||
export PATH="$HOME/.cargo/bin:$PATH"
|
export PATH="$HOME/.cargo/bin:$PATH"
|
||||||
cargo --version
|
cargo --version
|
||||||
# Use rust nightly (for singlepass, for now)
|
|
||||||
# - run:
|
|
||||||
# name: Install Rust nightly
|
|
||||||
# command: |
|
|
||||||
# export PATH="$HOME/.rustup/bin:$PATH"
|
|
||||||
# rustup default nightly-2019-04-11
|
|
||||||
- run:
|
- run:
|
||||||
name: Tests
|
name: Tests
|
||||||
command: |
|
command: |
|
||||||
@ -258,25 +263,15 @@ jobs:
|
|||||||
# We increase the ulimit for fixing cargo unclosed files in mac
|
# We increase the ulimit for fixing cargo unclosed files in mac
|
||||||
ulimit -n 8000
|
ulimit -n 8000
|
||||||
sudo sysctl -w kern.maxfiles=655360 kern.maxfilesperproc=327680
|
sudo sysctl -w kern.maxfiles=655360 kern.maxfilesperproc=327680
|
||||||
|
|
||||||
make test
|
make test
|
||||||
- run:
|
|
||||||
name: Emscripten Tests
|
|
||||||
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/"
|
|
||||||
# We increase the ulimit for fixing cargo unclosed files in mac
|
|
||||||
ulimit -n 8000
|
|
||||||
sudo sysctl -w kern.maxfiles=655360 kern.maxfilesperproc=327680
|
|
||||||
make test-emscripten-clif
|
|
||||||
make test-emscripten-singlepass
|
|
||||||
- run:
|
- run:
|
||||||
name: Release Build
|
name: Release Build
|
||||||
command: |
|
command: |
|
||||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||||
export PATH="$HOME/.cargo/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_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/"
|
||||||
make production-release
|
make release
|
||||||
cargo build --release --manifest-path wapm-cli/Cargo.toml --features telemetry
|
cargo build --release --manifest-path wapm-cli/Cargo.toml --features telemetry
|
||||||
mkdir -p artifacts
|
mkdir -p artifacts
|
||||||
make build-install
|
make build-install
|
||||||
@ -297,9 +292,6 @@ jobs:
|
|||||||
- save_cache:
|
- save_cache:
|
||||||
paths:
|
paths:
|
||||||
- ~/.cargo/registry/
|
- ~/.cargo/registry/
|
||||||
- target/debug/.fingerprint
|
|
||||||
- target/debug/build
|
|
||||||
- target/debug/deps
|
|
||||||
- target/release/.fingerprint
|
- target/release/.fingerprint
|
||||||
- target/release/build
|
- target/release/build
|
||||||
- target/release/deps
|
- target/release/deps
|
||||||
@ -308,41 +300,6 @@ jobs:
|
|||||||
- wapm-cli/target/release/deps
|
- wapm-cli/target/release/deps
|
||||||
key: v8-cargo-cache-darwin-nightly-{ arch }}-{{ checksum "Cargo.lock" }}
|
key: v8-cargo-cache-darwin-nightly-{ arch }}-{{ checksum "Cargo.lock" }}
|
||||||
|
|
||||||
test-rust-nightly:
|
|
||||||
docker:
|
|
||||||
- image: circleci/rust:latest
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- restore_cache:
|
|
||||||
keys:
|
|
||||||
- v8-cargo-cache-linux-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
|
|
||||||
- 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
|
|
||||||
rustup toolchain install nightly
|
|
||||||
rustup target add wasm32-wasi --toolchain nightly
|
|
||||||
- run: |
|
|
||||||
rustup default nightly
|
|
||||||
make test-wasi-singlepass
|
|
||||||
make test-wasi-clif
|
|
||||||
- run: rustup default nightly-2019-04-11
|
|
||||||
- run: |
|
|
||||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
|
||||||
make test
|
|
||||||
make test-singlepass
|
|
||||||
make test-emscripten-clif
|
|
||||||
make test-emscripten-singlepass
|
|
||||||
- save_cache:
|
|
||||||
paths:
|
|
||||||
- /usr/local/cargo/registry
|
|
||||||
- target/debug/.fingerprint
|
|
||||||
- target/debug/build
|
|
||||||
- target/debug/deps
|
|
||||||
key: v8-cargo-cache-linux-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}-nightly
|
|
||||||
|
|
||||||
publish-github-release:
|
publish-github-release:
|
||||||
docker:
|
docker:
|
||||||
- image: cibuilds/github
|
- image: cibuilds/github
|
||||||
@ -412,7 +369,7 @@ workflows:
|
|||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
- test-rust-nightly:
|
- test-stable:
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
|
83
Cargo.lock
generated
83
Cargo.lock
generated
@ -16,6 +16,11 @@ dependencies = [
|
|||||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "approx"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
@ -65,6 +70,16 @@ dependencies = [
|
|||||||
"libc 0.2.57 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.57 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bincode"
|
||||||
|
version = "1.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bindgen"
|
name = "bindgen"
|
||||||
version = "0.46.0"
|
version = "0.46.0"
|
||||||
@ -163,6 +178,16 @@ name = "cfg-if"
|
|||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cgmath"
|
||||||
|
version = "0.16.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clang-sys"
|
name = "clang-sys"
|
||||||
version = "0.26.4"
|
version = "0.26.4"
|
||||||
@ -203,6 +228,15 @@ dependencies = [
|
|||||||
"cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "constant_time_eq"
|
name = "constant_time_eq"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
@ -706,6 +740,14 @@ dependencies = [
|
|||||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.1.43"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
@ -814,6 +856,18 @@ dependencies = [
|
|||||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.57 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.6.5"
|
version = "0.6.5"
|
||||||
@ -999,6 +1053,11 @@ dependencies = [
|
|||||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rgb"
|
||||||
|
version = "0.8.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.15"
|
version = "0.1.15"
|
||||||
@ -1496,7 +1555,10 @@ dependencies = [
|
|||||||
name = "wasmer-runtime-core"
|
name = "wasmer-runtime-core"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"blake2b_simd 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"blake2b_simd 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1523,6 +1585,7 @@ name = "wasmer-singlepass-backend"
|
|||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"dynasm 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dynasm 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"dynasmrt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dynasmrt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1558,6 +1621,7 @@ dependencies = [
|
|||||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"wasmer-clif-backend 0.5.3",
|
"wasmer-clif-backend 0.5.3",
|
||||||
"wasmer-dev-utils 0.5.3",
|
"wasmer-dev-utils 0.5.3",
|
||||||
|
"wasmer-llvm-backend 0.5.3",
|
||||||
"wasmer-runtime-core 0.5.3",
|
"wasmer-runtime-core 0.5.3",
|
||||||
"wasmer-singlepass-backend 0.5.3",
|
"wasmer-singlepass-backend 0.5.3",
|
||||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1635,15 +1699,28 @@ dependencies = [
|
|||||||
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winconsole"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rgb 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
|
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
|
||||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
|
"checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94"
|
||||||
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
|
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
|
||||||
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
|
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
|
||||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||||
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
|
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
|
||||||
"checksum backtrace 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)" = "1a13fc43f04daf08ab4f71e3d27e1fc27fc437d3e95ac0063a796d92fb40f39b"
|
"checksum backtrace 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)" = "1a13fc43f04daf08ab4f71e3d27e1fc27fc437d3e95ac0063a796d92fb40f39b"
|
||||||
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
|
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
|
||||||
|
"checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7"
|
||||||
"checksum bindgen 0.46.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f7f7f0701772b17de73e4f5cbcb1dd6926f4706cba4c1ab62c5367f8bdc94e1"
|
"checksum bindgen 0.46.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f7f7f0701772b17de73e4f5cbcb1dd6926f4706cba4c1ab62c5367f8bdc94e1"
|
||||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||||
"checksum blake2b_simd 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce2571a6cd634670daa2977cc894c1cc2ba57c563c498e5a82c35446f34d056e"
|
"checksum blake2b_simd 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce2571a6cd634670daa2977cc894c1cc2ba57c563c498e5a82c35446f34d056e"
|
||||||
@ -1655,10 +1732,12 @@ dependencies = [
|
|||||||
"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d"
|
"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d"
|
||||||
"checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af"
|
"checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af"
|
||||||
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
||||||
|
"checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c"
|
||||||
"checksum clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ef0c1bcf2e99c649104bd7a7012d8f8802684400e03db0ec0af48583c6fa0e4"
|
"checksum clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ef0c1bcf2e99c649104bd7a7012d8f8802684400e03db0ec0af48583c6fa0e4"
|
||||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||||
"checksum cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "2ca4386c8954b76a8415b63959337d940d724b336cabd3afe189c2b51a7e1ff0"
|
"checksum cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "2ca4386c8954b76a8415b63959337d940d724b336cabd3afe189c2b51a7e1ff0"
|
||||||
|
"checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03"
|
||||||
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
|
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
|
||||||
"checksum cranelift-bforest 0.31.0 (git+https://github.com/wasmerio/cranelift.git?rev=2ada531d79b34a9e6c94c81f2615677e22d68780)" = "<none>"
|
"checksum cranelift-bforest 0.31.0 (git+https://github.com/wasmerio/cranelift.git?rev=2ada531d79b34a9e6c94c81f2615677e22d68780)" = "<none>"
|
||||||
"checksum cranelift-codegen 0.31.0 (git+https://github.com/wasmerio/cranelift.git?rev=2ada531d79b34a9e6c94c81f2615677e22d68780)" = "<none>"
|
"checksum cranelift-codegen 0.31.0 (git+https://github.com/wasmerio/cranelift.git?rev=2ada531d79b34a9e6c94c81f2615677e22d68780)" = "<none>"
|
||||||
@ -1715,6 +1794,7 @@ dependencies = [
|
|||||||
"checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b"
|
"checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b"
|
||||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||||
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
||||||
|
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||||
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
||||||
"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
|
"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
|
||||||
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
||||||
@ -1729,6 +1809,7 @@ dependencies = [
|
|||||||
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
||||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||||
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
|
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
|
||||||
|
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
|
||||||
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
|
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
|
||||||
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
|
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
|
||||||
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||||
@ -1749,6 +1830,7 @@ dependencies = [
|
|||||||
"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58"
|
"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58"
|
||||||
"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
|
"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
|
||||||
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
||||||
|
"checksum rgb 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "4f089652ca87f5a82a62935ec6172a534066c7b97be003cc8f702ee9a7a59c92"
|
||||||
"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
|
"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
|
||||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||||
"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f"
|
"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f"
|
||||||
@ -1804,3 +1886,4 @@ dependencies = [
|
|||||||
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
|
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
|
||||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
|
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
|
||||||
|
"checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032"
|
||||||
|
185
Makefile
185
Makefile
@ -1,41 +1,130 @@
|
|||||||
ifeq (test, $(firstword $(MAKECMDGOALS)))
|
|
||||||
runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
|
|
||||||
$(eval $(runargs):;@true)
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: spectests emtests clean build install lint precommit
|
.PHONY: spectests emtests clean build install lint precommit
|
||||||
|
|
||||||
# This will re-generate the Rust test files based on spectests/*.wast
|
# Generate files
|
||||||
spectests:
|
generate-spectests:
|
||||||
WASMER_RUNTIME_GENERATE_SPECTESTS=1 cargo build -p wasmer-runtime-core
|
WASMER_RUNTIME_GENERATE_SPECTESTS=1 cargo build -p wasmer-runtime-core --release
|
||||||
|
|
||||||
emtests:
|
generate-emtests:
|
||||||
WASM_EMSCRIPTEN_GENERATE_EMTESTS=1 cargo build -p wasmer-emscripten
|
WASM_EMSCRIPTEN_GENERATE_EMTESTS=1 cargo build -p wasmer-emscripten --release
|
||||||
|
|
||||||
wasitests:
|
generate-wasitests:
|
||||||
WASM_WASI_GENERATE_WASITESTS=1 cargo build -p wasmer-wasi
|
WASM_WASI_GENERATE_WASITESTS=1 cargo build -p wasmer-wasi --release
|
||||||
|
|
||||||
# clean:
|
generate: generate-spectests generate-emtests generate-wasitests
|
||||||
# rm -rf artifacts
|
|
||||||
|
|
||||||
build:
|
|
||||||
cargo build --features debug
|
|
||||||
|
|
||||||
install:
|
# Spectests
|
||||||
cargo install --path .
|
spectests-singlepass:
|
||||||
|
cargo test --manifest-path lib/spectests/Cargo.toml --release --features singlepass
|
||||||
|
|
||||||
integration-tests: release
|
spectests-cranelift:
|
||||||
|
cargo test --manifest-path lib/spectests/Cargo.toml --release --features clif
|
||||||
|
|
||||||
|
spectests-llvm:
|
||||||
|
cargo test --manifest-path lib/spectests/Cargo.toml --release --features llvm
|
||||||
|
|
||||||
|
spectests: spectests-singlepass spectests-cranelift spectests-llvm
|
||||||
|
|
||||||
|
|
||||||
|
# Emscripten tests
|
||||||
|
emtests-singlepass:
|
||||||
|
cargo test --manifest-path lib/emscripten/Cargo.toml --release --features singlepass -- --test-threads=1
|
||||||
|
|
||||||
|
emtests-cranelift:
|
||||||
|
cargo test --manifest-path lib/emscripten/Cargo.toml --release --features clif -- --test-threads=1
|
||||||
|
|
||||||
|
emtests-llvm:
|
||||||
|
cargo test --manifest-path lib/emscripten/Cargo.toml --release --features llvm -- --test-threads=1
|
||||||
|
|
||||||
|
emtests: emtests-singlepass emtests-cranelift emtests-llvm
|
||||||
|
|
||||||
|
|
||||||
|
# Middleware tests
|
||||||
|
middleware-singlepass:
|
||||||
|
cargo test --manifest-path lib/middleware-common/Cargo.toml --release --features singlepass
|
||||||
|
|
||||||
|
middleware-cranelift:
|
||||||
|
cargo test --manifest-path lib/middleware-common/Cargo.toml --release --features clif
|
||||||
|
|
||||||
|
middleware-llvm:
|
||||||
|
cargo test --manifest-path lib/middleware-common/Cargo.toml --release --features llvm
|
||||||
|
|
||||||
|
middleware: middleware-singlepass middleware-cranelift middleware-llvm
|
||||||
|
|
||||||
|
|
||||||
|
# Wasitests
|
||||||
|
wasitests-singlepass:
|
||||||
|
cargo test --manifest-path lib/wasi/Cargo.toml --release --features singlepass -- --test-threads=1
|
||||||
|
|
||||||
|
wasitests-cranelift:
|
||||||
|
cargo test --manifest-path lib/wasi/Cargo.toml --release --features clif -- --test-threads=1
|
||||||
|
|
||||||
|
wasitests-llvm:
|
||||||
|
cargo test --manifest-path lib/wasi/Cargo.toml --release --features llvm -- --test-threads=1
|
||||||
|
|
||||||
|
wasitests: wasitests-singlepass wasitests-cranelift wasitests-llvm
|
||||||
|
|
||||||
|
|
||||||
|
# Backends
|
||||||
|
singlepass: spectests-singlepass emtests-singlepass middleware-singlepass wasitests-singlepass
|
||||||
|
cargo test -p wasmer-singlepass-backend --release
|
||||||
|
|
||||||
|
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
|
||||||
|
cargo test -p wasmer-llvm-backend --release
|
||||||
|
|
||||||
|
|
||||||
|
# All tests
|
||||||
|
capi:
|
||||||
|
cargo build --release
|
||||||
|
cargo build -p wasmer-runtime-c-api --release
|
||||||
|
cargo test -p wasmer-runtime-c-api --release
|
||||||
|
|
||||||
|
test-rest: capi
|
||||||
|
cargo test --release --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-wasi --exclude wasmer-middleware-common --exclude wasmer-singlepass-backend --exclude wasmer-clif-backend --exclude wasmer-llvm-backend
|
||||||
|
|
||||||
|
circleci-clean:
|
||||||
|
@if [ ! -z "${CIRCLE_JOB}" ]; then rm -f /home/circleci/project/target/debug/deps/libcranelift_wasm* && rm -f /Users/distiller/project/target/debug/deps/libcranelift_wasm*; fi;
|
||||||
|
|
||||||
|
test: spectests emtests middleware wasitests circleci-clean test-rest
|
||||||
|
|
||||||
|
|
||||||
|
# Integration tests
|
||||||
|
integration-tests: release-fast
|
||||||
echo "Running Integration Tests"
|
echo "Running Integration Tests"
|
||||||
./integration_tests/lua/test.sh
|
./integration_tests/lua/test.sh
|
||||||
./integration_tests/nginx/test.sh
|
./integration_tests/nginx/test.sh
|
||||||
./integration_tests/cowsay/test.sh
|
./integration_tests/cowsay/test.sh
|
||||||
|
|
||||||
|
|
||||||
|
# Utils
|
||||||
lint:
|
lint:
|
||||||
cargo fmt --all -- --check
|
cargo fmt --all -- --check
|
||||||
cargo +nightly-2019-05-20 clippy --all
|
|
||||||
|
|
||||||
precommit: lint test
|
precommit: lint test
|
||||||
|
|
||||||
|
build:
|
||||||
|
cargo build --release --features debug
|
||||||
|
|
||||||
|
install:
|
||||||
|
cargo install --path .
|
||||||
|
|
||||||
|
release:
|
||||||
|
cargo build --release --features backend:singlepass,backend:llvm,loader:kernel
|
||||||
|
|
||||||
|
# Only one backend (cranelift)
|
||||||
|
release-fast:
|
||||||
|
# If you are in OS-X, you will need mingw-w64 for cross compiling to windows
|
||||||
|
# brew install mingw-w64
|
||||||
|
cargo build --release
|
||||||
|
|
||||||
|
bench:
|
||||||
|
cargo bench --all
|
||||||
|
|
||||||
|
|
||||||
|
# Build utils
|
||||||
build-install:
|
build-install:
|
||||||
mkdir -p ./install/bin
|
mkdir -p ./install/bin
|
||||||
cp ./wapm-cli/target/release/wapm ./install/bin/
|
cp ./wapm-cli/target/release/wapm ./install/bin/
|
||||||
@ -46,62 +135,6 @@ build-install:
|
|||||||
do-install:
|
do-install:
|
||||||
tar -C ~/.wasmer -zxvf wasmer.tar.gz
|
tar -C ~/.wasmer -zxvf wasmer.tar.gz
|
||||||
|
|
||||||
test:
|
|
||||||
# We use one thread so the emscripten stdouts doesn't collide
|
|
||||||
cargo test --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-singlepass-backend --exclude wasmer-wasi --exclude wasmer-middleware-common -- $(runargs)
|
|
||||||
# cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs)
|
|
||||||
cargo test --manifest-path lib/spectests/Cargo.toml --features clif
|
|
||||||
cargo test --manifest-path lib/middleware-common/Cargo.toml --features clif
|
|
||||||
@if [ ! -z "${CIRCLE_JOB}" ]; then rm -f /home/circleci/project/target/debug/deps/libcranelift_wasm* && rm -f /Users/distiller/project/target/debug/deps/libcranelift_wasm*; fi;
|
|
||||||
cargo test --manifest-path lib/spectests/Cargo.toml --features llvm
|
|
||||||
cargo test --manifest-path lib/runtime/Cargo.toml --features llvm
|
|
||||||
cargo test --manifest-path lib/middleware-common/Cargo.toml --features llvm
|
|
||||||
cargo build -p wasmer-runtime-c-api
|
|
||||||
cargo test -p wasmer-runtime-c-api -- --nocapture
|
|
||||||
|
|
||||||
test-singlepass:
|
|
||||||
cargo test --manifest-path lib/spectests/Cargo.toml --features singlepass
|
|
||||||
cargo test --manifest-path lib/runtime/Cargo.toml --features singlepass
|
|
||||||
cargo test --manifest-path lib/middleware-common/Cargo.toml --features singlepass
|
|
||||||
|
|
||||||
test-emscripten-llvm:
|
|
||||||
cargo test --manifest-path lib/emscripten/Cargo.toml --features llvm -- --test-threads=1 $(runargs)
|
|
||||||
|
|
||||||
test-emscripten-clif:
|
|
||||||
cargo test --manifest-path lib/emscripten/Cargo.toml --features clif -- --test-threads=1 $(runargs)
|
|
||||||
|
|
||||||
test-emscripten-singlepass:
|
|
||||||
cargo test --manifest-path lib/emscripten/Cargo.toml --features singlepass -- --test-threads=1 $(runargs)
|
|
||||||
|
|
||||||
test-wasi-clif:
|
|
||||||
cargo test --manifest-path lib/wasi/Cargo.toml --features "clif" -- --test-threads=1 $(runargs)
|
|
||||||
|
|
||||||
test-wasi-singlepass:
|
|
||||||
cargo test --manifest-path lib/wasi/Cargo.toml --features "singlepass" -- --test-threads=1 $(runargs)
|
|
||||||
|
|
||||||
singlepass-debug-release:
|
|
||||||
cargo +nightly build --features backend:singlepass,debug --release
|
|
||||||
|
|
||||||
singlepass-release:
|
|
||||||
cargo +nightly build --features backend:singlepass --release
|
|
||||||
|
|
||||||
singlepass-build:
|
|
||||||
cargo +nightly build --features backend:singlepass,debug
|
|
||||||
|
|
||||||
release:
|
|
||||||
# If you are in OS-X, you will need mingw-w64 for cross compiling to windows
|
|
||||||
# brew install mingw-w64
|
|
||||||
cargo build --release
|
|
||||||
|
|
||||||
production-release:
|
|
||||||
cargo build --release --features backend:singlepass,backend:llvm,loader:kernel
|
|
||||||
|
|
||||||
debug-release:
|
|
||||||
cargo build --release --features debug
|
|
||||||
|
|
||||||
extra-debug-release:
|
|
||||||
cargo build --release --features extra-debug
|
|
||||||
|
|
||||||
publish-release:
|
publish-release:
|
||||||
ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${VERSION} ./artifacts/
|
ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${VERSION} ./artifacts/
|
||||||
|
|
||||||
|
37
README.md
37
README.md
@ -153,6 +153,12 @@ nginx and Lua do not work on Windows. See [this issue](https://github.com/wasmer
|
|||||||
|
|
||||||
Wasmer is built with [Cargo](https://crates.io/), the Rust package manager.
|
Wasmer is built with [Cargo](https://crates.io/), the Rust package manager.
|
||||||
|
|
||||||
|
Set Rust Nightly:
|
||||||
|
```
|
||||||
|
rustup default nightly
|
||||||
|
```
|
||||||
|
|
||||||
|
And install Wasmer
|
||||||
```sh
|
```sh
|
||||||
# checkout code
|
# checkout code
|
||||||
git clone https://github.com/wasmerio/wasmer.git
|
git clone https://github.com/wasmerio/wasmer.git
|
||||||
@ -160,38 +166,45 @@ cd wasmer
|
|||||||
|
|
||||||
# install tools
|
# install tools
|
||||||
# make sure that `python` is accessible.
|
# make sure that `python` is accessible.
|
||||||
cargo install --path .
|
make install
|
||||||
```
|
```
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
Thanks to [spec tests](https://github.com/wasmerio/wasmer/tree/master/lib/spectests/spectests) we can ensure 100% compatibility with the WebAssembly spec test suite.
|
Thanks to [spec tests](https://github.com/wasmerio/wasmer/tree/master/lib/spectests/spectests) we can ensure 100% compatibility with the WebAssembly spec test suite.
|
||||||
|
|
||||||
Tests can be run with:
|
You can run all the tests with:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
rustup default nightly
|
||||||
make test
|
make test
|
||||||
```
|
```
|
||||||
|
|
||||||
If you need to regenerate the Rust tests from the spec tests
|
### Testing backends
|
||||||
you can run:
|
|
||||||
|
|
||||||
```sh
|
Each backend can be tested separately:
|
||||||
make spectests
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also run integration tests with:
|
* Singlepass: `make singlepass`
|
||||||
|
* Cranelift: `make cranelift`
|
||||||
|
* LLVM: `make llvm`
|
||||||
|
|
||||||
|
### Testing integrations
|
||||||
|
|
||||||
|
Each integration can be tested separately:
|
||||||
|
|
||||||
|
* Spec tests: `make spectests`
|
||||||
|
* Emscripten: `make emtests`
|
||||||
|
* WASI: `make wasi`
|
||||||
|
* Middleware: `make middleware`
|
||||||
|
* C API: `make capi`
|
||||||
|
|
||||||
```sh
|
|
||||||
make integration-tests
|
|
||||||
```
|
|
||||||
|
|
||||||
## Benchmarking
|
## Benchmarking
|
||||||
|
|
||||||
Benchmarks can be run with:
|
Benchmarks can be run with:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo bench --all
|
make bench
|
||||||
```
|
```
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
@ -2,7 +2,7 @@ status = [
|
|||||||
"ci/circleci: lint",
|
"ci/circleci: lint",
|
||||||
"ci/circleci: test",
|
"ci/circleci: test",
|
||||||
"ci/circleci: test-macos",
|
"ci/circleci: test-macos",
|
||||||
"ci/circleci: test-rust-nightly",
|
"ci/circleci: test-stable",
|
||||||
"continuous-integration/appveyor/branch"
|
"continuous-integration/appveyor/branch"
|
||||||
]
|
]
|
||||||
required_approvals = 1
|
required_approvals = 1
|
||||||
|
74
examples/iterative_hash/Cargo.lock
generated
Normal file
74
examples/iterative_hash/Cargo.lock
generated
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "blake2"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byte-tools"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-mac"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iterative_hash"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opaque-debug"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
"checksum blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91721a6330935673395a0607df4d49a9cb90ae12d259f1b3e0a3f6e1d486872e"
|
||||||
|
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||||
|
"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
|
||||||
|
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
|
||||||
|
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
|
||||||
|
"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409"
|
||||||
|
"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
|
||||||
|
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
12
examples/iterative_hash/Cargo.toml
Normal file
12
examples/iterative_hash/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "iterative_hash"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["losfair <zhy20000919@hotmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
blake2 = "0.8"
|
16
examples/iterative_hash/src/main.rs
Normal file
16
examples/iterative_hash/src/main.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
use blake2::{Blake2b, Digest};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut data: Vec<u8> = b"test".to_vec();
|
||||||
|
|
||||||
|
for i in 0.. {
|
||||||
|
let mut hasher = Blake2b::new();
|
||||||
|
hasher.input(&data);
|
||||||
|
let out = hasher.result();
|
||||||
|
data = out.to_vec();
|
||||||
|
|
||||||
|
if i % 1000000 == 0 {
|
||||||
|
println!("Round {}: {:?}", i, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
examples/trie_traversal/trie_traversal.rs
Normal file
67
examples/trie_traversal/trie_traversal.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#[link(wasm_import_module = "wasmer_suspend")]
|
||||||
|
extern "C" {
|
||||||
|
fn suspend();
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Node {
|
||||||
|
count: usize,
|
||||||
|
children: BTreeMap<char, Node>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
fn insert(&mut self, mut s: impl Iterator<Item = char>) {
|
||||||
|
match s.next() {
|
||||||
|
Some(x) => {
|
||||||
|
self.children.entry(x).or_default().insert(s);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn for_each_dyn(&self, cb: &dyn Fn(&str, usize), prefix: &mut String) {
|
||||||
|
if self.count > 0 {
|
||||||
|
cb(&prefix, self.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (k, v) in self.children.iter() {
|
||||||
|
prefix.push(*k);
|
||||||
|
v.for_each_dyn(cb, prefix);
|
||||||
|
prefix.pop().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut root = Node::default();
|
||||||
|
root.insert("Ava".chars());
|
||||||
|
root.insert("Alexander".chars());
|
||||||
|
root.insert("Aiden".chars());
|
||||||
|
root.insert("Bella".chars());
|
||||||
|
root.insert("Brianna".chars());
|
||||||
|
root.insert("Brielle".chars());
|
||||||
|
root.insert("Charlotte".chars());
|
||||||
|
root.insert("Chloe".chars());
|
||||||
|
root.insert("Camila".chars());
|
||||||
|
|
||||||
|
println!("Tree ready, suspending.");
|
||||||
|
unsafe {
|
||||||
|
suspend();
|
||||||
|
}
|
||||||
|
|
||||||
|
root.for_each_dyn(
|
||||||
|
&|seq, count| {
|
||||||
|
println!("{}: {}", seq, count);
|
||||||
|
unsafe {
|
||||||
|
suspend();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&mut "".into(),
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("[END]");
|
||||||
|
}
|
@ -164,6 +164,7 @@ impl Intrinsics {
|
|||||||
let memory_base_ty = i8_ty;
|
let memory_base_ty = i8_ty;
|
||||||
let memory_bound_ty = i8_ty;
|
let memory_bound_ty = i8_ty;
|
||||||
let internals_ty = i64_ty;
|
let internals_ty = i64_ty;
|
||||||
|
let interrupt_signal_mem_ty = i8_ty;
|
||||||
let local_function_ty = i8_ptr_ty;
|
let local_function_ty = i8_ptr_ty;
|
||||||
|
|
||||||
let anyfunc_ty = context.struct_type(
|
let anyfunc_ty = context.struct_type(
|
||||||
@ -222,6 +223,9 @@ impl Intrinsics {
|
|||||||
internals_ty
|
internals_ty
|
||||||
.ptr_type(AddressSpace::Generic)
|
.ptr_type(AddressSpace::Generic)
|
||||||
.as_basic_type_enum(),
|
.as_basic_type_enum(),
|
||||||
|
interrupt_signal_mem_ty
|
||||||
|
.ptr_type(AddressSpace::Generic)
|
||||||
|
.as_basic_type_enum(),
|
||||||
local_function_ty
|
local_function_ty
|
||||||
.ptr_type(AddressSpace::Generic)
|
.ptr_type(AddressSpace::Generic)
|
||||||
.as_basic_type_enum(),
|
.as_basic_type_enum(),
|
||||||
|
@ -17,6 +17,7 @@ impl FunctionMiddleware for CallTrace {
|
|||||||
Event::Internal(InternalEvent::FunctionBegin(id)) => sink.push(Event::Internal(
|
Event::Internal(InternalEvent::FunctionBegin(id)) => sink.push(Event::Internal(
|
||||||
InternalEvent::Breakpoint(Box::new(move |_| {
|
InternalEvent::Breakpoint(Box::new(move |_| {
|
||||||
eprintln!("func ({})", id);
|
eprintln!("func ({})", id);
|
||||||
|
Ok(())
|
||||||
})),
|
})),
|
||||||
)),
|
)),
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -94,11 +94,9 @@ impl FunctionMiddleware for Metering {
|
|||||||
sink.push(Event::WasmOwned(Operator::If {
|
sink.push(Event::WasmOwned(Operator::If {
|
||||||
ty: WpTypeOrFuncType::Type(WpType::EmptyBlockType),
|
ty: WpTypeOrFuncType::Type(WpType::EmptyBlockType),
|
||||||
}));
|
}));
|
||||||
sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new(
|
sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new(|_| {
|
||||||
move |ctx| unsafe {
|
Err(Box::new(ExecutionLimitExceededError))
|
||||||
(ctx.throw)(Box::new(ExecutionLimitExceededError));
|
}))));
|
||||||
},
|
|
||||||
))));
|
|
||||||
sink.push(Event::WasmOwned(Operator::End));
|
sink.push(Event::WasmOwned(Operator::End));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -17,7 +17,7 @@ add_executable(test-validate test-validate.c)
|
|||||||
|
|
||||||
find_library(
|
find_library(
|
||||||
WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so libwasmer_runtime_c_api.dll
|
WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so libwasmer_runtime_c_api.dll
|
||||||
PATHS ${CMAKE_SOURCE_DIR}/../../../target/debug/
|
PATHS ${CMAKE_SOURCE_DIR}/../../../target/release/
|
||||||
)
|
)
|
||||||
|
|
||||||
if(NOT WASMER_LIB)
|
if(NOT WASMER_LIB)
|
||||||
|
@ -18,6 +18,8 @@ errno = "0.2.4"
|
|||||||
libc = "0.2.49"
|
libc = "0.2.49"
|
||||||
hex = "0.3.2"
|
hex = "0.3.2"
|
||||||
smallvec = "0.6.9"
|
smallvec = "0.6.9"
|
||||||
|
bincode = "1.1"
|
||||||
|
colored = "1.8"
|
||||||
|
|
||||||
# Dependencies for caching.
|
# Dependencies for caching.
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
@ -47,6 +49,7 @@ field-offset = "0.1.1"
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
blake2b_simd = "0.4.1"
|
blake2b_simd = "0.4.1"
|
||||||
rustc_version = "0.2.3"
|
rustc_version = "0.2.3"
|
||||||
|
cc = "1.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug = []
|
debug = []
|
||||||
|
@ -28,4 +28,16 @@ fn main() {
|
|||||||
if rustc_version::version_meta().unwrap().channel == rustc_version::Channel::Nightly {
|
if rustc_version::version_meta().unwrap().channel == rustc_version::Channel::Nightly {
|
||||||
println!("cargo:rustc-cfg=nightly");
|
println!("cargo:rustc-cfg=nightly");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg!(all(target_os = "linux", target_arch = "x86_64")) {
|
||||||
|
cc::Build::new()
|
||||||
|
.file("image-loading-linux-x86-64.s")
|
||||||
|
.compile("image-loading");
|
||||||
|
} else if cfg!(all(target_os = "macos", target_arch = "x86_64")) {
|
||||||
|
cc::Build::new()
|
||||||
|
.file("image-loading-macos-x86-64.s")
|
||||||
|
.compile("image-loading");
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
69
lib/runtime-core/image-loading-linux-x86-64.s
Normal file
69
lib/runtime-core/image-loading-linux-x86-64.s
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# NOTE: Keep this consistent with `fault.rs`.
|
||||||
|
|
||||||
|
.globl run_on_alternative_stack
|
||||||
|
run_on_alternative_stack:
|
||||||
|
# (stack_end, stack_begin)
|
||||||
|
# We need to ensure 16-byte alignment here.
|
||||||
|
pushq %r15
|
||||||
|
pushq %r14
|
||||||
|
pushq %r13
|
||||||
|
pushq %r12
|
||||||
|
pushq %rbx
|
||||||
|
pushq %rbp
|
||||||
|
movq %rsp, -16(%rdi)
|
||||||
|
|
||||||
|
leaq run_on_alternative_stack.returning(%rip), %rax
|
||||||
|
movq %rax, -24(%rdi)
|
||||||
|
|
||||||
|
movq %rsi, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm0
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm1
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm2
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm3
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm4
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm5
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm6
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm7
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
popq %rbp
|
||||||
|
popq %rax
|
||||||
|
popq %rbx
|
||||||
|
popq %rcx
|
||||||
|
popq %rdx
|
||||||
|
popq %rdi
|
||||||
|
popq %rsi
|
||||||
|
popq %r8
|
||||||
|
popq %r9
|
||||||
|
popq %r10
|
||||||
|
popq %r11
|
||||||
|
popq %r12
|
||||||
|
popq %r13
|
||||||
|
popq %r14
|
||||||
|
popq %r15
|
||||||
|
retq
|
||||||
|
|
||||||
|
run_on_alternative_stack.returning:
|
||||||
|
movq (%rsp), %rsp
|
||||||
|
popq %rbp
|
||||||
|
popq %rbx
|
||||||
|
popq %r12
|
||||||
|
popq %r13
|
||||||
|
popq %r14
|
||||||
|
popq %r15
|
||||||
|
retq
|
69
lib/runtime-core/image-loading-macos-x86-64.s
Normal file
69
lib/runtime-core/image-loading-macos-x86-64.s
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# NOTE: Keep this consistent with `fault.rs`.
|
||||||
|
|
||||||
|
.globl _run_on_alternative_stack
|
||||||
|
_run_on_alternative_stack:
|
||||||
|
# (stack_end, stack_begin)
|
||||||
|
# We need to ensure 16-byte alignment here.
|
||||||
|
pushq %r15
|
||||||
|
pushq %r14
|
||||||
|
pushq %r13
|
||||||
|
pushq %r12
|
||||||
|
pushq %rbx
|
||||||
|
pushq %rbp
|
||||||
|
movq %rsp, -16(%rdi)
|
||||||
|
|
||||||
|
leaq _run_on_alternative_stack.returning(%rip), %rax
|
||||||
|
movq %rax, -24(%rdi)
|
||||||
|
|
||||||
|
movq %rsi, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm0
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm1
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm2
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm3
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm4
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm5
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm6
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
movq (%rsp), %xmm7
|
||||||
|
add $8, %rsp
|
||||||
|
|
||||||
|
popq %rbp
|
||||||
|
popq %rax
|
||||||
|
popq %rbx
|
||||||
|
popq %rcx
|
||||||
|
popq %rdx
|
||||||
|
popq %rdi
|
||||||
|
popq %rsi
|
||||||
|
popq %r8
|
||||||
|
popq %r9
|
||||||
|
popq %r10
|
||||||
|
popq %r11
|
||||||
|
popq %r12
|
||||||
|
popq %r13
|
||||||
|
popq %r14
|
||||||
|
popq %r15
|
||||||
|
retq
|
||||||
|
|
||||||
|
_run_on_alternative_stack.returning:
|
||||||
|
movq (%rsp), %rsp
|
||||||
|
popq %rbp
|
||||||
|
popq %rbx
|
||||||
|
popq %r12
|
||||||
|
popq %r13
|
||||||
|
popq %r14
|
||||||
|
popq %r15
|
||||||
|
retq
|
@ -1,6 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::CompileResult,
|
error::CompileResult,
|
||||||
module::ModuleInner,
|
module::ModuleInner,
|
||||||
|
state::ModuleStateMap,
|
||||||
typed_func::Wasm,
|
typed_func::Wasm,
|
||||||
types::{LocalFuncIndex, SigIndex},
|
types::{LocalFuncIndex, SigIndex},
|
||||||
vm,
|
vm,
|
||||||
@ -8,6 +9,7 @@ use crate::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cache::{Artifact, Error as CacheError},
|
cache::{Artifact, Error as CacheError},
|
||||||
|
codegen::BreakpointMap,
|
||||||
module::ModuleInfo,
|
module::ModuleInfo,
|
||||||
sys::Memory,
|
sys::Memory,
|
||||||
};
|
};
|
||||||
@ -84,6 +86,14 @@ pub trait RunnableModule: Send + Sync {
|
|||||||
local_func_index: LocalFuncIndex,
|
local_func_index: LocalFuncIndex,
|
||||||
) -> Option<NonNull<vm::Func>>;
|
) -> Option<NonNull<vm::Func>>;
|
||||||
|
|
||||||
|
fn get_module_state_map(&self) -> Option<ModuleStateMap> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_breakpoints(&self) -> Option<BreakpointMap> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// A wasm trampoline contains the necessary data to dynamically call an exported wasm function.
|
/// A wasm trampoline contains the necessary data to dynamically call an exported wasm function.
|
||||||
/// Given a particular signature index, we are returned a trampoline that is matched with that
|
/// Given a particular signature index, we are returned a trampoline that is matched with that
|
||||||
/// signature and an invoke function that can call the trampoline.
|
/// signature and an invoke function that can call the trampoline.
|
||||||
|
@ -9,6 +9,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
@ -16,6 +17,10 @@ use std::sync::{Arc, RwLock};
|
|||||||
use wasmparser::{self, WasmDecoder};
|
use wasmparser::{self, WasmDecoder};
|
||||||
use wasmparser::{Operator, Type as WpType};
|
use wasmparser::{Operator, Type as WpType};
|
||||||
|
|
||||||
|
pub type BreakpointHandler =
|
||||||
|
Box<Fn(BreakpointInfo) -> Result<(), Box<dyn Any>> + Send + Sync + 'static>;
|
||||||
|
pub type BreakpointMap = Arc<HashMap<usize, BreakpointHandler>>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Event<'a, 'b> {
|
pub enum Event<'a, 'b> {
|
||||||
Internal(InternalEvent),
|
Internal(InternalEvent),
|
||||||
@ -26,7 +31,7 @@ pub enum Event<'a, 'b> {
|
|||||||
pub enum InternalEvent {
|
pub enum InternalEvent {
|
||||||
FunctionBegin(u32),
|
FunctionBegin(u32),
|
||||||
FunctionEnd,
|
FunctionEnd,
|
||||||
Breakpoint(Box<Fn(BkptInfo) + Send + Sync + 'static>),
|
Breakpoint(BreakpointHandler),
|
||||||
SetInternal(u32),
|
SetInternal(u32),
|
||||||
GetInternal(u32),
|
GetInternal(u32),
|
||||||
}
|
}
|
||||||
@ -43,8 +48,8 @@ impl fmt::Debug for InternalEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BkptInfo {
|
pub struct BreakpointInfo<'a> {
|
||||||
pub throw: unsafe fn(Box<dyn Any>) -> !,
|
pub fault: Option<&'a dyn Any>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule, E: Debug> {
|
pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule, E: Debug> {
|
||||||
|
464
lib/runtime-core/src/fault.rs
Normal file
464
lib/runtime-core/src/fault.rs
Normal file
@ -0,0 +1,464 @@
|
|||||||
|
mod raw {
|
||||||
|
use std::ffi::c_void;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn run_on_alternative_stack(stack_end: *mut u64, stack_begin: *mut u64) -> u64;
|
||||||
|
pub fn setjmp(env: *mut c_void) -> i32;
|
||||||
|
pub fn longjmp(env: *mut c_void, val: i32) -> !;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::codegen::{BreakpointInfo, BreakpointMap};
|
||||||
|
use crate::state::x64::{build_instance_image, read_stack, X64Register, GPR, XMM};
|
||||||
|
use crate::vm;
|
||||||
|
use libc::{mmap, mprotect, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
|
||||||
|
use nix::sys::signal::{
|
||||||
|
sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGINT,
|
||||||
|
SIGSEGV, SIGTRAP,
|
||||||
|
};
|
||||||
|
use std::any::Any;
|
||||||
|
use std::cell::UnsafeCell;
|
||||||
|
use std::ffi::c_void;
|
||||||
|
use std::process;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Once;
|
||||||
|
|
||||||
|
pub(crate) unsafe fn run_on_alternative_stack(stack_end: *mut u64, stack_begin: *mut u64) -> u64 {
|
||||||
|
raw::run_on_alternative_stack(stack_end, stack_begin)
|
||||||
|
}
|
||||||
|
|
||||||
|
const TRAP_STACK_SIZE: usize = 1048576; // 1MB
|
||||||
|
|
||||||
|
const SETJMP_BUFFER_LEN: usize = 27;
|
||||||
|
type SetJmpBuffer = [i32; SETJMP_BUFFER_LEN];
|
||||||
|
|
||||||
|
struct UnwindInfo {
|
||||||
|
jmpbuf: SetJmpBuffer, // in
|
||||||
|
breakpoints: Option<BreakpointMap>,
|
||||||
|
payload: Option<Box<Any>>, // out
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
static UNWIND: UnsafeCell<Option<UnwindInfo>> = UnsafeCell::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InterruptSignalMem(*mut u8);
|
||||||
|
unsafe impl Send for InterruptSignalMem {}
|
||||||
|
unsafe impl Sync for InterruptSignalMem {}
|
||||||
|
|
||||||
|
const INTERRUPT_SIGNAL_MEM_SIZE: usize = 4096;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref INTERRUPT_SIGNAL_MEM: InterruptSignalMem = {
|
||||||
|
let ptr = unsafe {
|
||||||
|
mmap(
|
||||||
|
::std::ptr::null_mut(),
|
||||||
|
INTERRUPT_SIGNAL_MEM_SIZE,
|
||||||
|
PROT_READ | PROT_WRITE,
|
||||||
|
MAP_PRIVATE | MAP_ANON,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ptr as isize == -1 {
|
||||||
|
panic!("cannot allocate code memory");
|
||||||
|
}
|
||||||
|
InterruptSignalMem(ptr as _)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
static INTERRUPT_SIGNAL_DELIVERED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
pub unsafe fn get_wasm_interrupt_signal_mem() -> *mut u8 {
|
||||||
|
INTERRUPT_SIGNAL_MEM.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn set_wasm_interrupt() {
|
||||||
|
let mem: *mut u8 = INTERRUPT_SIGNAL_MEM.0;
|
||||||
|
if mprotect(mem as _, INTERRUPT_SIGNAL_MEM_SIZE, PROT_NONE) < 0 {
|
||||||
|
panic!("cannot set PROT_NONE on signal mem");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn clear_wasm_interrupt() {
|
||||||
|
let mem: *mut u8 = INTERRUPT_SIGNAL_MEM.0;
|
||||||
|
if mprotect(mem as _, INTERRUPT_SIGNAL_MEM_SIZE, PROT_READ | PROT_WRITE) < 0 {
|
||||||
|
panic!("cannot set PROT_READ | PROT_WRITE on signal mem");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
|
||||||
|
f: F,
|
||||||
|
breakpoints: Option<BreakpointMap>,
|
||||||
|
) -> Result<R, Box<Any>> {
|
||||||
|
let unwind = UNWIND.with(|x| x.get());
|
||||||
|
let old = (*unwind).take();
|
||||||
|
*unwind = Some(UnwindInfo {
|
||||||
|
jmpbuf: [0; SETJMP_BUFFER_LEN],
|
||||||
|
breakpoints: breakpoints,
|
||||||
|
payload: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
if raw::setjmp(&mut (*unwind).as_mut().unwrap().jmpbuf as *mut SetJmpBuffer as *mut _) != 0 {
|
||||||
|
// error
|
||||||
|
let ret = (*unwind).as_mut().unwrap().payload.take().unwrap();
|
||||||
|
*unwind = old;
|
||||||
|
Err(ret)
|
||||||
|
} else {
|
||||||
|
let ret = f();
|
||||||
|
// implicit control flow to the error case...
|
||||||
|
*unwind = old;
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn begin_unsafe_unwind(e: Box<Any>) -> ! {
|
||||||
|
let unwind = UNWIND.with(|x| x.get());
|
||||||
|
let inner = (*unwind)
|
||||||
|
.as_mut()
|
||||||
|
.expect("not within a catch_unsafe_unwind scope");
|
||||||
|
inner.payload = Some(e);
|
||||||
|
raw::longjmp(&mut inner.jmpbuf as *mut SetJmpBuffer as *mut _, 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn with_breakpoint_map<R, F: FnOnce(Option<&BreakpointMap>) -> R>(f: F) -> R {
|
||||||
|
let unwind = UNWIND.with(|x| x.get());
|
||||||
|
let inner = (*unwind)
|
||||||
|
.as_mut()
|
||||||
|
.expect("not within a catch_unsafe_unwind scope");
|
||||||
|
f(inner.breakpoints.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate_and_run<R, F: FnOnce() -> R>(size: usize, f: F) -> R {
|
||||||
|
struct Context<F: FnOnce() -> R, R> {
|
||||||
|
f: Option<F>,
|
||||||
|
ret: Option<R>,
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn invoke<F: FnOnce() -> R, R>(ctx: &mut Context<F, R>) {
|
||||||
|
let f = ctx.f.take().unwrap();
|
||||||
|
ctx.ret = Some(f());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let mut ctx = Context {
|
||||||
|
f: Some(f),
|
||||||
|
ret: None,
|
||||||
|
};
|
||||||
|
assert!(size % 16 == 0);
|
||||||
|
assert!(size >= 4096);
|
||||||
|
|
||||||
|
let mut stack: Vec<u64> = vec![0; size / 8];
|
||||||
|
let end_offset = stack.len();
|
||||||
|
|
||||||
|
stack[end_offset - 4] = invoke::<F, R> as usize as u64;
|
||||||
|
|
||||||
|
// NOTE: Keep this consistent with `image-loading-*.s`.
|
||||||
|
stack[end_offset - 4 - 10] = &mut ctx as *mut Context<F, R> as usize as u64; // rdi
|
||||||
|
const NUM_SAVED_REGISTERS: usize = 23;
|
||||||
|
let stack_begin = stack
|
||||||
|
.as_mut_ptr()
|
||||||
|
.offset((end_offset - 4 - NUM_SAVED_REGISTERS) as isize);
|
||||||
|
let stack_end = stack.as_mut_ptr().offset(end_offset as isize);
|
||||||
|
|
||||||
|
raw::run_on_alternative_stack(stack_end, stack_begin);
|
||||||
|
ctx.ret.take().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn signal_trap_handler(
|
||||||
|
signum: ::nix::libc::c_int,
|
||||||
|
siginfo: *mut siginfo_t,
|
||||||
|
ucontext: *mut c_void,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
let fault = get_fault_info(siginfo as _, ucontext);
|
||||||
|
|
||||||
|
let mut unwind_result: Box<dyn Any> = Box::new(());
|
||||||
|
|
||||||
|
let should_unwind = allocate_and_run(TRAP_STACK_SIZE, || {
|
||||||
|
let mut is_suspend_signal = false;
|
||||||
|
|
||||||
|
match Signal::from_c_int(signum) {
|
||||||
|
Ok(SIGTRAP) => {
|
||||||
|
// breakpoint
|
||||||
|
let out: Option<Result<(), Box<dyn Any>>> = with_breakpoint_map(|bkpt_map| {
|
||||||
|
bkpt_map.and_then(|x| x.get(&(fault.ip as usize))).map(|x| {
|
||||||
|
x(BreakpointInfo {
|
||||||
|
fault: Some(&fault),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
match out {
|
||||||
|
Some(Ok(())) => {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Some(Err(e)) => {
|
||||||
|
unwind_result = e;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(SIGSEGV) | Ok(SIGBUS) => {
|
||||||
|
if fault.faulting_addr as usize == get_wasm_interrupt_signal_mem() as usize {
|
||||||
|
is_suspend_signal = true;
|
||||||
|
clear_wasm_interrupt();
|
||||||
|
INTERRUPT_SIGNAL_DELIVERED.store(false, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make this safer
|
||||||
|
let ctx = &mut *(fault.known_registers[X64Register::GPR(GPR::R15).to_index().0].unwrap()
|
||||||
|
as *mut vm::Ctx);
|
||||||
|
let rsp = fault.known_registers[X64Register::GPR(GPR::RSP).to_index().0].unwrap();
|
||||||
|
|
||||||
|
let msm = (*ctx.module)
|
||||||
|
.runnable_module
|
||||||
|
.get_module_state_map()
|
||||||
|
.unwrap();
|
||||||
|
let code_base = (*ctx.module).runnable_module.get_code().unwrap().as_ptr() as usize;
|
||||||
|
let es_image = read_stack(
|
||||||
|
&msm,
|
||||||
|
code_base,
|
||||||
|
rsp as usize as *const u64,
|
||||||
|
fault.known_registers,
|
||||||
|
Some(fault.ip as usize as u64),
|
||||||
|
);
|
||||||
|
|
||||||
|
if is_suspend_signal {
|
||||||
|
let image = build_instance_image(ctx, es_image);
|
||||||
|
unwind_result = Box::new(image);
|
||||||
|
} else {
|
||||||
|
use colored::*;
|
||||||
|
if es_image.frames.len() > 0 {
|
||||||
|
eprintln!(
|
||||||
|
"\n{}",
|
||||||
|
"Wasmer encountered an error while running your WebAssembly program."
|
||||||
|
.bold()
|
||||||
|
.red()
|
||||||
|
);
|
||||||
|
es_image.print_backtrace_if_needed();
|
||||||
|
}
|
||||||
|
// Just let the error propagate otherrwise
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
});
|
||||||
|
|
||||||
|
if should_unwind {
|
||||||
|
begin_unsafe_unwind(unwind_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn sigint_handler(
|
||||||
|
_signum: ::nix::libc::c_int,
|
||||||
|
_siginfo: *mut siginfo_t,
|
||||||
|
_ucontext: *mut c_void,
|
||||||
|
) {
|
||||||
|
if INTERRUPT_SIGNAL_DELIVERED.swap(true, Ordering::SeqCst) {
|
||||||
|
eprintln!("Got another SIGINT before trap is triggered on WebAssembly side, aborting");
|
||||||
|
process::abort();
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
set_wasm_interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ensure_sighandler() {
|
||||||
|
INSTALL_SIGHANDLER.call_once(|| unsafe {
|
||||||
|
install_sighandler();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static INSTALL_SIGHANDLER: Once = Once::new();
|
||||||
|
|
||||||
|
unsafe fn install_sighandler() {
|
||||||
|
let sa_trap = SigAction::new(
|
||||||
|
SigHandler::SigAction(signal_trap_handler),
|
||||||
|
SaFlags::SA_ONSTACK,
|
||||||
|
SigSet::empty(),
|
||||||
|
);
|
||||||
|
sigaction(SIGFPE, &sa_trap).unwrap();
|
||||||
|
sigaction(SIGILL, &sa_trap).unwrap();
|
||||||
|
sigaction(SIGSEGV, &sa_trap).unwrap();
|
||||||
|
sigaction(SIGBUS, &sa_trap).unwrap();
|
||||||
|
sigaction(SIGTRAP, &sa_trap).unwrap();
|
||||||
|
|
||||||
|
let sa_interrupt = SigAction::new(
|
||||||
|
SigHandler::SigAction(sigint_handler),
|
||||||
|
SaFlags::SA_ONSTACK,
|
||||||
|
SigSet::empty(),
|
||||||
|
);
|
||||||
|
sigaction(SIGINT, &sa_interrupt).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FaultInfo {
|
||||||
|
pub faulting_addr: *const c_void,
|
||||||
|
pub ip: *const c_void,
|
||||||
|
pub known_registers: [Option<u64>; 24],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
||||||
|
pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo {
|
||||||
|
use libc::{
|
||||||
|
_libc_xmmreg, ucontext_t, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, REG_R8,
|
||||||
|
REG_R9, REG_RAX, REG_RBP, REG_RBX, REG_RCX, REG_RDI, REG_RDX, REG_RIP, REG_RSI, REG_RSP,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn read_xmm(reg: &_libc_xmmreg) -> u64 {
|
||||||
|
(reg.element[0] as u64) | ((reg.element[1] as u64) << 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct siginfo_t {
|
||||||
|
si_signo: i32,
|
||||||
|
si_errno: i32,
|
||||||
|
si_code: i32,
|
||||||
|
si_addr: u64,
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
let siginfo = siginfo as *const siginfo_t;
|
||||||
|
let si_addr = (*siginfo).si_addr;
|
||||||
|
|
||||||
|
let ucontext = ucontext as *const ucontext_t;
|
||||||
|
let gregs = &(*ucontext).uc_mcontext.gregs;
|
||||||
|
let fpregs = &*(*ucontext).uc_mcontext.fpregs;
|
||||||
|
|
||||||
|
let mut known_registers: [Option<u64>; 24] = [None; 24];
|
||||||
|
known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(gregs[REG_R15 as usize] as _);
|
||||||
|
known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(gregs[REG_R14 as usize] as _);
|
||||||
|
known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(gregs[REG_R13 as usize] as _);
|
||||||
|
known_registers[X64Register::GPR(GPR::R12).to_index().0] = Some(gregs[REG_R12 as usize] as _);
|
||||||
|
known_registers[X64Register::GPR(GPR::R11).to_index().0] = Some(gregs[REG_R11 as usize] as _);
|
||||||
|
known_registers[X64Register::GPR(GPR::R10).to_index().0] = Some(gregs[REG_R10 as usize] as _);
|
||||||
|
known_registers[X64Register::GPR(GPR::R9).to_index().0] = Some(gregs[REG_R9 as usize] as _);
|
||||||
|
known_registers[X64Register::GPR(GPR::R8).to_index().0] = Some(gregs[REG_R8 as usize] as _);
|
||||||
|
known_registers[X64Register::GPR(GPR::RSI).to_index().0] = Some(gregs[REG_RSI as usize] as _);
|
||||||
|
known_registers[X64Register::GPR(GPR::RDI).to_index().0] = Some(gregs[REG_RDI as usize] as _);
|
||||||
|
known_registers[X64Register::GPR(GPR::RDX).to_index().0] = Some(gregs[REG_RDX as usize] as _);
|
||||||
|
known_registers[X64Register::GPR(GPR::RCX).to_index().0] = Some(gregs[REG_RCX as usize] as _);
|
||||||
|
known_registers[X64Register::GPR(GPR::RBX).to_index().0] = Some(gregs[REG_RBX as usize] as _);
|
||||||
|
known_registers[X64Register::GPR(GPR::RAX).to_index().0] = Some(gregs[REG_RAX as usize] as _);
|
||||||
|
|
||||||
|
known_registers[X64Register::GPR(GPR::RBP).to_index().0] = Some(gregs[REG_RBP as usize] as _);
|
||||||
|
known_registers[X64Register::GPR(GPR::RSP).to_index().0] = Some(gregs[REG_RSP as usize] as _);
|
||||||
|
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM0).to_index().0] = Some(read_xmm(&fpregs._xmm[0]));
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM1).to_index().0] = Some(read_xmm(&fpregs._xmm[1]));
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM2).to_index().0] = Some(read_xmm(&fpregs._xmm[2]));
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM3).to_index().0] = Some(read_xmm(&fpregs._xmm[3]));
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM4).to_index().0] = Some(read_xmm(&fpregs._xmm[4]));
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM5).to_index().0] = Some(read_xmm(&fpregs._xmm[5]));
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM6).to_index().0] = Some(read_xmm(&fpregs._xmm[6]));
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM7).to_index().0] = Some(read_xmm(&fpregs._xmm[7]));
|
||||||
|
|
||||||
|
FaultInfo {
|
||||||
|
faulting_addr: si_addr as usize as _,
|
||||||
|
ip: gregs[REG_RIP as usize] as _,
|
||||||
|
known_registers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
||||||
|
pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct ucontext_t {
|
||||||
|
uc_onstack: u32,
|
||||||
|
uc_sigmask: u32,
|
||||||
|
uc_stack: libc::stack_t,
|
||||||
|
uc_link: *const ucontext_t,
|
||||||
|
uc_mcsize: u64,
|
||||||
|
uc_mcontext: *const mcontext_t,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
struct exception_state {
|
||||||
|
trapno: u16,
|
||||||
|
cpu: u16,
|
||||||
|
err: u32,
|
||||||
|
faultvaddr: u64,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
struct regs {
|
||||||
|
rax: u64,
|
||||||
|
rbx: u64,
|
||||||
|
rcx: u64,
|
||||||
|
rdx: u64,
|
||||||
|
rdi: u64,
|
||||||
|
rsi: u64,
|
||||||
|
rbp: u64,
|
||||||
|
rsp: u64,
|
||||||
|
r8: u64,
|
||||||
|
r9: u64,
|
||||||
|
r10: u64,
|
||||||
|
r11: u64,
|
||||||
|
r12: u64,
|
||||||
|
r13: u64,
|
||||||
|
r14: u64,
|
||||||
|
r15: u64,
|
||||||
|
rip: u64,
|
||||||
|
rflags: u64,
|
||||||
|
cs: u64,
|
||||||
|
fs: u64,
|
||||||
|
gs: u64,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
struct fpstate {
|
||||||
|
_unused: [u8; 168],
|
||||||
|
xmm: [[u64; 2]; 8],
|
||||||
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct mcontext_t {
|
||||||
|
es: exception_state,
|
||||||
|
ss: regs,
|
||||||
|
fs: fpstate,
|
||||||
|
}
|
||||||
|
|
||||||
|
let siginfo = siginfo as *const siginfo_t;
|
||||||
|
let si_addr = (*siginfo).si_addr;
|
||||||
|
|
||||||
|
let ucontext = ucontext as *const ucontext_t;
|
||||||
|
let ss = &(*(*ucontext).uc_mcontext).ss;
|
||||||
|
let fs = &(*(*ucontext).uc_mcontext).fs;
|
||||||
|
|
||||||
|
let mut known_registers: [Option<u64>; 24] = [None; 24];
|
||||||
|
|
||||||
|
known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(ss.r15);
|
||||||
|
known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(ss.r14);
|
||||||
|
known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(ss.r13);
|
||||||
|
known_registers[X64Register::GPR(GPR::R12).to_index().0] = Some(ss.r12);
|
||||||
|
known_registers[X64Register::GPR(GPR::R11).to_index().0] = Some(ss.r11);
|
||||||
|
known_registers[X64Register::GPR(GPR::R10).to_index().0] = Some(ss.r10);
|
||||||
|
known_registers[X64Register::GPR(GPR::R9).to_index().0] = Some(ss.r9);
|
||||||
|
known_registers[X64Register::GPR(GPR::R8).to_index().0] = Some(ss.r8);
|
||||||
|
known_registers[X64Register::GPR(GPR::RSI).to_index().0] = Some(ss.rsi);
|
||||||
|
known_registers[X64Register::GPR(GPR::RDI).to_index().0] = Some(ss.rdi);
|
||||||
|
known_registers[X64Register::GPR(GPR::RDX).to_index().0] = Some(ss.rdx);
|
||||||
|
known_registers[X64Register::GPR(GPR::RCX).to_index().0] = Some(ss.rcx);
|
||||||
|
known_registers[X64Register::GPR(GPR::RBX).to_index().0] = Some(ss.rbx);
|
||||||
|
known_registers[X64Register::GPR(GPR::RAX).to_index().0] = Some(ss.rax);
|
||||||
|
|
||||||
|
known_registers[X64Register::GPR(GPR::RBP).to_index().0] = Some(ss.rbp);
|
||||||
|
known_registers[X64Register::GPR(GPR::RSP).to_index().0] = Some(ss.rsp);
|
||||||
|
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM0).to_index().0] = Some(fs.xmm[0][0]);
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM1).to_index().0] = Some(fs.xmm[1][0]);
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM2).to_index().0] = Some(fs.xmm[2][0]);
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM3).to_index().0] = Some(fs.xmm[3][0]);
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM4).to_index().0] = Some(fs.xmm[4][0]);
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM5).to_index().0] = Some(fs.xmm[5][0]);
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM6).to_index().0] = Some(fs.xmm[6][0]);
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM7).to_index().0] = Some(fs.xmm[7][0]);
|
||||||
|
|
||||||
|
FaultInfo {
|
||||||
|
faulting_addr: si_addr,
|
||||||
|
ip: ss.rip as _,
|
||||||
|
known_registers,
|
||||||
|
}
|
||||||
|
}
|
@ -46,7 +46,7 @@ impl IsExport for Export {
|
|||||||
/// ```
|
/// ```
|
||||||
pub struct ImportObject {
|
pub struct ImportObject {
|
||||||
map: Rc<RefCell<HashMap<String, Box<dyn LikeNamespace>>>>,
|
map: Rc<RefCell<HashMap<String, Box<dyn LikeNamespace>>>>,
|
||||||
state_creator: Option<Rc<Fn() -> (*mut c_void, fn(*mut c_void))>>,
|
pub(crate) state_creator: Option<Rc<Fn() -> (*mut c_void, fn(*mut c_void))>>,
|
||||||
pub allow_missing_functions: bool,
|
pub allow_missing_functions: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,9 @@ pub mod vm;
|
|||||||
pub mod vmcalls;
|
pub mod vmcalls;
|
||||||
#[cfg(all(unix, target_arch = "x86_64"))]
|
#[cfg(all(unix, target_arch = "x86_64"))]
|
||||||
pub use trampoline_x64 as trampoline;
|
pub use trampoline_x64 as trampoline;
|
||||||
|
#[cfg(all(unix, target_arch = "x86_64"))]
|
||||||
|
pub mod fault;
|
||||||
|
pub mod state;
|
||||||
|
|
||||||
use self::error::CompileResult;
|
use self::error::CompileResult;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
|
@ -223,13 +223,6 @@ pub fn read_module<
|
|||||||
let fcg = mcg
|
let fcg = mcg
|
||||||
.next_function(Arc::clone(&info))
|
.next_function(Arc::clone(&info))
|
||||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||||
middlewares
|
|
||||||
.run(
|
|
||||||
Some(fcg),
|
|
||||||
Event::Internal(InternalEvent::FunctionBegin(id as u32)),
|
|
||||||
&info.read().unwrap(),
|
|
||||||
)
|
|
||||||
.map_err(|x| LoadError::Codegen(x))?;
|
|
||||||
|
|
||||||
let info_read = info.read().unwrap();
|
let info_read = info.read().unwrap();
|
||||||
let sig = info_read
|
let sig = info_read
|
||||||
@ -271,6 +264,13 @@ pub fn read_module<
|
|||||||
body_begun = true;
|
body_begun = true;
|
||||||
fcg.begin_body(&info.read().unwrap())
|
fcg.begin_body(&info.read().unwrap())
|
||||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||||
|
middlewares
|
||||||
|
.run(
|
||||||
|
Some(fcg),
|
||||||
|
Event::Internal(InternalEvent::FunctionBegin(id as u32)),
|
||||||
|
&info.read().unwrap(),
|
||||||
|
)
|
||||||
|
.map_err(|x| LoadError::Codegen(x))?;
|
||||||
}
|
}
|
||||||
middlewares
|
middlewares
|
||||||
.run(Some(fcg), Event::Wasm(op), &info.read().unwrap())
|
.run(Some(fcg), Event::Wasm(op), &info.read().unwrap())
|
||||||
|
840
lib/runtime-core/src/state.rs
Normal file
840
lib/runtime-core/src/state.rs
Normal file
@ -0,0 +1,840 @@
|
|||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::ops::Bound::{Included, Unbounded};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
pub struct RegisterIndex(pub usize);
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
pub enum WasmAbstractValue {
|
||||||
|
Runtime,
|
||||||
|
Const(u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MachineState {
|
||||||
|
pub stack_values: Vec<MachineValue>,
|
||||||
|
pub register_values: Vec<MachineValue>,
|
||||||
|
|
||||||
|
pub wasm_stack: Vec<WasmAbstractValue>,
|
||||||
|
pub wasm_stack_private_depth: usize,
|
||||||
|
|
||||||
|
pub wasm_inst_offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct MachineStateDiff {
|
||||||
|
pub last: Option<usize>,
|
||||||
|
pub stack_push: Vec<MachineValue>,
|
||||||
|
pub stack_pop: usize,
|
||||||
|
pub reg_diff: Vec<(RegisterIndex, MachineValue)>,
|
||||||
|
|
||||||
|
pub wasm_stack_push: Vec<WasmAbstractValue>,
|
||||||
|
pub wasm_stack_pop: usize,
|
||||||
|
pub wasm_stack_private_depth: usize, // absolute value; not a diff.
|
||||||
|
|
||||||
|
pub wasm_inst_offset: usize, // absolute value; not a diff.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
pub enum MachineValue {
|
||||||
|
Undefined,
|
||||||
|
Vmctx,
|
||||||
|
PreserveRegister(RegisterIndex),
|
||||||
|
CopyStackBPRelative(i32), // relative to Base Pointer, in byte offset
|
||||||
|
ExplicitShadow, // indicates that all values above this are above the shadow region
|
||||||
|
WasmStack(usize),
|
||||||
|
WasmLocal(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct FunctionStateMap {
|
||||||
|
pub initial: MachineState,
|
||||||
|
pub local_function_id: usize,
|
||||||
|
pub locals: Vec<WasmAbstractValue>,
|
||||||
|
pub shadow_size: usize, // for single-pass backend, 32 bytes on x86-64
|
||||||
|
pub diffs: Vec<MachineStateDiff>,
|
||||||
|
pub wasm_function_header_target_offset: Option<SuspendOffset>,
|
||||||
|
pub wasm_offset_to_target_offset: BTreeMap<usize, SuspendOffset>,
|
||||||
|
pub loop_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
|
||||||
|
pub call_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
|
||||||
|
pub trappable_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum SuspendOffset {
|
||||||
|
Loop(usize),
|
||||||
|
Call(usize),
|
||||||
|
Trappable(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct OffsetInfo {
|
||||||
|
pub diff_id: usize,
|
||||||
|
pub activate_offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ModuleStateMap {
|
||||||
|
pub local_functions: BTreeMap<usize, FunctionStateMap>,
|
||||||
|
pub total_size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct WasmFunctionStateDump {
|
||||||
|
pub local_function_id: usize,
|
||||||
|
pub wasm_inst_offset: usize,
|
||||||
|
pub stack: Vec<Option<u64>>,
|
||||||
|
pub locals: Vec<Option<u64>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct ExecutionStateImage {
|
||||||
|
pub frames: Vec<WasmFunctionStateDump>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct InstanceImage {
|
||||||
|
pub memory: Option<Vec<u8>>,
|
||||||
|
pub globals: Vec<u64>,
|
||||||
|
pub execution_state: ExecutionStateImage,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleStateMap {
|
||||||
|
fn lookup_call_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> {
|
||||||
|
if ip < base || ip - base >= self.total_size {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let (_, fsm) = self
|
||||||
|
.local_functions
|
||||||
|
.range((Unbounded, Included(&(ip - base))))
|
||||||
|
.last()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
match fsm.call_offsets.get(&(ip - base)) {
|
||||||
|
Some(x) => Some((fsm, fsm.diffs[x.diff_id].build_state(fsm))),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lookup_trappable_ip(
|
||||||
|
&self,
|
||||||
|
ip: usize,
|
||||||
|
base: usize,
|
||||||
|
) -> Option<(&FunctionStateMap, MachineState)> {
|
||||||
|
if ip < base || ip - base >= self.total_size {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let (_, fsm) = self
|
||||||
|
.local_functions
|
||||||
|
.range((Unbounded, Included(&(ip - base))))
|
||||||
|
.last()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
match fsm.trappable_offsets.get(&(ip - base)) {
|
||||||
|
Some(x) => Some((fsm, fsm.diffs[x.diff_id].build_state(fsm))),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lookup_loop_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> {
|
||||||
|
if ip < base || ip - base >= self.total_size {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let (_, fsm) = self
|
||||||
|
.local_functions
|
||||||
|
.range((Unbounded, Included(&(ip - base))))
|
||||||
|
.last()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
match fsm.loop_offsets.get(&(ip - base)) {
|
||||||
|
Some(x) => Some((fsm, fsm.diffs[x.diff_id].build_state(fsm))),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FunctionStateMap {
|
||||||
|
pub fn new(
|
||||||
|
initial: MachineState,
|
||||||
|
local_function_id: usize,
|
||||||
|
shadow_size: usize,
|
||||||
|
locals: Vec<WasmAbstractValue>,
|
||||||
|
) -> FunctionStateMap {
|
||||||
|
FunctionStateMap {
|
||||||
|
initial,
|
||||||
|
local_function_id,
|
||||||
|
shadow_size,
|
||||||
|
locals,
|
||||||
|
diffs: vec![],
|
||||||
|
wasm_function_header_target_offset: None,
|
||||||
|
wasm_offset_to_target_offset: BTreeMap::new(),
|
||||||
|
loop_offsets: BTreeMap::new(),
|
||||||
|
call_offsets: BTreeMap::new(),
|
||||||
|
trappable_offsets: BTreeMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MachineState {
|
||||||
|
pub fn diff(&self, old: &MachineState) -> MachineStateDiff {
|
||||||
|
let first_diff_stack_depth: usize = self
|
||||||
|
.stack_values
|
||||||
|
.iter()
|
||||||
|
.zip(old.stack_values.iter())
|
||||||
|
.enumerate()
|
||||||
|
.find(|&(_, (&a, &b))| a != b)
|
||||||
|
.map(|x| x.0)
|
||||||
|
.unwrap_or(old.stack_values.len().min(self.stack_values.len()));
|
||||||
|
assert_eq!(self.register_values.len(), old.register_values.len());
|
||||||
|
let reg_diff: Vec<_> = self
|
||||||
|
.register_values
|
||||||
|
.iter()
|
||||||
|
.zip(old.register_values.iter())
|
||||||
|
.enumerate()
|
||||||
|
.filter(|&(_, (&a, &b))| a != b)
|
||||||
|
.map(|(i, (&a, _))| (RegisterIndex(i), a))
|
||||||
|
.collect();
|
||||||
|
let first_diff_wasm_stack_depth: usize = self
|
||||||
|
.wasm_stack
|
||||||
|
.iter()
|
||||||
|
.zip(old.wasm_stack.iter())
|
||||||
|
.enumerate()
|
||||||
|
.find(|&(_, (&a, &b))| a != b)
|
||||||
|
.map(|x| x.0)
|
||||||
|
.unwrap_or(old.wasm_stack.len().min(self.wasm_stack.len()));
|
||||||
|
MachineStateDiff {
|
||||||
|
last: None,
|
||||||
|
stack_push: self.stack_values[first_diff_stack_depth..].to_vec(),
|
||||||
|
stack_pop: old.stack_values.len() - first_diff_stack_depth,
|
||||||
|
reg_diff: reg_diff,
|
||||||
|
|
||||||
|
wasm_stack_push: self.wasm_stack[first_diff_wasm_stack_depth..].to_vec(),
|
||||||
|
wasm_stack_pop: old.wasm_stack.len() - first_diff_wasm_stack_depth,
|
||||||
|
wasm_stack_private_depth: self.wasm_stack_private_depth,
|
||||||
|
|
||||||
|
wasm_inst_offset: self.wasm_inst_offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MachineStateDiff {
|
||||||
|
pub fn build_state(&self, m: &FunctionStateMap) -> MachineState {
|
||||||
|
let mut chain: Vec<&MachineStateDiff> = vec![];
|
||||||
|
chain.push(self);
|
||||||
|
let mut current = self.last;
|
||||||
|
while let Some(x) = current {
|
||||||
|
let that = &m.diffs[x];
|
||||||
|
current = that.last;
|
||||||
|
chain.push(that);
|
||||||
|
}
|
||||||
|
chain.reverse();
|
||||||
|
let mut state = m.initial.clone();
|
||||||
|
for x in chain {
|
||||||
|
for _ in 0..x.stack_pop {
|
||||||
|
state.stack_values.pop().unwrap();
|
||||||
|
}
|
||||||
|
for v in &x.stack_push {
|
||||||
|
state.stack_values.push(*v);
|
||||||
|
}
|
||||||
|
for &(index, v) in &x.reg_diff {
|
||||||
|
state.register_values[index.0] = v;
|
||||||
|
}
|
||||||
|
for _ in 0..x.wasm_stack_pop {
|
||||||
|
state.wasm_stack.pop().unwrap();
|
||||||
|
}
|
||||||
|
for v in &x.wasm_stack_push {
|
||||||
|
state.wasm_stack.push(*v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.wasm_stack_private_depth = self.wasm_stack_private_depth;
|
||||||
|
state.wasm_inst_offset = self.wasm_inst_offset;
|
||||||
|
state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExecutionStateImage {
|
||||||
|
pub fn print_backtrace_if_needed(&self) {
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
if let Ok(x) = env::var("WASMER_BACKTRACE") {
|
||||||
|
if x == "1" {
|
||||||
|
eprintln!("{}", self.colored_output());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintln!("Run with `WASMER_BACKTRACE=1` environment variable to display a backtrace.");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn colored_output(&self) -> String {
|
||||||
|
use colored::*;
|
||||||
|
|
||||||
|
fn join_strings(x: impl Iterator<Item = String>, sep: &str) -> String {
|
||||||
|
let mut ret = String::new();
|
||||||
|
let mut first = true;
|
||||||
|
|
||||||
|
for s in x {
|
||||||
|
if first {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
ret += sep;
|
||||||
|
}
|
||||||
|
ret += &s;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_optional_u64_sequence(x: &[Option<u64>]) -> String {
|
||||||
|
if x.len() == 0 {
|
||||||
|
"(empty)".into()
|
||||||
|
} else {
|
||||||
|
join_strings(
|
||||||
|
x.iter().enumerate().map(|(i, x)| {
|
||||||
|
format!(
|
||||||
|
"[{}] = {}",
|
||||||
|
i,
|
||||||
|
x.map(|x| format!("{}", x))
|
||||||
|
.unwrap_or_else(|| "?".to_string())
|
||||||
|
.bold()
|
||||||
|
.cyan()
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
", ",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ret = String::new();
|
||||||
|
|
||||||
|
if self.frames.len() == 0 {
|
||||||
|
ret += &"Unknown fault address, cannot read stack.".yellow();
|
||||||
|
ret += "\n";
|
||||||
|
} else {
|
||||||
|
ret += &"Backtrace:".bold();
|
||||||
|
ret += "\n";
|
||||||
|
for (i, f) in self.frames.iter().enumerate() {
|
||||||
|
ret += &format!("* Frame {} @ Local function {}", i, f.local_function_id).bold();
|
||||||
|
ret += "\n";
|
||||||
|
ret += &format!(
|
||||||
|
" {} {}\n",
|
||||||
|
"Offset:".bold().yellow(),
|
||||||
|
format!("{}", f.wasm_inst_offset).bold().cyan(),
|
||||||
|
);
|
||||||
|
ret += &format!(
|
||||||
|
" {} {}\n",
|
||||||
|
"Locals:".bold().yellow(),
|
||||||
|
format_optional_u64_sequence(&f.locals)
|
||||||
|
);
|
||||||
|
ret += &format!(
|
||||||
|
" {} {}\n\n",
|
||||||
|
"Stack:".bold().yellow(),
|
||||||
|
format_optional_u64_sequence(&f.stack)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstanceImage {
|
||||||
|
pub fn from_bytes(input: &[u8]) -> Option<InstanceImage> {
|
||||||
|
use bincode::deserialize;
|
||||||
|
match deserialize(input) {
|
||||||
|
Ok(x) => Some(x),
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
use bincode::serialize;
|
||||||
|
serialize(self).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(unix, target_arch = "x86_64"))]
|
||||||
|
pub mod x64 {
|
||||||
|
use super::*;
|
||||||
|
use crate::codegen::BreakpointMap;
|
||||||
|
use crate::fault::{catch_unsafe_unwind, run_on_alternative_stack};
|
||||||
|
use crate::structures::TypedIndex;
|
||||||
|
use crate::types::LocalGlobalIndex;
|
||||||
|
use crate::vm::Ctx;
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
|
pub fn new_machine_state() -> MachineState {
|
||||||
|
MachineState {
|
||||||
|
stack_values: vec![],
|
||||||
|
register_values: vec![MachineValue::Undefined; 16 + 8],
|
||||||
|
wasm_stack: vec![],
|
||||||
|
wasm_stack_private_depth: 0,
|
||||||
|
wasm_inst_offset: ::std::usize::MAX,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[warn(unused_variables)]
|
||||||
|
pub unsafe fn invoke_call_return_on_stack(
|
||||||
|
msm: &ModuleStateMap,
|
||||||
|
code_base: usize,
|
||||||
|
image: InstanceImage,
|
||||||
|
vmctx: &mut Ctx,
|
||||||
|
breakpoints: Option<BreakpointMap>,
|
||||||
|
) -> Result<u64, Box<dyn Any>> {
|
||||||
|
let mut stack: Vec<u64> = vec![0; 1048576 * 8 / 8]; // 8MB stack
|
||||||
|
let mut stack_offset: usize = stack.len();
|
||||||
|
|
||||||
|
stack_offset -= 3; // placeholder for call return
|
||||||
|
|
||||||
|
let mut last_stack_offset: u64 = 0; // rbp
|
||||||
|
|
||||||
|
let mut known_registers: [Option<u64>; 24] = [None; 24];
|
||||||
|
|
||||||
|
let local_functions_vec: Vec<&FunctionStateMap> =
|
||||||
|
msm.local_functions.iter().map(|(_, v)| v).collect();
|
||||||
|
|
||||||
|
// Bottom to top
|
||||||
|
for f in image.execution_state.frames.iter().rev() {
|
||||||
|
let fsm = local_functions_vec[f.local_function_id];
|
||||||
|
let suspend_offset = if f.wasm_inst_offset == ::std::usize::MAX {
|
||||||
|
fsm.wasm_function_header_target_offset
|
||||||
|
} else {
|
||||||
|
fsm.wasm_offset_to_target_offset
|
||||||
|
.get(&f.wasm_inst_offset)
|
||||||
|
.map(|x| *x)
|
||||||
|
}
|
||||||
|
.expect("instruction is not a critical point");
|
||||||
|
|
||||||
|
let (activate_offset, diff_id) = match suspend_offset {
|
||||||
|
SuspendOffset::Loop(x) => fsm.loop_offsets.get(&x),
|
||||||
|
SuspendOffset::Call(x) => fsm.call_offsets.get(&x),
|
||||||
|
SuspendOffset::Trappable(x) => fsm.trappable_offsets.get(&x),
|
||||||
|
}
|
||||||
|
.map(|x| (x.activate_offset, x.diff_id))
|
||||||
|
.expect("offset cannot be found in table");
|
||||||
|
|
||||||
|
let diff = &fsm.diffs[diff_id];
|
||||||
|
let state = diff.build_state(fsm);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = stack.as_ptr().offset(last_stack_offset as isize) as usize as u64; // push rbp
|
||||||
|
last_stack_offset = stack_offset as _;
|
||||||
|
|
||||||
|
let mut got_explicit_shadow = false;
|
||||||
|
|
||||||
|
for v in state.stack_values.iter() {
|
||||||
|
match *v {
|
||||||
|
MachineValue::Undefined => stack_offset -= 1,
|
||||||
|
MachineValue::Vmctx => {
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = vmctx as *mut Ctx as usize as u64;
|
||||||
|
}
|
||||||
|
MachineValue::PreserveRegister(index) => {
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[index.0].unwrap_or(0);
|
||||||
|
}
|
||||||
|
MachineValue::CopyStackBPRelative(byte_offset) => {
|
||||||
|
assert!(byte_offset % 8 == 0);
|
||||||
|
let target_offset = (byte_offset / 8) as isize;
|
||||||
|
let v = stack[(last_stack_offset as isize + target_offset) as usize];
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = v;
|
||||||
|
}
|
||||||
|
MachineValue::ExplicitShadow => {
|
||||||
|
assert!(fsm.shadow_size % 8 == 0);
|
||||||
|
stack_offset -= fsm.shadow_size / 8;
|
||||||
|
got_explicit_shadow = true;
|
||||||
|
}
|
||||||
|
MachineValue::WasmStack(x) => {
|
||||||
|
stack_offset -= 1;
|
||||||
|
match state.wasm_stack[x] {
|
||||||
|
WasmAbstractValue::Const(x) => {
|
||||||
|
stack[stack_offset] = x;
|
||||||
|
}
|
||||||
|
WasmAbstractValue::Runtime => {
|
||||||
|
stack[stack_offset] = f.stack[x].unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MachineValue::WasmLocal(x) => {
|
||||||
|
stack_offset -= 1;
|
||||||
|
match fsm.locals[x] {
|
||||||
|
WasmAbstractValue::Const(x) => {
|
||||||
|
stack[stack_offset] = x;
|
||||||
|
}
|
||||||
|
WasmAbstractValue::Runtime => {
|
||||||
|
stack[stack_offset] = f.locals[x].unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !got_explicit_shadow {
|
||||||
|
assert!(fsm.shadow_size % 8 == 0);
|
||||||
|
stack_offset -= fsm.shadow_size / 8;
|
||||||
|
}
|
||||||
|
for (i, v) in state.register_values.iter().enumerate() {
|
||||||
|
match *v {
|
||||||
|
MachineValue::Undefined => {}
|
||||||
|
MachineValue::Vmctx => {
|
||||||
|
known_registers[i] = Some(vmctx as *mut Ctx as usize as u64);
|
||||||
|
}
|
||||||
|
MachineValue::WasmStack(x) => match state.wasm_stack[x] {
|
||||||
|
WasmAbstractValue::Const(x) => {
|
||||||
|
known_registers[i] = Some(x);
|
||||||
|
}
|
||||||
|
WasmAbstractValue::Runtime => {
|
||||||
|
known_registers[i] = Some(f.stack[x].unwrap());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MachineValue::WasmLocal(x) => match fsm.locals[x] {
|
||||||
|
WasmAbstractValue::Const(x) => {
|
||||||
|
known_registers[i] = Some(x);
|
||||||
|
}
|
||||||
|
WasmAbstractValue::Runtime => {
|
||||||
|
known_registers[i] = Some(f.locals[x].unwrap());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no need to check 16-byte alignment here because it's possible that we're not at a call entry.
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = (code_base + activate_offset) as u64; // return address
|
||||||
|
}
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[X64Register::GPR(GPR::R15).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[X64Register::GPR(GPR::R14).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[X64Register::GPR(GPR::R13).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[X64Register::GPR(GPR::R12).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[X64Register::GPR(GPR::R11).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[X64Register::GPR(GPR::R10).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[X64Register::GPR(GPR::R9).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[X64Register::GPR(GPR::R8).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[X64Register::GPR(GPR::RSI).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[X64Register::GPR(GPR::RDI).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[X64Register::GPR(GPR::RDX).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[X64Register::GPR(GPR::RCX).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[X64Register::GPR(GPR::RBX).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = known_registers[X64Register::GPR(GPR::RAX).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] = stack.as_ptr().offset(last_stack_offset as isize) as usize as u64; // rbp
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] =
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM7).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] =
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM6).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] =
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM5).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] =
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM4).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] =
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM3).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] =
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM2).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] =
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM1).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
stack_offset -= 1;
|
||||||
|
stack[stack_offset] =
|
||||||
|
known_registers[X64Register::XMM(XMM::XMM0).to_index().0].unwrap_or(0);
|
||||||
|
|
||||||
|
if let Some(ref memory) = image.memory {
|
||||||
|
assert!(vmctx.internal.memory_bound <= memory.len());
|
||||||
|
|
||||||
|
if vmctx.internal.memory_bound < memory.len() {
|
||||||
|
let grow: unsafe extern "C" fn(ctx: &mut Ctx, memory_index: usize, delta: usize) =
|
||||||
|
::std::mem::transmute((*vmctx.internal.intrinsics).memory_grow);
|
||||||
|
grow(
|
||||||
|
vmctx,
|
||||||
|
0,
|
||||||
|
(memory.len() - vmctx.internal.memory_bound) / 65536,
|
||||||
|
);
|
||||||
|
assert_eq!(vmctx.internal.memory_bound, memory.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
::std::slice::from_raw_parts_mut(
|
||||||
|
vmctx.internal.memory_base,
|
||||||
|
vmctx.internal.memory_bound,
|
||||||
|
)
|
||||||
|
.copy_from_slice(memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
let globals_len = (*vmctx.module).info.globals.len();
|
||||||
|
for i in 0..globals_len {
|
||||||
|
(*(*vmctx.local_backing).globals[LocalGlobalIndex::new(i)].vm_local_global()).data =
|
||||||
|
image.globals[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(image); // free up host memory
|
||||||
|
|
||||||
|
catch_unsafe_unwind(
|
||||||
|
|| {
|
||||||
|
run_on_alternative_stack(
|
||||||
|
stack.as_mut_ptr().offset(stack.len() as isize),
|
||||||
|
stack.as_mut_ptr().offset(stack_offset as isize),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
breakpoints,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_instance_image(
|
||||||
|
vmctx: &mut Ctx,
|
||||||
|
execution_state: ExecutionStateImage,
|
||||||
|
) -> InstanceImage {
|
||||||
|
unsafe {
|
||||||
|
let memory = if vmctx.internal.memory_base.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(
|
||||||
|
::std::slice::from_raw_parts(
|
||||||
|
vmctx.internal.memory_base,
|
||||||
|
vmctx.internal.memory_bound,
|
||||||
|
)
|
||||||
|
.to_vec(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: Imported globals
|
||||||
|
let globals_len = (*vmctx.module).info.globals.len();
|
||||||
|
let globals: Vec<u64> = (0..globals_len)
|
||||||
|
.map(|i| {
|
||||||
|
(*vmctx.local_backing).globals[LocalGlobalIndex::new(i)]
|
||||||
|
.get()
|
||||||
|
.to_u64()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
InstanceImage {
|
||||||
|
memory: memory,
|
||||||
|
globals: globals,
|
||||||
|
execution_state: execution_state,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[warn(unused_variables)]
|
||||||
|
pub unsafe fn read_stack(
|
||||||
|
msm: &ModuleStateMap,
|
||||||
|
code_base: usize,
|
||||||
|
mut stack: *const u64,
|
||||||
|
initially_known_registers: [Option<u64>; 24],
|
||||||
|
mut initial_address: Option<u64>,
|
||||||
|
) -> ExecutionStateImage {
|
||||||
|
let mut known_registers: [Option<u64>; 24] = initially_known_registers;
|
||||||
|
let mut results: Vec<WasmFunctionStateDump> = vec![];
|
||||||
|
|
||||||
|
for _ in 0.. {
|
||||||
|
let ret_addr = initial_address.take().unwrap_or_else(|| {
|
||||||
|
let x = *stack;
|
||||||
|
stack = stack.offset(1);
|
||||||
|
x
|
||||||
|
});
|
||||||
|
let (fsm, state) = match msm
|
||||||
|
.lookup_call_ip(ret_addr as usize, code_base)
|
||||||
|
.or_else(|| msm.lookup_trappable_ip(ret_addr as usize, code_base))
|
||||||
|
.or_else(|| msm.lookup_loop_ip(ret_addr as usize, code_base))
|
||||||
|
{
|
||||||
|
Some(x) => x,
|
||||||
|
_ => return ExecutionStateImage { frames: results },
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut wasm_stack: Vec<Option<u64>> = state
|
||||||
|
.wasm_stack
|
||||||
|
.iter()
|
||||||
|
.map(|x| match *x {
|
||||||
|
WasmAbstractValue::Const(x) => Some(x),
|
||||||
|
WasmAbstractValue::Runtime => None,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let mut wasm_locals: Vec<Option<u64>> = fsm
|
||||||
|
.locals
|
||||||
|
.iter()
|
||||||
|
.map(|x| match *x {
|
||||||
|
WasmAbstractValue::Const(x) => Some(x),
|
||||||
|
WasmAbstractValue::Runtime => None,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// This must be before the next loop because that modifies `known_registers`.
|
||||||
|
for (i, v) in state.register_values.iter().enumerate() {
|
||||||
|
match *v {
|
||||||
|
MachineValue::Undefined => {}
|
||||||
|
MachineValue::Vmctx => {}
|
||||||
|
MachineValue::WasmStack(idx) => {
|
||||||
|
if let Some(v) = known_registers[i] {
|
||||||
|
wasm_stack[idx] = Some(v);
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"BUG: Register {} for WebAssembly stack slot {} has unknown value.",
|
||||||
|
i, idx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MachineValue::WasmLocal(idx) => {
|
||||||
|
if let Some(v) = known_registers[i] {
|
||||||
|
wasm_locals[idx] = Some(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut found_shadow = false;
|
||||||
|
for v in state.stack_values.iter() {
|
||||||
|
match *v {
|
||||||
|
MachineValue::ExplicitShadow => {
|
||||||
|
found_shadow = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found_shadow {
|
||||||
|
stack = stack.offset((fsm.shadow_size / 8) as isize);
|
||||||
|
}
|
||||||
|
|
||||||
|
for v in state.stack_values.iter().rev() {
|
||||||
|
match *v {
|
||||||
|
MachineValue::ExplicitShadow => {
|
||||||
|
stack = stack.offset((fsm.shadow_size / 8) as isize);
|
||||||
|
}
|
||||||
|
MachineValue::Undefined => {
|
||||||
|
stack = stack.offset(1);
|
||||||
|
}
|
||||||
|
MachineValue::Vmctx => {
|
||||||
|
stack = stack.offset(1);
|
||||||
|
}
|
||||||
|
MachineValue::PreserveRegister(idx) => {
|
||||||
|
known_registers[idx.0] = Some(*stack);
|
||||||
|
stack = stack.offset(1);
|
||||||
|
}
|
||||||
|
MachineValue::CopyStackBPRelative(_) => {
|
||||||
|
stack = stack.offset(1);
|
||||||
|
}
|
||||||
|
MachineValue::WasmStack(idx) => {
|
||||||
|
wasm_stack[idx] = Some(*stack);
|
||||||
|
stack = stack.offset(1);
|
||||||
|
}
|
||||||
|
MachineValue::WasmLocal(idx) => {
|
||||||
|
wasm_locals[idx] = Some(*stack);
|
||||||
|
stack = stack.offset(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stack = stack.offset(1); // RBP
|
||||||
|
|
||||||
|
wasm_stack.truncate(
|
||||||
|
wasm_stack
|
||||||
|
.len()
|
||||||
|
.checked_sub(state.wasm_stack_private_depth)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let wfs = WasmFunctionStateDump {
|
||||||
|
local_function_id: fsm.local_function_id,
|
||||||
|
wasm_inst_offset: state.wasm_inst_offset,
|
||||||
|
stack: wasm_stack,
|
||||||
|
locals: wasm_locals,
|
||||||
|
};
|
||||||
|
results.push(wfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
|
pub enum GPR {
|
||||||
|
RAX,
|
||||||
|
RCX,
|
||||||
|
RDX,
|
||||||
|
RBX,
|
||||||
|
RSP,
|
||||||
|
RBP,
|
||||||
|
RSI,
|
||||||
|
RDI,
|
||||||
|
R8,
|
||||||
|
R9,
|
||||||
|
R10,
|
||||||
|
R11,
|
||||||
|
R12,
|
||||||
|
R13,
|
||||||
|
R14,
|
||||||
|
R15,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
|
pub enum XMM {
|
||||||
|
XMM0,
|
||||||
|
XMM1,
|
||||||
|
XMM2,
|
||||||
|
XMM3,
|
||||||
|
XMM4,
|
||||||
|
XMM5,
|
||||||
|
XMM6,
|
||||||
|
XMM7,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum X64Register {
|
||||||
|
GPR(GPR),
|
||||||
|
XMM(XMM),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl X64Register {
|
||||||
|
pub fn to_index(&self) -> RegisterIndex {
|
||||||
|
match *self {
|
||||||
|
X64Register::GPR(x) => RegisterIndex(x as usize),
|
||||||
|
X64Register::XMM(x) => RegisterIndex(x as usize + 16),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,8 @@
|
|||||||
//! Variadic functions are not supported because `rax` is used by the trampoline code.
|
//! Variadic functions are not supported because `rax` is used by the trampoline code.
|
||||||
|
|
||||||
use crate::loader::CodeMemory;
|
use crate::loader::CodeMemory;
|
||||||
|
use crate::vm::Ctx;
|
||||||
|
use std::fmt;
|
||||||
use std::{mem, slice};
|
use std::{mem, slice};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@ -98,6 +100,46 @@ impl TrampolineBufferBuilder {
|
|||||||
idx
|
idx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_context_rsp_state_preserving_trampoline(
|
||||||
|
&mut self,
|
||||||
|
target: unsafe extern "C" fn(&mut Ctx, *const CallContext, *const u64),
|
||||||
|
context: *const CallContext,
|
||||||
|
) -> usize {
|
||||||
|
let idx = self.offsets.len();
|
||||||
|
self.offsets.push(self.code.len());
|
||||||
|
|
||||||
|
self.code.extend_from_slice(&[
|
||||||
|
0x53, // push %rbx
|
||||||
|
0x41, 0x54, // push %r12
|
||||||
|
0x41, 0x55, // push %r13
|
||||||
|
0x41, 0x56, // push %r14
|
||||||
|
0x41, 0x57, // push %r15
|
||||||
|
]);
|
||||||
|
self.code.extend_from_slice(&[
|
||||||
|
0x48, 0xbe, // movabsq ?, %rsi
|
||||||
|
]);
|
||||||
|
self.code.extend_from_slice(value_to_bytes(&context));
|
||||||
|
self.code.extend_from_slice(&[
|
||||||
|
0x48, 0x89, 0xe2, // mov %rsp, %rdx
|
||||||
|
]);
|
||||||
|
|
||||||
|
self.code.extend_from_slice(&[
|
||||||
|
0x48, 0xb8, // movabsq ?, %rax
|
||||||
|
]);
|
||||||
|
self.code.extend_from_slice(value_to_bytes(&target));
|
||||||
|
self.code.extend_from_slice(&[
|
||||||
|
0xff, 0xd0, // callq *%rax
|
||||||
|
]);
|
||||||
|
self.code.extend_from_slice(&[
|
||||||
|
0x48, 0x81, 0xc4, // add ?, %rsp
|
||||||
|
]);
|
||||||
|
self.code.extend_from_slice(value_to_bytes(&40i32)); // 5 * 8
|
||||||
|
self.code.extend_from_slice(&[
|
||||||
|
0xc3, //retq
|
||||||
|
]);
|
||||||
|
idx
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds a callinfo trampoline.
|
/// Adds a callinfo trampoline.
|
||||||
///
|
///
|
||||||
/// This generates a trampoline function that collects `num_params` parameters into an array
|
/// This generates a trampoline function that collects `num_params` parameters into an array
|
||||||
@ -196,6 +238,12 @@ impl TrampolineBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for TrampolineBuffer {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "TrampolineBuffer {{}}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -180,6 +180,10 @@ where
|
|||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_vm_func(&self) -> NonNull<vm::Func> {
|
||||||
|
self.f
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Args, Rets> Func<'a, Args, Rets, Host>
|
impl<'a, Args, Rets> Func<'a, Args, Rets, Host>
|
||||||
@ -364,30 +368,35 @@ macro_rules! impl_traits {
|
|||||||
impl< $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap> ExternalFunction<($( $x ),*), Rets> for FN {
|
impl< $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap> ExternalFunction<($( $x ),*), Rets> for FN {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn to_raw(&self) -> NonNull<vm::Func> {
|
fn to_raw(&self) -> NonNull<vm::Func> {
|
||||||
assert_eq!(mem::size_of::<Self>(), 0, "you cannot use a closure that captures state for `Func`.");
|
if mem::size_of::<Self>() == 0 {
|
||||||
|
/// This is required for the llvm backend to be able to unwind through this function.
|
||||||
|
#[cfg_attr(nightly, unwind(allowed))]
|
||||||
|
extern fn wrap<$( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap>( ctx: &mut Ctx $( ,$x: <$x as WasmExternType>::Native )* ) -> Rets::CStruct {
|
||||||
|
let f: FN = unsafe { mem::transmute_copy(&()) };
|
||||||
|
|
||||||
/// This is required for the llvm backend to be able to unwind through this function.
|
let err = match panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||||
#[cfg_attr(nightly, unwind(allowed))]
|
f( ctx $( ,WasmExternType::from_native($x) )* ).report()
|
||||||
extern fn wrap<$( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap>( ctx: &mut Ctx $( ,$x: <$x as WasmExternType>::Native )* ) -> Rets::CStruct {
|
})) {
|
||||||
let f: FN = unsafe { mem::transmute_copy(&()) };
|
Ok(Ok(returns)) => return returns.into_c_struct(),
|
||||||
|
Ok(Err(err)) => {
|
||||||
|
let b: Box<_> = err.into();
|
||||||
|
b as Box<dyn Any>
|
||||||
|
},
|
||||||
|
Err(err) => err,
|
||||||
|
};
|
||||||
|
|
||||||
let err = match panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
unsafe {
|
||||||
f( ctx $( ,WasmExternType::from_native($x) )* ).report()
|
(&*ctx.module).runnable_module.do_early_trap(err)
|
||||||
})) {
|
}
|
||||||
Ok(Ok(returns)) => return returns.into_c_struct(),
|
|
||||||
Ok(Err(err)) => {
|
|
||||||
let b: Box<_> = err.into();
|
|
||||||
b as Box<dyn Any>
|
|
||||||
},
|
|
||||||
Err(err) => err,
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
(&*ctx.module).runnable_module.do_early_trap(err)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap()
|
NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap()
|
||||||
|
} else {
|
||||||
|
assert_eq!(mem::size_of::<Self>(), mem::size_of::<usize>(), "you cannot use a closure that captures state for `Func`.");
|
||||||
|
NonNull::new(unsafe {
|
||||||
|
::std::mem::transmute_copy::<_, *mut vm::Func>(self)
|
||||||
|
}).unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,8 +38,8 @@ pub struct Ctx {
|
|||||||
|
|
||||||
/// These are pointers to things that are known to be owned
|
/// These are pointers to things that are known to be owned
|
||||||
/// by the owning `Instance`.
|
/// by the owning `Instance`.
|
||||||
local_backing: *mut LocalBacking,
|
pub local_backing: *mut LocalBacking,
|
||||||
import_backing: *mut ImportBacking,
|
pub import_backing: *mut ImportBacking,
|
||||||
pub module: *const ModuleInner,
|
pub module: *const ModuleInner,
|
||||||
|
|
||||||
//// This is intended to be user-supplied, per-instance
|
//// This is intended to be user-supplied, per-instance
|
||||||
@ -100,6 +100,8 @@ pub struct InternalCtx {
|
|||||||
pub memory_bound: usize,
|
pub memory_bound: usize,
|
||||||
|
|
||||||
pub internals: *mut [u64; INTERNALS_SIZE], // TODO: Make this dynamic?
|
pub internals: *mut [u64; INTERNALS_SIZE], // TODO: Make this dynamic?
|
||||||
|
|
||||||
|
pub interrupt_signal_mem: *mut u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
static INTERNAL_FIELDS: AtomicUsize = AtomicUsize::new(0);
|
static INTERNAL_FIELDS: AtomicUsize = AtomicUsize::new(0);
|
||||||
@ -207,6 +209,17 @@ fn get_intrinsics_for_module(m: &ModuleInfo) -> *const Intrinsics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(unix, target_arch = "x86_64"))]
|
||||||
|
fn get_interrupt_signal_mem() -> *mut u8 {
|
||||||
|
unsafe { crate::fault::get_wasm_interrupt_signal_mem() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(all(unix, target_arch = "x86_64")))]
|
||||||
|
fn get_interrupt_signal_mem() -> *mut u8 {
|
||||||
|
static mut REGION: u64 = 0;
|
||||||
|
unsafe { &mut REGION as *mut u64 as *mut u8 }
|
||||||
|
}
|
||||||
|
|
||||||
impl Ctx {
|
impl Ctx {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub unsafe fn new(
|
pub unsafe fn new(
|
||||||
@ -245,6 +258,8 @@ impl Ctx {
|
|||||||
memory_bound: mem_bound,
|
memory_bound: mem_bound,
|
||||||
|
|
||||||
internals: &mut local_backing.internals.0,
|
internals: &mut local_backing.internals.0,
|
||||||
|
|
||||||
|
interrupt_signal_mem: get_interrupt_signal_mem(),
|
||||||
},
|
},
|
||||||
local_functions: local_backing.local_functions.as_ptr(),
|
local_functions: local_backing.local_functions.as_ptr(),
|
||||||
|
|
||||||
@ -296,6 +311,8 @@ impl Ctx {
|
|||||||
memory_bound: mem_bound,
|
memory_bound: mem_bound,
|
||||||
|
|
||||||
internals: &mut local_backing.internals.0,
|
internals: &mut local_backing.internals.0,
|
||||||
|
|
||||||
|
interrupt_signal_mem: get_interrupt_signal_mem(),
|
||||||
},
|
},
|
||||||
local_functions: local_backing.local_functions.as_ptr(),
|
local_functions: local_backing.local_functions.as_ptr(),
|
||||||
|
|
||||||
@ -419,9 +436,13 @@ impl Ctx {
|
|||||||
12 * (mem::size_of::<usize>() as u8)
|
12 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offset_local_functions() -> u8 {
|
pub fn offset_interrupt_signal_mem() -> u8 {
|
||||||
13 * (mem::size_of::<usize>() as u8)
|
13 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn offset_local_functions() -> u8 {
|
||||||
|
14 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum InnerFunc {}
|
enum InnerFunc {}
|
||||||
@ -640,6 +661,11 @@ mod vm_offset_tests {
|
|||||||
offset_of!(InternalCtx => internals).get_byte_offset(),
|
offset_of!(InternalCtx => internals).get_byte_offset(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Ctx::offset_interrupt_signal_mem() as usize,
|
||||||
|
offset_of!(InternalCtx => interrupt_signal_mem).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ctx::offset_local_functions() as usize,
|
Ctx::offset_local_functions() as usize,
|
||||||
offset_of!(Ctx => local_functions).get_byte_offset(),
|
offset_of!(Ctx => local_functions).get_byte_offset(),
|
||||||
|
@ -18,3 +18,4 @@ nix = "0.13.0"
|
|||||||
libc = "0.2.49"
|
libc = "0.2.49"
|
||||||
smallvec = "0.6.9"
|
smallvec = "0.6.9"
|
||||||
hashbrown = "0.1"
|
hashbrown = "0.1"
|
||||||
|
colored = "1.8"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,38 +1,5 @@
|
|||||||
use dynasmrt::{x64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi};
|
use dynasmrt::{x64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi};
|
||||||
|
pub use wasmer_runtime_core::state::x64::{GPR, XMM};
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
|
||||||
pub enum GPR {
|
|
||||||
RAX,
|
|
||||||
RCX,
|
|
||||||
RDX,
|
|
||||||
RBX,
|
|
||||||
RSP,
|
|
||||||
RBP,
|
|
||||||
RSI,
|
|
||||||
RDI,
|
|
||||||
R8,
|
|
||||||
R9,
|
|
||||||
R10,
|
|
||||||
R11,
|
|
||||||
R12,
|
|
||||||
R13,
|
|
||||||
R14,
|
|
||||||
R15,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
|
||||||
pub enum XMM {
|
|
||||||
XMM0,
|
|
||||||
XMM1,
|
|
||||||
XMM2,
|
|
||||||
XMM3,
|
|
||||||
XMM4,
|
|
||||||
XMM5,
|
|
||||||
XMM6,
|
|
||||||
XMM7,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub enum Location {
|
pub enum Location {
|
||||||
@ -87,7 +54,7 @@ pub trait Emitter {
|
|||||||
type Offset;
|
type Offset;
|
||||||
|
|
||||||
fn get_label(&mut self) -> Self::Label;
|
fn get_label(&mut self) -> Self::Label;
|
||||||
fn get_offset(&mut self) -> Self::Offset;
|
fn get_offset(&self) -> Self::Offset;
|
||||||
|
|
||||||
fn emit_u64(&mut self, x: u64);
|
fn emit_u64(&mut self, x: u64);
|
||||||
|
|
||||||
@ -488,7 +455,7 @@ impl Emitter for Assembler {
|
|||||||
self.new_dynamic_label()
|
self.new_dynamic_label()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_offset(&mut self) -> AssemblyOffset {
|
fn get_offset(&self) -> AssemblyOffset {
|
||||||
self.offset()
|
self.offset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ extern crate smallvec;
|
|||||||
mod codegen_x64;
|
mod codegen_x64;
|
||||||
mod emitter_x64;
|
mod emitter_x64;
|
||||||
mod machine;
|
mod machine;
|
||||||
mod protect_unix;
|
pub mod protect_unix;
|
||||||
|
|
||||||
pub use codegen_x64::X64FunctionCode as FunctionCodeGenerator;
|
pub use codegen_x64::X64FunctionCode as FunctionCodeGenerator;
|
||||||
pub use codegen_x64::X64ModuleCodeGenerator as ModuleCodeGenerator;
|
pub use codegen_x64::X64ModuleCodeGenerator as ModuleCodeGenerator;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use crate::emitter_x64::*;
|
use crate::emitter_x64::*;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use wasmer_runtime_core::state::x64::X64Register;
|
||||||
|
use wasmer_runtime_core::state::*;
|
||||||
use wasmparser::Type as WpType;
|
use wasmparser::Type as WpType;
|
||||||
|
|
||||||
struct MachineStackOffset(usize);
|
struct MachineStackOffset(usize);
|
||||||
@ -10,6 +12,7 @@ pub struct Machine {
|
|||||||
used_xmms: HashSet<XMM>,
|
used_xmms: HashSet<XMM>,
|
||||||
stack_offset: MachineStackOffset,
|
stack_offset: MachineStackOffset,
|
||||||
save_area_offset: Option<MachineStackOffset>,
|
save_area_offset: Option<MachineStackOffset>,
|
||||||
|
pub state: MachineState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
@ -19,6 +22,7 @@ impl Machine {
|
|||||||
used_xmms: HashSet::new(),
|
used_xmms: HashSet::new(),
|
||||||
stack_offset: MachineStackOffset(0),
|
stack_offset: MachineStackOffset(0),
|
||||||
save_area_offset: None,
|
save_area_offset: None,
|
||||||
|
state: x64::new_machine_state(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,13 +133,13 @@ impl Machine {
|
|||||||
pub fn acquire_locations<E: Emitter>(
|
pub fn acquire_locations<E: Emitter>(
|
||||||
&mut self,
|
&mut self,
|
||||||
assembler: &mut E,
|
assembler: &mut E,
|
||||||
tys: &[WpType],
|
tys: &[(WpType, MachineValue)],
|
||||||
zeroed: bool,
|
zeroed: bool,
|
||||||
) -> SmallVec<[Location; 1]> {
|
) -> SmallVec<[Location; 1]> {
|
||||||
let mut ret = smallvec![];
|
let mut ret = smallvec![];
|
||||||
let mut delta_stack_offset: usize = 0;
|
let mut delta_stack_offset: usize = 0;
|
||||||
|
|
||||||
for ty in tys {
|
for (ty, mv) in tys {
|
||||||
let loc = match *ty {
|
let loc = match *ty {
|
||||||
WpType::F32 | WpType::F64 => self.pick_xmm().map(Location::XMM),
|
WpType::F32 | WpType::F64 => self.pick_xmm().map(Location::XMM),
|
||||||
WpType::I32 | WpType::I64 => self.pick_gpr().map(Location::GPR),
|
WpType::I32 | WpType::I64 => self.pick_gpr().map(Location::GPR),
|
||||||
@ -151,9 +155,14 @@ impl Machine {
|
|||||||
};
|
};
|
||||||
if let Location::GPR(x) = loc {
|
if let Location::GPR(x) = loc {
|
||||||
self.used_gprs.insert(x);
|
self.used_gprs.insert(x);
|
||||||
|
self.state.register_values[X64Register::GPR(x).to_index().0] = *mv;
|
||||||
} else if let Location::XMM(x) = loc {
|
} else if let Location::XMM(x) = loc {
|
||||||
self.used_xmms.insert(x);
|
self.used_xmms.insert(x);
|
||||||
|
self.state.register_values[X64Register::XMM(x).to_index().0] = *mv;
|
||||||
|
} else {
|
||||||
|
self.state.stack_values.push(*mv);
|
||||||
}
|
}
|
||||||
|
self.state.wasm_stack.push(WasmAbstractValue::Runtime);
|
||||||
ret.push(loc);
|
ret.push(loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,9 +189,13 @@ impl Machine {
|
|||||||
match *loc {
|
match *loc {
|
||||||
Location::GPR(ref x) => {
|
Location::GPR(ref x) => {
|
||||||
assert_eq!(self.used_gprs.remove(x), true);
|
assert_eq!(self.used_gprs.remove(x), true);
|
||||||
|
self.state.register_values[X64Register::GPR(*x).to_index().0] =
|
||||||
|
MachineValue::Undefined;
|
||||||
}
|
}
|
||||||
Location::XMM(ref x) => {
|
Location::XMM(ref x) => {
|
||||||
assert_eq!(self.used_xmms.remove(x), true);
|
assert_eq!(self.used_xmms.remove(x), true);
|
||||||
|
self.state.register_values[X64Register::XMM(*x).to_index().0] =
|
||||||
|
MachineValue::Undefined;
|
||||||
}
|
}
|
||||||
Location::Memory(GPR::RBP, x) => {
|
Location::Memory(GPR::RBP, x) => {
|
||||||
if x >= 0 {
|
if x >= 0 {
|
||||||
@ -194,9 +207,11 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
self.stack_offset.0 -= 8;
|
self.stack_offset.0 -= 8;
|
||||||
delta_stack_offset += 8;
|
delta_stack_offset += 8;
|
||||||
|
self.state.stack_values.pop().unwrap();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
self.state.wasm_stack.pop().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if delta_stack_offset != 0 {
|
if delta_stack_offset != 0 {
|
||||||
@ -213,12 +228,17 @@ impl Machine {
|
|||||||
match *loc {
|
match *loc {
|
||||||
Location::GPR(ref x) => {
|
Location::GPR(ref x) => {
|
||||||
assert_eq!(self.used_gprs.remove(x), true);
|
assert_eq!(self.used_gprs.remove(x), true);
|
||||||
|
self.state.register_values[X64Register::GPR(*x).to_index().0] =
|
||||||
|
MachineValue::Undefined;
|
||||||
}
|
}
|
||||||
Location::XMM(ref x) => {
|
Location::XMM(ref x) => {
|
||||||
assert_eq!(self.used_xmms.remove(x), true);
|
assert_eq!(self.used_xmms.remove(x), true);
|
||||||
|
self.state.register_values[X64Register::XMM(*x).to_index().0] =
|
||||||
|
MachineValue::Undefined;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
// Wasm state popping is deferred to `release_locations_only_osr_state`.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,9 +261,11 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
self.stack_offset.0 -= 8;
|
self.stack_offset.0 -= 8;
|
||||||
delta_stack_offset += 8;
|
delta_stack_offset += 8;
|
||||||
|
self.state.stack_values.pop().unwrap();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
// Wasm state popping is deferred to `release_locations_only_osr_state`.
|
||||||
}
|
}
|
||||||
|
|
||||||
if delta_stack_offset != 0 {
|
if delta_stack_offset != 0 {
|
||||||
@ -255,6 +277,12 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn release_locations_only_osr_state(&mut self, n: usize) {
|
||||||
|
for _ in 0..n {
|
||||||
|
self.state.wasm_stack.pop().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn release_locations_keep_state<E: Emitter>(&self, assembler: &mut E, locs: &[Location]) {
|
pub fn release_locations_keep_state<E: Emitter>(&self, assembler: &mut E, locs: &[Location]) {
|
||||||
let mut delta_stack_offset: usize = 0;
|
let mut delta_stack_offset: usize = 0;
|
||||||
let mut stack_offset = self.stack_offset.0;
|
let mut stack_offset = self.stack_offset.0;
|
||||||
@ -314,7 +342,11 @@ impl Machine {
|
|||||||
allocated += 1;
|
allocated += 1;
|
||||||
get_local_location(old_idx)
|
get_local_location(old_idx)
|
||||||
}
|
}
|
||||||
Location::Memory(_, _) => loc,
|
Location::Memory(_, _) => {
|
||||||
|
let old_idx = allocated;
|
||||||
|
allocated += 1;
|
||||||
|
get_local_location(old_idx)
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -325,6 +357,19 @@ impl Machine {
|
|||||||
allocated += 1;
|
allocated += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i, loc) in locations.iter().enumerate() {
|
||||||
|
match *loc {
|
||||||
|
Location::GPR(x) => {
|
||||||
|
self.state.register_values[X64Register::GPR(x).to_index().0] =
|
||||||
|
MachineValue::WasmLocal(i);
|
||||||
|
}
|
||||||
|
Location::Memory(_, _) => {
|
||||||
|
self.state.stack_values.push(MachineValue::WasmLocal(i));
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// How many machine stack slots did all the locals use?
|
// How many machine stack slots did all the locals use?
|
||||||
let num_mem_slots = locations
|
let num_mem_slots = locations
|
||||||
.iter()
|
.iter()
|
||||||
@ -346,15 +391,21 @@ impl Machine {
|
|||||||
|
|
||||||
// Save callee-saved registers.
|
// Save callee-saved registers.
|
||||||
for loc in locations.iter() {
|
for loc in locations.iter() {
|
||||||
if let Location::GPR(_) = *loc {
|
if let Location::GPR(x) = *loc {
|
||||||
a.emit_push(Size::S64, *loc);
|
a.emit_push(Size::S64, *loc);
|
||||||
self.stack_offset.0 += 8;
|
self.stack_offset.0 += 8;
|
||||||
|
self.state.stack_values.push(MachineValue::PreserveRegister(
|
||||||
|
X64Register::GPR(x).to_index(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save R15 for vmctx use.
|
// Save R15 for vmctx use.
|
||||||
a.emit_push(Size::S64, Location::GPR(GPR::R15));
|
a.emit_push(Size::S64, Location::GPR(GPR::R15));
|
||||||
self.stack_offset.0 += 8;
|
self.stack_offset.0 += 8;
|
||||||
|
self.state.stack_values.push(MachineValue::PreserveRegister(
|
||||||
|
X64Register::GPR(GPR::R15).to_index(),
|
||||||
|
));
|
||||||
|
|
||||||
// Save the offset of static area.
|
// Save the offset of static area.
|
||||||
self.save_area_offset = Some(MachineStackOffset(self.stack_offset.0));
|
self.save_area_offset = Some(MachineStackOffset(self.stack_offset.0));
|
||||||
@ -366,7 +417,17 @@ impl Machine {
|
|||||||
Location::GPR(_) => {
|
Location::GPR(_) => {
|
||||||
a.emit_mov(Size::S64, loc, locations[i]);
|
a.emit_mov(Size::S64, loc, locations[i]);
|
||||||
}
|
}
|
||||||
_ => break,
|
Location::Memory(_, _) => match locations[i] {
|
||||||
|
Location::GPR(_) => {
|
||||||
|
a.emit_mov(Size::S64, loc, locations[i]);
|
||||||
|
}
|
||||||
|
Location::Memory(_, _) => {
|
||||||
|
a.emit_mov(Size::S64, loc, Location::GPR(GPR::RAX));
|
||||||
|
a.emit_mov(Size::S64, Location::GPR(GPR::RAX), locations[i]);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,7 +490,11 @@ mod test {
|
|||||||
fn test_release_locations_keep_state_nopanic() {
|
fn test_release_locations_keep_state_nopanic() {
|
||||||
let mut machine = Machine::new();
|
let mut machine = Machine::new();
|
||||||
let mut assembler = Assembler::new().unwrap();
|
let mut assembler = Assembler::new().unwrap();
|
||||||
let locs = machine.acquire_locations(&mut assembler, &[WpType::I32; 10], false);
|
let locs = machine.acquire_locations(
|
||||||
|
&mut assembler,
|
||||||
|
&[(WpType::I32, MachineValue::Undefined); 10],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
machine.release_locations_keep_state(&mut assembler, &locs);
|
machine.release_locations_keep_state(&mut assembler, &locs);
|
||||||
}
|
}
|
||||||
|
@ -9,77 +9,18 @@
|
|||||||
//! are very special, the async signal unsafety of Rust's TLS implementation generally does not affect the correctness here
|
//! are very special, the async signal unsafety of Rust's TLS implementation generally does not affect the correctness here
|
||||||
//! unless you have memory unsafety elsewhere in your code.
|
//! unless you have memory unsafety elsewhere in your code.
|
||||||
//!
|
//!
|
||||||
use libc::{c_int, c_void, siginfo_t};
|
|
||||||
use nix::sys::signal::{
|
|
||||||
sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV,
|
|
||||||
SIGTRAP,
|
|
||||||
};
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::{Cell, RefCell, UnsafeCell};
|
use std::cell::Cell;
|
||||||
use std::collections::HashMap;
|
use wasmer_runtime_core::codegen::BreakpointMap;
|
||||||
use std::ptr;
|
use wasmer_runtime_core::fault::{begin_unsafe_unwind, catch_unsafe_unwind, ensure_sighandler};
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::Once;
|
|
||||||
use wasmer_runtime_core::codegen::BkptInfo;
|
|
||||||
use wasmer_runtime_core::typed_func::WasmTrapInfo;
|
use wasmer_runtime_core::typed_func::WasmTrapInfo;
|
||||||
|
|
||||||
extern "C" fn signal_trap_handler(
|
|
||||||
signum: ::nix::libc::c_int,
|
|
||||||
siginfo: *mut siginfo_t,
|
|
||||||
ucontext: *mut c_void,
|
|
||||||
) {
|
|
||||||
unsafe {
|
|
||||||
match Signal::from_c_int(signum) {
|
|
||||||
Ok(SIGTRAP) => {
|
|
||||||
let (_, ip) = get_faulting_addr_and_ip(siginfo as _, ucontext);
|
|
||||||
let bkpt_map = BKPT_MAP.with(|x| x.borrow().last().map(|x| x.clone()));
|
|
||||||
if let Some(bkpt_map) = bkpt_map {
|
|
||||||
if let Some(ref x) = bkpt_map.get(&(ip as usize)) {
|
|
||||||
(x)(BkptInfo { throw: throw });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
do_unwind(signum, siginfo as _, ucontext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
pub fn setjmp(env: *mut c_void) -> c_int;
|
|
||||||
fn longjmp(env: *mut c_void, val: c_int) -> !;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn install_sighandler() {
|
|
||||||
let sa = SigAction::new(
|
|
||||||
SigHandler::SigAction(signal_trap_handler),
|
|
||||||
SaFlags::SA_ONSTACK,
|
|
||||||
SigSet::empty(),
|
|
||||||
);
|
|
||||||
sigaction(SIGFPE, &sa).unwrap();
|
|
||||||
sigaction(SIGILL, &sa).unwrap();
|
|
||||||
sigaction(SIGSEGV, &sa).unwrap();
|
|
||||||
sigaction(SIGBUS, &sa).unwrap();
|
|
||||||
sigaction(SIGTRAP, &sa).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
const SETJMP_BUFFER_LEN: usize = 27;
|
|
||||||
pub static SIGHANDLER_INIT: Once = Once::new();
|
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
pub static SETJMP_BUFFER: UnsafeCell<[c_int; SETJMP_BUFFER_LEN]> = UnsafeCell::new([0; SETJMP_BUFFER_LEN]);
|
|
||||||
pub static CAUGHT_ADDRESSES: Cell<(*const c_void, *const c_void)> = Cell::new((ptr::null(), ptr::null()));
|
|
||||||
pub static CURRENT_EXECUTABLE_BUFFER: Cell<*const c_void> = Cell::new(ptr::null());
|
|
||||||
pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any>>> = Cell::new(None);
|
pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any>>> = Cell::new(None);
|
||||||
pub static BKPT_MAP: RefCell<Vec<Arc<HashMap<usize, Box<Fn(BkptInfo) + Send + Sync + 'static>>>>> = RefCell::new(Vec::new());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn trigger_trap() -> ! {
|
pub unsafe fn trigger_trap() -> ! {
|
||||||
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
begin_unsafe_unwind(Box::new(()));
|
||||||
|
|
||||||
longjmp(jmp_buf as *mut c_void, 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum CallProtError {
|
pub enum CallProtError {
|
||||||
@ -87,157 +28,26 @@ pub enum CallProtError {
|
|||||||
Error(Box<dyn Any>),
|
Error(Box<dyn Any>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_protected<T>(f: impl FnOnce() -> T) -> Result<T, CallProtError> {
|
pub fn call_protected<T>(
|
||||||
|
f: impl FnOnce() -> T,
|
||||||
|
breakpoints: Option<BreakpointMap>,
|
||||||
|
) -> Result<T, CallProtError> {
|
||||||
|
ensure_sighandler();
|
||||||
unsafe {
|
unsafe {
|
||||||
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
let ret = catch_unsafe_unwind(|| f(), breakpoints);
|
||||||
let prev_jmp_buf = *jmp_buf;
|
match ret {
|
||||||
|
Ok(x) => Ok(x),
|
||||||
SIGHANDLER_INIT.call_once(|| {
|
Err(e) => {
|
||||||
install_sighandler();
|
if let Some(data) = TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
|
||||||
});
|
Err(CallProtError::Error(data))
|
||||||
|
} else {
|
||||||
let signum = setjmp(jmp_buf as *mut _);
|
Err(CallProtError::Error(e))
|
||||||
if signum != 0 {
|
}
|
||||||
*jmp_buf = prev_jmp_buf;
|
|
||||||
|
|
||||||
if let Some(data) = TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
|
|
||||||
Err(CallProtError::Error(data))
|
|
||||||
} else {
|
|
||||||
// let (faulting_addr, _inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());
|
|
||||||
|
|
||||||
// let signal = match Signal::from_c_int(signum) {
|
|
||||||
// Ok(SIGFPE) => "floating-point exception",
|
|
||||||
// Ok(SIGILL) => "illegal instruction",
|
|
||||||
// Ok(SIGSEGV) => "segmentation violation",
|
|
||||||
// Ok(SIGBUS) => "bus error",
|
|
||||||
// Err(_) => "error while getting the Signal",
|
|
||||||
// _ => "unknown trapped signal",
|
|
||||||
// };
|
|
||||||
// // When the trap-handler is fully implemented, this will return more information.
|
|
||||||
// Err(RuntimeError::Trap {
|
|
||||||
// msg: format!("unknown trap at {:p} - {}", faulting_addr, signal).into(),
|
|
||||||
// }
|
|
||||||
// .into())
|
|
||||||
Err(CallProtError::Trap(WasmTrapInfo::Unknown))
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
let ret = f(); // TODO: Switch stack?
|
|
||||||
*jmp_buf = prev_jmp_buf;
|
|
||||||
Ok(ret)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn throw(payload: Box<dyn Any>) -> ! {
|
pub unsafe fn throw(payload: Box<dyn Any>) -> ! {
|
||||||
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
begin_unsafe_unwind(payload);
|
||||||
if *jmp_buf == [0; SETJMP_BUFFER_LEN] {
|
|
||||||
::std::process::abort();
|
|
||||||
}
|
|
||||||
TRAP_EARLY_DATA.with(|cell| cell.replace(Some(payload)));
|
|
||||||
longjmp(jmp_buf as *mut ::nix::libc::c_void, 0xffff);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unwinds to last protected_call.
|
|
||||||
pub unsafe fn do_unwind(signum: i32, siginfo: *const c_void, ucontext: *const c_void) -> ! {
|
|
||||||
// Since do_unwind is only expected to get called from WebAssembly code which doesn't hold any host resources (locks etc.)
|
|
||||||
// itself, accessing TLS here is safe. In case any other code calls this, it often indicates a memory safety bug and you should
|
|
||||||
// temporarily disable the signal handlers to debug it.
|
|
||||||
|
|
||||||
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
|
||||||
if *jmp_buf == [0; SETJMP_BUFFER_LEN] {
|
|
||||||
::std::process::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
CAUGHT_ADDRESSES.with(|cell| cell.set(get_faulting_addr_and_ip(siginfo, ucontext)));
|
|
||||||
|
|
||||||
longjmp(jmp_buf as *mut ::nix::libc::c_void, signum)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
|
||||||
unsafe fn get_faulting_addr_and_ip(
|
|
||||||
siginfo: *const c_void,
|
|
||||||
ucontext: *const c_void,
|
|
||||||
) -> (*const c_void, *const c_void) {
|
|
||||||
use libc::{ucontext_t, RIP};
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[repr(C)]
|
|
||||||
struct siginfo_t {
|
|
||||||
si_signo: i32,
|
|
||||||
si_errno: i32,
|
|
||||||
si_code: i32,
|
|
||||||
si_addr: u64,
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
let siginfo = siginfo as *const siginfo_t;
|
|
||||||
let si_addr = (*siginfo).si_addr;
|
|
||||||
|
|
||||||
let ucontext = ucontext as *const ucontext_t;
|
|
||||||
let rip = (*ucontext).uc_mcontext.gregs[RIP as usize];
|
|
||||||
|
|
||||||
(si_addr as _, rip as _)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
|
||||||
unsafe fn get_faulting_addr_and_ip(
|
|
||||||
siginfo: *const c_void,
|
|
||||||
ucontext: *const c_void,
|
|
||||||
) -> (*const c_void, *const c_void) {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[repr(C)]
|
|
||||||
struct ucontext_t {
|
|
||||||
uc_onstack: u32,
|
|
||||||
uc_sigmask: u32,
|
|
||||||
uc_stack: libc::stack_t,
|
|
||||||
uc_link: *const ucontext_t,
|
|
||||||
uc_mcsize: u64,
|
|
||||||
uc_mcontext: *const mcontext_t,
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
struct exception_state {
|
|
||||||
trapno: u16,
|
|
||||||
cpu: u16,
|
|
||||||
err: u32,
|
|
||||||
faultvaddr: u64,
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
struct regs {
|
|
||||||
rax: u64,
|
|
||||||
rbx: u64,
|
|
||||||
rcx: u64,
|
|
||||||
rdx: u64,
|
|
||||||
rdi: u64,
|
|
||||||
rsi: u64,
|
|
||||||
rbp: u64,
|
|
||||||
rsp: u64,
|
|
||||||
r8: u64,
|
|
||||||
r9: u64,
|
|
||||||
r10: u64,
|
|
||||||
r11: u64,
|
|
||||||
r12: u64,
|
|
||||||
r13: u64,
|
|
||||||
r14: u64,
|
|
||||||
r15: u64,
|
|
||||||
rip: u64,
|
|
||||||
rflags: u64,
|
|
||||||
cs: u64,
|
|
||||||
fs: u64,
|
|
||||||
gs: u64,
|
|
||||||
}
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[repr(C)]
|
|
||||||
struct mcontext_t {
|
|
||||||
es: exception_state,
|
|
||||||
ss: regs,
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
let siginfo = siginfo as *const siginfo_t;
|
|
||||||
let si_addr = (*siginfo).si_addr;
|
|
||||||
|
|
||||||
let ucontext = ucontext as *const ucontext_t;
|
|
||||||
let rip = (*(*ucontext).uc_mcontext).ss.rip;
|
|
||||||
|
|
||||||
(si_addr, rip as _)
|
|
||||||
}
|
}
|
||||||
|
16
lib/spectests/spectests/README.md
vendored
16
lib/spectests/spectests/README.md
vendored
@ -145,3 +145,19 @@ Currently `cranelift_wasm::ModuleEnvironment` does not provide `declare_table_im
|
|||||||
```
|
```
|
||||||
|
|
||||||
- `elem.wast`
|
- `elem.wast`
|
||||||
|
|
||||||
|
- `SKIP_UNARY_OPERATION` [memory_grow.wast]
|
||||||
|
In some versions of MacOS this is failing (perhaps because of the chip).
|
||||||
|
More info here:
|
||||||
|
```
|
||||||
|
Executing function c82_l299_action_invoke
|
||||||
|
thread 'test_memory_grow::test_module_5' panicked at 'assertion failed: `(left == right)`
|
||||||
|
left: `Ok([I32(0)])`,
|
||||||
|
right: `Ok([I32(31)])`', /Users/distiller/project/target/release/build/wasmer-spectests-98805f54de053dd1/out/spectests.rs:32304:5
|
||||||
|
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
|
||||||
|
|
||||||
|
|
||||||
|
failures:
|
||||||
|
test_memory_grow::test_module_5
|
||||||
|
```
|
||||||
|
https://circleci.com/gh/wasmerio/wasmer/9556
|
3
lib/spectests/spectests/memory_grow.wast
vendored
3
lib/spectests/spectests/memory_grow.wast
vendored
@ -296,7 +296,8 @@
|
|||||||
(assert_return (invoke "as-storeN-address"))
|
(assert_return (invoke "as-storeN-address"))
|
||||||
(assert_return (invoke "as-storeN-value"))
|
(assert_return (invoke "as-storeN-value"))
|
||||||
|
|
||||||
(assert_return (invoke "as-unary-operand") (i32.const 31))
|
;; SKIP_UNARY_OPERATION
|
||||||
|
;; (assert_return (invoke "as-unary-operand") (i32.const 31))
|
||||||
|
|
||||||
(assert_return (invoke "as-binary-left") (i32.const 11))
|
(assert_return (invoke "as-binary-left") (i32.const 11))
|
||||||
(assert_return (invoke "as-binary-right") (i32.const 9))
|
(assert_return (invoke "as-binary-right") (i32.const 9))
|
||||||
|
@ -19,6 +19,7 @@ log = "0.4.6"
|
|||||||
byteorder = "1.3.1"
|
byteorder = "1.3.1"
|
||||||
# hack to get tests to work
|
# hack to get tests to work
|
||||||
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.5.3", optional = true }
|
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.5.3", optional = true }
|
||||||
|
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.5.3", optional = true }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = "0.3"
|
winapi = "0.3"
|
||||||
@ -33,3 +34,4 @@ wasmer-dev-utils = { path = "../dev-utils", version = "0.5.3"}
|
|||||||
[features]
|
[features]
|
||||||
clif = []
|
clif = []
|
||||||
singlepass = ["wasmer-singlepass-backend"]
|
singlepass = ["wasmer-singlepass-backend"]
|
||||||
|
llvm = ["wasmer-llvm-backend"]
|
||||||
|
@ -1600,16 +1600,17 @@ pub fn path_open(
|
|||||||
|
|
||||||
pub fn path_readlink(
|
pub fn path_readlink(
|
||||||
ctx: &mut Ctx,
|
ctx: &mut Ctx,
|
||||||
fd: __wasi_fd_t,
|
dir_fd: __wasi_fd_t,
|
||||||
path: WasmPtr<u8, Array>,
|
path: WasmPtr<u8, Array>,
|
||||||
path_len: u32,
|
path_len: u32,
|
||||||
buf: WasmPtr<u8>,
|
buf: WasmPtr<u8, Array>,
|
||||||
buf_len: u32,
|
buf_len: u32,
|
||||||
bufused: WasmPtr<u32>,
|
buf_used: WasmPtr<u32>,
|
||||||
) -> __wasi_errno_t {
|
) -> __wasi_errno_t {
|
||||||
debug!("wasi::path_readlink");
|
debug!("wasi::path_readlink");
|
||||||
unimplemented!("wasi::path_readlink")
|
unimplemented!("wasi::path_readlink")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path_remove_directory(
|
pub fn path_remove_directory(
|
||||||
ctx: &mut Ctx,
|
ctx: &mut Ctx,
|
||||||
fd: __wasi_fd_t,
|
fd: __wasi_fd_t,
|
||||||
|
@ -12,7 +12,8 @@ macro_rules! assert_wasi_output {
|
|||||||
|
|
||||||
#[cfg(feature = "llvm")]
|
#[cfg(feature = "llvm")]
|
||||||
fn get_compiler() -> impl Compiler {
|
fn get_compiler() -> impl Compiler {
|
||||||
compile_error!("LLVM compiler not supported right now");
|
use wasmer_llvm_backend::LLVMCompiler;
|
||||||
|
LLVMCompiler::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "singlepass")]
|
#[cfg(feature = "singlepass")]
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
|
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate structopt;
|
extern crate structopt;
|
||||||
|
|
||||||
use std::thread;
|
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use wasmer::*;
|
|
||||||
use wasmer_runtime::Value;
|
|
||||||
use wasmer_runtime_core::{
|
|
||||||
self,
|
|
||||||
backend::{CompilerConfig, MemoryBoundCheckMode},
|
|
||||||
loader::Instance as LoadedInstance,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "loader:kernel")]
|
#[cfg(feature = "loader:kernel")]
|
||||||
use wasmer_singlepass_backend::SinglePassCompiler;
|
use wasmer_singlepass_backend::SinglePassCompiler;
|
||||||
|
|
||||||
use std::io::prelude::*;
|
|
||||||
#[cfg(feature = "loader:kernel")]
|
#[cfg(feature = "loader:kernel")]
|
||||||
use std::os::unix::net::{UnixListener, UnixStream};
|
use std::os::unix::net::{UnixListener, UnixStream};
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
#[structopt(name = "kwasmd", about = "Kernel-mode WebAssembly service.")]
|
#[structopt(name = "kwasmd", about = "Kernel-mode WebAssembly service.")]
|
||||||
enum CLIOptions {
|
enum CLIOptions {
|
||||||
@ -32,12 +24,17 @@ struct Listen {
|
|||||||
socket: String,
|
socket: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "loader:kernel")]
|
||||||
const CMD_RUN_CODE: u32 = 0x901;
|
const CMD_RUN_CODE: u32 = 0x901;
|
||||||
|
#[cfg(feature = "loader:kernel")]
|
||||||
const CMD_READ_MEMORY: u32 = 0x902;
|
const CMD_READ_MEMORY: u32 = 0x902;
|
||||||
|
#[cfg(feature = "loader:kernel")]
|
||||||
const CMD_WRITE_MEMORY: u32 = 0x903;
|
const CMD_WRITE_MEMORY: u32 = 0x903;
|
||||||
|
|
||||||
#[cfg(feature = "loader:kernel")]
|
#[cfg(feature = "loader:kernel")]
|
||||||
fn handle_client(mut stream: UnixStream) {
|
fn handle_client(mut stream: UnixStream) {
|
||||||
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
use std::io::{Read, Write};
|
||||||
let binary_size = stream.read_u32::<LittleEndian>().unwrap();
|
let binary_size = stream.read_u32::<LittleEndian>().unwrap();
|
||||||
if binary_size > 1048576 * 16 {
|
if binary_size > 1048576 * 16 {
|
||||||
println!("binary too large");
|
println!("binary too large");
|
||||||
@ -46,6 +43,11 @@ fn handle_client(mut stream: UnixStream) {
|
|||||||
let mut wasm_binary: Vec<u8> = Vec::with_capacity(binary_size as usize);
|
let mut wasm_binary: Vec<u8> = Vec::with_capacity(binary_size as usize);
|
||||||
unsafe { wasm_binary.set_len(binary_size as usize) };
|
unsafe { wasm_binary.set_len(binary_size as usize) };
|
||||||
stream.read_exact(&mut wasm_binary).unwrap();
|
stream.read_exact(&mut wasm_binary).unwrap();
|
||||||
|
use wasmer::webassembly;
|
||||||
|
use wasmer_runtime_core::{
|
||||||
|
backend::{CompilerConfig, MemoryBoundCheckMode},
|
||||||
|
loader::Instance,
|
||||||
|
};
|
||||||
let module = webassembly::compile_with_config_with(
|
let module = webassembly::compile_with_config_with(
|
||||||
&wasm_binary[..],
|
&wasm_binary[..],
|
||||||
CompilerConfig {
|
CompilerConfig {
|
||||||
@ -80,6 +82,7 @@ fn handle_client(mut stream: UnixStream) {
|
|||||||
println!("Too many arguments");
|
println!("Too many arguments");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
use wasmer_runtime::Value;
|
||||||
let mut args: Vec<Value> = Vec::with_capacity(arg_count as usize);
|
let mut args: Vec<Value> = Vec::with_capacity(arg_count as usize);
|
||||||
for _ in 0..arg_count {
|
for _ in 0..arg_count {
|
||||||
args.push(Value::I64(stream.read_u64::<LittleEndian>().unwrap() as _));
|
args.push(Value::I64(stream.read_u64::<LittleEndian>().unwrap() as _));
|
||||||
@ -131,6 +134,7 @@ fn handle_client(mut stream: UnixStream) {
|
|||||||
#[cfg(feature = "loader:kernel")]
|
#[cfg(feature = "loader:kernel")]
|
||||||
fn run_listen(opts: Listen) {
|
fn run_listen(opts: Listen) {
|
||||||
let listener = UnixListener::bind(&opts.socket).unwrap();
|
let listener = UnixListener::bind(&opts.socket).unwrap();
|
||||||
|
use std::thread;
|
||||||
for stream in listener.incoming() {
|
for stream in listener.incoming() {
|
||||||
match stream {
|
match stream {
|
||||||
Ok(stream) => {
|
Ok(stream) => {
|
||||||
|
@ -19,7 +19,6 @@ use wasmer_clif_backend::CraneliftCompiler;
|
|||||||
use wasmer_llvm_backend::LLVMCompiler;
|
use wasmer_llvm_backend::LLVMCompiler;
|
||||||
use wasmer_runtime::{
|
use wasmer_runtime::{
|
||||||
cache::{Cache as BaseCache, FileSystemCache, WasmHash, WASMER_VERSION_HASH},
|
cache::{Cache as BaseCache, FileSystemCache, WasmHash, WASMER_VERSION_HASH},
|
||||||
error::RuntimeError,
|
|
||||||
Func, Value,
|
Func, Value,
|
||||||
};
|
};
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
@ -112,6 +111,10 @@ struct Run {
|
|||||||
)]
|
)]
|
||||||
loader: Option<LoaderName>,
|
loader: Option<LoaderName>,
|
||||||
|
|
||||||
|
#[cfg(feature = "backend:singlepass")]
|
||||||
|
#[structopt(long = "resume")]
|
||||||
|
resume: Option<String>,
|
||||||
|
|
||||||
#[structopt(long = "command-name", hidden = true)]
|
#[structopt(long = "command-name", hidden = true)]
|
||||||
command_name: Option<String>,
|
command_name: Option<String>,
|
||||||
|
|
||||||
@ -151,7 +154,7 @@ impl FromStr for LoaderName {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
enum Backend {
|
enum Backend {
|
||||||
Cranelift,
|
Cranelift,
|
||||||
Singlepass,
|
Singlepass,
|
||||||
@ -502,24 +505,96 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
|||||||
mapped_dirs,
|
mapped_dirs,
|
||||||
);
|
);
|
||||||
|
|
||||||
let instance = module
|
#[allow(unused_mut)] // mut used in feature
|
||||||
|
let mut instance = module
|
||||||
.instantiate(&import_object)
|
.instantiate(&import_object)
|
||||||
.map_err(|e| format!("Can't instantiate module: {:?}", e))?;
|
.map_err(|e| format!("Can't instantiate module: {:?}", e))?;
|
||||||
|
|
||||||
let start: Func<(), ()> = instance.func("_start").map_err(|e| format!("{:?}", e))?;
|
let start: Func<(), ()> = instance.func("_start").map_err(|e| format!("{:?}", e))?;
|
||||||
|
|
||||||
let result = start.call();
|
#[cfg(feature = "backend:singlepass")]
|
||||||
|
unsafe {
|
||||||
|
if options.backend == Backend::Singlepass {
|
||||||
|
use wasmer_runtime_core::fault::{catch_unsafe_unwind, ensure_sighandler};
|
||||||
|
use wasmer_runtime_core::state::{
|
||||||
|
x64::invoke_call_return_on_stack, InstanceImage,
|
||||||
|
};
|
||||||
|
use wasmer_runtime_core::vm::Ctx;
|
||||||
|
|
||||||
if let Err(ref err) = result {
|
ensure_sighandler();
|
||||||
match err {
|
|
||||||
RuntimeError::Trap { msg } => panic!("wasm trap occured: {}", msg),
|
let start_raw: extern "C" fn(&mut Ctx) =
|
||||||
RuntimeError::Error { data } => {
|
::std::mem::transmute(start.get_vm_func());
|
||||||
if let Some(error_code) = data.downcast_ref::<wasmer_wasi::ExitCode>() {
|
|
||||||
std::process::exit(error_code.code as i32)
|
let mut image: Option<InstanceImage> = if let Some(ref path) = options.resume {
|
||||||
|
let mut f = File::open(path).unwrap();
|
||||||
|
let mut out: Vec<u8> = vec![];
|
||||||
|
f.read_to_end(&mut out).unwrap();
|
||||||
|
Some(InstanceImage::from_bytes(&out).expect("failed to decode image"))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let breakpoints = instance.module.runnable_module.get_breakpoints();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let ret = if let Some(image) = image.take() {
|
||||||
|
let msm = instance
|
||||||
|
.module
|
||||||
|
.runnable_module
|
||||||
|
.get_module_state_map()
|
||||||
|
.unwrap();
|
||||||
|
let code_base =
|
||||||
|
instance.module.runnable_module.get_code().unwrap().as_ptr()
|
||||||
|
as usize;
|
||||||
|
invoke_call_return_on_stack(
|
||||||
|
&msm,
|
||||||
|
code_base,
|
||||||
|
image,
|
||||||
|
instance.context_mut(),
|
||||||
|
breakpoints.clone(),
|
||||||
|
)
|
||||||
|
.map(|_| ())
|
||||||
|
} else {
|
||||||
|
catch_unsafe_unwind(
|
||||||
|
|| start_raw(instance.context_mut()),
|
||||||
|
breakpoints.clone(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if let Err(e) = ret {
|
||||||
|
if let Some(new_image) = e.downcast_ref::<InstanceImage>() {
|
||||||
|
let op = interactive_shell(InteractiveShellContext {
|
||||||
|
image: Some(new_image.clone()),
|
||||||
|
});
|
||||||
|
match op {
|
||||||
|
ShellExitOperation::ContinueWith(new_image) => {
|
||||||
|
image = Some(new_image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err("Error while executing WebAssembly".into());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic!("error: {:?}", err)
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
use wasmer_runtime::error::RuntimeError;
|
||||||
|
let result = start.call();
|
||||||
|
|
||||||
|
if let Err(ref err) = result {
|
||||||
|
match err {
|
||||||
|
RuntimeError::Trap { msg } => panic!("wasm trap occured: {}", msg),
|
||||||
|
RuntimeError::Error { data } => {
|
||||||
|
if let Some(error_code) = data.downcast_ref::<wasmer_wasi::ExitCode>() {
|
||||||
|
std::process::exit(error_code.code as i32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("error: {:?}", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let import_object = wasmer_runtime_core::import::ImportObject::new();
|
let import_object = wasmer_runtime_core::import::ImportObject::new();
|
||||||
@ -544,11 +619,95 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "backend:singlepass")]
|
||||||
|
struct InteractiveShellContext {
|
||||||
|
image: Option<wasmer_runtime_core::state::InstanceImage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "backend:singlepass")]
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum ShellExitOperation {
|
||||||
|
ContinueWith(wasmer_runtime_core::state::InstanceImage),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "backend:singlepass")]
|
||||||
|
fn interactive_shell(mut ctx: InteractiveShellContext) -> ShellExitOperation {
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
let mut stdout = ::std::io::stdout();
|
||||||
|
let stdin = ::std::io::stdin();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
print!("Wasmer> ");
|
||||||
|
stdout.flush().unwrap();
|
||||||
|
let mut line = String::new();
|
||||||
|
stdin.read_line(&mut line).unwrap();
|
||||||
|
let mut parts = line.split(" ").filter(|x| x.len() > 0).map(|x| x.trim());
|
||||||
|
|
||||||
|
let cmd = parts.next();
|
||||||
|
if cmd.is_none() {
|
||||||
|
println!("Command required");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let cmd = cmd.unwrap();
|
||||||
|
|
||||||
|
match cmd {
|
||||||
|
"snapshot" => {
|
||||||
|
let path = parts.next();
|
||||||
|
if path.is_none() {
|
||||||
|
println!("Usage: snapshot [out_path]");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let path = path.unwrap();
|
||||||
|
|
||||||
|
if let Some(ref image) = ctx.image {
|
||||||
|
let buf = image.to_bytes();
|
||||||
|
let mut f = match File::create(path) {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Cannot open output file at {}: {:?}", path, e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Err(e) = f.write_all(&buf) {
|
||||||
|
println!("Cannot write to output file at {}: {:?}", path, e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
println!("Done");
|
||||||
|
} else {
|
||||||
|
println!("Program state not available");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"continue" | "c" => {
|
||||||
|
if let Some(image) = ctx.image.take() {
|
||||||
|
return ShellExitOperation::ContinueWith(image);
|
||||||
|
} else {
|
||||||
|
println!("Program state not available, cannot continue execution");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"backtrace" | "bt" => {
|
||||||
|
if let Some(ref image) = ctx.image {
|
||||||
|
println!("{}", image.execution_state.colored_output());
|
||||||
|
} else {
|
||||||
|
println!("State not available");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"exit" | "quit" => {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
"" => {}
|
||||||
|
_ => {
|
||||||
|
println!("Unknown command: {}", cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn run(options: Run) {
|
fn run(options: Run) {
|
||||||
match execute_wasm(&options) {
|
match execute_wasm(&options) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(message) => {
|
Err(message) => {
|
||||||
eprintln!("{:?}", message);
|
eprintln!("execute_wasm: {:?}", message);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user