diff --git a/.circleci/config.yml b/.circleci/config.yml index 37b1de24e..eead29af0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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 diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index e3d87738d..e1d1c4ae3 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -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. diff --git a/CHANGELOG.md b/CHANGELOG.md index 93857f7d8..35838a19b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/Cargo.lock b/Cargo.lock index e3efff33d..9464d9102 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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)" = "" +"checksum cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "" +"checksum cranelift-codegen-meta 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "" +"checksum cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "" +"checksum cranelift-frontend 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "" +"checksum cranelift-native 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "" +"checksum cranelift-wasm 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "" "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" diff --git a/README.md b/README.md index b3a7a070d..27b04baab 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/lib/clif-backend/Cargo.toml b/lib/clif-backend/Cargo.toml index 60e791f2f..031387c08 100644 --- a/lib/clif-backend/Cargo.toml +++ b/lib/clif-backend/Cargo.toml @@ -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" diff --git a/lib/clif-backend/src/func_env.rs b/lib/clif-backend/src/code.rs similarity index 51% rename from lib/clif-backend/src/func_env.rs rename to lib/clif-backend/src/code.rs index 8a65444b7..576f513e1 100644 --- a/lib/clif-backend/src/func_env.rs +++ b/lib/clif-backend/src/code.rs @@ -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, + signatures: Option>>, + pub clif_signatures: Map, + function_signatures: Option>>, + functions: Vec, } -impl<'env, 'module, 'isa> FuncEnv<'env, 'module, 'isa> { - pub fn new(env: &'env ModuleEnv<'module, 'isa>) -> Self { - Self { env } +impl ModuleCodeGenerator + 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>, + ) -> 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(|¶m| { + 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), CodegenError> { + let mut func_bodies: Map = 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) -> 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, + ) -> 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 { + 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::>(), + returns: sig + .returns() + .iter() + .map(|returns| Converter(*returns).into()) + .collect::>(), + call_conv, + } +} + +impl From for CodegenError { + fn from(other: CompileError) -> CodegenError { + CodegenError { + message: format!("{:?}", other), + } + } +} + +impl From 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, + module_info: Arc>, + target_config: isa::TargetFrontendConfig, + position: Position, +} + +pub struct FunctionEnvironment { + module_info: Arc>, + target_config: isa::TargetFrontendConfig, + clif_signatures: Map, +} + +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 { 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 { 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 { 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 { // 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 { // 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 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 +} diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index 50fbe5dbf..074b0b670 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -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 { - 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 { - module::Module::from_cache(cache) - } - - // - // fn compile_to_backend_cache_data( - // &self, - // wasm: &[u8], - // _: Token, - // ) -> CompileResult<(Box, Vec, 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 { let flags = { let mut builder = settings::builder(); @@ -113,19 +37,14 @@ fn get_isa() -> Box { 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, +>; diff --git a/lib/clif-backend/src/module.rs b/lib/clif-backend/src/module.rs index ad0576e59..14adb1547 100644 --- a/lib/clif-backend/src/module.rs +++ b/lib/clif-backend/src/module.rs @@ -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, - ) -> CompileResult { - 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 { let (info, compiled_code, backend_cache) = BackendCache::from_cache(cache)?; @@ -179,3 +111,25 @@ impl From> for Type { } } } + +impl From> for ir::Type { + fn from(ty: Converter) -> 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> for ir::AbiParam { + fn from(ty: Converter) -> 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), + } + } +} diff --git a/lib/clif-backend/src/module_env.rs b/lib/clif-backend/src/module_env.rs deleted file mode 100644 index 7cf1dfaff..000000000 --- a/lib/clif-backend/src/module_env.rs +++ /dev/null @@ -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, - globals: Map, - func_bodies: Map, - namespace_table_builder: StringTableBuilder, - name_table_builder: StringTableBuilder, -} - -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> { - 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, - 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, - 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(|¶m| { - 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(()) - } -} diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index c9209eb8f..3d9e5df71 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -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" diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 400bcd94f..70d62d950 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -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>, pub stack_restore: Option>, pub set_threw: Option>, + pub mapped_dirs: HashMap, } impl<'a> EmscriptenData<'a> { - pub fn new(instance: &'a mut Instance) -> EmscriptenData<'a> { + pub fn new( + instance: &'a mut Instance, + mapped_dirs: HashMap, + ) -> 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, + 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; diff --git a/lib/emscripten/src/syscalls/mod.rs b/lib/emscripten/src/syscalls/mod.rs index 057a8ac19..94f118947 100644 --- a/lib/emscripten/src/syscalls/mod.rs +++ b/lib/emscripten/src/syscalls/mod.rs @@ -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, } diff --git a/lib/emscripten/src/syscalls/unix.rs b/lib/emscripten/src/syscalls/unix.rs index 83a972dfa..1c4db071b 100644 --- a/lib/emscripten/src/syscalls/unix.rs +++ b/lib/emscripten/src/syscalls/unix.rs @@ -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); diff --git a/lib/emscripten/src/syscalls/windows.rs b/lib/emscripten/src/syscalls/windows.rs index d74f3c55b..b3f7b748f 100644 --- a/lib/emscripten/src/syscalls/windows.rs +++ b/lib/emscripten/src/syscalls/windows.rs @@ -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); diff --git a/lib/emscripten/src/utils.rs b/lib/emscripten/src/utils.rs index 2ad5b9a40..112728130 100644 --- a/lib/emscripten/src/utils.rs +++ b/lib/emscripten/src/utils.rs @@ -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 { + 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::>(); + // 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 { + 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; diff --git a/lib/emscripten/tests/emtests/_common.rs b/lib/emscripten/tests/emtests/_common.rs index 43c1aecbf..993842a18 100644 --- a/lib/emscripten/tests/emtests/_common.rs +++ b/lib/emscripten/tests/emtests/_common.rs @@ -56,6 +56,7 @@ macro_rules! assert_emscripten_output { $name, $args, None, + vec![], ).expect("run_emscripten_instance finishes"); let output = capturer.end().unwrap().0; diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index 3c6fb39c7..1e49b3233 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -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" diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 4662ef345..8ad7cdfce 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -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 Ok(()) } - fn next_function(&mut self) -> Result<&mut LLVMFunctionCodeGenerator, CodegenError> { + fn next_function( + &mut self, + _module_info: Arc>, + ) -> 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) => ( diff --git a/lib/runtime-abi/Cargo.toml b/lib/runtime-abi/Cargo.toml index 865d67f18..61a00ac5c 100644 --- a/lib/runtime-abi/Cargo.toml +++ b/lib/runtime-abi/Cargo.toml @@ -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] diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index bd5078af3..775f8487e 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -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" diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index f7a997e29..71a38dc88 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -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, RM: RunnableModule, } /// Adds an import function. fn feed_import_function(&mut self) -> Result<(), E>; + fn feed_signatures(&mut self, signatures: Map) -> Result<(), E>; /// Sets function signatures. fn feed_function_signatures(&mut self, assoc: Map) -> 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>) -> Result<&mut FCG, E>; /// Finalizes this module. fn finalize(self, module_info: &ModuleInfo) -> Result<(RM, Box), 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: FunctionCodeGenerator, @@ -142,6 +159,10 @@ impl< compiler_config: CompilerConfig, _: Token, ) -> CompileResult { + 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]>, } diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 1ffbc71fc..111bc8754 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -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, diff --git a/lib/runtime-core/src/parse.rs b/lib/runtime-core/src/parse.rs index 7fdbd095a..7a76a46ac 100644 --- a/lib/runtime-core/src/parse.rs +++ b/lib/runtime-core/src/parse.rs @@ -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 { +) -> Result>, 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 { diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index 2569027b0..28068aa1b 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -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" diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 6b8ea5569..c59b524ed 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -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 Ok(()) } - fn next_function(&mut self) -> Result<&mut X64FunctionCode, CodegenError> { + fn next_function( + &mut self, + _module_info: Arc>, + ) -> 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 HashMap::new(), ), }; + let begin_offset = assembler.offset(); let begin_label_info = function_labels .entry(self.functions.len() + self.func_import_count) diff --git a/lib/spectests/examples/test.rs b/lib/spectests/examples/test.rs index 6f725e994..8ce199695 100644 --- a/lib/spectests/examples/test.rs +++ b/lib/spectests/examples/test.rs @@ -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()) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 3122631d3..19293e41d 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -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 {