Merge remote-tracking branch 'origin/feature/clif-cgapi' into feature/metering

This commit is contained in:
losfair 2019-05-31 15:40:05 +08:00
commit 8019505e65
28 changed files with 1122 additions and 949 deletions

View File

@ -284,10 +284,11 @@ jobs:
# VERSION=$(cargo pkgid | cut -d# -f2 | cut -d: -f2)
# echo "${VERSION}" >> artifacts/version
- run:
name: Dynamic library
name: Generate dynamic library for the runtime C API
command: |
export PATH="$HOME/.cargo/bin:$PATH"
cargo build --release --manifest-path lib/runtime-c-api/Cargo.toml
install_name_tool -id "@rpath/libwasmer_runtime_c_api.dylib" target/release/libwasmer_runtime_c_api.dylib
cp target/release/libwasmer_runtime_c_api.dylib ./artifacts
- persist_to_workspace:
root: .
@ -362,7 +363,7 @@ jobs:
# VERSION_TAG=$(git describe --exact-match --tags)
#if [ "$VERSION" == "$VERSION_TAG" ]; then
# echo "Versions match, publishing to Github"
ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} ${VERSION} ./artifacts/
ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} ${VERSION} ./artifacts/ || true
#else
# echo "Versions don't match. Wasmer output version (wasmer --version) is ${VERSION} while Git tag is ${VERSION_TAG}"
# exit 1

View File

