mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-14 22:55:40 +00:00
Merge #276
276: Single-pass native code generation for x86-64 using dynasm. r=losfair a=losfair Co-authored-by: losfair <zhy20000919@hotmail.com>
This commit is contained in:
commit
758ccc6894
@ -18,8 +18,10 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: Install lint deps
|
name: Install lint deps
|
||||||
command: |
|
command: |
|
||||||
|
git config --global --unset url."ssh://git@github.com".insteadOf || true
|
||||||
|
rustup toolchain install nightly
|
||||||
rustup component add rustfmt
|
rustup component add rustfmt
|
||||||
rustup component add clippy
|
rustup component add clippy --toolchain=nightly || cargo +nightly install --git https://github.com/rust-lang/rust-clippy/ --force clippy
|
||||||
- run:
|
- run:
|
||||||
name: Execute lints
|
name: Execute lints
|
||||||
command: |
|
command: |
|
||||||
@ -274,6 +276,9 @@ jobs:
|
|||||||
- run: |
|
- run: |
|
||||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||||
make test
|
make test
|
||||||
|
make test-nightly
|
||||||
|
make test-emscripten
|
||||||
|
make test-emscripten-nightly
|
||||||
- save_cache:
|
- save_cache:
|
||||||
paths:
|
paths:
|
||||||
- /usr/local/cargo/registry
|
- /usr/local/cargo/registry
|
||||||
|
68
Cargo.lock
generated
68
Cargo.lock
generated
@ -1,3 +1,5 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.6.10"
|
version = "0.6.10"
|
||||||
@ -367,6 +369,30 @@ dependencies = [
|
|||||||
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dynasm"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dynasmrt"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.5.1"
|
version = "1.5.1"
|
||||||
@ -605,6 +631,15 @@ dependencies = [
|
|||||||
"libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memmap"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memmap"
|
name = "memmap"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@ -670,6 +705,14 @@ dependencies = [
|
|||||||
"libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "owning_ref"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "owning_ref"
|
name = "owning_ref"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@ -1112,6 +1155,11 @@ dependencies = [
|
|||||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "take_mut"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "target-lexicon"
|
name = "target-lexicon"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -1315,6 +1363,18 @@ dependencies = [
|
|||||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasmer-dynasm-backend"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"dynasm 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"dynasmrt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"wasmer-runtime-core 0.2.1",
|
||||||
|
"wasmparser 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasmer-emscripten"
|
name = "wasmer-emscripten"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@ -1327,6 +1387,7 @@ dependencies = [
|
|||||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"wabt 0.7.4 (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.2.0",
|
"wasmer-clif-backend 0.2.0",
|
||||||
|
"wasmer-dynasm-backend 0.1.0",
|
||||||
"wasmer-llvm-backend 0.1.0",
|
"wasmer-llvm-backend 0.1.0",
|
||||||
"wasmer-runtime-core 0.2.1",
|
"wasmer-runtime-core 0.2.1",
|
||||||
]
|
]
|
||||||
@ -1362,6 +1423,7 @@ dependencies = [
|
|||||||
"tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"wabt 0.7.4 (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.2.0",
|
"wasmer-clif-backend 0.2.0",
|
||||||
|
"wasmer-dynasm-backend 0.1.0",
|
||||||
"wasmer-llvm-backend 0.1.0",
|
"wasmer-llvm-backend 0.1.0",
|
||||||
"wasmer-runtime-core 0.2.1",
|
"wasmer-runtime-core 0.2.1",
|
||||||
]
|
]
|
||||||
@ -1406,6 +1468,7 @@ version = "0.2.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"wabt 0.7.4 (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.2.0",
|
"wasmer-clif-backend 0.2.0",
|
||||||
|
"wasmer-dynasm-backend 0.1.0",
|
||||||
"wasmer-llvm-backend 0.1.0",
|
"wasmer-llvm-backend 0.1.0",
|
||||||
"wasmer-runtime-core 0.2.1",
|
"wasmer-runtime-core 0.2.1",
|
||||||
]
|
]
|
||||||
@ -1532,6 +1595,8 @@ dependencies = [
|
|||||||
"checksum csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd1c44c58078cfbeaf11fbb3eac9ae5534c23004ed770cc4bfb48e658ae4f04"
|
"checksum csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd1c44c58078cfbeaf11fbb3eac9ae5534c23004ed770cc4bfb48e658ae4f04"
|
||||||
"checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65"
|
"checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65"
|
||||||
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
|
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
|
||||||
|
"checksum dynasm 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b77e128faecc4d16cff7cae96c0c9e809f687f748a0dbc4d017996e48240a991"
|
||||||
|
"checksum dynasmrt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c408a211e7f5762829f5e46bdff0c14bc3b1517a21a4bb781c716bf88b0c68"
|
||||||
"checksum either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c67353c641dc847124ea1902d69bd753dee9bb3beff9aa3662ecf86c971d1fac"
|
"checksum either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c67353c641dc847124ea1902d69bd753dee9bb3beff9aa3662ecf86c971d1fac"
|
||||||
"checksum enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7798e7da2d4cb0d6d6fc467e8d6b5bf247e9e989f786dde1732d79899c32bb10"
|
"checksum enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7798e7da2d4cb0d6d6fc467e8d6b5bf247e9e989f786dde1732d79899c32bb10"
|
||||||
"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a"
|
"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a"
|
||||||
@ -1562,6 +1627,7 @@ dependencies = [
|
|||||||
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
|
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
|
||||||
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
||||||
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
|
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
|
||||||
|
"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
|
||||||
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
|
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
|
||||||
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
|
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
|
||||||
"checksum nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "921f61dc817b379d0834e45d5ec45beaacfae97082090a49c2cf30dcbc30206f"
|
"checksum nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "921f61dc817b379d0834e45d5ec45beaacfae97082090a49c2cf30dcbc30206f"
|
||||||
@ -1570,6 +1636,7 @@ dependencies = [
|
|||||||
"checksum nom 4.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22293d25d3f33a8567cc8a1dc20f40c7eeb761ce83d0fcca059858580790cac3"
|
"checksum nom 4.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22293d25d3f33a8567cc8a1dc20f40c7eeb761ce83d0fcca059858580790cac3"
|
||||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||||
"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
|
"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
|
||||||
|
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
|
||||||
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
||||||
"checksum page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f89ef58b3d32420dbd1a43d2f38ae92f6239ef12bb556ab09ca55445f5a67242"
|
"checksum page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f89ef58b3d32420dbd1a43d2f38ae92f6239ef12bb556ab09ca55445f5a67242"
|
||||||
"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
|
"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
|
||||||
@ -1623,6 +1690,7 @@ dependencies = [
|
|||||||
"checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2"
|
"checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2"
|
||||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||||
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
|
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
|
||||||
|
"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
|
||||||
"checksum target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4af5e2227f0b887d591d3724b796a96eff04226104d872f5b3883fcd427d64b9"
|
"checksum target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4af5e2227f0b887d591d3724b796a96eff04226104d872f5b3883fcd427d64b9"
|
||||||
"checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a"
|
"checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a"
|
||||||
"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
|
"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
|
||||||
|
@ -25,12 +25,11 @@ wasmer-clif-backend = { path = "lib/clif-backend" }
|
|||||||
wasmer-runtime = { path = "lib/runtime" }
|
wasmer-runtime = { path = "lib/runtime" }
|
||||||
wasmer-runtime-core = { path = "lib/runtime-core" }
|
wasmer-runtime-core = { path = "lib/runtime-core" }
|
||||||
wasmer-emscripten = { path = "lib/emscripten" }
|
wasmer-emscripten = { path = "lib/emscripten" }
|
||||||
|
|
||||||
[target.'cfg(not(windows))'.dependencies]
|
|
||||||
wasmer-llvm-backend = { path = "lib/llvm-backend", optional = true }
|
wasmer-llvm-backend = { path = "lib/llvm-backend", optional = true }
|
||||||
|
wasmer-dynasm-backend = { path = "lib/dynasm-backend", optional = true }
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["lib/clif-backend", "lib/runtime", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", "lib/runtime-c-api", "lib/llvm-backend"]
|
members = ["lib/clif-backend", "lib/dynasm-backend", "lib/runtime", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", "lib/runtime-c-api", "lib/llvm-backend"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
wabt = "0.7.2"
|
wabt = "0.7.2"
|
||||||
@ -42,3 +41,4 @@ default = ["fast-tests"]
|
|||||||
# This feature will allow cargo test to run much faster
|
# This feature will allow cargo test to run much faster
|
||||||
fast-tests = []
|
fast-tests = []
|
||||||
llvm = ["wasmer-llvm-backend"]
|
llvm = ["wasmer-llvm-backend"]
|
||||||
|
dynasm = ["wasmer-dynasm-backend"]
|
10
Makefile
10
Makefile
@ -28,23 +28,29 @@ integration-tests: release
|
|||||||
|
|
||||||
lint:
|
lint:
|
||||||
cargo fmt --all -- --check
|
cargo fmt --all -- --check
|
||||||
cargo clippy --all
|
cargo +nightly clippy --all
|
||||||
|
|
||||||
precommit: lint test
|
precommit: lint test
|
||||||
|
|
||||||
test:
|
test:
|
||||||
# We use one thread so the emscripten stdouts doesn't collide
|
# We use one thread so the emscripten stdouts doesn't collide
|
||||||
cargo test --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests -- $(runargs)
|
cargo test --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-dynasm-backend -- $(runargs)
|
||||||
# cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs)
|
# cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs)
|
||||||
cargo test --manifest-path lib/spectests/Cargo.toml --features clif
|
cargo test --manifest-path lib/spectests/Cargo.toml --features clif
|
||||||
cargo test --manifest-path lib/spectests/Cargo.toml --features llvm
|
cargo test --manifest-path lib/spectests/Cargo.toml --features llvm
|
||||||
cargo build -p wasmer-runtime-c-api
|
cargo build -p wasmer-runtime-c-api
|
||||||
cargo test -p wasmer-runtime-c-api -- --nocapture
|
cargo test -p wasmer-runtime-c-api -- --nocapture
|
||||||
|
|
||||||
|
test-nightly:
|
||||||
|
cargo test --manifest-path lib/spectests/Cargo.toml --features dynasm
|
||||||
|
|
||||||
test-emscripten:
|
test-emscripten:
|
||||||
cargo test --manifest-path lib/emscripten/Cargo.toml --features clif -- --test-threads=1 $(runargs)
|
cargo test --manifest-path lib/emscripten/Cargo.toml --features clif -- --test-threads=1 $(runargs)
|
||||||
cargo test --manifest-path lib/emscripten/Cargo.toml --features llvm -- --test-threads=1 $(runargs)
|
cargo test --manifest-path lib/emscripten/Cargo.toml --features llvm -- --test-threads=1 $(runargs)
|
||||||
|
|
||||||
|
test-emscripten-nightly:
|
||||||
|
cargo test --manifest-path lib/emscripten/Cargo.toml --features dynasm -- --test-threads=1 $(runargs)
|
||||||
|
|
||||||
release:
|
release:
|
||||||
# If you are in OS-X, you will need mingw-w64 for cross compiling to windows
|
# If you are in OS-X, you will need mingw-w64 for cross compiling to windows
|
||||||
# brew install mingw-w64
|
# brew install mingw-w64
|
||||||
|
37
examples/single_pass_tests/br_table.wat
Normal file
37
examples/single_pass_tests/br_table.wat
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
(module
|
||||||
|
(func $main (export "main")
|
||||||
|
(i32.eq (call $test (i32.const 0)) (i32.const 2))
|
||||||
|
(i32.eq (call $test (i32.const 1)) (i32.const 0))
|
||||||
|
(i32.eq (call $test (i32.const 2)) (i32.const 1))
|
||||||
|
(i32.eq (call $test (i32.const 3)) (i32.const 3))
|
||||||
|
(i32.eq (call $test (i32.const 4)) (i32.const 3))
|
||||||
|
(i32.and)
|
||||||
|
(i32.and)
|
||||||
|
(i32.and)
|
||||||
|
(i32.and)
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.eq)
|
||||||
|
(br_if 0)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $test (param $p i32) (result i32)
|
||||||
|
(block
|
||||||
|
(block
|
||||||
|
(block
|
||||||
|
(block
|
||||||
|
(block
|
||||||
|
(get_local $p)
|
||||||
|
(br_table 2 0 1 3)
|
||||||
|
)
|
||||||
|
(return (i32.const 0))
|
||||||
|
)
|
||||||
|
(return (i32.const 1))
|
||||||
|
)
|
||||||
|
(return (i32.const 2))
|
||||||
|
)
|
||||||
|
(return (i32.const 3))
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
23
examples/single_pass_tests/call.wat
Normal file
23
examples/single_pass_tests/call.wat
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
(module
|
||||||
|
(func $main (export "main")
|
||||||
|
(local $a i32)
|
||||||
|
(block
|
||||||
|
(set_local $a (i32.const 33))
|
||||||
|
(i32.const 11)
|
||||||
|
(call $foo (get_local $a))
|
||||||
|
(i32.add)
|
||||||
|
(i32.const 86)
|
||||||
|
(i32.eq)
|
||||||
|
(br_if 0)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $foo (param $input i32) (result i32)
|
||||||
|
(local $a i32)
|
||||||
|
(set_local $a (i32.const 42))
|
||||||
|
(get_local $a)
|
||||||
|
(get_local $input)
|
||||||
|
(i32.add)
|
||||||
|
)
|
||||||
|
)
|
25
examples/single_pass_tests/call_indirect.wat
Normal file
25
examples/single_pass_tests/call_indirect.wat
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
(module
|
||||||
|
(type $binop (func (param i32 i32) (result i32)))
|
||||||
|
(table 1 100 anyfunc)
|
||||||
|
(elem (i32.const 5) $sub)
|
||||||
|
(elem (i32.const 10) $add)
|
||||||
|
|
||||||
|
(func $main (export "main")
|
||||||
|
(if (i32.eq (call_indirect (type $binop) (i32.const 42) (i32.const 1) (i32.const 10)) (i32.const 43))
|
||||||
|
(then)
|
||||||
|
(else unreachable)
|
||||||
|
)
|
||||||
|
(if (i32.eq (call_indirect (type $binop) (i32.const 42) (i32.const 1) (i32.const 5)) (i32.const 41))
|
||||||
|
(then)
|
||||||
|
(else unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $add (param i32) (param i32) (result i32)
|
||||||
|
(i32.add (get_local 0) (get_local 1))
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $sub (param i32) (param i32) (result i32)
|
||||||
|
(i32.sub (get_local 0) (get_local 1))
|
||||||
|
)
|
||||||
|
)
|
36
examples/single_pass_tests/div.wat
Normal file
36
examples/single_pass_tests/div.wat
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
(module
|
||||||
|
(func $main (export "main")
|
||||||
|
(i32.const 1)
|
||||||
|
(if (i32.ne (i32.div_s (i32.const 2) (i32.const -1)) (i32.const -2))
|
||||||
|
(then unreachable)
|
||||||
|
)
|
||||||
|
(i32.const 2)
|
||||||
|
(if (i32.ne (i32.div_u (i32.const 2) (i32.const -1)) (i32.const 0))
|
||||||
|
(then unreachable)
|
||||||
|
)
|
||||||
|
(i32.const 3)
|
||||||
|
(if (i32.ne (i32.div_u (i32.const 10) (i32.const 5)) (i32.const 2))
|
||||||
|
(then unreachable)
|
||||||
|
)
|
||||||
|
(i32.const 4)
|
||||||
|
(if (i64.ne (i64.div_s (i64.const 300000000000) (i64.const -1)) (i64.const -300000000000))
|
||||||
|
(then unreachable)
|
||||||
|
)
|
||||||
|
(i32.const 5)
|
||||||
|
(if (i64.ne (i64.div_u (i64.const 300000000000) (i64.const -1)) (i64.const 0))
|
||||||
|
(then unreachable)
|
||||||
|
)
|
||||||
|
(i32.const 6)
|
||||||
|
(if (i64.ne (i64.div_u (i64.const 300000000000) (i64.const 2)) (i64.const 150000000000))
|
||||||
|
(then unreachable)
|
||||||
|
)
|
||||||
|
(i32.add)
|
||||||
|
(i32.add)
|
||||||
|
(i32.add)
|
||||||
|
(i32.add)
|
||||||
|
(i32.add)
|
||||||
|
(if (i32.ne (i32.const 21))
|
||||||
|
(then unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
26
examples/single_pass_tests/global.wat
Normal file
26
examples/single_pass_tests/global.wat
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
(module
|
||||||
|
(global $g1 (mut i32) (i32.const 0))
|
||||||
|
(global $g2 (mut i32) (i32.const 99))
|
||||||
|
(func $main (export "main")
|
||||||
|
(if (i32.eq (get_global $g1) (i32.const 0))
|
||||||
|
(then)
|
||||||
|
(else unreachable)
|
||||||
|
)
|
||||||
|
(if (i32.eq (get_global $g2) (i32.const 99))
|
||||||
|
(then)
|
||||||
|
(else unreachable)
|
||||||
|
)
|
||||||
|
|
||||||
|
(set_global $g1 (i32.add (get_global $g1) (i32.const 1)))
|
||||||
|
(set_global $g2 (i32.sub (get_global $g2) (i32.const 1)))
|
||||||
|
|
||||||
|
(if (i32.eq (get_global $g1) (i32.const 1))
|
||||||
|
(then)
|
||||||
|
(else unreachable)
|
||||||
|
)
|
||||||
|
(if (i32.eq (get_global $g2) (i32.const 98))
|
||||||
|
(then)
|
||||||
|
(else unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
44
examples/single_pass_tests/i32.wat
Normal file
44
examples/single_pass_tests/i32.wat
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
(module
|
||||||
|
(func $main (export "main") (result i32)
|
||||||
|
(local $v1 i32)
|
||||||
|
(block
|
||||||
|
(i32.const 10)
|
||||||
|
(set_local $v1)
|
||||||
|
|
||||||
|
(i32.const 42)
|
||||||
|
(get_local $v1)
|
||||||
|
(i32.add)
|
||||||
|
(i32.const 53)
|
||||||
|
(i32.eq)
|
||||||
|
(br_if 0)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.const -100)
|
||||||
|
(i32.const 41)
|
||||||
|
(i32.lt_s)
|
||||||
|
(i32.sub)
|
||||||
|
(br_if 0)
|
||||||
|
|
||||||
|
(i32.const -100)
|
||||||
|
(i32.const 41)
|
||||||
|
(i32.lt_u)
|
||||||
|
(br_if 0)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.const 100)
|
||||||
|
(i32.const -41)
|
||||||
|
(i32.gt_s)
|
||||||
|
(i32.sub)
|
||||||
|
(br_if 0)
|
||||||
|
|
||||||
|
(i32.const 100)
|
||||||
|
(i32.const -41)
|
||||||
|
(i32.gt_u)
|
||||||
|
(br_if 0)
|
||||||
|
|
||||||
|
(i32.const 0)
|
||||||
|
(return)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
48
examples/single_pass_tests/i64.wat
Normal file
48
examples/single_pass_tests/i64.wat
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
(module
|
||||||
|
(func $main (export "main") (result i64)
|
||||||
|
(local $v1 i64)
|
||||||
|
(block
|
||||||
|
(i64.const 10)
|
||||||
|
(set_local $v1)
|
||||||
|
|
||||||
|
(i64.const 42)
|
||||||
|
(get_local $v1)
|
||||||
|
(i64.add)
|
||||||
|
(i64.const 53)
|
||||||
|
(i64.eq)
|
||||||
|
(br_if 0)
|
||||||
|
|
||||||
|
(i64.const 1)
|
||||||
|
(i64.const -100)
|
||||||
|
(i64.const 41)
|
||||||
|
(i64.lt_s)
|
||||||
|
(i64.extend_u/i32)
|
||||||
|
(i64.sub)
|
||||||
|
(i32.wrap/i64)
|
||||||
|
(br_if 0)
|
||||||
|
|
||||||
|
(i64.const -100)
|
||||||
|
(i64.const 41)
|
||||||
|
(i64.lt_u)
|
||||||
|
(br_if 0)
|
||||||
|
|
||||||
|
(i64.const 1)
|
||||||
|
(i64.const 100)
|
||||||
|
(i64.const -41)
|
||||||
|
(i64.gt_s)
|
||||||
|
(i64.extend_u/i32)
|
||||||
|
(i64.sub)
|
||||||
|
(i32.wrap/i64)
|
||||||
|
(br_if 0)
|
||||||
|
|
||||||
|
(i64.const 100)
|
||||||
|
(i64.const -41)
|
||||||
|
(i64.gt_u)
|
||||||
|
(br_if 0)
|
||||||
|
|
||||||
|
(i64.const 0)
|
||||||
|
(return)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
33
examples/single_pass_tests/if_else.wat
Normal file
33
examples/single_pass_tests/if_else.wat
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
(module
|
||||||
|
(func $main (export "main")
|
||||||
|
(local $a i32)
|
||||||
|
(set_local $a (i32.const 33))
|
||||||
|
|
||||||
|
(block
|
||||||
|
(call $foo (if (result i32) (i32.eq (get_local $a) (i32.const 33))
|
||||||
|
(then (i32.const 1))
|
||||||
|
(else (i32.const 2))
|
||||||
|
))
|
||||||
|
(i32.eq (i32.const 43))
|
||||||
|
(br_if 0)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(call $foo (if (result i32) (i32.eq (get_local $a) (i32.const 30))
|
||||||
|
(then (i32.const 1))
|
||||||
|
(else (i32.const 2))
|
||||||
|
))
|
||||||
|
(i32.eq (i32.const 44))
|
||||||
|
(br_if 0)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $foo (param $input i32) (result i32)
|
||||||
|
(local $a i32)
|
||||||
|
(set_local $a (i32.const 42))
|
||||||
|
(get_local $a)
|
||||||
|
(get_local $input)
|
||||||
|
(i32.add)
|
||||||
|
)
|
||||||
|
)
|
16
examples/single_pass_tests/loop.wat
Normal file
16
examples/single_pass_tests/loop.wat
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
(module
|
||||||
|
(func $main (export "main") (result i32)
|
||||||
|
(local $count i32)
|
||||||
|
(local $sum i32)
|
||||||
|
(loop (result i32)
|
||||||
|
(set_local $count (i32.add (get_local $count) (i32.const 1)))
|
||||||
|
(set_local $sum (i32.add (get_local $sum) (get_local $count)))
|
||||||
|
(i32.sub (i32.const 1) (i32.eq
|
||||||
|
(get_local $count)
|
||||||
|
(i32.const 100000)
|
||||||
|
))
|
||||||
|
(br_if 0)
|
||||||
|
(get_local $sum)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
90
examples/single_pass_tests/memory.wat
Normal file
90
examples/single_pass_tests/memory.wat
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
(module
|
||||||
|
(memory 1)
|
||||||
|
(func $main (export "main")
|
||||||
|
(call $test_stack_layout)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $test_stack_layout
|
||||||
|
(local $addr i32)
|
||||||
|
(set_local $addr (i32.const 16))
|
||||||
|
|
||||||
|
(i32.store (get_local $addr) (i32.const 10))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 655360))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 11))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 720896))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 12))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 786432))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 13))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 851968))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 14))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 917504))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 15))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 983040))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 16))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 1048576))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 17))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 1114112))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 18))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 1179648))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 19))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 1245184))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
)
|
||||||
|
)
|
20
examples/single_pass_tests/select.wat
Normal file
20
examples/single_pass_tests/select.wat
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
(module
|
||||||
|
(func $main (export "main")
|
||||||
|
(if (i32.eq (select
|
||||||
|
(i32.const 10)
|
||||||
|
(i32.const 20)
|
||||||
|
(i32.const 1)
|
||||||
|
) (i32.const 10))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
(if (i32.eq (select
|
||||||
|
(i32.const 10)
|
||||||
|
(i32.const 20)
|
||||||
|
(i32.const 0)
|
||||||
|
) (i32.const 20))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
11
examples/single_pass_tests/tee_local.wat
Normal file
11
examples/single_pass_tests/tee_local.wat
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
(module
|
||||||
|
(func $main (export "main")
|
||||||
|
(local $x i32)
|
||||||
|
(tee_local $x (i32.const 3))
|
||||||
|
(i32.add (i32.const 4))
|
||||||
|
(if (i32.eq (i32.const 7))
|
||||||
|
(then)
|
||||||
|
(else unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
38
examples/single_pass_tests/unwinding.wat
Normal file
38
examples/single_pass_tests/unwinding.wat
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
(module
|
||||||
|
(func $main (export "main")
|
||||||
|
(i32.const 5)
|
||||||
|
(block (result i32)
|
||||||
|
(i32.const 10)
|
||||||
|
(block
|
||||||
|
(i32.const 20)
|
||||||
|
(block
|
||||||
|
(i32.const 50)
|
||||||
|
(br 1)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.add)
|
||||||
|
(if (i32.eq (i32.const 15))
|
||||||
|
(then)
|
||||||
|
(else unreachable)
|
||||||
|
)
|
||||||
|
|
||||||
|
(block (result i32)
|
||||||
|
(i32.const 10)
|
||||||
|
(block (result i32)
|
||||||
|
(i32.const 20)
|
||||||
|
(block
|
||||||
|
(i32.const 50)
|
||||||
|
(br 1)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
(i32.add)
|
||||||
|
)
|
||||||
|
(if (i32.eq (i32.const 60))
|
||||||
|
(then)
|
||||||
|
(else unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
18
lib/dynasm-backend/Cargo.toml
Normal file
18
lib/dynasm-backend/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "wasmer-dynasm-backend"
|
||||||
|
version = "0.1.0"
|
||||||
|
repository = "https://github.com/wasmerio/wasmer"
|
||||||
|
description = "Wasmer runtime Dynasm compiler backend"
|
||||||
|
license = "MIT"
|
||||||
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
wasmer-runtime-core = { path = "../runtime-core" }
|
||||||
|
wasmparser = "0.28.0"
|
||||||
|
dynasm = "0.3.1"
|
||||||
|
dynasmrt = "0.3.1"
|
||||||
|
lazy_static = "1.2.0"
|
||||||
|
byteorder = "1"
|
||||||
|
nix = "0.13.0"
|
||||||
|
libc = "0.2.49"
|
33
lib/dynasm-backend/src/codegen.rs
Normal file
33
lib/dynasm-backend/src/codegen.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use wasmer_runtime_core::{
|
||||||
|
backend::{FuncResolver, ProtectedCaller},
|
||||||
|
module::ModuleInfo,
|
||||||
|
structures::Map,
|
||||||
|
types::{FuncIndex, FuncSig, SigIndex},
|
||||||
|
};
|
||||||
|
use wasmparser::{Operator, Type as WpType};
|
||||||
|
|
||||||
|
pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator, PC: ProtectedCaller, FR: FuncResolver> {
|
||||||
|
fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), CodegenError>;
|
||||||
|
fn next_function(&mut self) -> Result<&mut FCG, CodegenError>;
|
||||||
|
fn finalize(self, module_info: &ModuleInfo) -> Result<(PC, FR), CodegenError>;
|
||||||
|
fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), CodegenError>;
|
||||||
|
fn feed_function_signatures(
|
||||||
|
&mut self,
|
||||||
|
assoc: Map<FuncIndex, SigIndex>,
|
||||||
|
) -> Result<(), CodegenError>;
|
||||||
|
fn feed_import_function(&mut self) -> Result<(), CodegenError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FunctionCodeGenerator {
|
||||||
|
fn feed_return(&mut self, ty: WpType) -> Result<(), CodegenError>;
|
||||||
|
fn feed_param(&mut self, ty: WpType) -> Result<(), CodegenError>;
|
||||||
|
fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError>;
|
||||||
|
fn begin_body(&mut self) -> Result<(), CodegenError>;
|
||||||
|
fn feed_opcode(&mut self, op: Operator, module_info: &ModuleInfo) -> Result<(), CodegenError>;
|
||||||
|
fn finalize(&mut self) -> Result<(), CodegenError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CodegenError {
|
||||||
|
pub message: &'static str,
|
||||||
|
}
|
5261
lib/dynasm-backend/src/codegen_x64.rs
Normal file
5261
lib/dynasm-backend/src/codegen_x64.rs
Normal file
File diff suppressed because it is too large
Load Diff
87
lib/dynasm-backend/src/lib.rs
Normal file
87
lib/dynasm-backend/src/lib.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#![feature(proc_macro_hygiene)]
|
||||||
|
|
||||||
|
#[cfg(not(any(
|
||||||
|
all(target_os = "macos", target_arch = "x86_64"),
|
||||||
|
all(target_os = "linux", target_arch = "x86_64"),
|
||||||
|
)))]
|
||||||
|
compile_error!("This crate doesn't yet support compiling on operating systems other than linux and macos and architectures other than x86_64");
|
||||||
|
|
||||||
|
extern crate dynasmrt;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate dynasm;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
|
||||||
|
extern crate byteorder;
|
||||||
|
|
||||||
|
mod codegen;
|
||||||
|
mod codegen_x64;
|
||||||
|
mod parse;
|
||||||
|
mod protect_unix;
|
||||||
|
mod stack;
|
||||||
|
|
||||||
|
use crate::codegen::{CodegenError, ModuleCodeGenerator};
|
||||||
|
use crate::parse::LoadError;
|
||||||
|
use wasmer_runtime_core::{
|
||||||
|
backend::{sys::Memory, Backend, CacheGen, Compiler, Token},
|
||||||
|
cache::{Artifact, Error as CacheError},
|
||||||
|
error::{CompileError, CompileResult},
|
||||||
|
module::{ModuleInfo, ModuleInner},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Placeholder;
|
||||||
|
impl CacheGen for Placeholder {
|
||||||
|
fn generate_cache(
|
||||||
|
&self,
|
||||||
|
_module: &ModuleInner,
|
||||||
|
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> {
|
||||||
|
Err(CacheError::Unknown(
|
||||||
|
"the dynasm backend doesn't support caching yet".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SinglePassCompiler {}
|
||||||
|
impl SinglePassCompiler {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Compiler for SinglePassCompiler {
|
||||||
|
fn compile(&self, wasm: &[u8], _: Token) -> CompileResult<ModuleInner> {
|
||||||
|
let mut mcg = codegen_x64::X64ModuleCodeGenerator::new();
|
||||||
|
let info = parse::read_module(wasm, Backend::Dynasm, &mut mcg)?;
|
||||||
|
let (ec, resolver) = mcg.finalize(&info)?;
|
||||||
|
Ok(ModuleInner {
|
||||||
|
cache_gen: Box::new(Placeholder),
|
||||||
|
func_resolver: Box::new(resolver),
|
||||||
|
protected_caller: Box::new(ec),
|
||||||
|
info: info,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn from_cache(&self, _artifact: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
|
||||||
|
Err(CacheError::Unknown(
|
||||||
|
"the dynasm backend doesn't support caching yet".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CodegenError> for CompileError {
|
||||||
|
fn from(other: CodegenError) -> CompileError {
|
||||||
|
CompileError::InternalError {
|
||||||
|
msg: other.message.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LoadError> for CompileError {
|
||||||
|
fn from(other: LoadError) -> CompileError {
|
||||||
|
CompileError::InternalError {
|
||||||
|
msg: format!("{:?}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
441
lib/dynasm-backend/src/parse.rs
Normal file
441
lib/dynasm-backend/src/parse.rs
Normal file
@ -0,0 +1,441 @@
|
|||||||
|
use crate::codegen::{CodegenError, FunctionCodeGenerator, ModuleCodeGenerator};
|
||||||
|
use wasmer_runtime_core::{
|
||||||
|
backend::{Backend, FuncResolver, ProtectedCaller},
|
||||||
|
module::{
|
||||||
|
DataInitializer, ExportIndex, ImportName, ModuleInfo, StringTable, StringTableBuilder,
|
||||||
|
TableInitializer,
|
||||||
|
},
|
||||||
|
structures::{Map, TypedIndex},
|
||||||
|
types::{
|
||||||
|
ElementType, FuncIndex, FuncSig, GlobalDescriptor, GlobalIndex, GlobalInit,
|
||||||
|
ImportedGlobalIndex, Initializer, MemoryDescriptor, MemoryIndex, SigIndex, TableDescriptor,
|
||||||
|
TableIndex, Type, Value,
|
||||||
|
},
|
||||||
|
units::Pages,
|
||||||
|
};
|
||||||
|
use wasmparser::{
|
||||||
|
BinaryReaderError, Data, DataKind, Element, ElementKind, Export, ExternalKind, FuncType,
|
||||||
|
Import, ImportSectionEntryType, InitExpr, ModuleReader, Operator, SectionCode, Type as WpType,
|
||||||
|
WasmDecoder,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum LoadError {
|
||||||
|
Parse(BinaryReaderError),
|
||||||
|
Codegen(CodegenError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BinaryReaderError> for LoadError {
|
||||||
|
fn from(other: BinaryReaderError) -> LoadError {
|
||||||
|
LoadError::Parse(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CodegenError> for LoadError {
|
||||||
|
fn from(other: CodegenError) -> LoadError {
|
||||||
|
LoadError::Codegen(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(bytes: &[u8]) -> Result<(), LoadError> {
|
||||||
|
let mut parser = wasmparser::ValidatingParser::new(
|
||||||
|
bytes,
|
||||||
|
Some(wasmparser::ValidatingParserConfig {
|
||||||
|
operator_config: wasmparser::OperatorValidatorConfig {
|
||||||
|
enable_threads: false,
|
||||||
|
enable_reference_types: false,
|
||||||
|
enable_simd: false,
|
||||||
|
enable_bulk_memory: false,
|
||||||
|
},
|
||||||
|
mutable_global_imports: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let state = parser.read();
|
||||||
|
match *state {
|
||||||
|
wasmparser::ParserState::EndWasm => break Ok(()),
|
||||||
|
wasmparser::ParserState::Error(err) => Err(LoadError::Parse(err))?,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_module<
|
||||||
|
MCG: ModuleCodeGenerator<FCG, PC, FR>,
|
||||||
|
FCG: FunctionCodeGenerator,
|
||||||
|
PC: ProtectedCaller,
|
||||||
|
FR: FuncResolver,
|
||||||
|
>(
|
||||||
|
wasm: &[u8],
|
||||||
|
backend: Backend,
|
||||||
|
mcg: &mut MCG,
|
||||||
|
) -> Result<ModuleInfo, LoadError> {
|
||||||
|
validate(wasm)?;
|
||||||
|
let mut 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: Default::default(),
|
||||||
|
|
||||||
|
data_initializers: Vec::new(),
|
||||||
|
elem_initializers: Vec::new(),
|
||||||
|
|
||||||
|
start_func: None,
|
||||||
|
|
||||||
|
func_assoc: Map::new(),
|
||||||
|
signatures: Map::new(),
|
||||||
|
backend: backend,
|
||||||
|
|
||||||
|
namespace_table: StringTable::new(),
|
||||||
|
name_table: StringTable::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut reader = ModuleReader::new(wasm)?;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if reader.eof() {
|
||||||
|
return Ok(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
let section = reader.read()?;
|
||||||
|
|
||||||
|
match section.code {
|
||||||
|
SectionCode::Type => {
|
||||||
|
let type_reader = section.get_type_section_reader()?;
|
||||||
|
|
||||||
|
for ty in type_reader {
|
||||||
|
let ty = ty?;
|
||||||
|
info.signatures.push(func_type_to_func_sig(ty)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
mcg.feed_signatures(info.signatures.clone())?;
|
||||||
|
}
|
||||||
|
SectionCode::Import => {
|
||||||
|
let import_reader = section.get_import_section_reader()?;
|
||||||
|
let mut namespace_builder = StringTableBuilder::new();
|
||||||
|
let mut name_builder = StringTableBuilder::new();
|
||||||
|
|
||||||
|
for import in import_reader {
|
||||||
|
let Import { module, field, ty } = import?;
|
||||||
|
|
||||||
|
let namespace_index = namespace_builder.register(module);
|
||||||
|
let name_index = name_builder.register(field);
|
||||||
|
let import_name = ImportName {
|
||||||
|
namespace_index,
|
||||||
|
name_index,
|
||||||
|
};
|
||||||
|
|
||||||
|
match ty {
|
||||||
|
ImportSectionEntryType::Function(sigindex) => {
|
||||||
|
let sigindex = SigIndex::new(sigindex as usize);
|
||||||
|
info.imported_functions.push(import_name);
|
||||||
|
info.func_assoc.push(sigindex);
|
||||||
|
mcg.feed_import_function()?;
|
||||||
|
}
|
||||||
|
ImportSectionEntryType::Table(table_ty) => {
|
||||||
|
assert_eq!(table_ty.element_type, WpType::AnyFunc);
|
||||||
|
let table_desc = TableDescriptor {
|
||||||
|
element: ElementType::Anyfunc,
|
||||||
|
minimum: table_ty.limits.initial,
|
||||||
|
maximum: table_ty.limits.maximum,
|
||||||
|
};
|
||||||
|
|
||||||
|
info.imported_tables.push((import_name, table_desc));
|
||||||
|
}
|
||||||
|
ImportSectionEntryType::Memory(memory_ty) => {
|
||||||
|
let mem_desc = MemoryDescriptor {
|
||||||
|
minimum: Pages(memory_ty.limits.initial),
|
||||||
|
maximum: memory_ty.limits.maximum.map(|max| Pages(max)),
|
||||||
|
shared: memory_ty.shared,
|
||||||
|
};
|
||||||
|
info.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.namespace_table = namespace_builder.finish();
|
||||||
|
info.name_table = name_builder.finish();
|
||||||
|
}
|
||||||
|
SectionCode::Function => {
|
||||||
|
let func_decl_reader = section.get_function_section_reader()?;
|
||||||
|
|
||||||
|
for sigindex in func_decl_reader {
|
||||||
|
let sigindex = sigindex?;
|
||||||
|
|
||||||
|
let sigindex = SigIndex::new(sigindex as usize);
|
||||||
|
info.func_assoc.push(sigindex);
|
||||||
|
}
|
||||||
|
|
||||||
|
mcg.feed_function_signatures(info.func_assoc.clone())?;
|
||||||
|
}
|
||||||
|
SectionCode::Table => {
|
||||||
|
let table_decl_reader = section.get_table_section_reader()?;
|
||||||
|
|
||||||
|
for table_ty in table_decl_reader {
|
||||||
|
let table_ty = table_ty?;
|
||||||
|
|
||||||
|
let table_desc = TableDescriptor {
|
||||||
|
element: ElementType::Anyfunc,
|
||||||
|
minimum: table_ty.limits.initial,
|
||||||
|
maximum: table_ty.limits.maximum,
|
||||||
|
};
|
||||||
|
|
||||||
|
info.tables.push(table_desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionCode::Memory => {
|
||||||
|
let mem_decl_reader = section.get_memory_section_reader()?;
|
||||||
|
|
||||||
|
for memory_ty in mem_decl_reader {
|
||||||
|
let memory_ty = memory_ty?;
|
||||||
|
|
||||||
|
let mem_desc = MemoryDescriptor {
|
||||||
|
minimum: Pages(memory_ty.limits.initial),
|
||||||
|
maximum: memory_ty.limits.maximum.map(|max| Pages(max)),
|
||||||
|
shared: memory_ty.shared,
|
||||||
|
};
|
||||||
|
|
||||||
|
info.memories.push(mem_desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionCode::Global => {
|
||||||
|
let global_decl_reader = section.get_global_section_reader()?;
|
||||||
|
|
||||||
|
for global in global_decl_reader {
|
||||||
|
let global = global?;
|
||||||
|
|
||||||
|
let desc = GlobalDescriptor {
|
||||||
|
mutable: global.ty.mutable,
|
||||||
|
ty: wp_type_to_type(global.ty.content_type)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
let global_init = GlobalInit {
|
||||||
|
desc,
|
||||||
|
init: eval_init_expr(&global.init_expr)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
info.globals.push(global_init);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionCode::Export => {
|
||||||
|
let export_reader = section.get_export_section_reader()?;
|
||||||
|
|
||||||
|
for export in export_reader {
|
||||||
|
let Export { field, kind, index } = export?;
|
||||||
|
|
||||||
|
let export_index = match kind {
|
||||||
|
ExternalKind::Function => ExportIndex::Func(FuncIndex::new(index as usize)),
|
||||||
|
ExternalKind::Table => ExportIndex::Table(TableIndex::new(index as usize)),
|
||||||
|
ExternalKind::Memory => {
|
||||||
|
ExportIndex::Memory(MemoryIndex::new(index as usize))
|
||||||
|
}
|
||||||
|
ExternalKind::Global => {
|
||||||
|
ExportIndex::Global(GlobalIndex::new(index as usize))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
info.exports.insert(field.to_string(), export_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionCode::Start => {
|
||||||
|
let start_index = section.get_start_section_content()?;
|
||||||
|
|
||||||
|
info.start_func = Some(FuncIndex::new(start_index as usize));
|
||||||
|
}
|
||||||
|
SectionCode::Element => {
|
||||||
|
let element_reader = section.get_element_section_reader()?;
|
||||||
|
|
||||||
|
for element in element_reader {
|
||||||
|
let Element { kind, items } = element?;
|
||||||
|
|
||||||
|
match kind {
|
||||||
|
ElementKind::Active {
|
||||||
|
table_index,
|
||||||
|
init_expr,
|
||||||
|
} => {
|
||||||
|
let table_index = TableIndex::new(table_index as usize);
|
||||||
|
let base = eval_init_expr(&init_expr)?;
|
||||||
|
let items_reader = items.get_items_reader()?;
|
||||||
|
|
||||||
|
let elements: Vec<_> = items_reader
|
||||||
|
.into_iter()
|
||||||
|
.map(|res| res.map(|index| FuncIndex::new(index as usize)))
|
||||||
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
|
let table_init = TableInitializer {
|
||||||
|
table_index,
|
||||||
|
base,
|
||||||
|
elements,
|
||||||
|
};
|
||||||
|
|
||||||
|
info.elem_initializers.push(table_init);
|
||||||
|
}
|
||||||
|
ElementKind::Passive(_ty) => {
|
||||||
|
return Err(BinaryReaderError {
|
||||||
|
message: "passive tables are not yet supported",
|
||||||
|
offset: -1isize as usize,
|
||||||
|
}
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionCode::Code => {
|
||||||
|
let mut code_reader = section.get_code_section_reader()?;
|
||||||
|
if code_reader.get_count() as usize > info.func_assoc.len() {
|
||||||
|
return Err(BinaryReaderError {
|
||||||
|
message: "code_reader.get_count() > info.func_assoc.len()",
|
||||||
|
offset: ::std::usize::MAX,
|
||||||
|
}
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
mcg.check_precondition(&info)?;
|
||||||
|
for i in 0..code_reader.get_count() {
|
||||||
|
let item = code_reader.read()?;
|
||||||
|
let fcg = mcg.next_function()?;
|
||||||
|
let sig = info
|
||||||
|
.signatures
|
||||||
|
.get(
|
||||||
|
*info
|
||||||
|
.func_assoc
|
||||||
|
.get(FuncIndex::new(i as usize + info.imported_functions.len()))
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
for ret in sig.returns() {
|
||||||
|
fcg.feed_return(type_to_wp_type(*ret))?;
|
||||||
|
}
|
||||||
|
for param in sig.params() {
|
||||||
|
fcg.feed_param(type_to_wp_type(*param))?;
|
||||||
|
}
|
||||||
|
for local in item.get_locals_reader()? {
|
||||||
|
let (count, ty) = local?;
|
||||||
|
fcg.feed_local(ty, count as usize)?;
|
||||||
|
}
|
||||||
|
fcg.begin_body()?;
|
||||||
|
for op in item.get_operators_reader()? {
|
||||||
|
let op = op?;
|
||||||
|
fcg.feed_opcode(op, &info)?;
|
||||||
|
}
|
||||||
|
fcg.finalize()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionCode::Data => {
|
||||||
|
let data_reader = section.get_data_section_reader()?;
|
||||||
|
|
||||||
|
for data in data_reader {
|
||||||
|
let Data { kind, data } = data?;
|
||||||
|
|
||||||
|
match kind {
|
||||||
|
DataKind::Active {
|
||||||
|
memory_index,
|
||||||
|
init_expr,
|
||||||
|
} => {
|
||||||
|
let memory_index = MemoryIndex::new(memory_index as usize);
|
||||||
|
let base = eval_init_expr(&init_expr)?;
|
||||||
|
|
||||||
|
let data_init = DataInitializer {
|
||||||
|
memory_index,
|
||||||
|
base,
|
||||||
|
data: data.to_vec(),
|
||||||
|
};
|
||||||
|
|
||||||
|
info.data_initializers.push(data_init);
|
||||||
|
}
|
||||||
|
DataKind::Passive => {
|
||||||
|
return Err(BinaryReaderError {
|
||||||
|
message: "passive memories are not yet supported",
|
||||||
|
offset: -1isize as usize,
|
||||||
|
}
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionCode::DataCount => {}
|
||||||
|
SectionCode::Custom { .. } => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wp_type_to_type(ty: WpType) -> Result<Type, BinaryReaderError> {
|
||||||
|
Ok(match ty {
|
||||||
|
WpType::I32 => Type::I32,
|
||||||
|
WpType::I64 => Type::I64,
|
||||||
|
WpType::F32 => Type::F32,
|
||||||
|
WpType::F64 => Type::F64,
|
||||||
|
WpType::V128 => {
|
||||||
|
return Err(BinaryReaderError {
|
||||||
|
message: "the wasmer llvm backend does not yet support the simd extension",
|
||||||
|
offset: -1isize as usize,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => panic!("broken invariant, invalid type"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_to_wp_type(ty: Type) -> WpType {
|
||||||
|
match ty {
|
||||||
|
Type::I32 => WpType::I32,
|
||||||
|
Type::I64 => WpType::I64,
|
||||||
|
Type::F32 => WpType::F32,
|
||||||
|
Type::F64 => WpType::F64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn func_type_to_func_sig(func_ty: FuncType) -> Result<FuncSig, BinaryReaderError> {
|
||||||
|
assert_eq!(func_ty.form, WpType::Func);
|
||||||
|
|
||||||
|
Ok(FuncSig::new(
|
||||||
|
func_ty
|
||||||
|
.params
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(wp_type_to_type)
|
||||||
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
|
func_ty
|
||||||
|
.returns
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(wp_type_to_type)
|
||||||
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_init_expr(expr: &InitExpr) -> Result<Initializer, BinaryReaderError> {
|
||||||
|
let mut reader = expr.get_operators_reader();
|
||||||
|
let (op, offset) = reader.read_with_offset()?;
|
||||||
|
Ok(match op {
|
||||||
|
Operator::GetGlobal { global_index } => {
|
||||||
|
Initializer::GetGlobal(ImportedGlobalIndex::new(global_index as usize))
|
||||||
|
}
|
||||||
|
Operator::I32Const { value } => Initializer::Const(Value::I32(value)),
|
||||||
|
Operator::I64Const { value } => Initializer::Const(Value::I64(value)),
|
||||||
|
Operator::F32Const { value } => {
|
||||||
|
Initializer::Const(Value::F32(f32::from_bits(value.bits())))
|
||||||
|
}
|
||||||
|
Operator::F64Const { value } => {
|
||||||
|
Initializer::Const(Value::F64(f64::from_bits(value.bits())))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(BinaryReaderError {
|
||||||
|
message: "init expr evaluation failed: unsupported opcode",
|
||||||
|
offset,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
202
lib/dynasm-backend/src/protect_unix.rs
Normal file
202
lib/dynasm-backend/src/protect_unix.rs
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
//! Installing signal handlers allows us to handle traps and out-of-bounds memory
|
||||||
|
//! accesses that occur when runniing webassembly.
|
||||||
|
//!
|
||||||
|
//! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622
|
||||||
|
//!
|
||||||
|
//! When a WebAssembly module triggers any traps, we perform recovery here.
|
||||||
|
//!
|
||||||
|
//! This module uses TLS (thread-local storage) to track recovery information. Since the four signals we're handling
|
||||||
|
//! are very special, the async signal unsafety of Rust's TLS implementation generally does not affect the correctness here
|
||||||
|
//! unless you have memory unsafety elsewhere in your code.
|
||||||
|
//!
|
||||||
|
use libc::{c_int, c_void, siginfo_t};
|
||||||
|
use nix::sys::signal::{
|
||||||
|
sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV,
|
||||||
|
};
|
||||||
|
use std::cell::{Cell, UnsafeCell};
|
||||||
|
use std::ptr;
|
||||||
|
use std::sync::Once;
|
||||||
|
use wasmer_runtime_core::error::{RuntimeError, RuntimeResult};
|
||||||
|
|
||||||
|
extern "C" fn signal_trap_handler(
|
||||||
|
signum: ::nix::libc::c_int,
|
||||||
|
siginfo: *mut siginfo_t,
|
||||||
|
ucontext: *mut c_void,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
do_unwind(signum, siginfo as _, ucontext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn setjmp(env: *mut c_void) -> c_int;
|
||||||
|
fn longjmp(env: *mut c_void, val: c_int) -> !;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn install_sighandler() {
|
||||||
|
let sa = SigAction::new(
|
||||||
|
SigHandler::SigAction(signal_trap_handler),
|
||||||
|
SaFlags::SA_ONSTACK,
|
||||||
|
SigSet::empty(),
|
||||||
|
);
|
||||||
|
sigaction(SIGFPE, &sa).unwrap();
|
||||||
|
sigaction(SIGILL, &sa).unwrap();
|
||||||
|
sigaction(SIGSEGV, &sa).unwrap();
|
||||||
|
sigaction(SIGBUS, &sa).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
const SETJMP_BUFFER_LEN: usize = 27;
|
||||||
|
pub static SIGHANDLER_INIT: Once = Once::new();
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
pub static SETJMP_BUFFER: UnsafeCell<[c_int; SETJMP_BUFFER_LEN]> = UnsafeCell::new([0; SETJMP_BUFFER_LEN]);
|
||||||
|
pub static CAUGHT_ADDRESSES: Cell<(*const c_void, *const c_void)> = Cell::new((ptr::null(), ptr::null()));
|
||||||
|
pub static CURRENT_EXECUTABLE_BUFFER: Cell<*const c_void> = Cell::new(ptr::null());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn trigger_trap() -> ! {
|
||||||
|
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
||||||
|
|
||||||
|
longjmp(jmp_buf as *mut c_void, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_protected<T>(f: impl FnOnce() -> T) -> RuntimeResult<T> {
|
||||||
|
unsafe {
|
||||||
|
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
||||||
|
let prev_jmp_buf = *jmp_buf;
|
||||||
|
|
||||||
|
SIGHANDLER_INIT.call_once(|| {
|
||||||
|
install_sighandler();
|
||||||
|
});
|
||||||
|
|
||||||
|
let signum = setjmp(jmp_buf as *mut _);
|
||||||
|
if signum != 0 {
|
||||||
|
*jmp_buf = prev_jmp_buf;
|
||||||
|
|
||||||
|
let (faulting_addr, _inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());
|
||||||
|
|
||||||
|
let signal = match Signal::from_c_int(signum) {
|
||||||
|
Ok(SIGFPE) => "floating-point exception",
|
||||||
|
Ok(SIGILL) => "illegal instruction",
|
||||||
|
Ok(SIGSEGV) => "segmentation violation",
|
||||||
|
Ok(SIGBUS) => "bus error",
|
||||||
|
Err(_) => "error while getting the Signal",
|
||||||
|
_ => "unkown trapped signal",
|
||||||
|
};
|
||||||
|
// When the trap-handler is fully implemented, this will return more information.
|
||||||
|
Err(RuntimeError::Trap {
|
||||||
|
msg: format!("unknown trap at {:p} - {}", faulting_addr, signal).into(),
|
||||||
|
}
|
||||||
|
.into())
|
||||||
|
} else {
|
||||||
|
let ret = f(); // TODO: Switch stack?
|
||||||
|
*jmp_buf = prev_jmp_buf;
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unwinds to last protected_call.
|
||||||
|
pub unsafe fn do_unwind(signum: i32, siginfo: *const c_void, ucontext: *const c_void) -> ! {
|
||||||
|
// Since do_unwind is only expected to get called from WebAssembly code which doesn't hold any host resources (locks etc.)
|
||||||
|
// itself, accessing TLS here is safe. In case any other code calls this, it often indicates a memory safety bug and you should
|
||||||
|
// temporarily disable the signal handlers to debug it.
|
||||||
|
|
||||||
|
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
||||||
|
if *jmp_buf == [0; SETJMP_BUFFER_LEN] {
|
||||||
|
::std::process::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
CAUGHT_ADDRESSES.with(|cell| cell.set(get_faulting_addr_and_ip(siginfo, ucontext)));
|
||||||
|
|
||||||
|
longjmp(jmp_buf as *mut ::nix::libc::c_void, signum)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
||||||
|
unsafe fn get_faulting_addr_and_ip(
|
||||||
|
siginfo: *const c_void,
|
||||||
|
ucontext: *const c_void,
|
||||||
|
) -> (*const c_void, *const c_void) {
|
||||||
|
use libc::{ucontext_t, RIP};
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct siginfo_t {
|
||||||
|
si_signo: i32,
|
||||||
|
si_errno: i32,
|
||||||
|
si_code: i32,
|
||||||
|
si_addr: u64,
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
let siginfo = siginfo as *const siginfo_t;
|
||||||
|
let si_addr = (*siginfo).si_addr;
|
||||||
|
|
||||||
|
let ucontext = ucontext as *const ucontext_t;
|
||||||
|
let rip = (*ucontext).uc_mcontext.gregs[RIP as usize];
|
||||||
|
|
||||||
|
(si_addr as _, rip as _)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
||||||
|
unsafe fn get_faulting_addr_and_ip(
|
||||||
|
siginfo: *const c_void,
|
||||||
|
ucontext: *const c_void,
|
||||||
|
) -> (*const c_void, *const c_void) {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct ucontext_t {
|
||||||
|
uc_onstack: u32,
|
||||||
|
uc_sigmask: u32,
|
||||||
|
uc_stack: libc::stack_t,
|
||||||
|
uc_link: *const ucontext_t,
|
||||||
|
uc_mcsize: u64,
|
||||||
|
uc_mcontext: *const mcontext_t,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
struct exception_state {
|
||||||
|
trapno: u16,
|
||||||
|
cpu: u16,
|
||||||
|
err: u32,
|
||||||
|
faultvaddr: u64,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
struct regs {
|
||||||
|
rax: u64,
|
||||||
|
rbx: u64,
|
||||||
|
rcx: u64,
|
||||||
|
rdx: u64,
|
||||||
|
rdi: u64,
|
||||||
|
rsi: u64,
|
||||||
|
rbp: u64,
|
||||||
|
rsp: u64,
|
||||||
|
r8: u64,
|
||||||
|
r9: u64,
|
||||||
|
r10: u64,
|
||||||
|
r11: u64,
|
||||||
|
r12: u64,
|
||||||
|
r13: u64,
|
||||||
|
r14: u64,
|
||||||
|
r15: u64,
|
||||||
|
rip: u64,
|
||||||
|
rflags: u64,
|
||||||
|
cs: u64,
|
||||||
|
fs: u64,
|
||||||
|
gs: u64,
|
||||||
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct mcontext_t {
|
||||||
|
es: exception_state,
|
||||||
|
ss: regs,
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
let siginfo = siginfo as *const siginfo_t;
|
||||||
|
let si_addr = (*siginfo).si_addr;
|
||||||
|
|
||||||
|
let ucontext = ucontext as *const ucontext_t;
|
||||||
|
let rip = (*(*ucontext).uc_mcontext).ss.rip;
|
||||||
|
|
||||||
|
(si_addr, rip as _)
|
||||||
|
}
|
164
lib/dynasm-backend/src/stack.rs
Normal file
164
lib/dynasm-backend/src/stack.rs
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
use crate::codegen::CodegenError;
|
||||||
|
use dynasmrt::DynamicLabel;
|
||||||
|
use wasmparser::Type as WpType;
|
||||||
|
|
||||||
|
/*#[repr(u8)]
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum RegisterName {
|
||||||
|
RDI,
|
||||||
|
RSI,
|
||||||
|
RDX,
|
||||||
|
RCX,
|
||||||
|
R8,
|
||||||
|
R9,
|
||||||
|
R10,
|
||||||
|
R11,
|
||||||
|
RBX,
|
||||||
|
R12,
|
||||||
|
R13,
|
||||||
|
R14,
|
||||||
|
R15,
|
||||||
|
Invalid,
|
||||||
|
}*/
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub enum IfElseState {
|
||||||
|
None,
|
||||||
|
If(DynamicLabel),
|
||||||
|
Else,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ControlFrame {
|
||||||
|
pub label: DynamicLabel,
|
||||||
|
pub loop_like: bool,
|
||||||
|
pub if_else: IfElseState,
|
||||||
|
pub returns: Vec<WpType>,
|
||||||
|
pub value_stack_depth_before: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ControlStack {
|
||||||
|
pub frames: Vec<ControlFrame>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ValueStack {
|
||||||
|
pub num_regs: u8,
|
||||||
|
pub values: Vec<ValueInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct ValueInfo {
|
||||||
|
pub ty: WpType,
|
||||||
|
pub location: ValueLocation,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum ValueLocation {
|
||||||
|
Register(ScratchRegister),
|
||||||
|
Stack,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct ScratchRegister(u8);
|
||||||
|
|
||||||
|
impl ScratchRegister {
|
||||||
|
pub fn raw_id(&self) -> u8 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValueLocation {
|
||||||
|
pub fn is_register(&self) -> bool {
|
||||||
|
if let ValueLocation::Register(_) = *self {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_register(&self) -> Result<ScratchRegister, CodegenError> {
|
||||||
|
if let ValueLocation::Register(id) = *self {
|
||||||
|
Ok(id)
|
||||||
|
} else {
|
||||||
|
Err(CodegenError {
|
||||||
|
message: "not a register location",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValueStack {
|
||||||
|
pub fn new(num_regs: u8) -> ValueStack {
|
||||||
|
ValueStack {
|
||||||
|
num_regs: num_regs,
|
||||||
|
values: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_location(&self, loc: &ValueLocation) -> ValueLocation {
|
||||||
|
match *loc {
|
||||||
|
ValueLocation::Register(ScratchRegister(x)) => {
|
||||||
|
if x >= self.num_regs - 1 {
|
||||||
|
ValueLocation::Stack
|
||||||
|
} else {
|
||||||
|
ValueLocation::Register(ScratchRegister(x + 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ValueLocation::Stack => ValueLocation::Stack,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, ty: WpType) -> ValueLocation {
|
||||||
|
let loc = self
|
||||||
|
.values
|
||||||
|
.last()
|
||||||
|
.map(|x| self.next_location(&x.location))
|
||||||
|
.unwrap_or(ValueLocation::Register(ScratchRegister(0)));
|
||||||
|
self.values.push(ValueInfo {
|
||||||
|
ty: ty,
|
||||||
|
location: loc,
|
||||||
|
});
|
||||||
|
loc
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self) -> Result<ValueInfo, CodegenError> {
|
||||||
|
match self.values.pop() {
|
||||||
|
Some(x) => Ok(x),
|
||||||
|
None => Err(CodegenError {
|
||||||
|
message: "no value on top of stack",
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop2(&mut self) -> Result<(ValueInfo, ValueInfo), CodegenError> {
|
||||||
|
if self.values.len() < 2 {
|
||||||
|
Err(CodegenError {
|
||||||
|
message: "less than 2 values on top of stack",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let v2 = self.values.pop().unwrap();
|
||||||
|
let v1 = self.values.pop().unwrap();
|
||||||
|
Ok((v1, v2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_depth(&mut self, target_depth: usize) {
|
||||||
|
self.values.truncate(target_depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ControlStack {
|
||||||
|
pub fn new(label: DynamicLabel, returns: Vec<WpType>) -> ControlStack {
|
||||||
|
ControlStack {
|
||||||
|
frames: vec![ControlFrame {
|
||||||
|
label: label,
|
||||||
|
loop_like: false,
|
||||||
|
if_else: IfElseState::None,
|
||||||
|
returns: returns,
|
||||||
|
value_stack_depth_before: 0,
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,20 +14,20 @@ lazy_static = "1.2.0"
|
|||||||
libc = "0.2.49"
|
libc = "0.2.49"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
time = "0.1.41"
|
time = "0.1.41"
|
||||||
|
wasmer-clif-backend = { path = "../clif-backend", version = "0.2.0" }
|
||||||
|
wasmer-dynasm-backend = { path = "../dynasm-backend", version = "0.1.0", optional = true }
|
||||||
|
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.1.0", optional = true }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
rand = "0.6"
|
rand = "0.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.2.0" }
|
|
||||||
wabt = "0.7.2"
|
wabt = "0.7.2"
|
||||||
|
|
||||||
[target.'cfg(not(windows))'.dev-dependencies]
|
|
||||||
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.1.0" }
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
glob = "0.2.11"
|
glob = "0.2.11"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
clif = []
|
clif = []
|
||||||
llvm = []
|
llvm = ["wasmer-llvm-backend"]
|
||||||
|
dynasm = ["wasmer-dynasm-backend"]
|
@ -186,7 +186,13 @@ mod tests {
|
|||||||
LLVMCompiler::new()
|
LLVMCompiler::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(feature = "llvm", feature = "clif")))]
|
#[cfg(feature = "dynasm")]
|
||||||
|
fn get_compiler() -> impl Compiler {
|
||||||
|
use wasmer_dynasm_backend::SinglePassCompiler;
|
||||||
|
SinglePassCompiler::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "llvm", feature = "clif", feature = "dynasm")))]
|
||||||
fn get_compiler() -> impl Compiler {
|
fn get_compiler() -> impl Compiler {
|
||||||
panic!("compiler not specified, activate a compiler via features");
|
panic!("compiler not specified, activate a compiler via features");
|
||||||
use wasmer_clif_backend::CraneliftCompiler;
|
use wasmer_clif_backend::CraneliftCompiler;
|
||||||
|
@ -20,7 +20,13 @@ macro_rules! assert_emscripten_output {
|
|||||||
LLVMCompiler::new()
|
LLVMCompiler::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(feature = "llvm", feature = "clif")))]
|
#[cfg(feature = "dynasm")]
|
||||||
|
fn get_compiler() -> impl Compiler {
|
||||||
|
use wasmer_dynasm_backend::SinglePassCompiler;
|
||||||
|
SinglePassCompiler::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "llvm", feature = "clif", feature = "dynasm")))]
|
||||||
fn get_compiler() -> impl Compiler {
|
fn get_compiler() -> impl Compiler {
|
||||||
panic!("compiler not specified, activate a compiler via features");
|
panic!("compiler not specified, activate a compiler via features");
|
||||||
use wasmer_clif_backend::CraneliftCompiler;
|
use wasmer_clif_backend::CraneliftCompiler;
|
||||||
|
@ -22,6 +22,7 @@ pub use crate::sig_registry::SigRegistry;
|
|||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum Backend {
|
pub enum Backend {
|
||||||
Cranelift,
|
Cranelift,
|
||||||
|
Dynasm,
|
||||||
LLVM,
|
LLVM,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
use crate::types::{FuncSig, GlobalDescriptor, MemoryDescriptor, TableDescriptor, Type, Value};
|
use crate::types::{
|
||||||
|
FuncSig, GlobalDescriptor, MemoryDescriptor, MemoryIndex, TableDescriptor, TableIndex, Type,
|
||||||
|
Value,
|
||||||
|
};
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
pub type CompileResult<T> = std::result::Result<T, CompileError>;
|
pub type CompileResult<T> = std::result::Result<T, CompileError>;
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
use crate::{memory::MemoryType, module::ModuleInfo, structures::TypedIndex, units::Pages};
|
use crate::error::{CompileError, CompileResult};
|
||||||
|
use crate::{
|
||||||
|
memory::MemoryType, module::ModuleInfo, module::ModuleInner, structures::TypedIndex,
|
||||||
|
units::Pages,
|
||||||
|
};
|
||||||
use std::{borrow::Cow, mem};
|
use std::{borrow::Cow, mem};
|
||||||
|
|
||||||
/// Represents a WebAssembly type.
|
/// Represents a WebAssembly type.
|
||||||
|
@ -13,32 +13,8 @@ use std::{ffi::c_void, mem, ptr};
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Ctx {
|
pub struct Ctx {
|
||||||
/// A pointer to an array of locally-defined memories, indexed by `MemoryIndex`.
|
// `internal` must be the first field of `Ctx`.
|
||||||
pub(crate) memories: *mut *mut LocalMemory,
|
pub(crate) internal: InternalCtx,
|
||||||
|
|
||||||
/// A pointer to an array of locally-defined tables, indexed by `TableIndex`.
|
|
||||||
pub(crate) tables: *mut *mut LocalTable,
|
|
||||||
|
|
||||||
/// A pointer to an array of locally-defined globals, indexed by `GlobalIndex`.
|
|
||||||
pub(crate) globals: *mut *mut LocalGlobal,
|
|
||||||
|
|
||||||
/// A pointer to an array of imported memories, indexed by `MemoryIndex,
|
|
||||||
pub(crate) imported_memories: *mut *mut LocalMemory,
|
|
||||||
|
|
||||||
/// A pointer to an array of imported tables, indexed by `TableIndex`.
|
|
||||||
pub(crate) imported_tables: *mut *mut LocalTable,
|
|
||||||
|
|
||||||
/// A pointer to an array of imported globals, indexed by `GlobalIndex`.
|
|
||||||
pub(crate) imported_globals: *mut *mut LocalGlobal,
|
|
||||||
|
|
||||||
/// A pointer to an array of imported functions, indexed by `FuncIndex`.
|
|
||||||
pub(crate) imported_funcs: *mut ImportedFunc,
|
|
||||||
|
|
||||||
/// A pointer to an array of signature ids. Conceptually, this maps
|
|
||||||
/// from a static, module-local signature id to a runtime-global
|
|
||||||
/// signature id. This is used to allow call-indirect to other
|
|
||||||
/// modules safely.
|
|
||||||
pub(crate) dynamic_sigindices: *const SigId,
|
|
||||||
|
|
||||||
pub(crate) local_functions: *const *const Func,
|
pub(crate) local_functions: *const *const Func,
|
||||||
|
|
||||||
@ -50,6 +26,41 @@ pub struct Ctx {
|
|||||||
pub data_finalizer: Option<extern "C" fn(data: *mut c_void)>,
|
pub data_finalizer: Option<extern "C" fn(data: *mut c_void)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The internal context of the currently running WebAssembly instance.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct InternalCtx {
|
||||||
|
/// A pointer to an array of locally-defined memories, indexed by `MemoryIndex`.
|
||||||
|
pub memories: *mut *mut LocalMemory,
|
||||||
|
|
||||||
|
/// A pointer to an array of locally-defined tables, indexed by `TableIndex`.
|
||||||
|
pub tables: *mut *mut LocalTable,
|
||||||
|
|
||||||
|
/// A pointer to an array of locally-defined globals, indexed by `GlobalIndex`.
|
||||||
|
pub globals: *mut *mut LocalGlobal,
|
||||||
|
|
||||||
|
/// A pointer to an array of imported memories, indexed by `MemoryIndex,
|
||||||
|
pub imported_memories: *mut *mut LocalMemory,
|
||||||
|
|
||||||
|
/// A pointer to an array of imported tables, indexed by `TableIndex`.
|
||||||
|
pub imported_tables: *mut *mut LocalTable,
|
||||||
|
|
||||||
|
/// A pointer to an array of imported globals, indexed by `GlobalIndex`.
|
||||||
|
pub imported_globals: *mut *mut LocalGlobal,
|
||||||
|
|
||||||
|
/// A pointer to an array of imported functions, indexed by `FuncIndex`.
|
||||||
|
pub imported_funcs: *mut ImportedFunc,
|
||||||
|
|
||||||
|
/// A pointer to an array of signature ids. Conceptually, this maps
|
||||||
|
/// from a static, module-local signature id to a runtime-global
|
||||||
|
/// signature id. This is used to allow call-indirect to other
|
||||||
|
/// modules safely.
|
||||||
|
pub dynamic_sigindices: *const SigId,
|
||||||
|
}
|
||||||
|
|
||||||
impl Ctx {
|
impl Ctx {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub unsafe fn new(
|
pub unsafe fn new(
|
||||||
@ -58,6 +69,7 @@ impl Ctx {
|
|||||||
module: &ModuleInner,
|
module: &ModuleInner,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
internal: InternalCtx {
|
||||||
memories: local_backing.vm_memories.as_mut_ptr(),
|
memories: local_backing.vm_memories.as_mut_ptr(),
|
||||||
tables: local_backing.vm_tables.as_mut_ptr(),
|
tables: local_backing.vm_tables.as_mut_ptr(),
|
||||||
globals: local_backing.vm_globals.as_mut_ptr(),
|
globals: local_backing.vm_globals.as_mut_ptr(),
|
||||||
@ -68,6 +80,7 @@ impl Ctx {
|
|||||||
imported_funcs: import_backing.vm_functions.as_mut_ptr(),
|
imported_funcs: import_backing.vm_functions.as_mut_ptr(),
|
||||||
|
|
||||||
dynamic_sigindices: local_backing.dynamic_sigindices.as_ptr(),
|
dynamic_sigindices: local_backing.dynamic_sigindices.as_ptr(),
|
||||||
|
},
|
||||||
local_functions: local_backing.local_functions.as_ptr(),
|
local_functions: local_backing.local_functions.as_ptr(),
|
||||||
|
|
||||||
local_backing,
|
local_backing,
|
||||||
@ -88,6 +101,7 @@ impl Ctx {
|
|||||||
data_finalizer: extern "C" fn(*mut c_void),
|
data_finalizer: extern "C" fn(*mut c_void),
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
internal: InternalCtx {
|
||||||
memories: local_backing.vm_memories.as_mut_ptr(),
|
memories: local_backing.vm_memories.as_mut_ptr(),
|
||||||
tables: local_backing.vm_tables.as_mut_ptr(),
|
tables: local_backing.vm_tables.as_mut_ptr(),
|
||||||
globals: local_backing.vm_globals.as_mut_ptr(),
|
globals: local_backing.vm_globals.as_mut_ptr(),
|
||||||
@ -98,6 +112,7 @@ impl Ctx {
|
|||||||
imported_funcs: import_backing.vm_functions.as_mut_ptr(),
|
imported_funcs: import_backing.vm_functions.as_mut_ptr(),
|
||||||
|
|
||||||
dynamic_sigindices: local_backing.dynamic_sigindices.as_ptr(),
|
dynamic_sigindices: local_backing.dynamic_sigindices.as_ptr(),
|
||||||
|
},
|
||||||
local_functions: local_backing.local_functions.as_ptr(),
|
local_functions: local_backing.local_functions.as_ptr(),
|
||||||
|
|
||||||
local_backing,
|
local_backing,
|
||||||
@ -333,43 +348,45 @@ impl Anyfunc {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod vm_offset_tests {
|
mod vm_offset_tests {
|
||||||
use super::{Anyfunc, Ctx, ImportedFunc, LocalGlobal, LocalMemory, LocalTable};
|
use super::{Anyfunc, Ctx, ImportedFunc, InternalCtx, LocalGlobal, LocalMemory, LocalTable};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn vmctx() {
|
fn vmctx() {
|
||||||
|
assert_eq!(0usize, offset_of!(Ctx => internal).get_byte_offset(),);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ctx::offset_memories() as usize,
|
Ctx::offset_memories() as usize,
|
||||||
offset_of!(Ctx => memories).get_byte_offset(),
|
offset_of!(InternalCtx => memories).get_byte_offset(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ctx::offset_tables() as usize,
|
Ctx::offset_tables() as usize,
|
||||||
offset_of!(Ctx => tables).get_byte_offset(),
|
offset_of!(InternalCtx => tables).get_byte_offset(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ctx::offset_globals() as usize,
|
Ctx::offset_globals() as usize,
|
||||||
offset_of!(Ctx => globals).get_byte_offset(),
|
offset_of!(InternalCtx => globals).get_byte_offset(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ctx::offset_imported_memories() as usize,
|
Ctx::offset_imported_memories() as usize,
|
||||||
offset_of!(Ctx => imported_memories).get_byte_offset(),
|
offset_of!(InternalCtx => imported_memories).get_byte_offset(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ctx::offset_imported_tables() as usize,
|
Ctx::offset_imported_tables() as usize,
|
||||||
offset_of!(Ctx => imported_tables).get_byte_offset(),
|
offset_of!(InternalCtx => imported_tables).get_byte_offset(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ctx::offset_imported_globals() as usize,
|
Ctx::offset_imported_globals() as usize,
|
||||||
offset_of!(Ctx => imported_globals).get_byte_offset(),
|
offset_of!(InternalCtx => imported_globals).get_byte_offset(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ctx::offset_imported_funcs() as usize,
|
Ctx::offset_imported_funcs() as usize,
|
||||||
offset_of!(Ctx => imported_funcs).get_byte_offset(),
|
offset_of!(InternalCtx => imported_funcs).get_byte_offset(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -17,7 +17,7 @@ pub unsafe extern "C" fn local_static_memory_grow(
|
|||||||
memory_index: LocalMemoryIndex,
|
memory_index: LocalMemoryIndex,
|
||||||
delta: Pages,
|
delta: Pages,
|
||||||
) -> i32 {
|
) -> i32 {
|
||||||
let local_memory = *ctx.memories.add(memory_index.index());
|
let local_memory = *ctx.internal.memories.add(memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut StaticMemory;
|
let memory = (*local_memory).memory as *mut StaticMemory;
|
||||||
|
|
||||||
match (*memory).grow(delta, &mut *local_memory) {
|
match (*memory).grow(delta, &mut *local_memory) {
|
||||||
@ -30,7 +30,7 @@ pub unsafe extern "C" fn local_static_memory_size(
|
|||||||
ctx: &vm::Ctx,
|
ctx: &vm::Ctx,
|
||||||
memory_index: LocalMemoryIndex,
|
memory_index: LocalMemoryIndex,
|
||||||
) -> Pages {
|
) -> Pages {
|
||||||
let local_memory = *ctx.memories.add(memory_index.index());
|
let local_memory = *ctx.internal.memories.add(memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut StaticMemory;
|
let memory = (*local_memory).memory as *mut StaticMemory;
|
||||||
|
|
||||||
(*memory).size()
|
(*memory).size()
|
||||||
@ -41,7 +41,7 @@ pub unsafe extern "C" fn local_dynamic_memory_grow(
|
|||||||
memory_index: LocalMemoryIndex,
|
memory_index: LocalMemoryIndex,
|
||||||
delta: Pages,
|
delta: Pages,
|
||||||
) -> i32 {
|
) -> i32 {
|
||||||
let local_memory = *ctx.memories.add(memory_index.index());
|
let local_memory = *ctx.internal.memories.add(memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut DynamicMemory;
|
let memory = (*local_memory).memory as *mut DynamicMemory;
|
||||||
|
|
||||||
match (*memory).grow(delta, &mut *local_memory) {
|
match (*memory).grow(delta, &mut *local_memory) {
|
||||||
@ -54,7 +54,7 @@ pub unsafe extern "C" fn local_dynamic_memory_size(
|
|||||||
ctx: &vm::Ctx,
|
ctx: &vm::Ctx,
|
||||||
memory_index: LocalMemoryIndex,
|
memory_index: LocalMemoryIndex,
|
||||||
) -> Pages {
|
) -> Pages {
|
||||||
let local_memory = *ctx.memories.add(memory_index.index());
|
let local_memory = *ctx.internal.memories.add(memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut DynamicMemory;
|
let memory = (*local_memory).memory as *mut DynamicMemory;
|
||||||
|
|
||||||
(*memory).size()
|
(*memory).size()
|
||||||
@ -69,7 +69,10 @@ pub unsafe extern "C" fn imported_static_memory_grow(
|
|||||||
import_memory_index: ImportedMemoryIndex,
|
import_memory_index: ImportedMemoryIndex,
|
||||||
delta: Pages,
|
delta: Pages,
|
||||||
) -> i32 {
|
) -> i32 {
|
||||||
let local_memory = *ctx.imported_memories.add(import_memory_index.index());
|
let local_memory = *ctx
|
||||||
|
.internal
|
||||||
|
.imported_memories
|
||||||
|
.add(import_memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut StaticMemory;
|
let memory = (*local_memory).memory as *mut StaticMemory;
|
||||||
|
|
||||||
match (*memory).grow(delta, &mut *local_memory) {
|
match (*memory).grow(delta, &mut *local_memory) {
|
||||||
@ -82,7 +85,10 @@ pub unsafe extern "C" fn imported_static_memory_size(
|
|||||||
ctx: &vm::Ctx,
|
ctx: &vm::Ctx,
|
||||||
import_memory_index: ImportedMemoryIndex,
|
import_memory_index: ImportedMemoryIndex,
|
||||||
) -> Pages {
|
) -> Pages {
|
||||||
let local_memory = *ctx.imported_memories.add(import_memory_index.index());
|
let local_memory = *ctx
|
||||||
|
.internal
|
||||||
|
.imported_memories
|
||||||
|
.add(import_memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut StaticMemory;
|
let memory = (*local_memory).memory as *mut StaticMemory;
|
||||||
|
|
||||||
(*memory).size()
|
(*memory).size()
|
||||||
@ -93,7 +99,7 @@ pub unsafe extern "C" fn imported_dynamic_memory_grow(
|
|||||||
memory_index: ImportedMemoryIndex,
|
memory_index: ImportedMemoryIndex,
|
||||||
delta: Pages,
|
delta: Pages,
|
||||||
) -> i32 {
|
) -> i32 {
|
||||||
let local_memory = *ctx.imported_memories.add(memory_index.index());
|
let local_memory = *ctx.internal.imported_memories.add(memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut DynamicMemory;
|
let memory = (*local_memory).memory as *mut DynamicMemory;
|
||||||
|
|
||||||
match (*memory).grow(delta, &mut *local_memory) {
|
match (*memory).grow(delta, &mut *local_memory) {
|
||||||
@ -106,7 +112,7 @@ pub unsafe extern "C" fn imported_dynamic_memory_size(
|
|||||||
ctx: &vm::Ctx,
|
ctx: &vm::Ctx,
|
||||||
memory_index: ImportedMemoryIndex,
|
memory_index: ImportedMemoryIndex,
|
||||||
) -> Pages {
|
) -> Pages {
|
||||||
let local_memory = *ctx.imported_memories.add(memory_index.index());
|
let local_memory = *ctx.internal.imported_memories.add(memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut DynamicMemory;
|
let memory = (*local_memory).memory as *mut DynamicMemory;
|
||||||
|
|
||||||
(*memory).size()
|
(*memory).size()
|
||||||
|
@ -9,6 +9,7 @@ edition = "2018"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
wasmer-dynasm-backend = { path = "../dynasm-backend", optional = true }
|
||||||
lazy_static = "1.2.0"
|
lazy_static = "1.2.0"
|
||||||
memmap = "0.7.0"
|
memmap = "0.7.0"
|
||||||
|
|
||||||
@ -19,6 +20,7 @@ version = "0.2.1"
|
|||||||
[dependencies.wasmer-clif-backend]
|
[dependencies.wasmer-clif-backend]
|
||||||
path = "../clif-backend"
|
path = "../clif-backend"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
optional = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.0.7"
|
tempfile = "3.0.7"
|
||||||
@ -30,8 +32,12 @@ path = "../llvm-backend"
|
|||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
default = ["default-compiler"]
|
||||||
|
default-compiler = ["wasmer-clif-backend"]
|
||||||
|
cache = ["default-compiler"]
|
||||||
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
||||||
llvm = ["wasmer-llvm-backend"]
|
llvm = ["wasmer-llvm-backend"]
|
||||||
|
dynasm = ["wasmer-dynasm-backend"]
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "nginx"
|
name = "nginx"
|
||||||
|
@ -159,7 +159,10 @@ pub fn default_compiler() -> &'static dyn Compiler {
|
|||||||
#[cfg(feature = "llvm")]
|
#[cfg(feature = "llvm")]
|
||||||
use wasmer_llvm_backend::LLVMCompiler as DefaultCompiler;
|
use wasmer_llvm_backend::LLVMCompiler as DefaultCompiler;
|
||||||
|
|
||||||
#[cfg(not(feature = "llvm"))]
|
#[cfg(feature = "dynasm")]
|
||||||
|
use wasmer_dynasm_backend::SinglePassCompiler as DefaultCompiler;
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "llvm", feature = "dynasm")))]
|
||||||
use wasmer_clif_backend::CraneliftCompiler as DefaultCompiler;
|
use wasmer_clif_backend::CraneliftCompiler as DefaultCompiler;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -10,19 +10,19 @@ build = "build/mod.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.0" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.0" }
|
||||||
|
wasmer-clif-backend = { path = "../clif-backend", version = "0.2.0" }
|
||||||
|
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.1.0", optional = true }
|
||||||
|
wasmer-dynasm-backend = { path = "../dynasm-backend", version = "0.1.0", optional = true }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
wabt = "0.7.2"
|
wabt = "0.7.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.2.0" }
|
|
||||||
wabt = "0.7.2"
|
wabt = "0.7.2"
|
||||||
|
|
||||||
[target.'cfg(not(windows))'.dependencies]
|
|
||||||
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.1.0", optional = true }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["fast-tests"]
|
default = ["fast-tests"]
|
||||||
fast-tests = []
|
fast-tests = []
|
||||||
clif = []
|
clif = []
|
||||||
llvm = ["wasmer-llvm-backend"]
|
llvm = ["wasmer-llvm-backend"]
|
||||||
|
dynasm = ["wasmer-dynasm-backend"]
|
@ -107,7 +107,13 @@ fn get_compiler() -> impl Compiler {
|
|||||||
LLVMCompiler::new()
|
LLVMCompiler::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(feature = "llvm", feature = "clif")))]
|
#[cfg(feature = "dynasm")]
|
||||||
|
fn get_compiler() -> impl Compiler {
|
||||||
|
use wasmer_dynasm_backend::SinglePassCompiler;
|
||||||
|
SinglePassCompiler::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "llvm", feature = "clif", feature = "dynasm")))]
|
||||||
fn get_compiler() -> impl Compiler {
|
fn get_compiler() -> impl Compiler {
|
||||||
panic!("compiler not specified, activate a compiler via features");
|
panic!("compiler not specified, activate a compiler via features");
|
||||||
use wasmer_clif_backend::CraneliftCompiler;
|
use wasmer_clif_backend::CraneliftCompiler;
|
||||||
|
@ -22,7 +22,13 @@ fn get_compiler() -> impl Compiler {
|
|||||||
LLVMCompiler::new()
|
LLVMCompiler::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(feature = "llvm", feature = "clif")))]
|
#[cfg(feature = "dynasm")]
|
||||||
|
fn get_compiler() -> impl Compiler {
|
||||||
|
use wasmer_dynasm_backend::SinglePassCompiler;
|
||||||
|
SinglePassCompiler::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "llvm", feature = "clif", feature = "dynasm")))]
|
||||||
fn get_compiler() -> impl Compiler {
|
fn get_compiler() -> impl Compiler {
|
||||||
panic!("compiler not specified, activate a compiler via features");
|
panic!("compiler not specified, activate a compiler via features");
|
||||||
use wasmer_clif_backend::CraneliftCompiler;
|
use wasmer_clif_backend::CraneliftCompiler;
|
||||||
|
@ -131,8 +131,9 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
|||||||
let module = webassembly::compile(&wasm_binary[..])
|
let module = webassembly::compile(&wasm_binary[..])
|
||||||
.map_err(|e| format!("Can't compile module: {:?}", e))?;
|
.map_err(|e| format!("Can't compile module: {:?}", e))?;
|
||||||
|
|
||||||
// We save the module into a cache file
|
// We try to save the module into a cache file
|
||||||
cache.store(hash, module.clone()).unwrap();
|
cache.store(hash, module.clone()).unwrap_or_default();
|
||||||
|
|
||||||
module
|
module
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@ use wasmer_runtime::{
|
|||||||
error::{CallResult, Result},
|
error::{CallResult, Result},
|
||||||
ImportObject, Instance, Module,
|
ImportObject, Instance, Module,
|
||||||
};
|
};
|
||||||
|
use wasmer_runtime_core::types::Value;
|
||||||
|
|
||||||
use wasmer_emscripten::{is_emscripten_module, run_emscripten_instance};
|
use wasmer_emscripten::{is_emscripten_module, run_emscripten_instance};
|
||||||
|
|
||||||
@ -86,7 +87,11 @@ pub fn run_instance(
|
|||||||
if is_emscripten_module(module) {
|
if is_emscripten_module(module) {
|
||||||
run_emscripten_instance(module, instance, path, args)?;
|
run_emscripten_instance(module, instance, path, args)?;
|
||||||
} else {
|
} else {
|
||||||
instance.call("main", &[])?;
|
let args: Vec<Value> = args
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| Value::I32(x.parse().unwrap()))
|
||||||
|
.collect();
|
||||||
|
instance.call("main", &args)?;
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
Loading…
Reference in New Issue
Block a user