Merge branch 'feature/add-syscalls-for-php' of github.com:wasmerio/wasmer into feature/add-syscalls-for-php

This commit is contained in:
Mark McCaskey 2019-03-25 10:45:19 -07:00
commit d825746245
42 changed files with 7019 additions and 85 deletions

View File

@ -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
View File

@ -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"

View File

@ -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"]

View File

@ -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

View 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)
)
)

View 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)
)
)

View 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))
)
)

View 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)
)
)
)

View 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)
)
)
)

View 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)
)
)

View 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)
)
)

View 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)
)
)

View 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)
)
)
)

View 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)
)
)

View 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))
)
)
)

View 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)
)
)
)

View 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)
)
)
)

View File

@ -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

View 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"

View 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,
}

File diff suppressed because it is too large Load Diff

View 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),
}
}
}

View 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,
});
}
})
}

View 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 _)
}

View 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,
}],
}
}
}

View File

@ -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"]

View File

@ -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;

View File

@ -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;

View File

@ -22,6 +22,7 @@ pub use crate::sig_registry::SigRegistry;
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
pub enum Backend {
Cranelift,
Dynasm,
LLVM,
}

View File

@ -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>;

View File

@ -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
}
);
}
}

View File

@ -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.

View File

@ -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.

View File

@ -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!(

View File

@ -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()

View File

@ -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"

View File

@ -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! {

View File

@ -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"]

View File

@ -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;

View File

@ -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;

View File

@ -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
}
};

View File

@ -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(())