@ -2,7 +2,7 @@
Wasmer uses the following components:
- [Cranelift](https://github.com/cranestation/cranelift): for compiling Wasm binaries to machine code
- Compiler backends: for compiling Wasm binaries to machine code ([more info here](https://github.com/wasmerio/wasmer/tree/master/lib#backends))
- [wabt](https://github.com/pepyakin/wabt-rs): for transforming `.wast` files to `.wasm` and running WebAssembly spec tests
- [wasmparser](https://github.com/yurydelendik/wasmparser.rs): for parsing the `.wasm` files and translating them into WebAssembly modules
@ -67,3 +67,8 @@ Once that's finished, we will have a `Instance` function that will be ready to e
Wasmer's Emscripten integration tries to wrap (and emulate) all the different syscalls that Emscripten needs.
We provide this integration by filling the `import_object` with the Emscripten functions, while instantiating the WebAssembly Instance.
## WASI
Wasmer's WASI integration implements all the different syscalls that WASI needs.
We provide this integration by filling the `import_object` with the WASI functions, while instantiating the WebAssembly Instance.

View File

@ -6,6 +6,7 @@ Blocks of changes will separated by version increments.
## **[Unreleased]**
- [#470](https://github.com/wasmerio/wasmer/pull/470) Add mapdir support to Emscripten, implement getdents for Unix
- [#467](https://github.com/wasmerio/wasmer/pull/467) `wasmer_instantiate` returns better error messages in the runtime C API
- [#463](https://github.com/wasmerio/wasmer/pull/463) Fix bug in WASI path_open allowing one level above preopened dir to be accessed
- [#461](https://github.com/wasmerio/wasmer/pull/461) Prevent passing negative lengths in various places in the runtime C API

102
Cargo.lock generated
View File

@ -53,7 +53,7 @@ dependencies = [
"backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -211,67 +211,67 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cranelift-bforest"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#84ec31b0fdfc10db491ef950815ee2961db057cb"
dependencies = [
"cranelift-entity 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
]
[[package]]
name = "cranelift-codegen"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#84ec31b0fdfc10db491ef950815ee2961db057cb"
dependencies = [
"cranelift-bforest 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-codegen-meta 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-entity 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-bforest 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
"cranelift-codegen-meta 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
"cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cranelift-codegen-meta"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#84ec31b0fdfc10db491ef950815ee2961db057cb"
dependencies = [
"cranelift-entity 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
]
[[package]]
name = "cranelift-entity"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#84ec31b0fdfc10db491ef950815ee2961db057cb"
[[package]]
name = "cranelift-frontend"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#84ec31b0fdfc10db491ef950815ee2961db057cb"
dependencies = [
"cranelift-codegen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cranelift-native"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#84ec31b0fdfc10db491ef950815ee2961db057cb"
dependencies = [
"cranelift-codegen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
"raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cranelift-wasm"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#84ec31b0fdfc10db491ef950815ee2961db057cb"
dependencies = [
"cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-codegen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-entity 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-frontend 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
"cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
"cranelift-frontend 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1002,7 +1002,7 @@ dependencies = [
[[package]]
name = "rustc-demangle"
version = "0.1.14"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -1125,16 +1125,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "structopt"
version = "0.2.15"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "structopt-derive"
version = "0.2.15"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1189,7 +1189,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "target-lexicon"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1362,7 +1362,7 @@ dependencies = [
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-backend 0.4.2",
"wasmer-dev-utils 0.4.2",
@ -1381,10 +1381,11 @@ name = "wasmer-clif-backend"
version = "0.4.2"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-codegen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-entity 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-native 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-wasm 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
"cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
"cranelift-frontend 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
"cranelift-native 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
"cranelift-wasm 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)",
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1393,10 +1394,10 @@ dependencies = [
"serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.4.2",
"wasmer-win-exception-handler 0.4.2",
"wasmparser 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1413,6 +1414,7 @@ version = "0.4.2"
dependencies = [
"byteorder 1.3.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.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1451,7 +1453,7 @@ dependencies = [
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.4.2",
"wasmparser 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1508,7 +1510,7 @@ dependencies = [
"serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmparser 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1525,7 +1527,7 @@ dependencies = [
"nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.4.2",
"wasmparser 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1574,11 +1576,6 @@ name = "wasmparser"
version = "0.29.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wasmparser"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "which"
version = "2.0.1"
@ -1659,13 +1656,13 @@ dependencies = [
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "2ca4386c8954b76a8415b63959337d940d724b336cabd3afe189c2b51a7e1ff0"
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
"checksum cranelift-bforest 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5a357d20666bf4a8c2d626a19f1b59dbca66cd844fb1e66c5612254fd0f7505"
"checksum cranelift-codegen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab00cb149a5bb0f7e6dd391357356a5d71c335a431e8eece94f32da2d5a043f7"
"checksum cranelift-codegen-meta 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3797a2f450ac71297e083dd440d0cdd0d3bceabe4a3ca6bcb9e4077e9c0327d"
"checksum cranelift-entity 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b66e28877b75b3d2b31250f780bb5db8f68ae3df681cd56add803b2567ac4fd"
"checksum cranelift-frontend 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b72d55fd732b1f7a99d043a36c54a5679b6ec8bc777c8d954fb97c4fa0fce7eb"
"checksum cranelift-native 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0239f34836621a127c2132980b2f5c32a1be1c40e2d1a9a1a9bd5af33c12aee"
"checksum cranelift-wasm 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740ebfba28c8433f06750f84819f1eb663ea9f5e4b9a81c01f4e52262d868b56"
"checksum cranelift-bforest 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "<none>"
"checksum cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "<none>"
"checksum cranelift-codegen-meta 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "<none>"
"checksum cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "<none>"
"checksum cranelift-frontend 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "<none>"
"checksum cranelift-native 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "<none>"
"checksum cranelift-wasm 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "<none>"
"checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394"
"checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e"
"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
@ -1748,7 +1745,7 @@ dependencies = [
"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58"
"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288"
"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f"
"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
@ -1765,14 +1762,14 @@ dependencies = [
"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3d0760c312538987d363c36c42339b55f5ee176ea8808bbe4543d484a291c8d1"
"checksum structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "528aeb7351d042e6ffbc2a6fb76a86f9b622fdf7c25932798e7a82cb03bc94c6"
"checksum structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fa19a5a708e22bb5be31c1b6108a2a902f909c4b9ba85cba44c06632386bc0ff"
"checksum structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d59d0ae8ef8de16e49e3ca7afa16024a3e0dfd974a75ef93fdc5464e34523f"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
"checksum target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6923974ce4eb5bd28814756256d8ab71c28dd6e7483313fe7ab6614306bf633"
"checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb"
"checksum tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef"
"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea"
@ -1795,7 +1792,6 @@ dependencies = [
"checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c"
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
"checksum wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "981a8797cf89762e0233ec45fae731cb79a4dfaee12d9f0fe6cee01e4ac58d00"
"checksum wasmparser 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "566a9eefa2267a1a32af59807326e84191cdff41c3fc2efda0a790d821615b31"
"checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"

View File

@ -33,6 +33,7 @@ Wasmer runtime can also be embedded in different languages, so you can use WebAs
* [**🐘 PHP**](https://github.com/wasmerio/php-ext-wasm)
* [**🐍 Python**](https://github.com/wasmerio/python-ext-wasm)
* [**💎 Ruby**](https://github.com/wasmerio/ruby-ext-wasm)
* [**🐹 Go**](https://github.com/wasmerio/go-ext-wasm)
### Usage

View File

@ -9,13 +9,14 @@ edition = "2018"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
cranelift-native = "0.30.0"
cranelift-codegen = "0.30.0"
cranelift-entity = "0.30.0"
cranelift-wasm = "0.30.0"
cranelift-native = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
cranelift-codegen = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
cranelift-entity = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
cranelift-frontend = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
cranelift-wasm = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
hashbrown = "0.1"
target-lexicon = "0.3.0"
wasmparser = "0.30.0"
target-lexicon = "0.4.0"
wasmparser = "0.29.2"
byteorder = "1"
nix = "0.13.0"
libc = "0.2.49"

View File

@ -1,51 +1,405 @@
use crate::{module::Converter, module_env::ModuleEnv, relocation::call_names};
use cranelift_codegen::{
cursor::FuncCursor,
ir::{self, InstBuilder},
isa,
// Parts of the following code are Copyright 2018 Cranelift Developers
// and subject to the license https://github.com/CraneStation/cranelift/blob/c47ca7bafc8fc48358f1baa72360e61fc1f7a0f2/cranelift-wasm/LICENSE
use crate::{
cache::CacheGenerator, get_isa, module, module::Converter, relocation::call_names,
resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines,
};
use cranelift_entity::EntityRef;
use cranelift_wasm::{self, FuncEnvironment, ModuleEnvironment};
use cranelift_codegen::entity::EntityRef;
use cranelift_codegen::ir::{self, Ebb, Function, InstBuilder};
use cranelift_codegen::isa::CallConv;
use cranelift_codegen::{cursor::FuncCursor, isa};
use cranelift_frontend::{FunctionBuilder, Position, Variable};
use cranelift_wasm::{self, FuncTranslator};
use cranelift_wasm::{get_vmctx_value_label, translate_operator};
use cranelift_wasm::{FuncEnvironment, ReturnMode, WasmError};
use std::mem;
use std::sync::{Arc, RwLock};
use wasmer_runtime_core::error::CompileError;
use wasmer_runtime_core::{
backend::{Backend, CacheGen, Token},
cache::{Artifact, Error as CacheError},
codegen::*,
memory::MemoryType,
structures::TypedIndex,
types::{FuncIndex, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex},
module::{ModuleInfo, ModuleInner},
structures::{Map, TypedIndex},
types::{
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex,
TableIndex,
},
vm,
};
use wasmparser::Type as WpType;
pub struct FuncEnv<'env, 'module, 'isa> {
env: &'env ModuleEnv<'module, 'isa>,
pub struct CraneliftModuleCodeGenerator {
isa: Box<isa::TargetIsa>,
signatures: Option<Arc<Map<SigIndex, FuncSig>>>,
pub clif_signatures: Map<SigIndex, ir::Signature>,
function_signatures: Option<Arc<Map<FuncIndex, SigIndex>>>,
functions: Vec<CraneliftFunctionCodeGenerator>,
}
impl<'env, 'module, 'isa> FuncEnv<'env, 'module, 'isa> {
pub fn new(env: &'env ModuleEnv<'module, 'isa>) -> Self {
Self { env }
impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
for CraneliftModuleCodeGenerator
{
fn new() -> Self {
let isa = get_isa();
CraneliftModuleCodeGenerator {
isa,
clif_signatures: Map::new(),
functions: vec![],
function_signatures: None,
signatures: None,
}
}
/// Creates a signature with VMContext as the last param
pub fn generate_signature(
&self,
clif_sig_index: cranelift_wasm::SignatureIndex,
) -> ir::Signature {
// Get signature
let mut signature = self.env.signatures[Converter(clif_sig_index).into()].clone();
fn backend_id() -> Backend {
Backend::Cranelift
}
// Add the vmctx parameter type to it
signature.params.insert(
0,
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
fn check_precondition(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> {
Ok(())
}
fn next_function(
&mut self,
module_info: Arc<RwLock<ModuleInfo>>,
) -> Result<&mut CraneliftFunctionCodeGenerator, CodegenError> {
// define_function_body(
let func_translator = FuncTranslator::new();
let func_index = LocalFuncIndex::new(self.functions.len());
let name = ir::ExternalName::user(0, func_index.index() as u32);
let sig = generate_signature(
self,
self.get_func_type(
&module_info.read().unwrap(),
Converter(func_index.convert_up(&module_info.read().unwrap())).into(),
),
);
// Return signature
signature
let func = ir::Function::with_name_signature(name, sig);
//func_translator.translate(body_bytes, body_offset, &mut func, &mut func_env)?;
let mut func_env = CraneliftFunctionCodeGenerator {
func,
func_translator,
next_local: 0,
clif_signatures: self.clif_signatures.clone(),
module_info: Arc::clone(&module_info),
target_config: self.isa.frontend_config().clone(),
position: Position::default(),
};
debug_assert_eq!(func_env.func.dfg.num_ebbs(), 0, "Function must be empty");
debug_assert_eq!(func_env.func.dfg.num_insts(), 0, "Function must be empty");
let mut builder = FunctionBuilder::new(
&mut func_env.func,
&mut func_env.func_translator.func_ctx,
&mut func_env.position,
);
// TODO srcloc
//builder.set_srcloc(cur_srcloc(&reader));
let entry_block = builder.create_ebb();
builder.append_ebb_params_for_function_params(entry_block);
builder.switch_to_block(entry_block); // This also creates values for the arguments.
builder.seal_block(entry_block);
// Make sure the entry block is inserted in the layout before we make any callbacks to
// `environ`. The callback functions may need to insert things in the entry block.
builder.ensure_inserted_ebb();
declare_wasm_parameters(&mut builder, entry_block);
// Set up the translation state with a single pushed control block representing the whole
// function and its return values.
let exit_block = builder.create_ebb();
builder.append_ebb_params_for_function_returns(exit_block);
func_env
.func_translator
.state
.initialize(&builder.func.signature, exit_block);
#[cfg(feature = "debug")]
{
use cranelift_codegen::cursor::{Cursor, FuncCursor};
use cranelift_codegen::ir::InstBuilder;
let entry_ebb = func.layout.entry_block().unwrap();
let ebb = func.dfg.make_ebb();
func.layout.insert_ebb(ebb, entry_ebb);
let mut pos = FuncCursor::new(&mut func).at_first_insertion_point(ebb);
let params = pos.func.dfg.ebb_params(entry_ebb).to_vec();
let new_ebb_params: Vec<_> = params
.iter()
.map(|&param| {
pos.func
.dfg
.append_ebb_param(ebb, pos.func.dfg.value_type(param))
})
.collect();
let start_debug = {
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I32),
],
returns: vec![],
});
let name = ir::ExternalName::testcase("strtdbug");
pos.func.import_function(ir::ExtFuncData {
name,
signature,
colocated: false,
})
};
let end_debug = {
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![ir::AbiParam::special(
ir::types::I64,
ir::ArgumentPurpose::VMContext,
)],
returns: vec![],
});
let name = ir::ExternalName::testcase("enddbug");
pos.func.import_function(ir::ExtFuncData {
name,
signature,
colocated: false,
})
};
let i32_print = {
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I32),
],
returns: vec![],
});
let name = ir::ExternalName::testcase("i32print");
pos.func.import_function(ir::ExtFuncData {
name,
signature,
colocated: false,
})
};
let i64_print = {
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I64),
],
returns: vec![],
});
let name = ir::ExternalName::testcase("i64print");
pos.func.import_function(ir::ExtFuncData {
name,
signature,
colocated: false,
})
};
let f32_print = {
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::F32),
],
returns: vec![],
});
let name = ir::ExternalName::testcase("f32print");
pos.func.import_function(ir::ExtFuncData {
name,
signature,
colocated: false,
})
};
let f64_print = {
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::F64),
],
returns: vec![],
});
let name = ir::ExternalName::testcase("f64print");
pos.func.import_function(ir::ExtFuncData {
name,
signature,
colocated: false,
})
};
let vmctx = pos
.func
.special_param(ir::ArgumentPurpose::VMContext)
.expect("missing vmctx parameter");
let func_index = pos.ins().iconst(
ir::types::I32,
func_index.index() as i64 + self.module.info.imported_functions.len() as i64,
);
pos.ins().call(start_debug, &[vmctx, func_index]);
for param in new_ebb_params.iter().cloned() {
match pos.func.dfg.value_type(param) {
ir::types::I32 => pos.ins().call(i32_print, &[vmctx, param]),
ir::types::I64 => pos.ins().call(i64_print, &[vmctx, param]),
ir::types::F32 => pos.ins().call(f32_print, &[vmctx, param]),
ir::types::F64 => pos.ins().call(f64_print, &[vmctx, param]),
_ => unimplemented!(),
};
}
pos.ins().call(end_debug, &[vmctx]);
pos.ins().jump(entry_ebb, new_ebb_params.as_slice());
}
self.functions.push(func_env);
Ok(self.functions.last_mut().unwrap())
}
fn finalize(
self,
module_info: &ModuleInfo,
) -> Result<(Caller, Box<dyn CacheGen>), CodegenError> {
let mut func_bodies: Map<LocalFuncIndex, ir::Function> = Map::new();
for f in self.functions.into_iter() {
func_bodies.push(f.func);
}
let (func_resolver_builder, handler_data) =
FuncResolverBuilder::new(&*self.isa, func_bodies, module_info)?;
let trampolines = Arc::new(Trampolines::new(&*self.isa, module_info));
let (func_resolver, backend_cache) = func_resolver_builder.finalize(
&self.signatures.as_ref().unwrap(),
Arc::clone(&trampolines),
handler_data.clone(),
)?;
let cache_gen = Box::new(CacheGenerator::new(
backend_cache,
Arc::clone(&func_resolver.memory),
));
Ok((
Caller::new(handler_data, trampolines, func_resolver),
cache_gen,
))
}
fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), CodegenError> {
self.signatures = Some(Arc::new(signatures));
let call_conv = self.isa.frontend_config().default_call_conv;
for (_sig_idx, func_sig) in self.signatures.as_ref().unwrap().iter() {
self.clif_signatures
.push(convert_func_sig(func_sig, call_conv));
}
Ok(())
}
fn feed_function_signatures(
&mut self,
assoc: Map<FuncIndex, SigIndex>,
) -> Result<(), CodegenError> {
self.function_signatures = Some(Arc::new(assoc));
Ok(())
}
fn feed_import_function(&mut self) -> Result<(), CodegenError> {
Ok(())
}
unsafe fn from_cache(cache: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
module::Module::from_cache(cache)
}
}
impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
fn convert_func_sig(sig: &FuncSig, call_conv: CallConv) -> ir::Signature {
ir::Signature {
params: sig
.params()
.iter()
.map(|params| Converter(*params).into())
.collect::<Vec<_>>(),
returns: sig
.returns()
.iter()
.map(|returns| Converter(*returns).into())
.collect::<Vec<_>>(),
call_conv,
}
}
impl From<CompileError> for CodegenError {
fn from(other: CompileError) -> CodegenError {
CodegenError {
message: format!("{:?}", other),
}
}
}
impl From<WasmError> for CodegenError {
fn from(other: WasmError) -> CodegenError {
CodegenError {
message: format!("{:?}", other),
}
}
}
pub struct CraneliftFunctionCodeGenerator {
func: Function,
func_translator: FuncTranslator,
next_local: usize,
pub clif_signatures: Map<SigIndex, ir::Signature>,
module_info: Arc<RwLock<ModuleInfo>>,
target_config: isa::TargetFrontendConfig,
position: Position,
}
pub struct FunctionEnvironment {
module_info: Arc<RwLock<ModuleInfo>>,
target_config: isa::TargetFrontendConfig,
clif_signatures: Map<SigIndex, ir::Signature>,
}
impl FuncEnvironment for FunctionEnvironment {
/// Gets configuration information needed for compiling functions
fn target_config(&self) -> isa::TargetFrontendConfig {
self.env.target_config()
self.target_config
}
/// Gets native pointers types.
@ -68,14 +422,16 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
&mut self,
func: &mut ir::Function,
clif_global_index: cranelift_wasm::GlobalIndex,
) -> cranelift_wasm::GlobalVariable {
) -> cranelift_wasm::WasmResult<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();
let local_global_addr = match global_index.local_or_import(&self.env.module.info) {
let (local_global_addr, ty) = match global_index
.local_or_import(&self.module_info.read().unwrap())
{
LocalOrImport::Local(local_global_index) => {
let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load {
base: vmctx,
@ -92,12 +448,19 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
global_type: ptr_type,
});
func.create_global_value(ir::GlobalValueData::Load {
base: local_global_ptr_ptr,
offset: 0.into(),
global_type: ptr_type,
readonly: true,
})
let ty = self.module_info.read().unwrap().globals[local_global_index]
.desc
.ty;
(
func.create_global_value(ir::GlobalValueData::Load {
base: local_global_ptr_ptr,
offset: 0.into(),
global_type: ptr_type,
readonly: true,
}),
ty,
)
}
LocalOrImport::Import(import_global_index) => {
let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load {
@ -115,20 +478,27 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
global_type: ptr_type,
});
func.create_global_value(ir::GlobalValueData::Load {
base: local_global_ptr_ptr,
offset: 0.into(),
global_type: ptr_type,
readonly: true,
})
let ty = self.module_info.read().unwrap().imported_globals[import_global_index]
.1
.ty;
(
func.create_global_value(ir::GlobalValueData::Load {
base: local_global_ptr_ptr,
offset: 0.into(),
global_type: ptr_type,
readonly: true,
}),
ty,
)
}
};
cranelift_wasm::GlobalVariable::Memory {
Ok(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,
}
ty: Converter(ty).into(),
})
}
/// Sets up the necessary preamble definitions in `func` to access the linear memory identified
@ -139,14 +509,14 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
&mut self,
func: &mut ir::Function,
clif_mem_index: cranelift_wasm::MemoryIndex,
) -> ir::Heap {
) -> cranelift_wasm::WasmResult<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();
let (local_memory_ptr_ptr, description) =
match mem_index.local_or_import(&self.env.module.info) {
match mem_index.local_or_import(&self.module_info.read().unwrap()) {
LocalOrImport::Local(local_mem_index) => {
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
base: vmctx,
@ -164,7 +534,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
offset: (local_memory_ptr_offset as i64).into(),
global_type: ptr_type,
}),
self.env.module.info.memories[local_mem_index],
self.module_info.read().unwrap().memories[local_mem_index],
)
}
LocalOrImport::Import(import_mem_index) => {
@ -184,7 +554,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
offset: (local_memory_ptr_offset as i64).into(),
global_type: ptr_type,
}),
self.env.module.info.imported_memories[import_mem_index].1,
self.module_info.read().unwrap().imported_memories[import_mem_index].1,
)
}
};
@ -217,7 +587,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
readonly: false,
});
func.create_heap(ir::HeapData {
Ok(func.create_heap(ir::HeapData {
base: local_memory_base,
min_size: (description.minimum.bytes().0 as u64).into(),
offset_guard_size: mem_type.guard_size().into(),
@ -225,9 +595,9 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
bound_gv: local_memory_bound,
},
index_type: ir::types::I32,
})
}))
}
mem_type @ MemoryType::Static | mem_type @ MemoryType::SharedStatic => func
mem_type @ MemoryType::Static | mem_type @ MemoryType::SharedStatic => Ok(func
.create_heap(ir::HeapData {
base: local_memory_base,
min_size: (description.minimum.bytes().0 as u64).into(),
@ -236,7 +606,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
bound: mem_type.bounds().unwrap().into(),
},
index_type: ir::types::I32,
}),
})),
}
}
@ -248,14 +618,14 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
&mut self,
func: &mut ir::Function,
clif_table_index: cranelift_wasm::TableIndex,
) -> ir::Table {
) -> cranelift_wasm::WasmResult<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();
let (table_struct_ptr_ptr, description) = match table_index
.local_or_import(&self.env.module.info)
.local_or_import(&self.module_info.read().unwrap())
{
LocalOrImport::Local(local_table_index) => {
let tables_base = func.create_global_value(ir::GlobalValueData::Load {
@ -276,7 +646,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
(
table_struct_ptr_ptr,
self.env.module.info.tables[local_table_index],
self.module_info.read().unwrap().tables[local_table_index],
)
}
LocalOrImport::Import(import_table_index) => {
@ -298,7 +668,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
(
table_struct_ptr_ptr,
self.env.module.info.imported_tables[import_table_index].1,
self.module_info.read().unwrap().imported_tables[import_table_index].1,
)
}
};
@ -326,13 +696,13 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
readonly: false,
});
func.create_table(ir::TableData {
Ok(func.create_table(ir::TableData {
base_gv: table_base,
min_size: (description.minimum as u64).into(),
bound_gv: table_count,
element_size: (vm::Anyfunc::size() as u64).into(),
index_type: ir::types::I32,
})
}))
}
/// Sets up a signature definition in `func`'s preamble.
@ -343,9 +713,9 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
&mut self,
func: &mut ir::Function,
clif_sig_index: cranelift_wasm::SignatureIndex,
) -> ir::SigRef {
) -> cranelift_wasm::WasmResult<ir::SigRef> {
// Create a signature reference out of specified signature (with VMContext param added).
func.import_signature(self.generate_signature(clif_sig_index))
Ok(func.import_signature(self.generate_signature(clif_sig_index)))
}
/// Sets up an external function definition in the preamble of `func` that can be used to
@ -356,9 +726,9 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
&mut self,
func: &mut ir::Function,
func_index: cranelift_wasm::FuncIndex,
) -> ir::FuncRef {
) -> cranelift_wasm::WasmResult<ir::FuncRef> {
// Get signature of function.
let signature_index = self.env.get_func_type(func_index);
let signature_index = self.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));
@ -367,12 +737,12 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let name = ir::ExternalName::user(0, func_index.as_u32());
// Create function reference from fuction data.
func.import_function(ir::ExtFuncData {
Ok(func.import_function(ir::ExtFuncData {
name,
signature,
// Make this colocated so all calls between local functions are relative.
colocated: true,
})
}))
}
/// Generates an indirect call IR with `callee` and `call_args`.
@ -485,7 +855,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let callee_index: FuncIndex = Converter(clif_callee_index).into();
let ptr_type = self.pointer_type();
match callee_index.local_or_import(&self.env.module.info) {
match callee_index.local_or_import(&self.module_info.read().unwrap()) {
LocalOrImport::Local(local_function_index) => {
// this is an internal function
let vmctx = pos
@ -596,16 +966,16 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
let (namespace, mem_index, description) =
match mem_index.local_or_import(&self.env.module.info) {
match mem_index.local_or_import(&self.module_info.read().unwrap()) {
LocalOrImport::Local(local_mem_index) => (
call_names::LOCAL_NAMESPACE,
local_mem_index.index(),
self.env.module.info.memories[local_mem_index],
self.module_info.read().unwrap().memories[local_mem_index],
),
LocalOrImport::Import(import_mem_index) => (
call_names::IMPORT_NAMESPACE,
import_mem_index.index(),
self.env.module.info.imported_memories[import_mem_index].1,
self.module_info.read().unwrap().imported_memories[import_mem_index].1,
),
};
@ -660,16 +1030,16 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
let (namespace, mem_index, description) =
match mem_index.local_or_import(&self.env.module.info) {
match mem_index.local_or_import(&self.module_info.read().unwrap()) {
LocalOrImport::Local(local_mem_index) => (
call_names::LOCAL_NAMESPACE,
local_mem_index.index(),
self.env.module.info.memories[local_mem_index],
self.module_info.read().unwrap().memories[local_mem_index],
),
LocalOrImport::Import(import_mem_index) => (
call_names::IMPORT_NAMESPACE,
import_mem_index.index(),
self.env.module.info.imported_memories[import_mem_index].1,
self.module_info.read().unwrap().imported_memories[import_mem_index].1,
),
};
@ -698,3 +1068,200 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
}
}
impl FunctionEnvironment {
pub fn get_func_type(
&self,
func_index: cranelift_wasm::FuncIndex,
) -> cranelift_wasm::SignatureIndex {
let sig_index: SigIndex =
self.module_info.read().unwrap().func_assoc[Converter(func_index).into()];
Converter(sig_index).into()
}
/// Creates a signature with VMContext as the last param
pub fn generate_signature(
&self,
clif_sig_index: cranelift_wasm::SignatureIndex,
) -> ir::Signature {
// Get signature
let mut signature = self.clif_signatures[Converter(clif_sig_index).into()].clone();
// Add the vmctx parameter type to it
signature.params.insert(
0,
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
);
// Return signature
signature
}
}
impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
fn feed_return(&mut self, _ty: WpType) -> Result<(), CodegenError> {
Ok(())
}
fn feed_param(&mut self, _ty: WpType) -> Result<(), CodegenError> {
self.next_local += 1;
Ok(())
}
fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError> {
let mut next_local = self.next_local;
cranelift_wasm::declare_locals(&mut self.builder(), n as u32, ty, &mut next_local)?;
self.next_local = next_local;
Ok(())
}
fn begin_body(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> {
Ok(())
}
fn feed_event(&mut self, event: Event, _module_info: &ModuleInfo) -> Result<(), CodegenError> {
let op = match event {
Event::Wasm(x) => x,
Event::WasmOwned(ref x) => x,
Event::Internal(_x) => {
return Ok(());
}
};
//let builder = self.builder.as_mut().unwrap();
//let func_environment = FuncEnv::new();
//let state = TranslationState::new();
let mut function_environment = FunctionEnvironment {
module_info: Arc::clone(&self.module_info),
target_config: self.target_config.clone(),
clif_signatures: self.clif_signatures.clone(),
};
if self.func_translator.state.control_stack.is_empty() {
return Ok(());
}
let mut builder = FunctionBuilder::new(
&mut self.func,
&mut self.func_translator.func_ctx,
&mut self.position,
);
let state = &mut self.func_translator.state;
translate_operator(op, &mut builder, state, &mut function_environment)?;
Ok(())
}
fn finalize(&mut self) -> Result<(), CodegenError> {
let return_mode = self.return_mode();
let mut builder = FunctionBuilder::new(
&mut self.func,
&mut self.func_translator.func_ctx,
&mut self.position,
);
let state = &mut self.func_translator.state;
// The final `End` operator left us in the exit block where we need to manually add a return
// instruction.
//
// If the exit block is unreachable, it may not have the correct arguments, so we would
// generate a return instruction that doesn't match the signature.
if state.reachable {
debug_assert!(builder.is_pristine());
if !builder.is_unreachable() {
match return_mode {
ReturnMode::NormalReturns => builder.ins().return_(&state.stack),
ReturnMode::FallthroughReturn => builder.ins().fallthrough_return(&state.stack),
};
}
}
// Discard any remaining values on the stack. Either we just returned them,
// or the end of the function is unreachable.
state.stack.clear();
self.builder().finalize();
Ok(())
}
}
#[derive(Debug)]
pub struct CodegenError {
pub message: String,
}
impl CraneliftModuleCodeGenerator {
/// Return the signature index for the given function index.
pub fn get_func_type(
&self,
module_info: &ModuleInfo,
func_index: cranelift_wasm::FuncIndex,
) -> cranelift_wasm::SignatureIndex {
let sig_index: SigIndex = module_info.func_assoc[Converter(func_index).into()];
Converter(sig_index).into()
}
}
impl CraneliftFunctionCodeGenerator {
pub fn builder(&mut self) -> FunctionBuilder {
FunctionBuilder::new(
&mut self.func,
&mut self.func_translator.func_ctx,
&mut self.position,
)
}
pub fn return_mode(&self) -> ReturnMode {
ReturnMode::NormalReturns
}
}
/// Creates a signature with VMContext as the last param
fn generate_signature(
env: &CraneliftModuleCodeGenerator,
clif_sig_index: cranelift_wasm::SignatureIndex,
) -> ir::Signature {
// Get signature
let mut signature = env.clif_signatures[Converter(clif_sig_index).into()].clone();
// Add the vmctx parameter type to it
signature.params.insert(
0,
ir::AbiParam::special(pointer_type(env), ir::ArgumentPurpose::VMContext),
);
// Return signature
signature
}
fn pointer_type(mcg: &CraneliftModuleCodeGenerator) -> ir::Type {
ir::Type::int(u16::from(mcg.isa.frontend_config().pointer_bits())).unwrap()
}
/// Declare local variables for the signature parameters that correspond to WebAssembly locals.
///
/// Return the number of local variables declared.
fn declare_wasm_parameters(builder: &mut FunctionBuilder, entry_block: Ebb) -> usize {
let sig_len = builder.func.signature.params.len();
let mut next_local = 0;
for i in 0..sig_len {
let param_type = builder.func.signature.params[i];
// There may be additional special-purpose parameters following the normal WebAssembly
// signature parameters. For example, a `vmctx` pointer.
if param_type.purpose == ir::ArgumentPurpose::Normal {
// This is a normal WebAssembly signature parameter, so create a local for it.
let local = Variable::new(next_local);
builder.declare_var(local, param_type.value_type);
next_local += 1;
let param_value = builder.ebb_params(entry_block)[i];
builder.def_var(local, param_value);
}
if param_type.purpose == ir::ArgumentPurpose::VMContext {
let param_value = builder.ebb_params(entry_block)[i];
builder.set_val_label(param_value, get_vmctx_value_label());
}
}
next_local
}

View File

@ -1,10 +1,9 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
mod cache;
mod func_env;
mod code;
mod libcalls;
mod module;
mod module_env;
mod relocation;
mod resolver;
mod signal;
@ -16,87 +15,12 @@ use cranelift_codegen::{
};
use target_lexicon::Triple;
use wasmer_runtime_core::cache::{Artifact, Error as CacheError};
use wasmer_runtime_core::{
backend::{Compiler, CompilerConfig, Token},
error::{CompileError, CompileResult},
module::ModuleInner,
};
#[macro_use]
extern crate serde_derive;
extern crate rayon;
extern crate serde;
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],
compiler_config: CompilerConfig,
_: Token,
) -> CompileResult<ModuleInner> {
validate(wasm)?;
let isa = get_isa();
let mut module = module::Module::new(&compiler_config);
let module_env = module_env::ModuleEnv::new(&mut module, &*isa);
let func_bodies = module_env.translate(wasm)?;
module.compile(&*isa, func_bodies)
}
/// Create a wasmer Module from an already-compiled cache.
unsafe fn from_cache(&self, cache: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
module::Module::from_cache(cache)
}
//
// fn compile_to_backend_cache_data(
// &self,
// wasm: &[u8],
// _: Token,
// ) -> CompileResult<(Box<ModuleInfo>, Vec<u8>, Memory)> {
// validate(wasm)?;
// let isa = get_isa();
// let mut module = module::Module::new(wasm);
// let module_env = module_env::ModuleEnv::new(&mut module, &*isa);
// let func_bodies = module_env.translate(wasm)?;
// let (info, backend_cache, compiled_code) = module
// .compile_to_backend_cache(&*isa, func_bodies)
// .map_err(|e| CompileError::InternalError {
// msg: format!("{:?}", e),
// })?;
// let buffer =
// backend_cache
// .into_backend_data()
// .map_err(|e| CompileError::InternalError {
// msg: format!("{:?}", e),
// })?;
// Ok((Box::new(info), buffer, compiled_code))
// }
}
fn get_isa() -> Box<isa::TargetIsa> {
let flags = {
let mut builder = settings::builder();
@ -113,19 +37,14 @@ fn get_isa() -> Box<isa::TargetIsa> {
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(),
})?,
_ => {}
}
}
}
/// The current version of this crate
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
use wasmer_runtime_core::codegen::SimpleStreamingCompilerGen;
pub type CraneliftCompiler = SimpleStreamingCompilerGen<
code::CraneliftModuleCodeGenerator,
code::CraneliftFunctionCodeGenerator,
signal::Caller,
code::CodegenError,
>;

