mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 14:25:32 +00:00
Merge pull request #80 from wasmerio/feature/vm_refactor
VM Refactor, new runtime, and the ability to have multiple compilers.
This commit is contained in:
commit
62b8e7cc2d
@ -1,83 +1,127 @@
|
||||
version: 2
|
||||
jobs:
|
||||
# Job used for testing
|
||||
test:
|
||||
lint:
|
||||
docker:
|
||||
- image: circleci/rust:latest
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v4-test-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
- run: sudo apt-get install -y cmake
|
||||
- run: make test
|
||||
- run: rustup component add rustfmt
|
||||
- run: make lint
|
||||
- v5-lint-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: |
|
||||
sudo apt-get install -y cmake
|
||||
sudo apt-get install texinfo
|
||||
sudo apt-get install libclang-dev llvm-3.9-dev libclang-3.9-dev clang-3.9
|
||||
- run:
|
||||
name: Install lint deps
|
||||
command: |
|
||||
rustup component add rustfmt
|
||||
rustup component add clippy
|
||||
- run:
|
||||
name: Execute lints
|
||||
command: make lint
|
||||
- save_cache:
|
||||
paths:
|
||||
- /usr/local/cargo/registry
|
||||
- target/debug/.fingerprint
|
||||
- target/debug/build
|
||||
- target/debug/deps
|
||||
key: v4-test-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
|
||||
test-macos:
|
||||
macos:
|
||||
xcode: "9.0"
|
||||
key: v5-lint-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
|
||||
test:
|
||||
docker:
|
||||
- image: circleci/rust:latest
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v4-cargo-cache-darwin-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
- v5-test-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
- run:
|
||||
name: Install CMAKE
|
||||
name: Install dependencies
|
||||
command: |
|
||||
curl -O https://cmake.org/files/v3.4/cmake-3.4.1-Darwin-x86_64.tar.gz
|
||||
tar xf cmake-3.4.1-Darwin-x86_64.tar.gz
|
||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||
sudo apt-get install -y cmake
|
||||
sudo apt-get install texinfo
|
||||
sudo apt-get install libclang-dev llvm-3.9-dev libclang-3.9-dev clang-3.9
|
||||
- run: make test
|
||||
- save_cache:
|
||||
paths:
|
||||
- /usr/local/cargo/registry
|
||||
- target/debug/.fingerprint
|
||||
- target/debug/build
|
||||
- target/debug/deps
|
||||
key: v5-test-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
|
||||
test-macos:
|
||||
macos:
|
||||
xcode: "9.0"
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v5-cargo-cache-darwin-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
- v5-cargo-cache-darwin-{{ arch }}-brew
|
||||
- run:
|
||||
name: Update Brew
|
||||
command: brew update || true
|
||||
- run:
|
||||
name: Install crate dependencies
|
||||
command: |
|
||||
brew install libtool || true
|
||||
brew install autoconf cmake libffi || true
|
||||
- save_cache:
|
||||
paths:
|
||||
- /usr/local/Homebrew
|
||||
key: v5-cargo-cache-darwin-{{ arch }}-brew
|
||||
- run:
|
||||
name: Install Rust
|
||||
command: |
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
cargo --version
|
||||
rustup component add rustfmt
|
||||
- run:
|
||||
name: Execute tests
|
||||
command: |
|
||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
# 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
|
||||
make lint
|
||||
- run:
|
||||
name: Execute integration tests
|
||||
command: |
|
||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
./integration_tests/nginx/test.sh
|
||||
make integration-tests
|
||||
- save_cache:
|
||||
paths:
|
||||
- /usr/local/cargo/registry
|
||||
- target/debug/.fingerprint
|
||||
- target/debug/build
|
||||
- target/debug/deps
|
||||
- target/release/.fingerprint
|
||||
- target/release/build
|
||||
- target/release/deps
|
||||
key: v5-cargo-cache-darwin-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
|
||||
test-and-build:
|
||||
docker:
|
||||
- image: circleci/rust:latest
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v4-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
- run: sudo apt-get install -y cmake
|
||||
- v5-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: |
|
||||
sudo apt-get install -y cmake
|
||||
sudo apt-get install texinfo
|
||||
sudo apt-get install libclang-dev llvm-3.9-dev libclang-3.9-dev clang-3.9
|
||||
- run:
|
||||
name: Execute tests
|
||||
command: make test
|
||||
- run: rustup component add rustfmt
|
||||
- run:
|
||||
name: Execute lints
|
||||
command: make lint
|
||||
- run:
|
||||
name: Make release build
|
||||
command: |
|
||||
@ -101,44 +145,47 @@ jobs:
|
||||
- target/release/.fingerprint
|
||||
- target/release/build
|
||||
- target/release/deps
|
||||
key: v4-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
- /usr/local/Homebrew
|
||||
key: v5-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
|
||||
test-and-build-macos:
|
||||
macos:
|
||||
xcode: "9.0"
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v4-cargo-cache-darwin-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
- v5-cargo-cache-darwin-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
- v5-cargo-cache-darwin-{{ arch }}-brew
|
||||
- run:
|
||||
name: Install CMAKE
|
||||
name: Update Brew
|
||||
command: brew update || true
|
||||
- run:
|
||||
name: Install crate dependencies
|
||||
command: |
|
||||
curl -O https://cmake.org/files/v3.4/cmake-3.4.1-Darwin-x86_64.tar.gz
|
||||
tar xf cmake-3.4.1-Darwin-x86_64.tar.gz
|
||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||
brew install libtool || true
|
||||
brew install autoconf cmake libffi || true
|
||||
- save_cache:
|
||||
paths:
|
||||
- /usr/local/Homebrew
|
||||
key: v5-cargo-cache-darwin-{{ arch }}-brew
|
||||
- run:
|
||||
name: Install Rust
|
||||
command: |
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
cargo --version
|
||||
rustup component add rustfmt
|
||||
- run:
|
||||
name: Execute tests
|
||||
command: |
|
||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
# 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
|
||||
make lint
|
||||
- run:
|
||||
name: Make release build
|
||||
command: |
|
||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
make release
|
||||
mkdir -p artifacts
|
||||
@ -158,18 +205,22 @@ jobs:
|
||||
- target/release/.fingerprint
|
||||
- target/release/build
|
||||
- target/release/deps
|
||||
key: v4-cargo-cache-darwin-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
key: v5-cargo-cache-darwin-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||
|
||||
test-rust-nightly:
|
||||
docker:
|
||||
- image: circleci/rust:latest
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v4-test-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }}-nightly
|
||||
- run: sudo apt-get install -y cmake
|
||||
- v5-test-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }}-nightly
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: |
|
||||
sudo apt-get install -y cmake
|
||||
sudo apt-get install texinfo
|
||||
sudo apt-get install libclang-dev llvm-3.9-dev libclang-3.9-dev clang-3.9
|
||||
- run: rustup default nightly
|
||||
- run: make test
|
||||
- save_cache:
|
||||
@ -178,7 +229,7 @@ jobs:
|
||||
- target/debug/.fingerprint
|
||||
- target/debug/build
|
||||
- target/debug/deps
|
||||
key: v4-test-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }}-nightly
|
||||
key: v5-test-cargo-cache-linux-{{ arch }}-{{ checksum "Cargo.lock" }}-nightly
|
||||
|
||||
publish-github-release:
|
||||
docker:
|
||||
@ -210,6 +261,7 @@ workflows:
|
||||
version: 2
|
||||
main:
|
||||
jobs:
|
||||
- lint
|
||||
- test:
|
||||
filters:
|
||||
branches:
|
||||
@ -230,15 +282,11 @@ workflows:
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
# :
|
||||
# filters:
|
||||
# tags:
|
||||
# only: /^\d+\.\d+\.\d+$/
|
||||
|
||||
- publish-github-release:
|
||||
requires:
|
||||
- lint
|
||||
- test-and-build
|
||||
- test-and-build-macos
|
||||
filters:
|
||||
tags:
|
||||
only: /^\d+\.\d+\.\d+$/
|
||||
branches:
|
||||
only: master
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
/target
|
||||
**/target
|
||||
**/*.rs.bk
|
||||
/artifacts
|
||||
.DS_Store
|
||||
|
276
Cargo.lock
generated
276
Cargo.lock
generated
@ -1,3 +1,8 @@
|
||||
[[package]]
|
||||
name = "abort_on_panic"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.6.8"
|
||||
@ -53,6 +58,24 @@ dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.31.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clang-sys 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.4"
|
||||
@ -73,11 +96,29 @@ name = "cc"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "0.21.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.32.0"
|
||||
@ -253,6 +294,15 @@ name = "either"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.2.4"
|
||||
@ -300,6 +350,11 @@ dependencies = [
|
||||
"synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "field-offset"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
@ -324,6 +379,15 @@ name = "glob"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indicatif"
|
||||
version = "0.10.3"
|
||||
@ -341,6 +405,20 @@ name = "itoa"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.2.0"
|
||||
@ -356,6 +434,36 @@ name = "libc"
|
||||
version = "0.2.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libffi"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"abort_on_panic 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libffi-sys 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libffi-sys"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bindgen 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"make-cmd 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.1.5"
|
||||
@ -365,6 +473,14 @@ dependencies = [
|
||||
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.5"
|
||||
@ -381,6 +497,19 @@ dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "make-cmd"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.1.0"
|
||||
@ -413,6 +542,14 @@ name = "nodrop"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "3.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.6"
|
||||
@ -442,6 +579,16 @@ dependencies = [
|
||||
"stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "page_size"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.7.0"
|
||||
@ -463,6 +610,16 @@ dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.20"
|
||||
@ -471,6 +628,11 @@ dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.8"
|
||||
@ -598,6 +760,18 @@ dependencies = [
|
||||
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.0.5"
|
||||
@ -610,6 +784,14 @@ dependencies = [
|
||||
"utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.2"
|
||||
@ -898,9 +1080,12 @@ dependencies = [
|
||||
"docopt 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (git+https://github.com/rust-lang/libc)",
|
||||
"libffi 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -912,10 +1097,58 @@ dependencies = [
|
||||
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wabt 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmer-clif-backend 0.1.0",
|
||||
"wasmer-emscripten 0.1.1",
|
||||
"wasmer-runtime 0.1.0",
|
||||
"wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-clif-backend"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-entity 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-native 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-wasm 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libffi 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmer-runtime 0.1.0",
|
||||
"wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-emscripten"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (git+https://github.com/rust-lang/libc)",
|
||||
"time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wabt 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmer-clif-backend 0.1.0",
|
||||
"wasmer-runtime 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-runtime"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wabt 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmer-clif-backend 0.1.0",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.22.1"
|
||||
@ -926,6 +1159,19 @@ name = "wasmparser"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.6"
|
||||
@ -935,6 +1181,11 @@ dependencies = [
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
@ -946,17 +1197,21 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum abort_on_panic 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fa948f9ec9f095cc955efbe4fd00ac5774ef933cc2442562a8fe5a57c4ef919"
|
||||
"checksum aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "68f56c7353e5a9547cbd76ed90f7bb5ffc3ba09d4ea9bd1d8c06c8b1142eeb5a"
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
|
||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||
"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
|
||||
"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0"
|
||||
"checksum bindgen 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "57253399c086f4f29e57ffd3b5cdbc23a806a00292619351aa4cfa39cb49d4ea"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
|
||||
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
|
||||
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
||||
"checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c"
|
||||
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
|
||||
"checksum clang-sys 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e414af9726e1d11660801e73ccc7fb81803fb5f49e5903a25b348b2b3b480d2e"
|
||||
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||
"checksum clicolors-control 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "51872be694bb3bcbd1ea95c6dd467c2c46c6c64d287e1c9084ace7c3116ae9c0"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
@ -974,34 +1229,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
|
||||
"checksum docopt 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d60c92df70dfaaabecc14b409fd79f55ba0f247780529db1d73bfa601e1d3ac0"
|
||||
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
|
||||
"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
|
||||
"checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e"
|
||||
"checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067"
|
||||
"checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02"
|
||||
"checksum failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6dd377bcc1b1b7ce911967e3ec24fa19c3224394ec05b54aa7b083d498341ac7"
|
||||
"checksum failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64c2d913fe8ed3b6c6518eedf4538255b989945c14c2a7d5cbff62a5e2120596"
|
||||
"checksum field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64e9bc339e426139e02601fa69d101e96a92aee71b58bc01697ec2a63a5c9e68"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "64b7d419d0622ae02fe5da6b9a5e1964b610a65bb37923b976aeebb6dbb8f86e"
|
||||
"checksum indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "40ecd1e2ee08e6c255ce890f5a99d17000850e664e7acf119fb03b25b0575bfe"
|
||||
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum libc 0.2.44 (git+https://github.com/rust-lang/libc)" = "<none>"
|
||||
"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311"
|
||||
"checksum libffi 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8a9dac273181f514d742b6b858be5153570c5b80dd4d6020093c0fa584578b1"
|
||||
"checksum libffi-sys 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4675d5d7fdbba34b66218fae3b0d528c2b29580a64ca2ccc5bbfc5af2324b373"
|
||||
"checksum libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd38073de8f7965d0c17d30546d4bb6da311ab428d1c7a3fc71dff7f9d4979b9"
|
||||
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
|
||||
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
|
||||
"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f"
|
||||
"checksum mach 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9"
|
||||
"checksum make-cmd 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8ca8afbe8af1785e09636acb5a41e08a765f5f0340568716c18a8700ba3c0d3"
|
||||
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
|
||||
"checksum memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4b3629fe9fdbff6daa6c33b90f7c08355c1aca05a3d01fa8063b822fcf185f3b"
|
||||
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
|
||||
"checksum nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "921f61dc817b379d0834e45d5ec45beaacfae97082090a49c2cf30dcbc30206f"
|
||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||
"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b"
|
||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
|
||||
"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee"
|
||||
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
||||
"checksum page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f89ef58b3d32420dbd1a43d2f38ae92f6239ef12bb556ab09ca55445f5a67242"
|
||||
"checksum parking_lot 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9723236a9525c757d9725b993511e3fc941e33f27751942232f0058298297edf"
|
||||
"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
|
||||
"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
|
||||
"checksum proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "3d7b7eaaa90b4a90a932a9ea6666c95a389e424eff347f0f793979289429feee"
|
||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||
"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
|
||||
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
||||
"checksum rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a"
|
||||
@ -1016,7 +1287,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356"
|
||||
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
|
||||
"checksum regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2069749032ea3ec200ca51e4a31df41759190a88edca0d2d86ee8bedf7073341"
|
||||
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
|
||||
"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d"
|
||||
"checksum region 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9d3f2bb4b7085e6996e2765b56b783bd8f3a8a4ea5b95683063ca13cded993"
|
||||
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
||||
@ -1055,6 +1328,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum wabt-sys 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0cc8982bfe0a923f152e96d991e50a6f97fe73ca4af6d9d84d76634f03051fa2"
|
||||
"checksum wasmparser 0.22.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46e666ecb4a406483a59a49f9d0c17f327e70da53a128eccddae2eadb95865c"
|
||||
"checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060"
|
||||
"checksum which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e84a603e7e0b1ce1aa1ee2b109c7be00155ce52df5081590d1ffb93f4f515cb2"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
15
Cargo.toml
15
Cargo.toml
@ -1,13 +1,12 @@
|
||||
[package]
|
||||
name = "wasmer"
|
||||
version = "0.1.4"
|
||||
authors = ["Syrus Akbary <me@syrusakbary.com>"]
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
edition = "2018"
|
||||
repository = "https://github.com/wasmerio/wasmer"
|
||||
publish = true
|
||||
description = "High-Performance WebAssembly JIT interpreter"
|
||||
license = "MIT"
|
||||
build = "build/mod.rs"
|
||||
include = [
|
||||
"examples/**/*",
|
||||
"src/**/*",
|
||||
@ -42,14 +41,22 @@ region = "0.3.0"
|
||||
# spin = "0.4.10"
|
||||
log = "0.4.5"
|
||||
target-lexicon = "0.2.0"
|
||||
# libc = "0.2"
|
||||
libc = { git = "https://github.com/rust-lang/libc" }
|
||||
nix = "0.12.0"
|
||||
rayon = "1.0.3"
|
||||
byteorder = "1"
|
||||
indicatif = "0.10"
|
||||
console = "0.7.1"
|
||||
field-offset = "0.1.1"
|
||||
hashbrown = "0.1"
|
||||
libffi = "0.6.4"
|
||||
time = "0.1.41"
|
||||
wasmer-clif-backend = { path = "lib/clif-backend" }
|
||||
wasmer-runtime = { path = "lib/runtime" }
|
||||
wasmer-emscripten = { path = "lib/emscripten" }
|
||||
libc = { git = "https://github.com/rust-lang/libc" }
|
||||
|
||||
[workspace]
|
||||
members = ["lib/clif-backend", "lib/runtime", "lib/emscripten"]
|
||||
|
||||
[build-dependencies]
|
||||
wabt = "0.7.2"
|
||||
|
16
Makefile
16
Makefile
@ -7,10 +7,10 @@ endif
|
||||
|
||||
# This will re-generate the Rust test files based on spectests/*.wast
|
||||
spectests:
|
||||
WASM_GENERATE_SPECTESTS=1 cargo build
|
||||
WASMER_RUNTIME_GENERATE_SPECTESTS=1 cargo build -p wasmer-runtime
|
||||
|
||||
emtests:
|
||||
WASM_GENERATE_EMTESTS=1 cargo build
|
||||
WASM_EMSCRIPTEN_GENERATE_EMTESTS=1 cargo build -p wasmer-emscripten
|
||||
|
||||
# clean:
|
||||
# rm -rf artifacts
|
||||
@ -21,14 +21,22 @@ build:
|
||||
install:
|
||||
cargo install --path .
|
||||
|
||||
integration-tests: release
|
||||
echo "Running Integration Tests"
|
||||
# Commented for now until we fix emscripten
|
||||
# ./integration_tests/nginx/test.sh
|
||||
|
||||
lint:
|
||||
cargo fmt -- --check
|
||||
cargo fmt --all -- --check
|
||||
cargo clippy --all
|
||||
|
||||
precommit: lint test
|
||||
|
||||
test:
|
||||
# We use one thread so the emscripten stdouts doesn't collide
|
||||
cargo test -- --test-threads=1 $(runargs)
|
||||
# cargo test --all -- --test-threads=1 $(runargs)
|
||||
# cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs)
|
||||
cargo test -p wasmer-runtime -- --test-threads=1 $(runargs)
|
||||
|
||||
release:
|
||||
# If you are in OS-X, you will need mingw-w64 for cross compiling to windows
|
||||
|
@ -57,6 +57,13 @@ you can run:
|
||||
make spectests
|
||||
```
|
||||
|
||||
You can also run integration tests with:
|
||||
|
||||
```sh
|
||||
make integration-tests
|
||||
```
|
||||
|
||||
|
||||
## Roadmap
|
||||
|
||||
Wasmer is an open project guided by strong principles, aiming to be modular, flexible and fast. It is open to the community to help set its direction.
|
||||
|
19
build/mod.rs
19
build/mod.rs
@ -1,19 +0,0 @@
|
||||
extern crate glob;
|
||||
extern crate wabt;
|
||||
|
||||
use std::env;
|
||||
|
||||
mod emtests;
|
||||
mod spectests;
|
||||
|
||||
static SPECTESTS_ENV_VAR: &str = "WASM_GENERATE_SPECTESTS";
|
||||
static EMTESTS_ENV_VAR: &str = "WASM_GENERATE_EMTESTS";
|
||||
|
||||
fn main() {
|
||||
if env::var(SPECTESTS_ENV_VAR).unwrap_or("0".to_string()) == "1" {
|
||||
spectests::build();
|
||||
}
|
||||
if env::var(EMTESTS_ENV_VAR).unwrap_or("0".to_string()) == "1" {
|
||||
emtests::build();
|
||||
}
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
#! /bin/bash
|
||||
|
||||
# Build the release and run nginx
|
||||
make release
|
||||
nohup ./target/release/wasmer run examples/nginx/nginx.wasm -- -p integration_tests/nginx/ -c nginx.conf &
|
||||
sleep 3s
|
||||
|
||||
|
1
lib/.gitignore
vendored
Normal file
1
lib/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
.Cargo.lock
|
21
lib/clif-backend/Cargo.toml
Normal file
21
lib/clif-backend/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "wasmer-clif-backend"
|
||||
version = "0.1.0"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasmer-runtime = { path = "../runtime" }
|
||||
cranelift-native = "0.26.0"
|
||||
cranelift-codegen = "0.26.0"
|
||||
cranelift-entity = "0.26.0"
|
||||
cranelift-wasm = "0.26.0"
|
||||
hashbrown = "0.1"
|
||||
target-lexicon = "0.2.0"
|
||||
wasmparser = "0.23.0"
|
||||
byteorder = "1"
|
||||
nix = "0.12.0"
|
||||
# We depend on libffi for now.
|
||||
# This will be removed asap.
|
||||
libffi = "0.6.4"
|
||||
|
138
lib/clif-backend/src/call/mod.rs
Normal file
138
lib/clif-backend/src/call/mod.rs
Normal file
@ -0,0 +1,138 @@
|
||||
mod recovery;
|
||||
mod sighandler;
|
||||
|
||||
pub use self::recovery::HandlerData;
|
||||
|
||||
use crate::call::recovery::call_protected;
|
||||
use hashbrown::HashSet;
|
||||
use libffi::high::{arg as libffi_arg, call as libffi_call, CodePtr};
|
||||
use std::iter;
|
||||
use wasmer_runtime::{
|
||||
backend::{ProtectedCaller, Token},
|
||||
error::RuntimeResult,
|
||||
export::Context,
|
||||
module::{ExportIndex, ModuleInner},
|
||||
types::{FuncIndex, FuncSig, LocalOrImport, Type, Value},
|
||||
vm::{self, ImportBacking},
|
||||
};
|
||||
|
||||
pub struct Caller {
|
||||
func_export_set: HashSet<FuncIndex>,
|
||||
handler_data: HandlerData,
|
||||
}
|
||||
|
||||
impl Caller {
|
||||
pub fn new(module: &ModuleInner, handler_data: HandlerData) -> Self {
|
||||
let mut func_export_set = HashSet::new();
|
||||
for export_index in module.exports.values() {
|
||||
if let ExportIndex::Func(func_index) = export_index {
|
||||
func_export_set.insert(*func_index);
|
||||
}
|
||||
}
|
||||
if let Some(start_func_index) = module.start_func {
|
||||
func_export_set.insert(start_func_index);
|
||||
}
|
||||
|
||||
Self {
|
||||
func_export_set,
|
||||
handler_data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtectedCaller for Caller {
|
||||
fn call(
|
||||
&self,
|
||||
module: &ModuleInner,
|
||||
func_index: FuncIndex,
|
||||
params: &[Value],
|
||||
returns: &mut [Value],
|
||||
import_backing: &ImportBacking,
|
||||
vmctx: *mut vm::Ctx,
|
||||
_: Token,
|
||||
) -> RuntimeResult<()> {
|
||||
let (func_ptr, ctx, signature) = get_func_from_index(&module, import_backing, func_index);
|
||||
|
||||
let vmctx_ptr = match ctx {
|
||||
Context::External(external_vmctx) => external_vmctx,
|
||||
Context::Internal => vmctx,
|
||||
};
|
||||
|
||||
assert!(self.func_export_set.contains(&func_index));
|
||||
|
||||
assert!(
|
||||
returns.len() == signature.returns.len() && signature.returns.len() <= 1,
|
||||
"multi-value returns not yet supported"
|
||||
);
|
||||
|
||||
assert!(signature.check_sig(params), "incorrect signature");
|
||||
|
||||
let libffi_args: Vec<_> = params
|
||||
.iter()
|
||||
.map(|val| match val {
|
||||
Value::I32(ref x) => libffi_arg(x),
|
||||
Value::I64(ref x) => libffi_arg(x),
|
||||
Value::F32(ref x) => libffi_arg(x),
|
||||
Value::F64(ref x) => libffi_arg(x),
|
||||
})
|
||||
.chain(iter::once(libffi_arg(&vmctx_ptr)))
|
||||
.collect();
|
||||
|
||||
let code_ptr = CodePtr::from_ptr(func_ptr as _);
|
||||
|
||||
call_protected(&self.handler_data, || {
|
||||
// Only supports zero or one return values for now.
|
||||
// To support multiple returns, we will have to
|
||||
// generate trampolines instead of using libffi.
|
||||
match signature.returns.first() {
|
||||
Some(ty) => {
|
||||
let val = match ty {
|
||||
Type::I32 => Value::I32(unsafe { libffi_call(code_ptr, &libffi_args) }),
|
||||
Type::I64 => Value::I64(unsafe { libffi_call(code_ptr, &libffi_args) }),
|
||||
Type::F32 => Value::F32(unsafe { libffi_call(code_ptr, &libffi_args) }),
|
||||
Type::F64 => Value::F64(unsafe { libffi_call(code_ptr, &libffi_args) }),
|
||||
};
|
||||
returns[0] = val;
|
||||
}
|
||||
// call with no returns
|
||||
None => unsafe {
|
||||
libffi_call::<()>(code_ptr, &libffi_args);
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn get_func_from_index<'a>(
|
||||
module: &'a ModuleInner,
|
||||
import_backing: &ImportBacking,
|
||||
func_index: FuncIndex,
|
||||
) -> (*const vm::Func, Context, &'a FuncSig) {
|
||||
let sig_index = *module
|
||||
.func_assoc
|
||||
.get(func_index)
|
||||
.expect("broken invariant, incorrect func index");
|
||||
|
||||
let (func_ptr, ctx) = match func_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_func_index) => (
|
||||
module
|
||||
.func_resolver
|
||||
.get(&module, local_func_index)
|
||||
.expect("broken invariant, func resolver not synced with module.exports")
|
||||
.cast()
|
||||
.as_ptr() as *const _,
|
||||
Context::Internal,
|
||||
),
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
let imported_func = import_backing.imported_func(imported_func_index);
|
||||
(
|
||||
imported_func.func as *const _,
|
||||
Context::External(imported_func.vmctx),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let signature = module.sig_registry.lookup_func_sig(sig_index);
|
||||
|
||||
(func_ptr, ctx, signature)
|
||||
}
|
189
lib/clif-backend/src/call/recovery.rs
Normal file
189
lib/clif-backend/src/call/recovery.rs
Normal file
@ -0,0 +1,189 @@
|
||||
//! When a WebAssembly module triggers any traps, we perform recovery here.
|
||||
//!
|
||||
//! This module uses TLS (thread-local storage) to track recovery information. Since the four signals we're handling
|
||||
//! 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.
|
||||
|
||||
use crate::call::sighandler::install_sighandler;
|
||||
use crate::relocation::{TrapData, TrapSink};
|
||||
use cranelift_codegen::ir::TrapCode;
|
||||
use nix::libc::{c_void, siginfo_t};
|
||||
use nix::sys::signal::{Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV};
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
use std::ptr;
|
||||
use std::sync::Once;
|
||||
use wasmer_runtime::{
|
||||
error::{RuntimeError, RuntimeResult},
|
||||
structures::TypedIndex,
|
||||
types::{MemoryIndex, TableIndex},
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
pub fn setjmp(env: *mut ::nix::libc::c_void) -> ::nix::libc::c_int;
|
||||
fn longjmp(env: *mut ::nix::libc::c_void, val: ::nix::libc::c_int) -> !;
|
||||
}
|
||||
|
||||
const SETJMP_BUFFER_LEN: usize = 27;
|
||||
pub static SIGHANDLER_INIT: Once = Once::new();
|
||||
|
||||
thread_local! {
|
||||
pub static SETJMP_BUFFER: UnsafeCell<[::nix::libc::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 struct HandlerData {
|
||||
trap_data: TrapSink,
|
||||
buffer_ptr: *const c_void,
|
||||
buffer_size: usize,
|
||||
}
|
||||
|
||||
impl HandlerData {
|
||||
pub fn new(trap_data: TrapSink, buffer_ptr: *const c_void, buffer_size: usize) -> Self {
|
||||
Self {
|
||||
trap_data,
|
||||
buffer_ptr,
|
||||
buffer_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lookup(&self, ip: *const c_void) -> Option<TrapData> {
|
||||
let ip = ip as usize;
|
||||
let buffer_ptr = self.buffer_ptr as usize;
|
||||
|
||||
if buffer_ptr <= ip && ip < buffer_ptr + self.buffer_size {
|
||||
let offset = ip - buffer_ptr;
|
||||
self.trap_data.lookup(offset)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> RuntimeResult<T> {
|
||||
unsafe {
|
||||
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
||||
let prev_jmp_buf = *jmp_buf;
|
||||
|
||||
SIGHANDLER_INIT.call_once(|| {
|
||||
install_sighandler();
|
||||
});
|
||||
|
||||
let signum = setjmp(jmp_buf as *mut ::nix::libc::c_void);
|
||||
if signum != 0 {
|
||||
*jmp_buf = prev_jmp_buf;
|
||||
let (faulting_addr, _) = CAUGHT_ADDRESSES.with(|cell| cell.get());
|
||||
|
||||
if let Some(TrapData {
|
||||
trapcode,
|
||||
srcloc: _,
|
||||
}) = handler_data.lookup(faulting_addr)
|
||||
{
|
||||
Err(match Signal::from_c_int(signum) {
|
||||
Ok(SIGILL) => match trapcode {
|
||||
TrapCode::BadSignature => RuntimeError::IndirectCallSignature {
|
||||
table: TableIndex::new(0),
|
||||
},
|
||||
TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull {
|
||||
table: TableIndex::new(0),
|
||||
},
|
||||
TrapCode::HeapOutOfBounds => {
|
||||
let addr =
|
||||
(faulting_addr as usize) - (handler_data.buffer_ptr as usize);
|
||||
if addr <= handler_data.buffer_size {
|
||||
// in the memory
|
||||
RuntimeError::OutOfBoundsAccess {
|
||||
memory: MemoryIndex::new(0),
|
||||
addr: addr as u32,
|
||||
}
|
||||
} else {
|
||||
// if there's an invalid access outside of the memory, including guard pages
|
||||
// just kill the process.
|
||||
panic!("invalid memory access, way out of bounds")
|
||||
}
|
||||
}
|
||||
TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds {
|
||||
table: TableIndex::new(0),
|
||||
},
|
||||
_ => RuntimeError::Unknown {
|
||||
msg: "unknown trap".to_string(),
|
||||
},
|
||||
},
|
||||
Ok(SIGSEGV) | Ok(SIGBUS) => {
|
||||
let addr = (faulting_addr as usize) - (handler_data.buffer_ptr as usize);
|
||||
if addr <= handler_data.buffer_size {
|
||||
// in the memory
|
||||
RuntimeError::OutOfBoundsAccess {
|
||||
memory: MemoryIndex::new(0),
|
||||
addr: addr as u32,
|
||||
}
|
||||
} else {
|
||||
// if there's an invalid access outside of the memory, including guard pages
|
||||
// just kill the process.
|
||||
panic!("invalid memory access, way out of bounds")
|
||||
}
|
||||
}
|
||||
Ok(SIGFPE) => RuntimeError::IllegalArithmeticOperation,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
.into())
|
||||
} else {
|
||||
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",
|
||||
_ => "unkown trapped signal",
|
||||
};
|
||||
// When the trap-handler is fully implemented, this will return more information.
|
||||
Err(RuntimeError::Unknown {
|
||||
msg: format!("trap at {:p} - {}", faulting_addr, signal),
|
||||
}
|
||||
.into())
|
||||
}
|
||||
} else {
|
||||
let ret = f(); // TODO: Switch stack?
|
||||
*jmp_buf = prev_jmp_buf;
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unwinds to last protected_call.
|
||||
pub unsafe fn do_unwind(signum: i32, siginfo: *mut siginfo_t, 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: *mut siginfo_t,
|
||||
_ucontext: *const c_void,
|
||||
) -> (*const c_void, *const c_void) {
|
||||
(ptr::null(), ptr::null())
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
||||
unsafe fn get_faulting_addr_and_ip(
|
||||
siginfo: *mut siginfo_t,
|
||||
_ucontext: *const c_void,
|
||||
) -> (*const c_void, *const c_void) {
|
||||
((*siginfo).si_addr, ptr::null())
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
all(target_os = "macos", target_arch = "x86_64"),
|
||||
all(target_os = "linux", target_arch = "x86_64"),
|
||||
)))]
|
||||
compile_error!("This crate doesn't yet support compiling on operating systems other than linux and macos and architectures other than x86_64");
|
@ -1,10 +1,8 @@
|
||||
//! We install signal handlers to handle WebAssembly traps within
|
||||
//! our Rust code. Otherwise we will have errors that stop the Rust process
|
||||
//! such as `process didn't exit successfully: ... (signal: 8, SIGFPE: erroneous arithmetic operation)`
|
||||
//! Installing signal handlers allows us to handle traps and out-of-bounds memory
|
||||
//! accesses that occur when runniing webassembly.
|
||||
//!
|
||||
//! Please read more about this here: https://github.com/CraneStation/wasmtime/issues/15
|
||||
//! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622
|
||||
use super::recovery;
|
||||
use crate::call::recovery;
|
||||
use nix::libc::{c_void, siginfo_t};
|
||||
use nix::sys::signal::{
|
||||
sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGFPE, SIGILL, SIGSEGV,
|
||||
@ -25,9 +23,9 @@ pub unsafe fn install_sighandler() {
|
||||
extern "C" fn signal_trap_handler(
|
||||
signum: ::nix::libc::c_int,
|
||||
siginfo: *mut siginfo_t,
|
||||
_ucontext: *mut c_void,
|
||||
ucontext: *mut c_void,
|
||||
) {
|
||||
unsafe {
|
||||
recovery::do_unwind(signum, siginfo);
|
||||
recovery::do_unwind(signum, siginfo, ucontext);
|
||||
}
|
||||
}
|
1037
lib/clif-backend/src/codegen.rs
Normal file
1037
lib/clif-backend/src/codegen.rs
Normal file
File diff suppressed because it is too large
Load Diff
665
lib/clif-backend/src/func_env.rs
Normal file
665
lib/clif-backend/src/func_env.rs
Normal file
@ -0,0 +1,665 @@
|
||||
use crate::{module::Converter, module_env::ModuleEnv};
|
||||
use cranelift_codegen::{
|
||||
cursor::FuncCursor,
|
||||
ir::{self, InstBuilder},
|
||||
isa,
|
||||
};
|
||||
use cranelift_wasm::{self, FuncEnvironment, ModuleEnvironment};
|
||||
use wasmer_runtime::{
|
||||
memory::LinearMemory,
|
||||
structures::TypedIndex,
|
||||
types::{FuncIndex, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex},
|
||||
vm,
|
||||
};
|
||||
|
||||
pub struct FuncEnv<'env, 'module, 'isa> {
|
||||
env: &'env ModuleEnv<'module, 'isa>,
|
||||
}
|
||||
|
||||
impl<'env, 'module, 'isa> FuncEnv<'env, 'module, 'isa> {
|
||||
pub fn new(env: &'env ModuleEnv<'module, 'isa>) -> Self {
|
||||
Self { env }
|
||||
}
|
||||
|
||||
/// Creates a signature with VMContext as the last param
|
||||
pub fn generate_signature(&self, sig_index: cranelift_wasm::SignatureIndex) -> ir::Signature {
|
||||
// Get signature
|
||||
let mut signature = self.env.signatures[Converter(sig_index).into()].clone();
|
||||
|
||||
// Add the vmctx parameter type to it
|
||||
signature.params.push(ir::AbiParam::special(
|
||||
self.pointer_type(),
|
||||
ir::ArgumentPurpose::VMContext,
|
||||
));
|
||||
|
||||
// Return signature
|
||||
signature
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
||||
/// Gets configuration information needed for compiling functions
|
||||
fn target_config(&self) -> isa::TargetFrontendConfig {
|
||||
self.env.target_config()
|
||||
}
|
||||
|
||||
/// Gets native pointers types.
|
||||
///
|
||||
/// `I64` on 64-bit arch; `I32` on 32-bit arch.
|
||||
fn pointer_type(&self) -> ir::Type {
|
||||
ir::Type::int(u16::from(self.target_config().pointer_bits())).unwrap()
|
||||
}
|
||||
|
||||
/// Gets the size of a native pointer in bytes.
|
||||
fn pointer_bytes(&self) -> u8 {
|
||||
self.target_config().pointer_bytes()
|
||||
}
|
||||
|
||||
/// Sets up the necessary preamble definitions in `func` to access the global identified
|
||||
/// by `index`.
|
||||
///
|
||||
/// The index space covers both imported and locally declared globals.
|
||||
fn make_global(
|
||||
&mut self,
|
||||
func: &mut ir::Function,
|
||||
clif_global_index: cranelift_wasm::GlobalIndex,
|
||||
) -> cranelift_wasm::GlobalVariable {
|
||||
let global_index: GlobalIndex = Converter(clif_global_index).into();
|
||||
|
||||
// Create VMContext value.
|
||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
let ptr_type = self.pointer_type();
|
||||
|
||||
match global_index.local_or_import(self.env.module) {
|
||||
LocalOrImport::Local(local_global_index) => {
|
||||
let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_globals() as i32).into(),
|
||||
global_type: self.pointer_type(),
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let offset = local_global_index.index() * vm::LocalGlobal::size() as usize;
|
||||
|
||||
let local_global_addr = func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: globals_base_addr,
|
||||
offset: (offset as i64).into(),
|
||||
global_type: ptr_type,
|
||||
});
|
||||
|
||||
// Create global variable based on the data above.
|
||||
cranelift_wasm::GlobalVariable::Memory {
|
||||
gv: local_global_addr,
|
||||
offset: (vm::LocalGlobal::offset_data() as i32).into(),
|
||||
ty: self.env.get_global(clif_global_index).ty,
|
||||
}
|
||||
}
|
||||
LocalOrImport::Import(imported_global_index) => {
|
||||
let imported_globals_base_addr =
|
||||
func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_imported_globals() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let offset = imported_global_index.index() * vm::ImportedGlobal::size() as usize;
|
||||
let imported_global_addr = func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: imported_globals_base_addr,
|
||||
offset: (offset as i64).into(),
|
||||
global_type: ptr_type,
|
||||
});
|
||||
|
||||
let local_global_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: imported_global_addr,
|
||||
offset: (vm::ImportedGlobal::offset_global() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
cranelift_wasm::GlobalVariable::Memory {
|
||||
gv: local_global_addr,
|
||||
offset: (vm::LocalGlobal::offset_data() as i32).into(),
|
||||
ty: self.env.get_global(clif_global_index).ty,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up the necessary preamble definitions in `func` to access the linear memory identified
|
||||
/// by `index`.
|
||||
///
|
||||
/// The index space covers both imported and locally declared memories.
|
||||
fn make_heap(
|
||||
&mut self,
|
||||
func: &mut ir::Function,
|
||||
clif_mem_index: cranelift_wasm::MemoryIndex,
|
||||
) -> ir::Heap {
|
||||
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
|
||||
// Create VMContext value.
|
||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
let ptr_type = self.pointer_type();
|
||||
|
||||
match mem_index.local_or_import(self.env.module) {
|
||||
LocalOrImport::Local(local_mem_index) => {
|
||||
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_memories() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let memory_offset = local_mem_index.index() * vm::LocalMemory::size() as usize;
|
||||
|
||||
let memory_struct_addr = func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: memories_base_addr,
|
||||
offset: (memory_offset as i64).into(),
|
||||
global_type: ptr_type,
|
||||
});
|
||||
|
||||
let memory_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: memory_struct_addr,
|
||||
offset: (vm::LocalMemory::offset_base() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
func.create_heap(ir::HeapData {
|
||||
base: memory_base_addr,
|
||||
min_size: (self.env.module.memories[local_mem_index].min as u64).into(),
|
||||
offset_guard_size: (LinearMemory::DEFAULT_GUARD_SIZE as u64).into(),
|
||||
style: ir::HeapStyle::Static {
|
||||
bound: (LinearMemory::DEFAULT_HEAP_SIZE as u64).into(),
|
||||
},
|
||||
index_type: ir::types::I32,
|
||||
})
|
||||
}
|
||||
LocalOrImport::Import(imported_mem_index) => {
|
||||
let imported_memories_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_imported_memories() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let imported_memory_offset =
|
||||
imported_mem_index.index() * vm::ImportedMemory::size() as usize;
|
||||
|
||||
let imported_memory_struct_addr =
|
||||
func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: imported_memories_base,
|
||||
offset: (imported_memory_offset as i64).into(),
|
||||
global_type: ptr_type,
|
||||
});
|
||||
|
||||
let local_memory_struct_addr =
|
||||
func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: imported_memory_struct_addr,
|
||||
offset: (vm::ImportedMemory::offset_memory() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let local_memory_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: local_memory_struct_addr,
|
||||
offset: (vm::LocalMemory::offset_base() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
func.create_heap(ir::HeapData {
|
||||
base: local_memory_base,
|
||||
min_size: (self.env.module.imported_memories[imported_mem_index].1.min as u64)
|
||||
.into(),
|
||||
offset_guard_size: (LinearMemory::DEFAULT_GUARD_SIZE as u64).into(),
|
||||
style: ir::HeapStyle::Static {
|
||||
bound: (LinearMemory::DEFAULT_HEAP_SIZE as u64).into(),
|
||||
},
|
||||
index_type: ir::types::I32,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up the necessary preamble definitions in `func` to access the table identified
|
||||
/// by `index`.
|
||||
///
|
||||
/// The index space covers both imported and locally declared tables.
|
||||
fn make_table(
|
||||
&mut self,
|
||||
func: &mut ir::Function,
|
||||
clif_table_index: cranelift_wasm::TableIndex,
|
||||
) -> ir::Table {
|
||||
let table_index: TableIndex = Converter(clif_table_index).into();
|
||||
// Create VMContext value.
|
||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
let ptr_type = self.pointer_type();
|
||||
|
||||
match table_index.local_or_import(self.env.module) {
|
||||
LocalOrImport::Local(local_table_index) => {
|
||||
let tables_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_tables() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let table_struct_offset =
|
||||
local_table_index.index() * vm::LocalTable::size() as usize;
|
||||
|
||||
let table_struct_addr = func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: tables_base,
|
||||
offset: (table_struct_offset as i64).into(),
|
||||
global_type: ptr_type,
|
||||
});
|
||||
|
||||
let table_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: table_struct_addr,
|
||||
offset: (vm::LocalTable::offset_base() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
// we will support growing tables, so this cannot be readonly.
|
||||
readonly: false,
|
||||
});
|
||||
|
||||
let table_bound = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: table_struct_addr,
|
||||
offset: (vm::LocalTable::offset_current_elements() as i32).into(),
|
||||
// the number of elements in a table will always fit in an `i32`.
|
||||
global_type: ir::types::I32,
|
||||
readonly: false,
|
||||
});
|
||||
|
||||
func.create_table(ir::TableData {
|
||||
base_gv: table_base,
|
||||
min_size: (self.env.module.tables[local_table_index].min as u64).into(),
|
||||
bound_gv: table_bound,
|
||||
element_size: (vm::Anyfunc::size() as u64).into(),
|
||||
index_type: ir::types::I32,
|
||||
})
|
||||
}
|
||||
LocalOrImport::Import(imported_table_index) => {
|
||||
let imported_tables_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_imported_tables() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let imported_table_struct_offset =
|
||||
imported_table_index.index() * vm::ImportedTable::size() as usize;
|
||||
|
||||
let imported_table_struct_addr =
|
||||
func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: imported_tables_base,
|
||||
offset: (imported_table_struct_offset as i64).into(),
|
||||
global_type: ptr_type,
|
||||
});
|
||||
|
||||
let local_table_struct_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: imported_table_struct_addr,
|
||||
offset: (vm::ImportedTable::offset_table() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let local_table_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: local_table_struct_addr,
|
||||
offset: (vm::LocalTable::offset_base() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: false,
|
||||
});
|
||||
|
||||
let local_table_bound = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: local_table_struct_addr,
|
||||
offset: (vm::LocalTable::offset_current_elements() as i32).into(),
|
||||
global_type: ir::types::I32,
|
||||
readonly: false,
|
||||
});
|
||||
|
||||
func.create_table(ir::TableData {
|
||||
base_gv: local_table_base,
|
||||
min_size: (self.env.module.imported_tables[imported_table_index].1.min as u64)
|
||||
.into(),
|
||||
bound_gv: local_table_bound,
|
||||
element_size: (vm::Anyfunc::size() as u64).into(),
|
||||
index_type: ir::types::I32,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up a signature definition in `func`'s preamble.
|
||||
///
|
||||
/// Signature may contain additional argument, but arguments marked as ArgumentPurpose::Normal`
|
||||
/// must correspond to the arguments in the wasm signature
|
||||
fn make_indirect_sig(
|
||||
&mut self,
|
||||
func: &mut ir::Function,
|
||||
index: cranelift_wasm::SignatureIndex,
|
||||
) -> ir::SigRef {
|
||||
// Create a signature reference out of specified signature (with VMContext param added).
|
||||
func.import_signature(self.generate_signature(index))
|
||||
}
|
||||
|
||||
/// Sets up an external function definition in the preamble of `func` that can be used to
|
||||
/// directly call the function `index`.
|
||||
///
|
||||
/// The index space covers both imported functions and functions defined in the current module.
|
||||
fn make_direct_func(
|
||||
&mut self,
|
||||
func: &mut ir::Function,
|
||||
func_index: cranelift_wasm::FuncIndex,
|
||||
) -> ir::FuncRef {
|
||||
// Get signature of function.
|
||||
let signature_index = self.env.get_func_type(func_index);
|
||||
|
||||
// Create a signature reference from specified signature (with VMContext param added).
|
||||
let signature = func.import_signature(self.generate_signature(signature_index));
|
||||
|
||||
// Get name of function.
|
||||
let name = ir::ExternalName::user(0, func_index.as_u32());
|
||||
|
||||
// Create function reference from fuction data.
|
||||
func.import_function(ir::ExtFuncData {
|
||||
name,
|
||||
signature,
|
||||
colocated: false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Generates an indirect call IR with `callee` and `call_args`.
|
||||
///
|
||||
/// Inserts instructions at `pos` to the function `callee` in the table
|
||||
/// `table_index` with WebAssembly signature `sig_index`
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))]
|
||||
fn translate_call_indirect(
|
||||
&mut self,
|
||||
mut pos: FuncCursor,
|
||||
_table_index: cranelift_wasm::TableIndex,
|
||||
table: ir::Table,
|
||||
sig_index: cranelift_wasm::SignatureIndex,
|
||||
sig_ref: ir::SigRef,
|
||||
callee: ir::Value,
|
||||
call_args: &[ir::Value],
|
||||
) -> cranelift_wasm::WasmResult<ir::Inst> {
|
||||
// Get the pointer type based on machine's pointer size.
|
||||
let ptr_type = self.pointer_type();
|
||||
|
||||
// The `callee` value is an index into a table of Anyfunc structures.
|
||||
let entry_addr = pos.ins().table_addr(ptr_type, table, callee, 0);
|
||||
|
||||
let mflags = ir::MemFlags::trusted();
|
||||
|
||||
let func_ptr = pos.ins().load(
|
||||
ptr_type,
|
||||
mflags,
|
||||
entry_addr,
|
||||
vm::Anyfunc::offset_func() as i32,
|
||||
);
|
||||
let vmctx_ptr = pos.ins().load(
|
||||
ptr_type,
|
||||
mflags,
|
||||
entry_addr,
|
||||
vm::Anyfunc::offset_vmctx() as i32,
|
||||
);
|
||||
let found_sig = pos.ins().load(
|
||||
ir::types::I32,
|
||||
mflags,
|
||||
entry_addr,
|
||||
vm::Anyfunc::offset_sig_id() as i32,
|
||||
);
|
||||
|
||||
pos.ins().trapz(func_ptr, ir::TrapCode::IndirectCallToNull);
|
||||
|
||||
let deduplicated_sig_index = self
|
||||
.env
|
||||
.module
|
||||
.sig_registry
|
||||
.lookup_deduplicated_sigindex(Converter(sig_index).into());
|
||||
let expected_sig = pos
|
||||
.ins()
|
||||
.iconst(ir::types::I32, deduplicated_sig_index.index() as i64);
|
||||
let not_equal_flags = pos.ins().ifcmp(found_sig, expected_sig);
|
||||
|
||||
pos.ins().trapif(
|
||||
ir::condcodes::IntCC::NotEqual,
|
||||
not_equal_flags,
|
||||
ir::TrapCode::BadSignature,
|
||||
);
|
||||
|
||||
// Build a value list for the indirect call instruction containing the call_args
|
||||
// and the vmctx parameter.
|
||||
let mut args = Vec::with_capacity(call_args.len() + 1);
|
||||
args.extend(call_args.iter().cloned());
|
||||
args.push(vmctx_ptr);
|
||||
|
||||
Ok(pos.ins().call_indirect(sig_ref, func_ptr, &args))
|
||||
}
|
||||
|
||||
/// Generates a call IR with `callee` and `call_args` and inserts it at `pos`
|
||||
/// TODO: add support for imported functions
|
||||
fn translate_call(
|
||||
&mut self,
|
||||
mut pos: FuncCursor,
|
||||
clif_callee_index: cranelift_wasm::FuncIndex,
|
||||
callee: ir::FuncRef,
|
||||
call_args: &[ir::Value],
|
||||
) -> cranelift_wasm::WasmResult<ir::Inst> {
|
||||
let callee_index: FuncIndex = Converter(clif_callee_index).into();
|
||||
|
||||
match callee_index.local_or_import(self.env.module) {
|
||||
LocalOrImport::Local(_) => {
|
||||
// this is an internal function
|
||||
let vmctx = pos
|
||||
.func
|
||||
.special_param(ir::ArgumentPurpose::VMContext)
|
||||
.expect("missing vmctx parameter");
|
||||
|
||||
let mut args = Vec::with_capacity(call_args.len() + 1);
|
||||
args.extend(call_args.iter().cloned());
|
||||
args.push(vmctx);
|
||||
|
||||
Ok(pos.ins().call(callee, &args))
|
||||
}
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
let ptr_type = self.pointer_type();
|
||||
// this is an imported function
|
||||
let vmctx = pos.func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
|
||||
let imported_funcs = pos.func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_imported_funcs() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let imported_func_offset =
|
||||
imported_func_index.index() * vm::ImportedFunc::size() as usize;
|
||||
|
||||
let imported_func_struct_addr =
|
||||
pos.func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: imported_funcs,
|
||||
offset: (imported_func_offset as i64).into(),
|
||||
global_type: ptr_type,
|
||||
});
|
||||
|
||||
let imported_func_addr = pos.func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: imported_func_struct_addr,
|
||||
offset: (vm::ImportedFunc::offset_func() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let imported_vmctx_addr = pos.func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: imported_func_struct_addr,
|
||||
offset: (vm::ImportedFunc::offset_vmctx() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let imported_func_addr = pos.ins().global_value(ptr_type, imported_func_addr);
|
||||
let imported_vmctx_addr = pos.ins().global_value(ptr_type, imported_vmctx_addr);
|
||||
|
||||
let sig_ref = pos.func.dfg.ext_funcs[callee].signature;
|
||||
|
||||
let mut args = Vec::with_capacity(call_args.len() + 1);
|
||||
args.extend(call_args.iter().cloned());
|
||||
args.push(imported_vmctx_addr);
|
||||
|
||||
Ok(pos
|
||||
.ins()
|
||||
.call_indirect(sig_ref, imported_func_addr, &args[..]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates code corresponding to wasm `memory.grow`.
|
||||
///
|
||||
/// `index` refers to the linear memory to query.
|
||||
///
|
||||
/// `heap` refers to the IR generated by `make_heap`.
|
||||
///
|
||||
/// `val` refers the value to grow the memory by.
|
||||
fn translate_memory_grow(
|
||||
&mut self,
|
||||
mut pos: FuncCursor,
|
||||
clif_mem_index: cranelift_wasm::MemoryIndex,
|
||||
_heap: ir::Heap,
|
||||
by_value: ir::Value,
|
||||
) -> cranelift_wasm::WasmResult<ir::Value> {
|
||||
let signature = pos.func.import_signature(ir::Signature {
|
||||
call_conv: self.target_config().default_call_conv,
|
||||
params: vec![
|
||||
ir::AbiParam::new(ir::types::I32),
|
||||
ir::AbiParam::new(ir::types::I32),
|
||||
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
|
||||
],
|
||||
returns: vec![ir::AbiParam::new(ir::types::I32)],
|
||||
});
|
||||
|
||||
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
|
||||
|
||||
let (name, mem_index) = match mem_index.local_or_import(self.env.module) {
|
||||
LocalOrImport::Local(local_mem_index) => {
|
||||
(
|
||||
// local_static_memory_grow
|
||||
ir::ExternalName::user(1, 0),
|
||||
local_mem_index.index(),
|
||||
)
|
||||
}
|
||||
LocalOrImport::Import(imported_mem_index) => {
|
||||
(
|
||||
// imported_static_memory_grow
|
||||
ir::ExternalName::user(1, 2),
|
||||
imported_mem_index.index(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let mem_grow_func = pos.func.import_function(ir::ExtFuncData {
|
||||
name,
|
||||
signature,
|
||||
colocated: false,
|
||||
});
|
||||
|
||||
let const_mem_index = pos.ins().iconst(ir::types::I32, mem_index as i64);
|
||||
|
||||
let vmctx = pos
|
||||
.func
|
||||
.special_param(ir::ArgumentPurpose::VMContext)
|
||||
.expect("missing vmctx parameter");
|
||||
|
||||
let call_inst = pos
|
||||
.ins()
|
||||
.call(mem_grow_func, &[const_mem_index, by_value, vmctx]);
|
||||
|
||||
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
|
||||
}
|
||||
|
||||
/// Generates code corresponding to wasm `memory.size`.
|
||||
///
|
||||
/// `index` refers to the linear memory to query.
|
||||
///
|
||||
/// `heap` refers to the IR generated by `make_heap`.
|
||||
fn translate_memory_size(
|
||||
&mut self,
|
||||
mut pos: FuncCursor,
|
||||
clif_mem_index: cranelift_wasm::MemoryIndex,
|
||||
_heap: ir::Heap,
|
||||
) -> cranelift_wasm::WasmResult<ir::Value> {
|
||||
// let signature = pos.func.import_signature(ir::Signature {
|
||||
// call_conv: self.target_config().default_call_conv,
|
||||
// params: vec![
|
||||
// ir::AbiParam::new(ir::types::I32),
|
||||
// ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
|
||||
// ],
|
||||
// returns: vec![ir::AbiParam::new(ir::types::I32)],
|
||||
// });
|
||||
|
||||
// let size_mem_func = pos.func.import_function(ir::ExtFuncData {
|
||||
// // `ir::ExternalName` for static_grow_memory`
|
||||
// name: ir::ExternalName::user(1, 1),
|
||||
// signature,
|
||||
// colocated: false,
|
||||
// });
|
||||
|
||||
// // Create a memory index value.
|
||||
// let memory_index = pos.ins().iconst(ir::types::I32, index.index() as i64);
|
||||
|
||||
// // Create a VMContext value.
|
||||
// let vmctx = pos
|
||||
// .func
|
||||
// .special_param(ir::ArgumentPurpose::VMContext)
|
||||
// .expect("missing vmctx parameter");
|
||||
|
||||
// // Insert call instructions for `grow_memory`.
|
||||
// let call_inst = pos.ins().call(size_mem_func, &[memory_index, vmctx]);
|
||||
|
||||
// // Return value.
|
||||
// Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
|
||||
|
||||
let signature = pos.func.import_signature(ir::Signature {
|
||||
call_conv: self.target_config().default_call_conv,
|
||||
params: vec![
|
||||
ir::AbiParam::new(ir::types::I32),
|
||||
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
|
||||
],
|
||||
returns: vec![ir::AbiParam::new(ir::types::I32)],
|
||||
});
|
||||
|
||||
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
|
||||
|
||||
let (name, mem_index) = match mem_index.local_or_import(self.env.module) {
|
||||
LocalOrImport::Local(local_mem_index) => {
|
||||
(
|
||||
// local_static_memory_size
|
||||
ir::ExternalName::user(1, 1),
|
||||
local_mem_index.index(),
|
||||
)
|
||||
}
|
||||
LocalOrImport::Import(imported_mem_index) => {
|
||||
(
|
||||
// imported_static_memory_size
|
||||
ir::ExternalName::user(1, 3),
|
||||
imported_mem_index.index(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let mem_grow_func = pos.func.import_function(ir::ExtFuncData {
|
||||
name,
|
||||
signature,
|
||||
colocated: false,
|
||||
});
|
||||
|
||||
let const_mem_index = pos.ins().iconst(ir::types::I32, mem_index as i64);
|
||||
let vmctx = pos
|
||||
.func
|
||||
.special_param(ir::ArgumentPurpose::VMContext)
|
||||
.expect("missing vmctx parameter");
|
||||
|
||||
let call_inst = pos.ins().call(mem_grow_func, &[const_mem_index, vmctx]);
|
||||
|
||||
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
|
||||
}
|
||||
}
|
73
lib/clif-backend/src/lib.rs
Normal file
73
lib/clif-backend/src/lib.rs
Normal file
@ -0,0 +1,73 @@
|
||||
// pub mod codegen;
|
||||
mod call;
|
||||
mod func_env;
|
||||
mod libcalls;
|
||||
mod module;
|
||||
mod module_env;
|
||||
mod relocation;
|
||||
mod resolver;
|
||||
|
||||
use cranelift_codegen::{
|
||||
isa,
|
||||
settings::{self, Configurable},
|
||||
};
|
||||
use target_lexicon::Triple;
|
||||
use wasmer_runtime::{
|
||||
backend::{Compiler, Token},
|
||||
error::{CompileError, CompileResult},
|
||||
module::ModuleInner,
|
||||
};
|
||||
use wasmparser::{self, WasmDecoder};
|
||||
|
||||
pub struct CraneliftCompiler {}
|
||||
|
||||
impl CraneliftCompiler {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Compiler for CraneliftCompiler {
|
||||
// Compiles wasm binary to a wasmer module.
|
||||
fn compile(&self, wasm: &[u8], _: Token) -> CompileResult<ModuleInner> {
|
||||
validate(wasm)?;
|
||||
|
||||
let isa = get_isa();
|
||||
|
||||
let mut module = module::Module::empty();
|
||||
let module_env = module_env::ModuleEnv::new(&mut module, &*isa);
|
||||
let func_bodies = module_env.translate(wasm)?;
|
||||
|
||||
module.compile(&*isa, func_bodies)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_isa() -> Box<isa::TargetIsa> {
|
||||
let flags = {
|
||||
let mut builder = settings::builder();
|
||||
builder.set("opt_level", "best").unwrap();
|
||||
|
||||
if cfg!(not(test)) {
|
||||
builder.set("enable_verifier", "false").unwrap();
|
||||
}
|
||||
|
||||
let flags = settings::Flags::new(builder);
|
||||
debug_assert_eq!(flags.opt_level(), settings::OptLevel::Best);
|
||||
flags
|
||||
};
|
||||
isa::lookup(Triple::host()).unwrap().finish(flags)
|
||||
}
|
||||
|
||||
fn validate(bytes: &[u8]) -> CompileResult<()> {
|
||||
let mut parser = wasmparser::ValidatingParser::new(bytes, None);
|
||||
loop {
|
||||
let state = parser.read();
|
||||
match *state {
|
||||
wasmparser::ParserState::EndWasm => break Ok(()),
|
||||
wasmparser::ParserState::Error(err) => Err(CompileError::ValidationError {
|
||||
msg: err.message.to_string(),
|
||||
})?,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
83
lib/clif-backend/src/libcalls.rs
Normal file
83
lib/clif-backend/src/libcalls.rs
Normal file
@ -0,0 +1,83 @@
|
||||
use std::{f32, f64};
|
||||
|
||||
// F32
|
||||
pub extern "C" fn ceilf32(x: f32) -> f32 {
|
||||
x.ceil()
|
||||
}
|
||||
|
||||
pub extern "C" fn floorf32(x: f32) -> f32 {
|
||||
x.floor()
|
||||
}
|
||||
|
||||
pub extern "C" fn truncf32(x: f32) -> f32 {
|
||||
x.trunc()
|
||||
}
|
||||
|
||||
/// `f32.round()` doesn't have the correct behavior. Ideally, we'd use
|
||||
/// "https://doc.rust-lang.org/std/intrinsics/fn.nearbyintf32.html" for this,
|
||||
/// but support for stable compilers is necessary, so we must implement
|
||||
/// this ourselves.
|
||||
/// This is ported from "https://github.com/rust-lang/rust/issues/55107#issuecomment-431247454"
|
||||
pub extern "C" fn nearbyintf32(x: f32) -> f32 {
|
||||
#[inline]
|
||||
fn copysign(x: f32, y: f32) -> f32 {
|
||||
let bitmask = y.to_bits() & (1 << 31);
|
||||
f32::from_bits(x.to_bits() | bitmask)
|
||||
}
|
||||
|
||||
if x.is_nan() {
|
||||
f32::from_bits(x.to_bits() | (1 << 22))
|
||||
} else {
|
||||
let k = f32::EPSILON.recip();
|
||||
let a = x.abs();
|
||||
if a < k {
|
||||
copysign((a + k) - k, x)
|
||||
} else {
|
||||
x
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// F64
|
||||
pub extern "C" fn ceilf64(x: f64) -> f64 {
|
||||
x.ceil()
|
||||
}
|
||||
|
||||
pub extern "C" fn floorf64(x: f64) -> f64 {
|
||||
x.floor()
|
||||
}
|
||||
|
||||
pub extern "C" fn truncf64(x: f64) -> f64 {
|
||||
x.trunc()
|
||||
}
|
||||
|
||||
/// `f64.round()` doesn't have the correct behavior. Ideally, we'd use
|
||||
/// "https://doc.rust-lang.org/std/intrinsics/fn.nearbyintf64.html" for this,
|
||||
/// but support for stable compilers is necessary, so we must implement
|
||||
/// this ourselves.
|
||||
/// This is ported from "https://github.com/rust-lang/rust/issues/55007#issuecomment-431247454"
|
||||
pub extern "C" fn nearbyintf64(x: f64) -> f64 {
|
||||
#[inline]
|
||||
fn copysign(x: f64, y: f64) -> f64 {
|
||||
let bitmask = y.to_bits() & (1 << 63);
|
||||
f64::from_bits(x.to_bits() | bitmask)
|
||||
}
|
||||
|
||||
if x.is_nan() {
|
||||
f64::from_bits(x.to_bits() | (1 << 51))
|
||||
} else {
|
||||
let k = f64::EPSILON.recip();
|
||||
let a = x.abs();
|
||||
if a < k {
|
||||
copysign((a + k) - k, x)
|
||||
} else {
|
||||
x
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A declaration for the stack probe function in Rust's standard library, for
|
||||
/// catching callstack overflow.
|
||||
extern "C" {
|
||||
pub fn __rust_probestack();
|
||||
}
|
180
lib/clif-backend/src/module.rs
Normal file
180
lib/clif-backend/src/module.rs
Normal file
@ -0,0 +1,180 @@
|
||||
use crate::{call::Caller, resolver::FuncResolverBuilder};
|
||||
use cranelift_codegen::{ir, isa};
|
||||
use cranelift_entity::EntityRef;
|
||||
use cranelift_wasm;
|
||||
use hashbrown::HashMap;
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
ptr::NonNull,
|
||||
};
|
||||
use wasmer_runtime::{
|
||||
backend::SigRegistry,
|
||||
backend::{FuncResolver, ProtectedCaller, Token},
|
||||
error::{CompileResult, RuntimeResult},
|
||||
module::ModuleInner,
|
||||
structures::{Map, TypedIndex},
|
||||
types::{
|
||||
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, MemoryIndex, SigIndex, TableIndex, Type,
|
||||
Value,
|
||||
},
|
||||
vm::{self, ImportBacking},
|
||||
};
|
||||
|
||||
struct Placeholder;
|
||||
|
||||
impl FuncResolver for Placeholder {
|
||||
fn get(
|
||||
&self,
|
||||
_module: &ModuleInner,
|
||||
_local_func_index: LocalFuncIndex,
|
||||
) -> Option<NonNull<vm::Func>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtectedCaller for Placeholder {
|
||||
fn call(
|
||||
&self,
|
||||
_module: &ModuleInner,
|
||||
_func_index: FuncIndex,
|
||||
_params: &[Value],
|
||||
_returns: &mut [Value],
|
||||
_import_backing: &ImportBacking,
|
||||
_vmctx: *mut vm::Ctx,
|
||||
_: Token,
|
||||
) -> RuntimeResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// This contains all of the items in a `ModuleInner` except the `func_resolver`.
|
||||
pub struct Module {
|
||||
pub module: ModuleInner,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
module: ModuleInner {
|
||||
// this is a placeholder
|
||||
func_resolver: Box::new(Placeholder),
|
||||
protected_caller: Box::new(Placeholder),
|
||||
|
||||
memories: Map::new(),
|
||||
globals: Map::new(),
|
||||
tables: Map::new(),
|
||||
|
||||
imported_functions: Map::new(),
|
||||
imported_memories: Map::new(),
|
||||
imported_tables: Map::new(),
|
||||
imported_globals: Map::new(),
|
||||
|
||||
exports: HashMap::new(),
|
||||
|
||||
data_initializers: Vec::new(),
|
||||
elem_initializers: Vec::new(),
|
||||
|
||||
start_func: None,
|
||||
|
||||
func_assoc: Map::new(),
|
||||
sig_registry: SigRegistry::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile(
|
||||
mut self,
|
||||
isa: &isa::TargetIsa,
|
||||
functions: Map<LocalFuncIndex, ir::Function>,
|
||||
) -> CompileResult<ModuleInner> {
|
||||
// we have to deduplicate `module.func_assoc`
|
||||
let func_assoc = &mut self.module.func_assoc;
|
||||
let sig_registry = &self.module.sig_registry;
|
||||
func_assoc.iter_mut().for_each(|(_, sig_index)| {
|
||||
*sig_index = sig_registry.lookup_deduplicated_sigindex(*sig_index);
|
||||
});
|
||||
|
||||
let (func_resolver_builder, handler_data) = FuncResolverBuilder::new(isa, functions)?;
|
||||
self.module.func_resolver = Box::new(func_resolver_builder.finalize()?);
|
||||
|
||||
self.module.protected_caller = Box::new(Caller::new(&self.module, handler_data));
|
||||
|
||||
Ok(self.module)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Module {
|
||||
type Target = ModuleInner;
|
||||
|
||||
fn deref(&self) -> &ModuleInner {
|
||||
&self.module
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Module {
|
||||
fn deref_mut(&mut self) -> &mut ModuleInner {
|
||||
&mut self.module
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Converter<T>(pub T);
|
||||
|
||||
macro_rules! convert_clif_to_runtime_index {
|
||||
($clif_index:ident, $runtime_index:ident) => {
|
||||
impl From<Converter<cranelift_wasm::$clif_index>> for $runtime_index {
|
||||
fn from(clif_index: Converter<cranelift_wasm::$clif_index>) -> Self {
|
||||
$runtime_index::new(clif_index.0.index())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Converter<$runtime_index>> for cranelift_wasm::$clif_index {
|
||||
fn from(runtime_index: Converter<$runtime_index>) -> Self {
|
||||
cranelift_wasm::$clif_index::new(runtime_index.0.index())
|
||||
}
|
||||
}
|
||||
};
|
||||
($(($clif_index:ident: $runtime_index:ident),)*) => {
|
||||
$(
|
||||
convert_clif_to_runtime_index!($clif_index, $runtime_index);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
convert_clif_to_runtime_index![
|
||||
(FuncIndex: FuncIndex),
|
||||
(MemoryIndex: MemoryIndex),
|
||||
(TableIndex: TableIndex),
|
||||
(GlobalIndex: GlobalIndex),
|
||||
(SignatureIndex: SigIndex),
|
||||
];
|
||||
|
||||
impl<'a> From<Converter<&'a ir::Signature>> for FuncSig {
|
||||
fn from(signature: Converter<&'a ir::Signature>) -> Self {
|
||||
FuncSig {
|
||||
params: signature
|
||||
.0
|
||||
.params
|
||||
.iter()
|
||||
.map(|param| Converter(param.value_type).into())
|
||||
.collect(),
|
||||
returns: signature
|
||||
.0
|
||||
.returns
|
||||
.iter()
|
||||
.map(|ret| Converter(ret.value_type).into())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Converter<ir::Type>> for Type {
|
||||
fn from(ty: Converter<ir::Type>) -> Self {
|
||||
match ty.0 {
|
||||
ir::types::I32 => Type::I32,
|
||||
ir::types::I64 => Type::I64,
|
||||
ir::types::F32 => Type::F32,
|
||||
ir::types::F64 => Type::F64,
|
||||
_ => panic!("unsupported wasm type"),
|
||||
}
|
||||
}
|
||||
}
|
364
lib/clif-backend/src/module_env.rs
Normal file
364
lib/clif-backend/src/module_env.rs
Normal file
@ -0,0 +1,364 @@
|
||||
use crate::{
|
||||
func_env::FuncEnv,
|
||||
module::{Converter, Module},
|
||||
};
|
||||
use cranelift_codegen::{ir, isa};
|
||||
use cranelift_wasm::{self, translate_module, FuncTranslator, ModuleEnvironment};
|
||||
use wasmer_runtime::{
|
||||
error::{CompileError, CompileResult},
|
||||
module::{DataInitializer, ExportIndex, ImportName, TableInitializer},
|
||||
structures::{Map, TypedIndex},
|
||||
types::{
|
||||
ElementType, Global, GlobalDesc, GlobalIndex, Initializer, LocalFuncIndex, LocalOrImport,
|
||||
Memory, SigIndex, Table, Value,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct ModuleEnv<'module, 'isa> {
|
||||
pub module: &'module mut Module,
|
||||
isa: &'isa isa::TargetIsa,
|
||||
pub signatures: Map<SigIndex, ir::Signature>,
|
||||
globals: Map<GlobalIndex, cranelift_wasm::Global>,
|
||||
func_bodies: Map<LocalFuncIndex, ir::Function>,
|
||||
}
|
||||
|
||||
impl<'module, 'isa> ModuleEnv<'module, 'isa> {
|
||||
pub fn new(module: &'module mut Module, isa: &'isa isa::TargetIsa) -> Self {
|
||||
Self {
|
||||
module,
|
||||
isa,
|
||||
signatures: Map::new(),
|
||||
globals: Map::new(),
|
||||
func_bodies: Map::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn translate(mut self, wasm: &[u8]) -> CompileResult<Map<LocalFuncIndex, ir::Function>> {
|
||||
translate_module(wasm, &mut self)
|
||||
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
|
||||
Ok(self.func_bodies)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa> {
|
||||
/// Get the information needed to produce Cranelift IR for the current target.
|
||||
fn target_config(&self) -> isa::TargetFrontendConfig {
|
||||
self.isa.frontend_config()
|
||||
}
|
||||
|
||||
/// Declares a function signature to the environment.
|
||||
fn declare_signature(&mut self, sig: &ir::Signature) {
|
||||
self.signatures.push(sig.clone());
|
||||
self.module.sig_registry.register(Converter(sig).into());
|
||||
}
|
||||
|
||||
/// Return the signature with the given index.
|
||||
fn get_signature(&self, sig_index: cranelift_wasm::SignatureIndex) -> &ir::Signature {
|
||||
&self.signatures[Converter(sig_index).into()]
|
||||
}
|
||||
|
||||
/// Declares a function import to the environment.
|
||||
fn declare_func_import(
|
||||
&mut self,
|
||||
sig_index: cranelift_wasm::SignatureIndex,
|
||||
namespace: &'data str,
|
||||
name: &'data str,
|
||||
) {
|
||||
self.module.func_assoc.push(Converter(sig_index).into());
|
||||
|
||||
// Add import names to list of imported functions
|
||||
self.module.imported_functions.push(ImportName {
|
||||
namespace: namespace.to_string(),
|
||||
name: name.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Return the number of imported funcs.
|
||||
fn get_num_func_imports(&self) -> usize {
|
||||
self.module.imported_functions.len()
|
||||
}
|
||||
|
||||
/// Declares the type (signature) of a local function in the module.
|
||||
fn declare_func_type(&mut self, sig_index: cranelift_wasm::SignatureIndex) {
|
||||
self.module.func_assoc.push(Converter(sig_index).into());
|
||||
}
|
||||
|
||||
/// Return the signature index for the given function index.
|
||||
fn get_func_type(
|
||||
&self,
|
||||
func_index: cranelift_wasm::FuncIndex,
|
||||
) -> cranelift_wasm::SignatureIndex {
|
||||
Converter(self.module.func_assoc[Converter(func_index).into()]).into()
|
||||
}
|
||||
|
||||
/// Declares a global to the environment.
|
||||
fn declare_global(&mut self, global: cranelift_wasm::Global) {
|
||||
use cranelift_wasm::GlobalInit;
|
||||
|
||||
let desc = GlobalDesc {
|
||||
mutable: global.mutability,
|
||||
ty: Converter(global.ty).into(),
|
||||
};
|
||||
|
||||
let init = match global.initializer {
|
||||
GlobalInit::I32Const(x) => Initializer::Const(Value::I32(x)),
|
||||
GlobalInit::I64Const(x) => Initializer::Const(Value::I64(x)),
|
||||
GlobalInit::F32Const(x) => Initializer::Const(Value::F32(f32::from_bits(x))),
|
||||
GlobalInit::F64Const(x) => Initializer::Const(Value::F64(f64::from_bits(x))),
|
||||
GlobalInit::GetGlobal(global_index) => {
|
||||
assert!(!desc.mutable);
|
||||
let global_index: GlobalIndex = Converter(global_index).into();
|
||||
let imported_global_index = global_index
|
||||
.local_or_import(self.module)
|
||||
.import()
|
||||
.expect("invalid global initializer when declaring an imported global");
|
||||
Initializer::GetGlobal(imported_global_index)
|
||||
}
|
||||
_ => panic!("invalid global initializer when declaring a local global"),
|
||||
};
|
||||
|
||||
// Add global ir to the list of globals
|
||||
self.module.globals.push(Global { desc, init });
|
||||
|
||||
self.globals.push(global);
|
||||
}
|
||||
|
||||
/// Declares a global import to the environment.
|
||||
fn declare_global_import(
|
||||
&mut self,
|
||||
global: cranelift_wasm::Global,
|
||||
namespace: &'data str,
|
||||
name: &'data str,
|
||||
) {
|
||||
assert!(match global.initializer {
|
||||
cranelift_wasm::GlobalInit::Import => true,
|
||||
_ => false,
|
||||
});
|
||||
|
||||
let import_name = ImportName {
|
||||
namespace: namespace.to_string(),
|
||||
name: name.to_string(),
|
||||
};
|
||||
|
||||
let desc = GlobalDesc {
|
||||
mutable: global.mutability,
|
||||
ty: Converter(global.ty).into(),
|
||||
};
|
||||
|
||||
// Add global ir to the list of globals
|
||||
self.module.imported_globals.push((import_name, desc));
|
||||
|
||||
self.globals.push(global);
|
||||
}
|
||||
|
||||
/// Return the global for the given global index.
|
||||
fn get_global(&self, global_index: cranelift_wasm::GlobalIndex) -> &cranelift_wasm::Global {
|
||||
&self.globals[Converter(global_index).into()]
|
||||
}
|
||||
|
||||
/// Declares a table to the environment.
|
||||
fn declare_table(&mut self, table: cranelift_wasm::Table) {
|
||||
use cranelift_wasm::TableElementType;
|
||||
// Add table ir to the list of tables
|
||||
self.module.tables.push(Table {
|
||||
ty: match table.ty {
|
||||
TableElementType::Func => ElementType::Anyfunc,
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
min: table.minimum,
|
||||
max: table.maximum,
|
||||
});
|
||||
}
|
||||
|
||||
/// Declares a table import to the environment.
|
||||
fn declare_table_import(
|
||||
&mut self,
|
||||
table: cranelift_wasm::Table,
|
||||
namespace: &'data str,
|
||||
name: &'data str,
|
||||
) {
|
||||
use cranelift_wasm::TableElementType;
|
||||
|
||||
let import_name = ImportName {
|
||||
namespace: namespace.to_string(),
|
||||
name: name.to_string(),
|
||||
};
|
||||
|
||||
let imported_table = Table {
|
||||
ty: match table.ty {
|
||||
TableElementType::Func => ElementType::Anyfunc,
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
min: table.minimum,
|
||||
max: table.maximum,
|
||||
};
|
||||
|
||||
// Add import names to list of imported tables
|
||||
self.module
|
||||
.imported_tables
|
||||
.push((import_name, imported_table));
|
||||
}
|
||||
|
||||
/// Fills a declared table with references to functions in the module.
|
||||
fn declare_table_elements(
|
||||
&mut self,
|
||||
table_index: cranelift_wasm::TableIndex,
|
||||
base: Option<cranelift_wasm::GlobalIndex>,
|
||||
offset: usize,
|
||||
elements: Vec<cranelift_wasm::FuncIndex>,
|
||||
) {
|
||||
// Convert Cranelift GlobalIndex to wamser GlobalIndex
|
||||
// let base = base.map(|index| WasmerGlobalIndex::new(index.index()));
|
||||
let base = match base {
|
||||
Some(global_index) => {
|
||||
let global_index: GlobalIndex = Converter(global_index).into();
|
||||
Initializer::GetGlobal(match global_index.local_or_import(self.module) {
|
||||
LocalOrImport::Import(imported_global_index) => imported_global_index,
|
||||
LocalOrImport::Local(_) => {
|
||||
panic!("invalid global initializer when declaring an imported global")
|
||||
}
|
||||
})
|
||||
}
|
||||
None => Initializer::Const((offset as i32).into()),
|
||||
};
|
||||
|
||||
// Add table initializer to list of table initializers
|
||||
self.module.elem_initializers.push(TableInitializer {
|
||||
table_index: Converter(table_index).into(),
|
||||
base,
|
||||
elements: elements
|
||||
.iter()
|
||||
.map(|&func_index| Converter(func_index).into())
|
||||
.collect(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Declares a memory to the environment
|
||||
fn declare_memory(&mut self, memory: cranelift_wasm::Memory) {
|
||||
self.module.memories.push(Memory {
|
||||
min: memory.minimum,
|
||||
max: memory.maximum,
|
||||
shared: memory.shared,
|
||||
});
|
||||
}
|
||||
|
||||
/// Declares a memory import to the environment.
|
||||
fn declare_memory_import(
|
||||
&mut self,
|
||||
memory: cranelift_wasm::Memory,
|
||||
namespace: &'data str,
|
||||
name: &'data str,
|
||||
) {
|
||||
let import_name = ImportName {
|
||||
namespace: namespace.to_string(),
|
||||
name: name.to_string(),
|
||||
};
|
||||
|
||||
let memory = Memory {
|
||||
min: memory.minimum,
|
||||
max: memory.maximum,
|
||||
shared: memory.shared,
|
||||
};
|
||||
|
||||
// Add import names to list of imported memories
|
||||
self.module.imported_memories.push((import_name, memory));
|
||||
}
|
||||
|
||||
/// Fills a declared memory with bytes at module instantiation.
|
||||
fn declare_data_initialization(
|
||||
&mut self,
|
||||
memory_index: cranelift_wasm::MemoryIndex,
|
||||
base: Option<cranelift_wasm::GlobalIndex>,
|
||||
offset: usize,
|
||||
data: &'data [u8],
|
||||
) {
|
||||
// Convert Cranelift GlobalIndex to wamser GlobalIndex
|
||||
let base = match base {
|
||||
Some(global_index) => {
|
||||
let global_index: GlobalIndex = Converter(global_index).into();
|
||||
Initializer::GetGlobal(match global_index.local_or_import(self.module) {
|
||||
LocalOrImport::Import(imported_global_index) => imported_global_index,
|
||||
LocalOrImport::Local(_) => {
|
||||
panic!("invalid global initializer when declaring an imported global")
|
||||
}
|
||||
})
|
||||
}
|
||||
None => Initializer::Const((offset as i32).into()),
|
||||
};
|
||||
|
||||
// Add data initializer to list of data initializers
|
||||
self.module.data_initializers.push(DataInitializer {
|
||||
memory_index: Converter(memory_index).into(),
|
||||
base,
|
||||
data: data.to_vec(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Declares a function export to the environment.
|
||||
fn declare_func_export(&mut self, func_index: cranelift_wasm::FuncIndex, name: &'data str) {
|
||||
self.module.exports.insert(
|
||||
name.to_string(),
|
||||
ExportIndex::Func(Converter(func_index).into()),
|
||||
);
|
||||
}
|
||||
/// Declares a table export to the environment.
|
||||
fn declare_table_export(&mut self, table_index: cranelift_wasm::TableIndex, name: &'data str) {
|
||||
self.module.exports.insert(
|
||||
name.to_string(),
|
||||
ExportIndex::Table(Converter(table_index).into()),
|
||||
);
|
||||
}
|
||||
/// Declares a memory export to the environment.
|
||||
fn declare_memory_export(
|
||||
&mut self,
|
||||
memory_index: cranelift_wasm::MemoryIndex,
|
||||
name: &'data str,
|
||||
) {
|
||||
self.module.exports.insert(
|
||||
name.to_string(),
|
||||
ExportIndex::Memory(Converter(memory_index).into()),
|
||||
);
|
||||
}
|
||||
/// Declares a global export to the environment.
|
||||
fn declare_global_export(
|
||||
&mut self,
|
||||
global_index: cranelift_wasm::GlobalIndex,
|
||||
name: &'data str,
|
||||
) {
|
||||
self.module.exports.insert(
|
||||
name.to_string(),
|
||||
ExportIndex::Global(Converter(global_index).into()),
|
||||
);
|
||||
}
|
||||
|
||||
/// Declares a start function.
|
||||
fn declare_start_func(&mut self, func_index: cranelift_wasm::FuncIndex) {
|
||||
self.module.start_func = Some(Converter(func_index).into());
|
||||
}
|
||||
|
||||
/// Provides the contents of a function body.
|
||||
fn define_function_body(&mut self, body_bytes: &'data [u8]) -> cranelift_wasm::WasmResult<()> {
|
||||
let mut func_translator = FuncTranslator::new();
|
||||
|
||||
let func_body = {
|
||||
let mut func_env = FuncEnv::new(self);
|
||||
let func_index = self.func_bodies.next_index();
|
||||
let name = ir::ExternalName::user(0, func_index.index() as u32);
|
||||
|
||||
let sig = func_env.generate_signature(
|
||||
self.get_func_type(Converter(func_index.convert_up(self.module)).into()),
|
||||
);
|
||||
|
||||
let mut func = ir::Function::with_name_signature(name, sig);
|
||||
|
||||
func_translator.translate(body_bytes, &mut func, &mut func_env)?;
|
||||
|
||||
func
|
||||
};
|
||||
|
||||
// Add function body to list of function bodies.
|
||||
self.func_bodies.push(func_body);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -3,9 +3,10 @@
|
||||
//! any other calls that this function is doing, so we can "patch" the
|
||||
//! function addrs in runtime with the functions we need.
|
||||
use cranelift_codegen::binemit;
|
||||
use cranelift_codegen::ir::{self, ExternalName, LibCall, SourceLoc, TrapCode};
|
||||
|
||||
pub use cranelift_codegen::binemit::Reloc;
|
||||
use cranelift_codegen::ir::{self, ExternalName, LibCall, SourceLoc, TrapCode};
|
||||
use hashbrown::HashMap;
|
||||
use wasmer_runtime::{structures::TypedIndex, types::LocalFuncIndex};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Relocation {
|
||||
@ -19,14 +20,21 @@ pub struct Relocation {
|
||||
pub target: RelocationType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum VmCall {
|
||||
LocalStaticMemoryGrow,
|
||||
LocalStaticMemorySize,
|
||||
ImportedStaticMemoryGrow,
|
||||
ImportedStaticMemorySize,
|
||||
}
|
||||
|
||||
/// Specify the type of relocation
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RelocationType {
|
||||
Normal(u32),
|
||||
Normal(LocalFuncIndex),
|
||||
Intrinsic(String),
|
||||
LibCall(LibCall),
|
||||
GrowMemory,
|
||||
CurrentMemory,
|
||||
VmCall(VmCall),
|
||||
}
|
||||
|
||||
/// Implementation of a relocation sink that just saves all the information for later
|
||||
@ -61,22 +69,35 @@ impl binemit::RelocSink for RelocSink {
|
||||
reloc,
|
||||
offset,
|
||||
addend,
|
||||
target: RelocationType::Normal(index as _),
|
||||
target: RelocationType::Normal(LocalFuncIndex::new(index as usize)),
|
||||
});
|
||||
}
|
||||
ExternalName::User {
|
||||
namespace: 1,
|
||||
index,
|
||||
} => {
|
||||
let target = RelocationType::VmCall(match index {
|
||||
0 => VmCall::LocalStaticMemoryGrow,
|
||||
1 => VmCall::LocalStaticMemorySize,
|
||||
2 => VmCall::ImportedStaticMemoryGrow,
|
||||
3 => VmCall::ImportedStaticMemorySize,
|
||||
_ => unimplemented!(),
|
||||
});
|
||||
self.func_relocs.push(Relocation {
|
||||
reloc,
|
||||
offset,
|
||||
addend,
|
||||
target,
|
||||
});
|
||||
}
|
||||
ExternalName::TestCase { length, ascii } => {
|
||||
let (slice, _) = ascii.split_at(length as usize);
|
||||
let name = String::from_utf8(slice.to_vec()).unwrap();
|
||||
let relocation_type = match name.as_str() {
|
||||
"current_memory" => RelocationType::CurrentMemory,
|
||||
"grow_memory" => RelocationType::GrowMemory,
|
||||
_ => RelocationType::Intrinsic(name),
|
||||
};
|
||||
self.func_relocs.push(Relocation {
|
||||
reloc,
|
||||
offset,
|
||||
addend,
|
||||
target: relocation_type,
|
||||
target: RelocationType::Intrinsic(name),
|
||||
});
|
||||
}
|
||||
ExternalName::LibCall(libcall) => {
|
||||
@ -112,32 +133,50 @@ impl RelocSink {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct TrapData {
|
||||
pub offset: usize,
|
||||
pub code: TrapCode,
|
||||
pub trapcode: TrapCode,
|
||||
pub srcloc: SourceLoc,
|
||||
}
|
||||
|
||||
/// Simple implementation of a TrapSink
|
||||
/// that saves the info for later.
|
||||
pub struct TrapSink {
|
||||
current_func_offset: usize,
|
||||
trap_datas: Vec<TrapData>,
|
||||
trap_datas: HashMap<usize, TrapData>,
|
||||
}
|
||||
|
||||
impl TrapSink {
|
||||
pub fn new(current_func_offset: usize) -> TrapSink {
|
||||
pub fn new() -> TrapSink {
|
||||
TrapSink {
|
||||
current_func_offset,
|
||||
trap_datas: Vec::new(),
|
||||
trap_datas: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl binemit::TrapSink for TrapSink {
|
||||
fn trap(&mut self, offset: u32, _: SourceLoc, code: TrapCode) {
|
||||
self.trap_datas.push(TrapData {
|
||||
offset: self.current_func_offset + offset as usize,
|
||||
code,
|
||||
pub fn lookup(&self, offset: usize) -> Option<TrapData> {
|
||||
self.trap_datas.get(&offset).cloned()
|
||||
}
|
||||
|
||||
pub fn drain_local(&mut self, current_func_offset: usize, local: &mut LocalTrapSink) {
|
||||
local.trap_datas.drain(..).for_each(|(offset, trap_data)| {
|
||||
self.trap_datas
|
||||
.insert(current_func_offset + offset, trap_data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LocalTrapSink {
|
||||
trap_datas: Vec<(usize, TrapData)>,
|
||||
}
|
||||
|
||||
impl LocalTrapSink {
|
||||
pub fn new() -> Self {
|
||||
LocalTrapSink { trap_datas: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
impl binemit::TrapSink for LocalTrapSink {
|
||||
fn trap(&mut self, offset: u32, srcloc: SourceLoc, trapcode: TrapCode) {
|
||||
self.trap_datas
|
||||
.push((offset as usize, TrapData { trapcode, srcloc }));
|
||||
}
|
||||
}
|
219
lib/clif-backend/src/resolver.rs
Normal file
219
lib/clif-backend/src/resolver.rs
Normal file
@ -0,0 +1,219 @@
|
||||
use crate::call::HandlerData;
|
||||
use crate::libcalls;
|
||||
use crate::relocation::{
|
||||
LocalTrapSink, Reloc, RelocSink, Relocation, RelocationType, TrapSink, VmCall,
|
||||
};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use cranelift_codegen::{ir, isa, Context};
|
||||
use std::mem;
|
||||
use std::ptr::{write_unaligned, NonNull};
|
||||
use wasmer_runtime::{
|
||||
self,
|
||||
backend::{
|
||||
self,
|
||||
sys::{Memory, Protect},
|
||||
},
|
||||
error::{CompileError, CompileResult},
|
||||
structures::Map,
|
||||
types::LocalFuncIndex,
|
||||
vm, vmcalls,
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct FuncResolverBuilder {
|
||||
resolver: FuncResolver,
|
||||
relocations: Map<LocalFuncIndex, Vec<Relocation>>,
|
||||
}
|
||||
|
||||
impl FuncResolverBuilder {
|
||||
pub fn new(
|
||||
isa: &isa::TargetIsa,
|
||||
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
||||
) -> CompileResult<(Self, HandlerData)> {
|
||||
let mut compiled_functions: Vec<Vec<u8>> = Vec::with_capacity(function_bodies.len());
|
||||
let mut relocations = Map::with_capacity(function_bodies.len());
|
||||
|
||||
let mut trap_sink = TrapSink::new();
|
||||
let mut local_trap_sink = LocalTrapSink::new();
|
||||
|
||||
let mut ctx = Context::new();
|
||||
let mut total_size = 0;
|
||||
|
||||
for (_, func) in function_bodies {
|
||||
ctx.func = func;
|
||||
let mut code_buf = Vec::new();
|
||||
let mut reloc_sink = RelocSink::new();
|
||||
|
||||
ctx.compile_and_emit(isa, &mut code_buf, &mut reloc_sink, &mut local_trap_sink)
|
||||
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
|
||||
ctx.clear();
|
||||
|
||||
// Clear the local trap sink and consolidate all trap info
|
||||
// into a single location.
|
||||
trap_sink.drain_local(total_size, &mut local_trap_sink);
|
||||
|
||||
// Round up each function's size to pointer alignment.
|
||||
total_size += round_up(code_buf.len(), mem::size_of::<usize>());
|
||||
|
||||
compiled_functions.push(code_buf);
|
||||
relocations.push(reloc_sink.func_relocs);
|
||||
}
|
||||
|
||||
let mut memory = Memory::with_size(total_size)
|
||||
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
|
||||
unsafe {
|
||||
memory
|
||||
.protect(0..memory.size(), Protect::ReadWrite)
|
||||
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
|
||||
}
|
||||
|
||||
// Normally, excess memory due to alignment and page-rounding would
|
||||
// be filled with null-bytes. On x86 (and x86_64),
|
||||
// "\x00\x00" disassembles to "add byte ptr [eax],al".
|
||||
//
|
||||
// If the instruction pointer falls out of its designated area,
|
||||
// it would be better if it would immediately crash instead of
|
||||
// continuing on and causing non-local issues.
|
||||
//
|
||||
// "\xCC" disassembles to "int3", which will immediately cause
|
||||
// an interrupt that we can catch if we want.
|
||||
for i in unsafe { memory.as_slice_mut() } {
|
||||
*i = 0xCC;
|
||||
}
|
||||
|
||||
let mut map = Map::with_capacity(compiled_functions.len());
|
||||
|
||||
let mut previous_end = 0;
|
||||
for compiled in compiled_functions.iter() {
|
||||
let new_end = previous_end + round_up(compiled.len(), mem::size_of::<usize>());
|
||||
unsafe {
|
||||
memory.as_slice_mut()[previous_end..previous_end + compiled.len()]
|
||||
.copy_from_slice(&compiled[..]);
|
||||
}
|
||||
map.push(previous_end);
|
||||
previous_end = new_end;
|
||||
}
|
||||
|
||||
let handler_data = HandlerData::new(trap_sink, memory.as_ptr() as _, memory.size());
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
resolver: FuncResolver { map, memory },
|
||||
relocations,
|
||||
},
|
||||
handler_data,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn finalize(mut self) -> CompileResult<FuncResolver> {
|
||||
for (index, relocs) in self.relocations.iter() {
|
||||
for ref reloc in relocs {
|
||||
let target_func_address: isize = match reloc.target {
|
||||
RelocationType::Normal(local_func_index) => {
|
||||
// This will always be an internal function
|
||||
// because imported functions are not
|
||||
// called in this way.
|
||||
self.resolver.lookup(local_func_index).unwrap().as_ptr() as isize
|
||||
}
|
||||
RelocationType::LibCall(libcall) => match libcall {
|
||||
ir::LibCall::CeilF32 => libcalls::ceilf32 as isize,
|
||||
ir::LibCall::FloorF32 => libcalls::floorf32 as isize,
|
||||
ir::LibCall::TruncF32 => libcalls::truncf32 as isize,
|
||||
ir::LibCall::NearestF32 => libcalls::nearbyintf32 as isize,
|
||||
ir::LibCall::CeilF64 => libcalls::ceilf64 as isize,
|
||||
ir::LibCall::FloorF64 => libcalls::floorf64 as isize,
|
||||
ir::LibCall::TruncF64 => libcalls::truncf64 as isize,
|
||||
ir::LibCall::NearestF64 => libcalls::nearbyintf64 as isize,
|
||||
ir::LibCall::Probestack => libcalls::__rust_probestack as isize,
|
||||
_ => Err(CompileError::InternalError {
|
||||
msg: format!("unexpected libcall: {}", libcall),
|
||||
})?,
|
||||
},
|
||||
RelocationType::Intrinsic(ref name) => Err(CompileError::InternalError {
|
||||
msg: format!("unexpected intrinsic: {}", name),
|
||||
})?,
|
||||
RelocationType::VmCall(vmcall) => match vmcall {
|
||||
VmCall::LocalStaticMemoryGrow => vmcalls::local_static_memory_grow as _,
|
||||
VmCall::LocalStaticMemorySize => vmcalls::local_static_memory_size as _,
|
||||
VmCall::ImportedStaticMemoryGrow => {
|
||||
vmcalls::imported_static_memory_grow as _
|
||||
}
|
||||
VmCall::ImportedStaticMemorySize => {
|
||||
vmcalls::imported_static_memory_size as _
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// We need the address of the current function
|
||||
// because these calls are relative.
|
||||
let func_addr = self.resolver.lookup(index).unwrap().as_ptr();
|
||||
|
||||
// Determine relocation type and apply relocation.
|
||||
match reloc.reloc {
|
||||
Reloc::Abs8 => {
|
||||
let ptr_to_write = (target_func_address as u64)
|
||||
.checked_add(reloc.addend as u64)
|
||||
.unwrap();
|
||||
let empty_space_offset = self.resolver.map[index] + reloc.offset as usize;
|
||||
let ptr_slice = unsafe {
|
||||
&mut self.resolver.memory.as_slice_mut()
|
||||
[empty_space_offset..empty_space_offset + 8]
|
||||
};
|
||||
LittleEndian::write_u64(ptr_slice, ptr_to_write);
|
||||
}
|
||||
Reloc::X86PCRel4 => unsafe {
|
||||
let reloc_address = func_addr.offset(reloc.offset as isize) as isize;
|
||||
let reloc_addend = reloc.addend as isize;
|
||||
// TODO: Handle overflow.
|
||||
let reloc_delta_i32 =
|
||||
(target_func_address - reloc_address + reloc_addend) as i32;
|
||||
write_unaligned(reloc_address as *mut i32, reloc_delta_i32);
|
||||
},
|
||||
_ => Err(CompileError::InternalError {
|
||||
msg: format!("unsupported reloc kind: {}", reloc.reloc),
|
||||
})?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
self.resolver
|
||||
.memory
|
||||
.protect(0..self.resolver.memory.size(), Protect::ReadExec)
|
||||
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;;
|
||||
}
|
||||
|
||||
Ok(self.resolver)
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves a function index to a function address.
|
||||
pub struct FuncResolver {
|
||||
map: Map<LocalFuncIndex, usize>,
|
||||
memory: Memory,
|
||||
}
|
||||
|
||||
impl FuncResolver {
|
||||
fn lookup(&self, local_func_index: LocalFuncIndex) -> Option<NonNull<vm::Func>> {
|
||||
let offset = *self.map.get(local_func_index)?;
|
||||
let ptr = unsafe { self.memory.as_ptr().add(offset) };
|
||||
|
||||
NonNull::new(ptr).map(|nonnull| nonnull.cast())
|
||||
}
|
||||
}
|
||||
|
||||
// Implements FuncResolver trait.
|
||||
impl backend::FuncResolver for FuncResolver {
|
||||
fn get(
|
||||
&self,
|
||||
_module: &wasmer_runtime::module::ModuleInner,
|
||||
index: LocalFuncIndex,
|
||||
) -> Option<NonNull<vm::Func>> {
|
||||
self.lookup(index)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn round_up(n: usize, multiple: usize) -> usize {
|
||||
(n + multiple - 1) & !(multiple - 1)
|
||||
}
|
20
lib/emscripten/Cargo.toml
Normal file
20
lib/emscripten/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "wasmer-emscripten"
|
||||
version = "0.1.1"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
edition = "2018"
|
||||
build = "build/mod.rs"
|
||||
|
||||
[dependencies]
|
||||
hashbrown = "0.1"
|
||||
wasmer-runtime = { path = "../runtime" }
|
||||
libc = { git = "https://github.com/rust-lang/libc" }
|
||||
byteorder = "1"
|
||||
time = "0.1.41"
|
||||
|
||||
[dev-dependencies]
|
||||
wasmer-clif-backend = { path = "../clif-backend" }
|
||||
wabt = "0.7.2"
|
||||
|
||||
[build-dependencies]
|
||||
glob = "0.2.11"
|
@ -85,7 +85,7 @@ pub fn compile(file: &str, ignores: &Vec<String>) -> Option<String> {
|
||||
|
||||
let rs_module_name = module_name.to_lowercase();
|
||||
let rust_test_filepath = format!(
|
||||
concat!(env!("CARGO_MANIFEST_DIR"), "/src/emtests/{}.rs"),
|
||||
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/emtests/{}.rs"),
|
||||
rs_module_name.as_str()
|
||||
);
|
||||
|
||||
@ -138,7 +138,7 @@ fn test_{rs_module_name}() {{
|
||||
}
|
||||
|
||||
pub fn build() {
|
||||
let rust_test_modpath = concat!(env!("CARGO_MANIFEST_DIR"), "/src/emtests/mod.rs");
|
||||
let rust_test_modpath = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/emtests/mod.rs");
|
||||
|
||||
let mut modules: Vec<String> = Vec::new();
|
||||
// modules.reserve_exact(TESTS.len());
|
11
lib/emscripten/build/mod.rs
Normal file
11
lib/emscripten/build/mod.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use std::env;
|
||||
|
||||
mod emtests;
|
||||
|
||||
static EMTESTS_ENV_VAR: &str = "WASM_EMSCRIPTEN_GENERATE_EMTESTS";
|
||||
|
||||
fn main() {
|
||||
if env::var(EMTESTS_ENV_VAR).unwrap_or("0".to_string()) == "1" {
|
||||
emtests::build();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user