mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 06:15:33 +00:00
Merge branch 'master' into feature/add-syscalls-for-php
This commit is contained in:
commit
4210bcd822
@ -18,8 +18,10 @@ jobs:
|
||||
- run:
|
||||
name: Install lint deps
|
||||
command: |
|
||||
git config --global --unset url."ssh://git@github.com".insteadOf || true
|
||||
rustup toolchain install nightly
|
||||
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:
|
||||
name: Execute lints
|
||||
command: |
|
||||
@ -274,6 +276,9 @@ jobs:
|
||||
- run: |
|
||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||
make test
|
||||
make test-nightly
|
||||
make test-emscripten
|
||||
make test-emscripten-nightly
|
||||
- save_cache:
|
||||
paths:
|
||||
- /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]]
|
||||
name = "aho-corasick"
|
||||
version = "0.6.10"
|
||||
@ -367,6 +369,30 @@ dependencies = [
|
||||
"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]]
|
||||
name = "either"
|
||||
version = "1.5.1"
|
||||
@ -605,6 +631,15 @@ dependencies = [
|
||||
"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]]
|
||||
name = "memmap"
|
||||
version = "0.7.0"
|
||||
@ -670,6 +705,14 @@ dependencies = [
|
||||
"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]]
|
||||
name = "owning_ref"
|
||||
version = "0.4.0"
|
||||
@ -1112,6 +1155,11 @@ dependencies = [
|
||||
"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]]
|
||||
name = "target-lexicon"
|
||||
version = "0.2.0"
|
||||
@ -1315,6 +1363,18 @@ dependencies = [
|
||||
"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]]
|
||||
name = "wasmer-emscripten"
|
||||
version = "0.2.1"
|
||||
@ -1327,6 +1387,7 @@ dependencies = [
|
||||
"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)",
|
||||
"wasmer-clif-backend 0.2.0",
|
||||
"wasmer-dynasm-backend 0.1.0",
|
||||
"wasmer-llvm-backend 0.1.0",
|
||||
"wasmer-runtime-core 0.2.1",
|
||||
]
|
||||
@ -1362,6 +1423,7 @@ dependencies = [
|
||||
"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)",
|
||||
"wasmer-clif-backend 0.2.0",
|
||||
"wasmer-dynasm-backend 0.1.0",
|
||||
"wasmer-llvm-backend 0.1.0",
|
||||
"wasmer-runtime-core 0.2.1",
|
||||
]
|
||||
@ -1406,6 +1468,7 @@ version = "0.2.0"
|
||||
dependencies = [
|
||||
"wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmer-clif-backend 0.2.0",
|
||||
"wasmer-dynasm-backend 0.1.0",
|
||||
"wasmer-llvm-backend 0.1.0",
|
||||
"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-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 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 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"
|
||||
@ -1562,6 +1627,7 @@ dependencies = [
|
||||
"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 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 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"
|
||||
@ -1570,6 +1636,7 @@ dependencies = [
|
||||
"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_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 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"
|
||||
@ -1623,6 +1690,7 @@ dependencies = [
|
||||
"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 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 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"
|
||||
|
@ -25,12 +25,11 @@ wasmer-clif-backend = { path = "lib/clif-backend" }
|
||||
wasmer-runtime = { path = "lib/runtime" }
|
||||
wasmer-runtime-core = { path = "lib/runtime-core" }
|
||||
wasmer-emscripten = { path = "lib/emscripten" }
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
wasmer-llvm-backend = { path = "lib/llvm-backend", optional = true }
|
||||
wasmer-dynasm-backend = { path = "lib/dynasm-backend", optional = true }
|
||||
|
||||
[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]
|
||||
wabt = "0.7.2"
|
||||
@ -42,3 +41,4 @@ default = ["fast-tests"]
|
||||
# This feature will allow cargo test to run much faster
|
||||
fast-tests = []
|
||||
llvm = ["wasmer-llvm-backend"]
|
||||
dynasm = ["wasmer-dynasm-backend"]
|
10
Makefile
10
Makefile
@ -28,23 +28,29 @@ integration-tests: release
|
||||
|
||||
lint:
|
||||
cargo fmt --all -- --check
|
||||
cargo clippy --all
|
||||
cargo +nightly clippy --all
|
||||
|
||||
precommit: lint test
|
||||
|
||||
test:
|
||||
# We use one thread so the emscripten stdouts doesn't collide
|
||||
cargo test --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests -- $(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 --manifest-path lib/spectests/Cargo.toml --features clif
|
||||
cargo test --manifest-path lib/spectests/Cargo.toml --features llvm
|
||||
cargo build -p wasmer-runtime-c-api
|
||||
cargo test -p wasmer-runtime-c-api -- --nocapture
|
||||
|
||||
test-nightly:
|
||||
cargo test --manifest-path lib/spectests/Cargo.toml --features dynasm
|
||||
|
||||
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 llvm -- --test-threads=1 $(runargs)
|
||||
|
||||
test-emscripten-nightly:
|
||||
cargo test --manifest-path lib/emscripten/Cargo.toml --features dynasm -- --test-threads=1 $(runargs)
|
||||
|
||||
release:
|
||||
# If you are in OS-X, you will need mingw-w64 for cross compiling to windows
|
||||
# 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)
|
||||
)
|
||||
)
|
||||
)
|
@ -33,5 +33,6 @@ to tune the codegen properties (compile speed, performance, etc) to best fit the
|
||||
|
||||
Currently, we support multiple backends for compiling WebAssembly to machine code:
|
||||
|
||||
- [clif-backend](./clif-backend/): Cranelift backend
|
||||
- [llvm-backend](./llvm-backend/): LLVM backend
|
||||
- [dynasm-backend](./dynasm-backend/): Dynasm backend - super fast compilation, slower runtime speed
|
||||
- [clif-backend](./clif-backend/): Cranelift backend - slower compilation, normal runtime speed
|
||||
- [llvm-backend](./llvm-backend/): LLVM backend - slow compilation, native runtime speed
|
||||
|
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"
|
||||
byteorder = "1"
|
||||
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]
|
||||
rand = "0.6"
|
||||
|
||||
[dev-dependencies]
|
||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.2.0" }
|
||||
wabt = "0.7.2"
|
||||
|
||||
[target.'cfg(not(windows))'.dev-dependencies]
|
||||
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.1.0" }
|
||||
|
||||
[build-dependencies]
|
||||
glob = "0.2.11"
|
||||
|
||||
[features]
|
||||
clif = []
|
||||
llvm = []
|
||||
llvm = ["wasmer-llvm-backend"]
|
||||
dynasm = ["wasmer-dynasm-backend"]
|
@ -186,7 +186,13 @@ mod tests {
|
||||
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 {
|
||||
panic!("compiler not specified, activate a compiler via features");
|
||||
use wasmer_clif_backend::CraneliftCompiler;
|
||||
|
@ -20,7 +20,13 @@ macro_rules! assert_emscripten_output {
|
||||
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 {
|
||||
panic!("compiler not specified, activate a compiler via features");
|
||||
use wasmer_clif_backend::CraneliftCompiler;
|
||||
|
@ -22,6 +22,7 @@ pub use crate::sig_registry::SigRegistry;
|
||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Backend {
|
||||
Cranelift,
|
||||
Dynasm,
|
||||
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 std::any::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
pub type CompileResult<T> = std::result::Result<T, CompileError>;
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::export::Export;
|
||||
use hashbrown::{hash_map::Entry, HashMap};
|
||||
use std::collections::VecDeque;
|
||||
use std::{
|
||||
cell::{Ref, RefCell},
|
||||
rc::Rc,
|
||||
@ -7,6 +8,8 @@ use std::{
|
||||
|
||||
pub trait LikeNamespace {
|
||||
fn get_export(&self, name: &str) -> Option<Export>;
|
||||
fn get_exports(&self) -> Vec<(String, Export)>;
|
||||
fn maybe_insert(&mut self, name: &str, export: Export) -> Option<()>;
|
||||
}
|
||||
|
||||
pub trait IsExport {
|
||||
@ -97,6 +100,53 @@ impl ImportObject {
|
||||
map: Rc::clone(&self.map),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_objects(&self) -> VecDeque<(String, String, Export)> {
|
||||
let mut out = VecDeque::new();
|
||||
for (name, ns) in self.map.borrow().iter() {
|
||||
for (id, exp) in ns.get_exports() {
|
||||
out.push_back((name.clone(), id, exp));
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ImportObjectIterator {
|
||||
elements: VecDeque<(String, String, Export)>,
|
||||
}
|
||||
|
||||
impl Iterator for ImportObjectIterator {
|
||||
type Item = (String, String, Export);
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.elements.pop_front()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for ImportObject {
|
||||
type IntoIter = ImportObjectIterator;
|
||||
type Item = (String, String, Export);
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
ImportObjectIterator {
|
||||
elements: self.get_objects(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Extend<(String, String, Export)> for ImportObject {
|
||||
fn extend<T: IntoIterator<Item = (String, String, Export)>>(&mut self, iter: T) {
|
||||
let mut map = self.map.borrow_mut();
|
||||
for (ns, id, exp) in iter.into_iter() {
|
||||
if let Some(like_ns) = map.get_mut(&ns) {
|
||||
like_ns.maybe_insert(&id, exp);
|
||||
} else {
|
||||
let mut new_ns = Namespace::new();
|
||||
new_ns.insert(id, exp);
|
||||
map.insert(ns, Box::new(new_ns));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Namespace {
|
||||
@ -123,4 +173,76 @@ impl LikeNamespace for Namespace {
|
||||
fn get_export(&self, name: &str) -> Option<Export> {
|
||||
self.map.get(name).map(|is_export| is_export.to_export())
|
||||
}
|
||||
|
||||
fn get_exports(&self) -> Vec<(String, Export)> {
|
||||
self.map
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), v.to_export()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn maybe_insert(&mut self, name: &str, export: Export) -> Option<()> {
|
||||
self.map.insert(name.to_owned(), Box::new(export));
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::export::Export;
|
||||
use crate::global::Global;
|
||||
use crate::types::Value;
|
||||
|
||||
#[test]
|
||||
fn extending_works() {
|
||||
let mut imports1 = imports! {
|
||||
"dog" => {
|
||||
"happy" => Global::new(Value::I32(0)),
|
||||
},
|
||||
};
|
||||
|
||||
let imports2 = imports! {
|
||||
"dog" => {
|
||||
"small" => Global::new(Value::I32(2)),
|
||||
},
|
||||
"cat" => {
|
||||
"small" => Global::new(Value::I32(3)),
|
||||
},
|
||||
};
|
||||
|
||||
imports1.extend(imports2);
|
||||
|
||||
let cat_ns = imports1.get_namespace("cat").unwrap();
|
||||
assert!(cat_ns.get_export("small").is_some());
|
||||
|
||||
let dog_ns = imports1.get_namespace("dog").unwrap();
|
||||
assert!(dog_ns.get_export("happy").is_some());
|
||||
assert!(dog_ns.get_export("small").is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extending_conflict_overwrites() {
|
||||
let mut imports1 = imports! {
|
||||
"dog" => {
|
||||
"happy" => Global::new(Value::I32(0)),
|
||||
},
|
||||
};
|
||||
|
||||
let imports2 = imports! {
|
||||
"dog" => {
|
||||
"happy" => Global::new(Value::I32(4)),
|
||||
},
|
||||
};
|
||||
|
||||
imports1.extend(imports2);
|
||||
let dog_ns = imports1.get_namespace("dog").unwrap();
|
||||
|
||||
assert!(
|
||||
if let Export::Global(happy_dog_global) = dog_ns.get_export("happy").unwrap() {
|
||||
happy_dog_global.get() == Value::I32(4)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -427,6 +427,14 @@ impl LikeNamespace for Instance {
|
||||
|
||||
Some(self.inner.get_export_from_index(&self.module, export_index))
|
||||
}
|
||||
|
||||
fn get_exports(&self) -> Vec<(String, Export)> {
|
||||
unimplemented!("Use the exports method instead");
|
||||
}
|
||||
|
||||
fn maybe_insert(&mut self, _name: &str, _export: Export) -> Option<()> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// A representation of an exported WebAssembly function.
|
||||
|
@ -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};
|
||||
|
||||
/// Represents a WebAssembly type.
|
||||
|
@ -13,32 +13,8 @@ use std::{ffi::c_void, mem, ptr};
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Ctx {
|
||||
/// A pointer to an array of locally-defined memories, indexed by `MemoryIndex`.
|
||||
pub(crate) memories: *mut *mut LocalMemory,
|
||||
|
||||
/// 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,
|
||||
// `internal` must be the first field of `Ctx`.
|
||||
pub(crate) internal: InternalCtx,
|
||||
|
||||
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)>,
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn new(
|
||||
@ -58,16 +69,18 @@ impl Ctx {
|
||||
module: &ModuleInner,
|
||||
) -> Self {
|
||||
Self {
|
||||
memories: local_backing.vm_memories.as_mut_ptr(),
|
||||
tables: local_backing.vm_tables.as_mut_ptr(),
|
||||
globals: local_backing.vm_globals.as_mut_ptr(),
|
||||
internal: InternalCtx {
|
||||
memories: local_backing.vm_memories.as_mut_ptr(),
|
||||
tables: local_backing.vm_tables.as_mut_ptr(),
|
||||
globals: local_backing.vm_globals.as_mut_ptr(),
|
||||
|
||||
imported_memories: import_backing.vm_memories.as_mut_ptr(),
|
||||
imported_tables: import_backing.vm_tables.as_mut_ptr(),
|
||||
imported_globals: import_backing.vm_globals.as_mut_ptr(),
|
||||
imported_funcs: import_backing.vm_functions.as_mut_ptr(),
|
||||
imported_memories: import_backing.vm_memories.as_mut_ptr(),
|
||||
imported_tables: import_backing.vm_tables.as_mut_ptr(),
|
||||
imported_globals: import_backing.vm_globals.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_backing,
|
||||
@ -88,16 +101,18 @@ impl Ctx {
|
||||
data_finalizer: extern "C" fn(*mut c_void),
|
||||
) -> Self {
|
||||
Self {
|
||||
memories: local_backing.vm_memories.as_mut_ptr(),
|
||||
tables: local_backing.vm_tables.as_mut_ptr(),
|
||||
globals: local_backing.vm_globals.as_mut_ptr(),
|
||||
internal: InternalCtx {
|
||||
memories: local_backing.vm_memories.as_mut_ptr(),
|
||||
tables: local_backing.vm_tables.as_mut_ptr(),
|
||||
globals: local_backing.vm_globals.as_mut_ptr(),
|
||||
|
||||
imported_memories: import_backing.vm_memories.as_mut_ptr(),
|
||||
imported_tables: import_backing.vm_tables.as_mut_ptr(),
|
||||
imported_globals: import_backing.vm_globals.as_mut_ptr(),
|
||||
imported_funcs: import_backing.vm_functions.as_mut_ptr(),
|
||||
imported_memories: import_backing.vm_memories.as_mut_ptr(),
|
||||
imported_tables: import_backing.vm_tables.as_mut_ptr(),
|
||||
imported_globals: import_backing.vm_globals.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_backing,
|
||||
@ -333,43 +348,45 @@ impl Anyfunc {
|
||||
|
||||
#[cfg(test)]
|
||||
mod vm_offset_tests {
|
||||
use super::{Anyfunc, Ctx, ImportedFunc, LocalGlobal, LocalMemory, LocalTable};
|
||||
use super::{Anyfunc, Ctx, ImportedFunc, InternalCtx, LocalGlobal, LocalMemory, LocalTable};
|
||||
|
||||
#[test]
|
||||
fn vmctx() {
|
||||
assert_eq!(0usize, offset_of!(Ctx => internal).get_byte_offset(),);
|
||||
|
||||
assert_eq!(
|
||||
Ctx::offset_memories() as usize,
|
||||
offset_of!(Ctx => memories).get_byte_offset(),
|
||||
offset_of!(InternalCtx => memories).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Ctx::offset_tables() as usize,
|
||||
offset_of!(Ctx => tables).get_byte_offset(),
|
||||
offset_of!(InternalCtx => tables).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Ctx::offset_globals() as usize,
|
||||
offset_of!(Ctx => globals).get_byte_offset(),
|
||||
offset_of!(InternalCtx => globals).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Ctx::offset_imported_memories() as usize,
|
||||
offset_of!(Ctx => imported_memories).get_byte_offset(),
|
||||
offset_of!(InternalCtx => imported_memories).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Ctx::offset_imported_tables() as usize,
|
||||
offset_of!(Ctx => imported_tables).get_byte_offset(),
|
||||
offset_of!(InternalCtx => imported_tables).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Ctx::offset_imported_globals() as usize,
|
||||
offset_of!(Ctx => imported_globals).get_byte_offset(),
|
||||
offset_of!(InternalCtx => imported_globals).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Ctx::offset_imported_funcs() as usize,
|
||||
offset_of!(Ctx => imported_funcs).get_byte_offset(),
|
||||
offset_of!(InternalCtx => imported_funcs).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
|
@ -17,7 +17,7 @@ pub unsafe extern "C" fn local_static_memory_grow(
|
||||
memory_index: LocalMemoryIndex,
|
||||
delta: Pages,
|
||||
) -> 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;
|
||||
|
||||
match (*memory).grow(delta, &mut *local_memory) {
|
||||
@ -30,7 +30,7 @@ pub unsafe extern "C" fn local_static_memory_size(
|
||||
ctx: &vm::Ctx,
|
||||
memory_index: LocalMemoryIndex,
|
||||
) -> 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;
|
||||
|
||||
(*memory).size()
|
||||
@ -41,7 +41,7 @@ pub unsafe extern "C" fn local_dynamic_memory_grow(
|
||||
memory_index: LocalMemoryIndex,
|
||||
delta: Pages,
|
||||
) -> 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;
|
||||
|
||||
match (*memory).grow(delta, &mut *local_memory) {
|
||||
@ -54,7 +54,7 @@ pub unsafe extern "C" fn local_dynamic_memory_size(
|
||||
ctx: &vm::Ctx,
|
||||
memory_index: LocalMemoryIndex,
|
||||
) -> 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;
|
||||
|
||||
(*memory).size()
|
||||
@ -69,7 +69,10 @@ pub unsafe extern "C" fn imported_static_memory_grow(
|
||||
import_memory_index: ImportedMemoryIndex,
|
||||
delta: Pages,
|
||||
) -> 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;
|
||||
|
||||
match (*memory).grow(delta, &mut *local_memory) {
|
||||
@ -82,7 +85,10 @@ pub unsafe extern "C" fn imported_static_memory_size(
|
||||
ctx: &vm::Ctx,
|
||||
import_memory_index: ImportedMemoryIndex,
|
||||
) -> 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;
|
||||
|
||||
(*memory).size()
|
||||
@ -93,7 +99,7 @@ pub unsafe extern "C" fn imported_dynamic_memory_grow(
|
||||
memory_index: ImportedMemoryIndex,
|
||||
delta: Pages,
|
||||
) -> 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;
|
||||
|
||||
match (*memory).grow(delta, &mut *local_memory) {
|
||||
@ -106,7 +112,7 @@ pub unsafe extern "C" fn imported_dynamic_memory_size(
|
||||
ctx: &vm::Ctx,
|
||||
memory_index: ImportedMemoryIndex,
|
||||
) -> 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;
|
||||
|
||||
(*memory).size()
|
||||
|
@ -9,6 +9,7 @@ edition = "2018"
|
||||
readme = "README.md"
|
||||
|
||||
[dependencies]
|
||||
wasmer-dynasm-backend = { path = "../dynasm-backend", optional = true }
|
||||
lazy_static = "1.2.0"
|
||||
memmap = "0.7.0"
|
||||
|
||||
@ -19,6 +20,7 @@ version = "0.2.1"
|
||||
[dependencies.wasmer-clif-backend]
|
||||
path = "../clif-backend"
|
||||
version = "0.2.0"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.0.7"
|
||||
@ -30,8 +32,12 @@ path = "../llvm-backend"
|
||||
optional = true
|
||||
|
||||
[features]
|
||||
default = ["default-compiler"]
|
||||
default-compiler = ["wasmer-clif-backend"]
|
||||
cache = ["default-compiler"]
|
||||
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
||||
llvm = ["wasmer-llvm-backend"]
|
||||
dynasm = ["wasmer-dynasm-backend"]
|
||||
|
||||
[[bench]]
|
||||
name = "nginx"
|
||||
|
@ -159,7 +159,10 @@ pub fn default_compiler() -> &'static dyn Compiler {
|
||||
#[cfg(feature = "llvm")]
|
||||
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;
|
||||
|
||||
lazy_static! {
|
||||
|
@ -10,19 +10,19 @@ build = "build/mod.rs"
|
||||
|
||||
[dependencies]
|
||||
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]
|
||||
wabt = "0.7.2"
|
||||
|
||||
[dev-dependencies]
|
||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.2.0" }
|
||||
wabt = "0.7.2"
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.1.0", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["fast-tests"]
|
||||
fast-tests = []
|
||||
clif = []
|
||||
llvm = ["wasmer-llvm-backend"]
|
||||
dynasm = ["wasmer-dynasm-backend"]
|
@ -107,7 +107,13 @@ fn get_compiler() -> impl Compiler {
|
||||
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 {
|
||||
panic!("compiler not specified, activate a compiler via features");
|
||||
use wasmer_clif_backend::CraneliftCompiler;
|
||||
|
@ -22,7 +22,13 @@ fn get_compiler() -> impl Compiler {
|
||||
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 {
|
||||
panic!("compiler not specified, activate a compiler via features");
|
||||
use wasmer_clif_backend::CraneliftCompiler;
|
||||
|
@ -131,8 +131,9 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
||||
let module = webassembly::compile(&wasm_binary[..])
|
||||
.map_err(|e| format!("Can't compile module: {:?}", e))?;
|
||||
|
||||
// We save the module into a cache file
|
||||
cache.store(hash, module.clone()).unwrap();
|
||||
// We try to save the module into a cache file
|
||||
cache.store(hash, module.clone()).unwrap_or_default();
|
||||
|
||||
module
|
||||
}
|
||||
};
|
||||
|
@ -4,6 +4,7 @@ use wasmer_runtime::{
|
||||
error::{CallResult, Result},
|
||||
ImportObject, Instance, Module,
|
||||
};
|
||||
use wasmer_runtime_core::types::Value;
|
||||
|
||||
use wasmer_emscripten::{is_emscripten_module, run_emscripten_instance};
|
||||
|
||||
@ -86,7 +87,11 @@ pub fn run_instance(
|
||||
if is_emscripten_module(module) {
|
||||
run_emscripten_instance(module, instance, path, args)?;
|
||||
} else {
|
||||
instance.call("main", &[])?;
|
||||
let args: Vec<Value> = args
|
||||
.into_iter()
|
||||
.map(|x| Value::I32(x.parse().unwrap()))
|
||||
.collect();
|
||||
instance.call("main", &args)?;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
Loading…
Reference in New Issue
Block a user