View File

@ -1,22 +1,17 @@
use crate::cache::{BackendCache, CacheGenerator};
use crate::{resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines};
use crate::{resolver::FuncResolverBuilder, signal::Caller};
use cranelift_codegen::{ir, isa};
use cranelift_codegen::ir;
use cranelift_entity::EntityRef;
use cranelift_wasm;
use hashbrown::HashMap;
use std::sync::Arc;
use wasmer_runtime_core::cache::{Artifact, Error as CacheError};
use wasmer_runtime_core::{
backend::{Backend, CompilerConfig},
error::CompileResult,
module::{ModuleInfo, ModuleInner, StringTable},
structures::{Map, TypedIndex},
types::{
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, MemoryIndex, SigIndex, TableIndex, Type,
},
module::{ModuleInfo, ModuleInner},
structures::TypedIndex,
types::{FuncIndex, FuncSig, GlobalIndex, MemoryIndex, SigIndex, TableIndex, Type},
};
/// This contains all of the items in a `ModuleInner` except the `func_resolver`.
@ -25,69 +20,6 @@ pub struct Module {
}
impl Module {
pub fn new(compiler_config: &CompilerConfig) -> Self {
Self {
info: ModuleInfo {
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(),
signatures: Map::new(),
backend: Backend::Cranelift,
namespace_table: StringTable::new(),
name_table: StringTable::new(),
em_symbol_map: compiler_config.symbol_map.clone(),
custom_sections: HashMap::new(),
},
}
}
pub fn compile(
self,
isa: &isa::TargetIsa,
functions: Map<LocalFuncIndex, ir::Function>,
) -> CompileResult<ModuleInner> {
let (func_resolver_builder, handler_data) =
FuncResolverBuilder::new(isa, functions, &self.info)?;
let trampolines = Arc::new(Trampolines::new(isa, &self.info));
let (func_resolver, backend_cache) = func_resolver_builder.finalize(
&self.info.signatures,
Arc::clone(&trampolines),
handler_data.clone(),
)?;
let cache_gen = Box::new(CacheGenerator::new(
backend_cache,
Arc::clone(&func_resolver.memory),
));
let runnable_module = Caller::new(handler_data, trampolines, func_resolver);
Ok(ModuleInner {
runnable_module: Box::new(runnable_module),
cache_gen,
info: self.info,
})
}
pub fn from_cache(cache: Artifact) -> Result<ModuleInner, CacheError> {
let (info, compiled_code, backend_cache) = BackendCache::from_cache(cache)?;
@ -179,3 +111,25 @@ impl From<Converter<ir::Type>> for Type {
}
}
}
impl From<Converter<Type>> for ir::Type {
fn from(ty: Converter<Type>) -> Self {
match ty.0 {
Type::I32 => ir::types::I32,
Type::I64 => ir::types::I64,
Type::F32 => ir::types::F32,
Type::F64 => ir::types::F64,
}
}
}
impl From<Converter<Type>> for ir::AbiParam {
fn from(ty: Converter<Type>) -> Self {
match ty.0 {
Type::I32 => ir::AbiParam::new(ir::types::I32),
Type::I64 => ir::AbiParam::new(ir::types::I64),
Type::F32 => ir::AbiParam::new(ir::types::F32),
Type::F64 => ir::AbiParam::new(ir::types::F64),
}
}
}

View File

@ -1,557 +0,0 @@
use crate::{
func_env::FuncEnv,
module::{Converter, Module},
};
use cranelift_codegen::{ir, isa};
use cranelift_wasm::{self, translate_module, FuncTranslator, ModuleEnvironment};
use wasmer_runtime_core::{
error::{CompileError, CompileResult},
module::{
DataInitializer, ExportIndex, ImportName, NameIndex, NamespaceIndex, StringTableBuilder,
TableInitializer,
},
structures::{Map, TypedIndex},
types::{
ElementType, GlobalDescriptor, GlobalIndex, GlobalInit, Initializer, LocalFuncIndex,
LocalOrImport, MemoryDescriptor, SigIndex, TableDescriptor, Value,
},
units::Pages,
};
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>,
namespace_table_builder: StringTableBuilder<NamespaceIndex>,
name_table_builder: StringTableBuilder<NameIndex>,
}
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(),
namespace_table_builder: StringTableBuilder::new(),
name_table_builder: StringTableBuilder::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() })?;
self.module.info.namespace_table = self.namespace_table_builder.finish();
self.module.info.name_table = self.name_table_builder.finish();
Ok(self.func_bodies)
}
/// Return the global for the given global index.
pub fn get_global(&self, global_index: cranelift_wasm::GlobalIndex) -> &cranelift_wasm::Global {
&self.globals[Converter(global_index).into()]
}
/// Return the signature index for the given function index.
pub fn get_func_type(
&self,
func_index: cranelift_wasm::FuncIndex,
) -> cranelift_wasm::SignatureIndex {
let sig_index: SigIndex = self.module.info.func_assoc[Converter(func_index).into()];
Converter(sig_index).into()
}
}
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.info.signatures.push(Converter(sig).into());
}
/// Declares a function import to the environment.
fn declare_func_import(
&mut self,
clif_sig_index: cranelift_wasm::SignatureIndex,
namespace: &'data str,
name: &'data str,
) {
// We convert the cranelift signature index to
// a wasmer signature index without deduplicating
// because we'll deduplicate later.
let sig_index = Converter(clif_sig_index).into();
self.module.info.func_assoc.push(sig_index);
let namespace_index = self.namespace_table_builder.register(namespace);
let name_index = self.name_table_builder.register(name);
// Add import names to list of imported functions
self.module.info.imported_functions.push(ImportName {
namespace_index,
name_index,
});
}
/// Declares the type (signature) of a local function in the module.
fn declare_func_type(&mut self, clif_sig_index: cranelift_wasm::SignatureIndex) {
// We convert the cranelift signature index to
// a wasmer signature index without deduplicating
// because we'll deduplicate later.
let sig_index = Converter(clif_sig_index).into();
self.module.info.func_assoc.push(sig_index);
}
/// Declares a global to the environment.
fn declare_global(&mut self, global: cranelift_wasm::Global) {
let desc = GlobalDescriptor {
mutable: global.mutability,
ty: Converter(global.ty).into(),
};
let init = match global.initializer {
cranelift_wasm::GlobalInit::I32Const(x) => Initializer::Const(Value::I32(x)),
cranelift_wasm::GlobalInit::I64Const(x) => Initializer::Const(Value::I64(x)),
cranelift_wasm::GlobalInit::F32Const(x) => {
Initializer::Const(Value::F32(f32::from_bits(x)))
}
cranelift_wasm::GlobalInit::F64Const(x) => {
Initializer::Const(Value::F64(f64::from_bits(x)))
}
cranelift_wasm::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.info)
.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.info.globals.push(GlobalInit { 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 namespace_index = self.namespace_table_builder.register(namespace);
let name_index = self.name_table_builder.register(name);
let import_name = ImportName {
namespace_index,
name_index,
};
let desc = GlobalDescriptor {
mutable: global.mutability,
ty: Converter(global.ty).into(),
};
// Add global ir to the list of globals
self.module.info.imported_globals.push((import_name, desc));
self.globals.push(global);
}
/// 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.info.tables.push(TableDescriptor {
element: match table.ty {
TableElementType::Func => ElementType::Anyfunc,
_ => unimplemented!(),
},
minimum: table.minimum,
maximum: 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 namespace_index = self.namespace_table_builder.register(namespace);
let name_index = self.name_table_builder.register(name);
let import_name = ImportName {
namespace_index,
name_index,
};
let imported_table = TableDescriptor {
element: match table.ty {
TableElementType::Func => ElementType::Anyfunc,
_ => unimplemented!(),
},
minimum: table.minimum,
maximum: table.maximum,
};
// Add import names to list of imported tables
self.module
.info
.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: Box<[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.info) {
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.info.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.info.memories.push(MemoryDescriptor {
minimum: Pages(memory.minimum),
maximum: memory.maximum.map(|max| Pages(max)),
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 namespace_index = self.namespace_table_builder.register(namespace);
let name_index = self.name_table_builder.register(name);
let import_name = ImportName {
namespace_index,
name_index,
};
let memory = MemoryDescriptor {
minimum: Pages(memory.minimum),
maximum: memory.maximum.map(|max| Pages(max)),
shared: memory.shared,
};
// Add import names to list of imported memories
self.module
.info
.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.info) {
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.info.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.info.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.info.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.info.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.info.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.info.start_func = Some(Converter(func_index).into());
}
/// Provides the contents of a function body.
fn define_function_body(
&mut self,
body_bytes: &'data [u8],
body_offset: usize,
) -> 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.info)).into()),
);
let mut func = ir::Function::with_name_signature(name, sig);
func_translator.translate(body_bytes, body_offset, &mut func, &mut func_env)?;
#[cfg(feature = "debug")]
{
use cranelift_codegen::cursor::{Cursor, FuncCursor};
use cranelift_codegen::ir::InstBuilder;
let entry_ebb = func.layout.entry_block().unwrap();
let ebb = func.dfg.make_ebb();
func.layout.insert_ebb(ebb, entry_ebb);
let mut pos = FuncCursor::new(&mut func).at_first_insertion_point(ebb);
let params = pos.func.dfg.ebb_params(entry_ebb).to_vec();
let new_ebb_params: Vec<_> = params
.iter()
.map(|&param| {
pos.func
.dfg
.append_ebb_param(ebb, pos.func.dfg.value_type(param))
})
.collect();
let start_debug = {
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I32),
],
returns: vec![],
});
let name = ir::ExternalName::testcase("strtdbug");
pos.func.import_function(ir::ExtFuncData {
name,
signature,
colocated: false,
})
};
let end_debug = {
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![ir::AbiParam::special(
ir::types::I64,
ir::ArgumentPurpose::VMContext,
)],
returns: vec![],
});
let name = ir::ExternalName::testcase("enddbug");
pos.func.import_function(ir::ExtFuncData {
name,
signature,
colocated: false,
})
};
let i32_print = {
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I32),
],
returns: vec![],
});
let name = ir::ExternalName::testcase("i32print");
pos.func.import_function(ir::ExtFuncData {
name,
signature,
colocated: false,
})
};
let i64_print = {
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::I64),
],
returns: vec![],
});
let name = ir::ExternalName::testcase("i64print");
pos.func.import_function(ir::ExtFuncData {
name,
signature,
colocated: false,
})
};
let f32_print = {
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::F32),
],
returns: vec![],
});
let name = ir::ExternalName::testcase("f32print");
pos.func.import_function(ir::ExtFuncData {
name,
signature,
colocated: false,
})
};
let f64_print = {
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
ir::AbiParam::new(ir::types::F64),
],
returns: vec![],
});
let name = ir::ExternalName::testcase("f64print");
pos.func.import_function(ir::ExtFuncData {
name,
signature,
colocated: false,
})
};
let vmctx = pos
.func
.special_param(ir::ArgumentPurpose::VMContext)
.expect("missing vmctx parameter");
let func_index = pos.ins().iconst(
ir::types::I32,
func_index.index() as i64 + self.module.info.imported_functions.len() as i64,
);
pos.ins().call(start_debug, &[vmctx, func_index]);
for param in new_ebb_params.iter().cloned() {
match pos.func.dfg.value_type(param) {
ir::types::I32 => pos.ins().call(i32_print, &[vmctx, param]),
ir::types::I64 => pos.ins().call(i64_print, &[vmctx, param]),
ir::types::F32 => pos.ins().call(f32_print, &[vmctx, param]),
ir::types::F64 => pos.ins().call(f64_print, &[vmctx, param]),
_ => unimplemented!(),
};
}
pos.ins().call(end_debug, &[vmctx]);
pos.ins().jump(entry_ebb, new_ebb_params.as_slice());
}
func
};
// Add function body to list of function bodies.
self.func_bodies.push(func_body);
Ok(())
}
}

View File

@ -9,14 +9,15 @@ edition = "2018"
build = "build/mod.rs"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
byteorder = "1"
hashbrown = "0.1"
lazy_static = "1.2.0"
libc = "0.2.49"
byteorder = "1"
time = "0.1.41"
wasmer-clif-backend = { path = "../clif-backend", version = "0.4.2" }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.2", optional = true }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.4.2", optional = true }
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.2", optional = true }
[target.'cfg(windows)'.dependencies]
rand = "0.6"

View File

@ -3,8 +3,10 @@
#[macro_use]
extern crate wasmer_runtime_core;
use hashbrown::HashMap;
use lazy_static::lazy_static;
use std::cell::UnsafeCell;
use std::path::PathBuf;
use std::{f64, ffi::c_void};
use wasmer_runtime_core::{
error::CallResult,
@ -141,10 +143,14 @@ pub struct EmscriptenData<'a> {
pub stack_save: Option<Func<'a, (), i32>>,
pub stack_restore: Option<Func<'a, (i32)>>,
pub set_threw: Option<Func<'a, (i32, i32)>>,
pub mapped_dirs: HashMap<String, PathBuf>,
}
impl<'a> EmscriptenData<'a> {
pub fn new(instance: &'a mut Instance) -> EmscriptenData<'a> {
pub fn new(
instance: &'a mut Instance,
mapped_dirs: HashMap<String, PathBuf>,
) -> EmscriptenData<'a> {
let malloc = instance.func("_malloc").unwrap();
let free = instance.func("_free").unwrap();
let memalign = instance.func("_memalign").ok();
@ -272,6 +278,7 @@ impl<'a> EmscriptenData<'a> {
stack_save,
stack_restore,
set_threw,
mapped_dirs,
}
}
}
@ -282,8 +289,9 @@ pub fn run_emscripten_instance(
path: &str,
args: Vec<&str>,
entrypoint: Option<String>,
mapped_dirs: Vec<(String, PathBuf)>,
) -> CallResult<()> {
let mut data = EmscriptenData::new(instance);
let mut data = EmscriptenData::new(instance, mapped_dirs.into_iter().collect());
let data_ptr = &mut data as *mut _ as *mut c_void;
instance.context_mut().data = data_ptr;

View File

@ -10,7 +10,8 @@ pub use self::unix::*;
#[cfg(windows)]
pub use self::windows::*;
use super::utils::copy_stat_into_wasm;
use crate::utils::{copy_stat_into_wasm, get_cstr_path, get_current_directory};
use super::varargs::VarArgs;
use byteorder::{ByteOrder, LittleEndian};
/// NOTE: TODO: These syscalls only support wasm_32 for now because they assume offsets are u32
@ -95,12 +96,19 @@ pub fn ___syscall6(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
pub fn ___syscall12(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall12 (chdir) {}", _which);
let path_ptr = varargs.get_str(ctx);
unsafe {
let _path = std::ffi::CStr::from_ptr(path_ptr);
let ret = chdir(path_ptr);
debug!("=> path: {:?}, ret: {}", _path, ret);
let real_path_owned = get_cstr_path(ctx, path_ptr);
let real_path = if let Some(ref rp) = real_path_owned {
rp.as_c_str().as_ptr()
} else {
path_ptr
};
let ret = unsafe { chdir(real_path) };
debug!(
"=> path: {:?}, ret: {}",
unsafe { std::ffi::CStr::from_ptr(real_path) },
ret
}
);
ret
}
pub fn ___syscall10(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
@ -124,11 +132,23 @@ pub fn ___syscall38(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall38 (rename)");
let old_path = varargs.get_str(ctx);
let new_path = varargs.get_str(ctx);
let result = unsafe { rename(old_path, new_path) };
let real_old_path_owned = get_cstr_path(ctx, old_path);
let real_old_path = if let Some(ref rp) = real_old_path_owned {
rp.as_c_str().as_ptr()
} else {
old_path
};
let real_new_path_owned = get_cstr_path(ctx, new_path);
let real_new_path = if let Some(ref rp) = real_new_path_owned {
rp.as_c_str().as_ptr()
} else {
new_path
};
let result = unsafe { rename(real_old_path, real_new_path) };
debug!(
"=> old_path: {}, new_path: {}, result: {}",
unsafe { std::ffi::CStr::from_ptr(old_path).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(new_path).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(real_old_path).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(real_new_path).to_str().unwrap() },
result
);
result
@ -138,7 +158,13 @@ pub fn ___syscall38(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
pub fn ___syscall40(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall40 (rmdir)");
let pathname_addr = varargs.get_str(ctx);
unsafe { rmdir(pathname_addr) }
let real_path_owned = get_cstr_path(ctx, pathname_addr);
let real_path = if let Some(ref rp) = real_path_owned {
rp.as_c_str().as_ptr()
} else {
pathname_addr
};
unsafe { rmdir(real_path) }
}
// pipe
@ -244,10 +270,9 @@ pub fn ___syscall110(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
// getcwd
pub fn ___syscall183(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall183");
use std::env;
let buf_offset: c_int = varargs.get(ctx);
let _size: c_int = varargs.get(ctx);
let path = env::current_dir();
let path = get_current_directory(ctx);
let path_string = path.unwrap().display().to_string();
let len = path_string.len();
unsafe {
@ -420,12 +445,19 @@ pub fn ___syscall195(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
let pathname_addr = varargs.get_str(ctx);
let buf: u32 = varargs.get(ctx);
let real_path_owned = get_cstr_path(ctx, pathname_addr);
let real_path = if let Some(ref rp) = real_path_owned {
rp.as_c_str().as_ptr()
} else {
pathname_addr
};
unsafe {
let mut _stat: stat = std::mem::zeroed();
let ret = stat(pathname_addr, &mut _stat);
let ret = stat(real_path, &mut _stat);
debug!(
"=> pathname: {}, buf: {} = {}, last os error: {}",
std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap(),
std::ffi::CStr::from_ptr(real_path).to_str().unwrap(),
buf,
ret,
Error::last_os_error()
@ -457,11 +489,6 @@ pub fn ___syscall197(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
0
}
pub fn ___syscall220(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall220");
-1
}
// fcntl64
pub fn ___syscall221(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall221 (fcntl64) {}", _which);
@ -474,7 +501,7 @@ pub fn ___syscall221(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
// |FNONBLOCK - 0x04
debug!("=> fd: {}, cmd: {}", _fd, cmd);
match cmd {
2 => 0,
1 | 2 => 0,
13 | 14 => 0, // pretend file locking worked
_ => -1,
}

View File

@ -43,6 +43,7 @@ use libc::{
pid_t,
pread,
pwrite,
readdir,
// readv,
recvfrom,
recvmsg,
@ -107,8 +108,14 @@ pub fn ___syscall5(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
let pathname_addr = varargs.get_str(ctx);
let flags: i32 = varargs.get(ctx);
let mode: u32 = varargs.get(ctx);
let _path_str = unsafe { std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap() };
let fd = unsafe { open(pathname_addr, flags, mode) };
let real_path_owned = utils::get_cstr_path(ctx, pathname_addr);
let real_path = if let Some(ref rp) = real_path_owned {
rp.as_c_str().as_ptr()
} else {
pathname_addr
};
let _path_str = unsafe { std::ffi::CStr::from_ptr(real_path).to_str().unwrap() };
let fd = unsafe { open(real_path, flags, mode) };
debug!(
"=> path: {}, flags: {}, mode: {} = fd: {}, last os error: {}",
_path_str,
@ -154,11 +161,23 @@ pub fn ___syscall83(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
let path1 = varargs.get_str(ctx);
let path2 = varargs.get_str(ctx);
let result = unsafe { symlink(path1, path2) };
let real_path1_owned = utils::get_cstr_path(ctx, path1);
let real_path1 = if let Some(ref rp) = real_path1_owned {
rp.as_c_str().as_ptr()
} else {
path1
};
let real_path2_owned = utils::get_cstr_path(ctx, path2);
let real_path2 = if let Some(ref rp) = real_path2_owned {
rp.as_c_str().as_ptr()
} else {
path2
};
let result = unsafe { symlink(real_path1, real_path2) };
debug!(
"=> path1: {}, path2: {}, result: {}",
unsafe { std::ffi::CStr::from_ptr(path1).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(path2).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(real_path1).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(real_path2).to_str().unwrap() },
result,
);
result
@ -181,12 +200,18 @@ pub fn ___syscall194(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
pub fn ___syscall198(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall198 (lchown) {}", _which);
let path_ptr = varargs.get_str(ctx);
let real_path_owned = utils::get_cstr_path(ctx, path_ptr);
let real_path = if let Some(ref rp) = real_path_owned {
rp.as_c_str().as_ptr()
} else {
path_ptr
};
let uid: uid_t = varargs.get(ctx);
let gid: gid_t = varargs.get(ctx);
let result = unsafe { lchown(path_ptr, uid, gid) };
let result = unsafe { lchown(real_path, uid, gid) };
debug!(
"=> path: {}, uid: {}, gid: {}, result: {}",
unsafe { std::ffi::CStr::from_ptr(path_ptr).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(real_path).to_str().unwrap() },
uid,
gid,
result,
@ -216,10 +241,16 @@ pub fn ___syscall212(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
debug!("emscripten::___syscall212 (chown) {}", _which);
let pathname_addr = varargs.get_str(ctx);
let real_path_owned = utils::get_cstr_path(ctx, pathname_addr);
let real_path = if let Some(ref rp) = real_path_owned {
rp.as_c_str().as_ptr()
} else {
pathname_addr
};
let owner: u32 = varargs.get(ctx);
let group: u32 = varargs.get(ctx);
unsafe { chown(pathname_addr, owner, group) }
unsafe { chown(real_path, owner, group) }
}
/// madvise
@ -239,11 +270,17 @@ pub fn ___syscall219(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
pub fn ___syscall33(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall33 (access) {}", _which);
let path = varargs.get_str(ctx);
let real_path_owned = utils::get_cstr_path(ctx, path);
let real_path = if let Some(ref rp) = real_path_owned {
rp.as_c_str().as_ptr()
} else {
path
};
let amode: c_int = varargs.get(ctx);
let result = unsafe { access(path, amode) };
let result = unsafe { access(real_path, amode) };
debug!(
"=> path: {}, amode: {}, result: {}",
unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(real_path).to_str().unwrap() },
amode,
result
);
@ -261,8 +298,14 @@ pub fn ___syscall34(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
pub fn ___syscall39(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall39 (mkdir) {}", _which);
let pathname_addr = varargs.get_str(ctx);
let real_path_owned = utils::get_cstr_path(ctx, pathname_addr);
let real_path = if let Some(ref rp) = real_path_owned {
rp.as_c_str().as_ptr()
} else {
pathname_addr
};
let mode: u32 = varargs.get(ctx);
unsafe { mkdir(pathname_addr, mode as _) }
unsafe { mkdir(real_path, mode as _) }
}
/// dup
@ -761,6 +804,12 @@ pub fn ___syscall122(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
pub fn ___syscall196(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall196 (lstat64) {}", _which);
let path = varargs.get_str(ctx);
let real_path_owned = utils::get_cstr_path(ctx, path);
let real_path = if let Some(ref rp) = real_path_owned {
rp.as_c_str().as_ptr()
} else {
path
};
let buf_ptr: u32 = varargs.get(ctx);
unsafe {
let mut stat: stat = std::mem::zeroed();
@ -771,9 +820,9 @@ pub fn ___syscall196(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
let stat_ptr = &mut stat as *mut stat;
#[cfg(target_os = "macos")]
let ret = lstat64(path, stat_ptr);
let ret = lstat64(real_path, stat_ptr);
#[cfg(not(target_os = "macos"))]
let ret = lstat(path, stat_ptr);
let ret = lstat(real_path, stat_ptr);
debug!("ret: {}", ret);
if ret != 0 {
@ -784,6 +833,45 @@ pub fn ___syscall196(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
0
}
// getdents
// dirent structure is
// i64, i64, u16 (280), i8, [i8; 256]
pub fn ___syscall220(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall220");
let fd: i32 = varargs.get(ctx);
let dirp_addr: i32 = varargs.get(ctx);
let count: u32 = varargs.get(ctx);
let dirp = emscripten_memory_pointer!(ctx.memory(0), dirp_addr) as *mut u8;
// need to persist stream across calls?
let dir: *mut libc::DIR = unsafe { libc::fdopendir(fd) };
let mut pos = 0;
let offset = 280;
while pos + offset <= count as usize {
let dirent = unsafe { readdir(dir) };
if dirent.is_null() {
break;
}
#[allow(clippy::cast_ptr_alignment)]
unsafe {
*(dirp.add(pos) as *mut u64) = (*dirent).d_ino;
*(dirp.add(pos + 8) as *mut u64) = pos as u64 + offset as u64;
*(dirp.add(pos + 16) as *mut u16) = offset as u16;
*(dirp.add(pos + 18) as *mut u8) = (*dirent).d_type;
let upper_bound = std::cmp::min((*dirent).d_reclen, 254) as usize;
let mut i = 0;
while i < upper_bound {
*(dirp.add(pos + 19 + i) as *mut i8) = (*dirent).d_name[i];
i += 1;
}
*(dirp.add(pos + 19 + i) as *mut i8) = 0 as i8;
}
pos += offset;
}
pos as i32
}
/// fallocate
pub fn ___syscall324(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall324 (fallocate) {}", _which);

View File

@ -1,4 +1,4 @@
use crate::utils::copy_cstr_into_wasm;
use crate::utils::{copy_cstr_into_wasm, get_cstr_path};
use crate::varargs::VarArgs;
use libc::mkdir;
use libc::open;
@ -19,9 +19,15 @@ pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
#[cfg(not(feature = "debug"))]
let _ = which;
let pathname_addr = varargs.get_str(ctx);
let real_path_owned = get_cstr_path(ctx, pathname_addr);
let real_path = if let Some(ref rp) = real_path_owned {
rp.as_c_str().as_ptr()
} else {
pathname_addr
};
let flags: i32 = varargs.get(ctx);
let mode: u32 = varargs.get(ctx);
let path_str = unsafe { std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap() };
let path_str = unsafe { std::ffi::CStr::from_ptr(real_path).to_str().unwrap() };
match path_str {
"/dev/urandom" => {
// create a fake urandom file for windows, super hacky
@ -47,7 +53,7 @@ pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
fd
}
_ => {
let fd = unsafe { open(pathname_addr, flags, mode) };
let fd = unsafe { open(real_path, flags, mode) };
debug!(
"=> pathname: {}, flags: {}, mode: {} = fd: {}\npath: {}",
path_str, flags, mode, fd, path_str
@ -95,7 +101,13 @@ pub fn ___syscall39(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int
#[cfg(not(feature = "debug"))]
let _ = which;
let pathname_addr = varargs.get_str(ctx);
unsafe { mkdir(pathname_addr) }
let real_path_owned = get_cstr_path(ctx, pathname_addr);
let real_path = if let Some(ref rp) = real_path_owned {
rp.as_c_str().as_ptr()
} else {
pathname_addr
};
unsafe { mkdir(real_path) }
}
/// dup
@ -249,6 +261,12 @@ pub fn ___syscall196(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
-1
}
// getdents
pub fn ___syscall220(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall220");
-1
}
/// fchown
pub fn ___syscall207(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall207 (fchown) {}", _which);

View File

@ -5,6 +5,7 @@ use libc::stat;
use std::ffi::CStr;
use std::mem::size_of;
use std::os::raw::c_char;
use std::path::PathBuf;
use std::slice;
use wasmer_runtime_core::memory::Memory;
use wasmer_runtime_core::{
@ -204,6 +205,61 @@ pub fn read_string_from_wasm(memory: &Memory, offset: u32) -> String {
String::from_utf8_lossy(&v).to_owned().to_string()
}
/// This function trys to find an entry in mapdir
/// translating paths into their correct value
pub fn get_cstr_path(ctx: &mut Ctx, path: *const i8) -> Option<std::ffi::CString> {
use std::collections::VecDeque;
let path_str = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }.to_string();
let data = get_emscripten_data(ctx);
let path = PathBuf::from(path_str);
let mut prefix_added = false;
let mut components = path.components().collect::<VecDeque<_>>();
// TODO(mark): handle absolute/non-canonical/non-relative paths too (this
// functionality should be shared among the abis)
if components.len() == 1 {
components.push_front(std::path::Component::CurDir);
prefix_added = true;
}
let mut cumulative_path = PathBuf::new();
for c in components.into_iter() {
cumulative_path.push(c);
if let Some(val) = data
.mapped_dirs
.get(&cumulative_path.to_string_lossy().to_string())
{
let rest_of_path = if !prefix_added {
path.strip_prefix(cumulative_path).ok()?
} else {
&path
};
let rebased_path = val.join(rest_of_path);
return std::ffi::CString::new(rebased_path.to_string_lossy().as_bytes()).ok();
}
}
None
}
/// gets the current directory
/// handles mapdir logic
pub fn get_current_directory(ctx: &mut Ctx) -> Option<PathBuf> {
if let Some(val) = get_emscripten_data(ctx).mapped_dirs.get(".") {
return Some(val.clone());
}
std::env::current_dir()
.map(|cwd| {
if let Some(val) = get_emscripten_data(ctx)
.mapped_dirs
.get(&cwd.to_string_lossy().to_string())
{
val.clone()
} else {
cwd
}
})
.ok()
}
#[cfg(test)]
mod tests {
use super::is_emscripten_module;

View File

@ -56,6 +56,7 @@ macro_rules! assert_emscripten_output {
$name,
$args,
None,
vec![],
).expect("run_emscripten_instance finishes");
let output = capturer.end().unwrap().0;

View File

@ -7,7 +7,7 @@ edition = "2018"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
inkwell = { git = "https://github.com/wasmerio/inkwell", branch = "llvm7-0" }
wasmparser = "0.30.0"
wasmparser = "0.29.2"
hashbrown = "0.1.8"
smallvec = "0.6.8"
goblin = "0.0.20"

View File

@ -8,7 +8,7 @@ use inkwell::{
AddressSpace, FloatPredicate, IntPredicate,
};
use smallvec::SmallVec;
use std::sync::Arc;
use std::sync::{Arc, RwLock};
use wasmer_runtime_core::{
backend::{Backend, CacheGen, Token},
cache::{Artifact, Error as CacheError},
@ -2551,7 +2551,10 @@ impl ModuleCodeGenerator<LLVMFunctionCodeGenerator, LLVMBackend, CodegenError>
Ok(())
}
fn next_function(&mut self) -> Result<&mut LLVMFunctionCodeGenerator, CodegenError> {
fn next_function(
&mut self,
_module_info: Arc<RwLock<ModuleInfo>>,
) -> Result<&mut LLVMFunctionCodeGenerator, CodegenError> {
// Creates a new function and returns the function-scope code generator for it.
let (context, builder, intrinsics, breakpoints) = match self.functions.last_mut() {
Some(x) => (

View File

@ -13,7 +13,7 @@ wasmer-runtime-core = { path = "../runtime-core" }
hashbrown = "0.1"
failure = "0.1"
tar = "0.4"
wasmparser = "0.30.0"
wasmparser = "0.29.2"
zstd = "0.4"
# [target.'cfg(unix)'.dependencies.zbox]

View File

@ -10,7 +10,7 @@ edition = "2018"
[dependencies]
nix = "0.12.0"
page_size = "0.4.1"
wasmparser = "0.30.0"
wasmparser = "0.29.2"
parking_lot = "0.7.1"
lazy_static = "1.2.0"
indexmap = "1.0.2"

View File

@ -11,6 +11,8 @@ use smallvec::SmallVec;
use std::fmt;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::sync::{Arc, RwLock};
use wasmparser::{self, WasmDecoder};
use wasmparser::{Operator, Type as WpType};
#[derive(Debug)]
@ -57,13 +59,14 @@ pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule,
}
/// Adds an import function.
fn feed_import_function(&mut self) -> Result<(), E>;
fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), E>;
/// Sets function signatures.
fn feed_function_signatures(&mut self, assoc: Map<FuncIndex, SigIndex>) -> Result<(), E>;
/// Checks the precondition for a module.
fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), E>;
/// Creates a new function and returns the function-scope code generator for it.
fn next_function(&mut self) -> Result<&mut FCG, E>;
fn next_function(&mut self, module_info: Arc<RwLock<ModuleInfo>>) -> Result<&mut FCG, E>;
/// Finalizes this module.
fn finalize(self, module_info: &ModuleInfo) -> Result<(RM, Box<dyn CacheGen>), E>;
@ -128,6 +131,20 @@ impl<
}
}
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(),
})?,
_ => {}
}
}
}
impl<
MCG: ModuleCodeGenerator<FCG, RM, E>,
FCG: FunctionCodeGenerator<E>,
@ -142,6 +159,10 @@ impl<
compiler_config: CompilerConfig,
_: Token,
) -> CompileResult<ModuleInner> {
if requires_pre_validation(MCG::backend_id()) {
validate(wasm)?;
}
let mut mcg = MCG::new();
let mut chain = (self.middleware_chain_generator)();
let info = crate::parse::read_module(
@ -152,14 +173,14 @@ impl<
&compiler_config,
)?;
let (exec_context, cache_gen) =
mcg.finalize(&info)
mcg.finalize(&info.read().unwrap())
.map_err(|x| CompileError::InternalError {
msg: format!("{:?}", x),
})?;
Ok(ModuleInner {
cache_gen,
runnable_module: Box::new(exec_context),
info,
info: Arc::try_unwrap(info).unwrap().into_inner().unwrap(),
})
}
@ -172,6 +193,14 @@ impl<
}
}
fn requires_pre_validation(backend: Backend) -> bool {
match backend {
Backend::Cranelift => true,
Backend::LLVM => false,
Backend::Singlepass => false,
}
}
pub struct EventSink<'a, 'b> {
buffer: SmallVec<[Event<'a, 'b>; 2]>,
}

View File

@ -27,7 +27,7 @@ pub struct ModuleInner {
pub info: ModuleInfo,
}
#[derive(Clone, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ModuleInfo {
// This are strictly local and the typsystem ensures that.
pub memories: Map<LocalMemoryIndex, MemoryDescriptor>,

View File

@ -16,6 +16,7 @@ use crate::{
};
use hashbrown::HashMap;
use std::fmt::Debug;
use std::sync::{Arc, RwLock};
use wasmparser::{
BinaryReaderError, ExternalKind, FuncType, ImportSectionEntryType, Operator, Type as WpType,
WasmDecoder,
@ -52,10 +53,10 @@ pub fn read_module<
mcg: &mut MCG,
middlewares: &mut MiddlewareChain,
compiler_config: &CompilerConfig,
) -> Result<ModuleInfo, LoadError> {
) -> Result<Arc<RwLock<ModuleInfo>>, LoadError> {
mcg.feed_compiler_config(compiler_config)
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
let mut info = ModuleInfo {
let info = Arc::new(RwLock::new(ModuleInfo {
memories: Map::new(),
globals: Map::new(),
tables: Map::new(),
@ -82,7 +83,7 @@ pub fn read_module<
em_symbol_map: compiler_config.symbol_map.clone(),
custom_sections: HashMap::new(),
};
}));
let mut parser = wasmparser::ValidatingParser::new(
wasm,
@ -105,10 +106,13 @@ pub fn read_module<
use wasmparser::ParserState;
let state = parser.read();
match *state {
ParserState::EndWasm => break Ok(info),
ParserState::EndWasm => break,
ParserState::Error(err) => Err(LoadError::Parse(err))?,
ParserState::TypeSectionEntry(ref ty) => {
info.signatures.push(func_type_to_func_sig(ty)?);
info.write()
.unwrap()
.signatures
.push(func_type_to_func_sig(ty)?);
}
ParserState::ImportSectionEntry { module, field, ty } => {
let namespace_index = namespace_builder.as_mut().unwrap().register(module);
@ -121,8 +125,8 @@ pub fn read_module<
match ty {
ImportSectionEntryType::Function(sigindex) => {
let sigindex = SigIndex::new(sigindex as usize);
info.imported_functions.push(import_name);
info.func_assoc.push(sigindex);
info.write().unwrap().imported_functions.push(import_name);
info.write().unwrap().func_assoc.push(sigindex);
mcg.feed_import_function()
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
}
@ -134,7 +138,10 @@ pub fn read_module<
maximum: table_ty.limits.maximum,
};
info.imported_tables.push((import_name, table_desc));
info.write()
.unwrap()
.imported_tables
.push((import_name, table_desc));
}
ImportSectionEntryType::Memory(memory_ty) => {
let mem_desc = MemoryDescriptor {
@ -142,20 +149,26 @@ pub fn read_module<
maximum: memory_ty.limits.maximum.map(|max| Pages(max)),
shared: memory_ty.shared,
};
info.imported_memories.push((import_name, mem_desc));
info.write()
.unwrap()
.imported_memories
.push((import_name, mem_desc));
}
ImportSectionEntryType::Global(global_ty) => {
let global_desc = GlobalDescriptor {
mutable: global_ty.mutable,
ty: wp_type_to_type(global_ty.content_type)?,
};
info.imported_globals.push((import_name, global_desc));
info.write()
.unwrap()
.imported_globals
.push((import_name, global_desc));
}
}
}
ParserState::FunctionSectionEntry(sigindex) => {
let sigindex = SigIndex::new(sigindex as usize);
info.func_assoc.push(sigindex);
info.write().unwrap().func_assoc.push(sigindex);
}
ParserState::TableSectionEntry(table_ty) => {
let table_desc = TableDescriptor {
@ -164,7 +177,7 @@ pub fn read_module<
maximum: table_ty.limits.maximum,
};
info.tables.push(table_desc);
info.write().unwrap().tables.push(table_desc);
}
ParserState::MemorySectionEntry(memory_ty) => {
let mem_desc = MemoryDescriptor {
@ -173,7 +186,7 @@ pub fn read_module<
shared: memory_ty.shared,
};
info.memories.push(mem_desc);
info.write().unwrap().memories.push(mem_desc);
}
ParserState::ExportSectionEntry { field, kind, index } => {
let export_index = match kind {
@ -183,42 +196,51 @@ pub fn read_module<
ExternalKind::Global => ExportIndex::Global(GlobalIndex::new(index as usize)),
};
info.exports.insert(field.to_string(), export_index);
info.write()
.unwrap()
.exports
.insert(field.to_string(), export_index);
}
ParserState::StartSectionEntry(start_index) => {
info.start_func = Some(FuncIndex::new(start_index as usize));
info.write().unwrap().start_func = Some(FuncIndex::new(start_index as usize));
}
ParserState::BeginFunctionBody { .. } => {
let id = func_count.wrapping_add(1);
func_count = id;
if func_count == 0 {
info.namespace_table = namespace_builder.take().unwrap().finish();
info.name_table = name_builder.take().unwrap().finish();
mcg.feed_signatures(info.signatures.clone())
info.write().unwrap().namespace_table =
namespace_builder.take().unwrap().finish();
info.write().unwrap().name_table = name_builder.take().unwrap().finish();
mcg.feed_signatures(info.read().unwrap().signatures.clone())
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
mcg.feed_function_signatures(info.func_assoc.clone())
mcg.feed_function_signatures(info.read().unwrap().func_assoc.clone())
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
mcg.check_precondition(&info)
mcg.check_precondition(&info.read().unwrap())
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
}
let fcg = mcg
.next_function()
.next_function(Arc::clone(&info))
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
middlewares
.run(
Some(fcg),
Event::Internal(InternalEvent::FunctionBegin(id as u32)),
&info,
&info.read().unwrap(),
)
.map_err(|x| LoadError::Codegen(x))?;
let sig = info
let info_read = info.read().unwrap();
let sig = info_read
.signatures
.get(
*info
.read()
.unwrap()
.func_assoc
.get(FuncIndex::new(id as usize + info.imported_functions.len()))
.get(FuncIndex::new(
id as usize + info.read().unwrap().imported_functions.len(),
))
.unwrap(),
)
.unwrap();
@ -235,22 +257,22 @@ pub fn read_module<
loop {
let state = parser.read();
match *state {
ParserState::Error(err) => return Err(LoadError::Parse(err)),
match state {
ParserState::Error(err) => return Err(LoadError::Parse(*err)),
ParserState::FunctionBodyLocals { ref locals } => {
for &(count, ty) in locals.iter() {
fcg.feed_local(ty, count as usize)
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
}
}
ParserState::CodeOperator(ref op) => {
ParserState::CodeOperator(op) => {
if !body_begun {
body_begun = true;
fcg.begin_body(&info)
fcg.begin_body(&info.read().unwrap())
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
}
middlewares
.run(Some(fcg), Event::Wasm(op), &info)
.run(Some(fcg), Event::Wasm(op), &info.read().unwrap())
.map_err(|x| LoadError::Codegen(x))?;
}
ParserState::EndFunctionBody => break,
@ -261,7 +283,7 @@ pub fn read_module<
.run(
Some(fcg),
Event::Internal(InternalEvent::FunctionEnd),
&info,
&info.read().unwrap(),
)
.map_err(|x| LoadError::Codegen(x))?;
fcg.finalize()
@ -301,7 +323,7 @@ pub fn read_module<
elements: elements.unwrap(),
};
info.elem_initializers.push(table_init);
info.write().unwrap().elem_initializers.push(table_init);
}
ParserState::BeginActiveDataSectionEntry(memory_index) => {
let memory_index = MemoryIndex::new(memory_index as usize);
@ -332,7 +354,7 @@ pub fn read_module<
base: base.unwrap(),
data,
};
info.data_initializers.push(data_init);
info.write().unwrap().data_initializers.push(data_init);
}
ParserState::BeginGlobalSectionEntry(ty) => {
let init = loop {
@ -353,12 +375,13 @@ pub fn read_module<
let global_init = GlobalInit { desc, init };
info.globals.push(global_init);
info.write().unwrap().globals.push(global_init);
}
_ => {}
}
}
Ok(info)
}
pub fn wp_type_to_type(ty: WpType) -> Result<Type, BinaryReaderError> {

View File

@ -9,7 +9,7 @@ edition = "2018"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
wasmparser = "0.30.0"
wasmparser = "0.29.2"
dynasm = "0.3.2"
dynasmrt = "0.3.1"
lazy_static = "1.2.0"

View File

@ -8,7 +8,11 @@ use dynasmrt::{
};
use smallvec::SmallVec;
use std::ptr::NonNull;
use std::{any::Any, collections::HashMap, sync::Arc};
use std::{
any::Any,
collections::HashMap,
sync::{Arc, RwLock},
};
use wasmer_runtime_core::{
backend::{
sys::Memory, Backend, CacheGen, CompilerConfig, MemoryBoundCheckMode, RunnableModule, Token,
@ -319,7 +323,10 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
Ok(())
}
fn next_function(&mut self) -> Result<&mut X64FunctionCode, CodegenError> {
fn next_function(
&mut self,
_module_info: Arc<RwLock<ModuleInfo>>,
) -> Result<&mut X64FunctionCode, CodegenError> {
let (mut assembler, mut function_labels, breakpoints) = match self.functions.last_mut() {
Some(x) => (
x.assembler.take().unwrap(),
@ -332,6 +339,7 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
HashMap::new(),
),
};
let begin_offset = assembler.offset();
let begin_label_info = function_labels
.entry(self.functions.len() + self.func_import_count)

View File

@ -1,6 +1,6 @@
use wabt::wat2wasm;
use wasmer_clif_backend::CraneliftCompiler;
use wasmer_runtime_core::{import::ImportObject, Instance};
use wasmer_runtime_core::{backend::Compiler, import::ImportObject, Instance};
fn main() {
let instance = create_module_1();
@ -24,13 +24,38 @@ fn create_module_1() -> Instance {
(elem (;1;) (i32.const 9) 1))
"#;
let wasm_binary = wat2wasm(module_str.as_bytes()).expect("WAST not valid or malformed");
let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &CraneliftCompiler::new())
let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &get_compiler())
.expect("WASM can't be compiled");
module
.instantiate(&generate_imports())
.expect("WASM can't be instantiated")
}
#[cfg(feature = "clif")]
fn get_compiler() -> impl Compiler {
use wasmer_clif_backend::CraneliftCompiler;
CraneliftCompiler::new()
}
#[cfg(feature = "llvm")]
fn get_compiler() -> impl Compiler {
use wasmer_llvm_backend::LLVMCompiler;
LLVMCompiler::new()
}
#[cfg(feature = "singlepass")]
fn get_compiler() -> impl Compiler {
use wasmer_singlepass_backend::SinglePassCompiler;
SinglePassCompiler::new()
}
#[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))]
fn get_compiler() -> impl Compiler {
panic!("compiler not specified, activate a compiler via features");
use wasmer_clif_backend::CraneliftCompiler;
CraneliftCompiler::new()
}
static IMPORT_MODULE: &str = r#"
(module
(type $t0 (func (param i32)))
@ -44,7 +69,7 @@ static IMPORT_MODULE: &str = r#"
pub fn generate_imports() -> ImportObject {
let wasm_binary = wat2wasm(IMPORT_MODULE.as_bytes()).expect("WAST not valid or malformed");
let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &CraneliftCompiler::new())
let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &get_compiler())
.expect("WASM can't be compiled");
let instance = module
.instantiate(&ImportObject::new())

View File

@ -471,9 +471,6 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
.instantiate(&import_object)
.map_err(|e| format!("Can't instantiate module: {:?}", e))?;
if !mapped_dirs.is_empty() {
eprintln!("WARN: mapdir is not implemented for emscripten targets");
}
wasmer_emscripten::run_emscripten_instance(
&module,
&mut instance,
@ -484,6 +481,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
},
options.args.iter().map(|arg| arg.as_str()).collect(),
options.em_entrypoint.clone(),
mapped_dirs,
)
.map_err(|e| format!("{:?}", e))?;
} else {