mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-16 17:18:57 +00:00
Merge remote-tracking branch 'origin/master' into middleware
This commit is contained in:
243
Cargo.lock
generated
243
Cargo.lock
generated
@@ -148,6 +148,24 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
@@ -326,6 +344,41 @@ dependencies = [
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63f696897c88b57f4ffe3c69d8e1a0613c7d0e6c4833363c8560fbde9c47b966"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"cast",
|
||||
"clap",
|
||||
"criterion-plot",
|
||||
"csv",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"num-traits",
|
||||
"oorandom",
|
||||
"plotters",
|
||||
"rayon",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"tinytemplate",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion-plot"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddeaf7989f00f2e1d871a26a110f3ed713632feac17f65f03ca938c542618b60"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"itertools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.7.3"
|
||||
@@ -383,6 +436,28 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"csv-core",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv-core"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.14"
|
||||
@@ -765,6 +840,15 @@ version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce10c23ad2ea25ceca0093bd3192229da4c5b3c0f2de499c1ecac0d98d452177"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
@@ -1021,6 +1105,12 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
version = "11.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94af325bc33c7f60191be4e2c984d48aaa21e2854f473b85398344b60c9b6358"
|
||||
|
||||
[[package]]
|
||||
name = "orbclient"
|
||||
version = "0.3.27"
|
||||
@@ -1104,6 +1194,18 @@ version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d1685fbe7beba33de0330629da9d955ac75bd54f33d7b79f9a895590124f6bb"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.8"
|
||||
@@ -1390,6 +1492,15 @@ dependencies = [
|
||||
"thread_local",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.18"
|
||||
@@ -1444,6 +1555,15 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.0"
|
||||
@@ -1685,7 +1805,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "test-utils"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"wasmer",
|
||||
"wasmer-compiler",
|
||||
@@ -1743,6 +1863,16 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinytemplate"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d3dc76004a03cec1c5932bca4cdc2e39aaa798e3f82363dd94f9adf6098c12f"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.6"
|
||||
@@ -1855,15 +1985,80 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c2dc4aa152834bc334f506c1a06b866416a8b6697d5c9f75b9a689c8486def0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ded84f06e0ed21499f6184df0e0cb3494727b0c5da89534e0fcc55c51d812101"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "838e423688dac18d73e31edce74ddfac468e37b1506ad163ffaf0a46f703ffe3"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3156052d8ec77142051a533cdd686cba889537b213f948cd1d20869926e68e92"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9ba19973a58daf4db6f352eda73dc0e289493cd29fb2632eb172085b6521acd"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-common"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
"serde",
|
||||
@@ -1871,7 +2066,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cfg-if",
|
||||
@@ -1897,7 +2092,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-bin"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"atty",
|
||||
@@ -1905,8 +2100,10 @@ dependencies = [
|
||||
"bytesize",
|
||||
"cfg-if",
|
||||
"colored",
|
||||
"criterion",
|
||||
"distance",
|
||||
"glob",
|
||||
"lazy_static",
|
||||
"rustc_version",
|
||||
"structopt",
|
||||
"test-generator",
|
||||
@@ -1929,7 +2126,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-c-api"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"cfg-if",
|
||||
@@ -1945,7 +2142,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-cache"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"hex",
|
||||
@@ -1956,7 +2153,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-compiler"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"enumset",
|
||||
"hashbrown",
|
||||
@@ -1973,7 +2170,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-compiler-cranelift"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"cranelift-frontend",
|
||||
@@ -1991,7 +2188,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-compiler-llvm"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"cc",
|
||||
@@ -2013,7 +2210,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-compiler-singlepass"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"dynasm",
|
||||
@@ -2031,7 +2228,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-engine"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bincode",
|
||||
@@ -2051,7 +2248,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-engine-dummy"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"serde",
|
||||
@@ -2064,7 +2261,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-engine-jit"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"region",
|
||||
@@ -2079,7 +2276,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-engine-native"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"cfg-if",
|
||||
@@ -2098,7 +2295,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-runtime"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"cc",
|
||||
@@ -2116,7 +2313,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-wasi"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"byteorder",
|
||||
@@ -2134,7 +2331,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-wasi-experimental-io-devices"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"minifb",
|
||||
"ref_thread_local",
|
||||
@@ -2146,7 +2343,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-wast"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"thiserror",
|
||||
@@ -2248,6 +2445,16 @@ dependencies = [
|
||||
"dlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b72fe77fd39e4bd3eaa4412fd299a0be6b3dfe9d2597e2f1c20beb968f41d17"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "3.1.1"
|
||||
|
||||
47
Cargo.toml
47
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-bin"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
repository = "https://github.com/wasmerio/wasmer"
|
||||
description = "High-Performance WebAssembly Framework"
|
||||
@@ -25,20 +25,20 @@ path = "src/bin/wasmer.rs"
|
||||
doc = false
|
||||
|
||||
[dependencies]
|
||||
wasmer = { version = "0.16.2", path = "lib/api", default-features = false }
|
||||
wasmer-compiler = { version = "0.16.2", path = "lib/compiler" }
|
||||
wasmer-compiler-cranelift = { version = "0.16.2", path = "lib/compiler-cranelift", optional = true }
|
||||
wasmer-compiler-singlepass = { version = "0.16.2", path = "lib/compiler-singlepass", optional = true }
|
||||
wasmer-compiler-llvm = { version = "0.16.2", path = "lib/compiler-llvm", optional = true }
|
||||
#wasmer-emscripten = { version = "0.16.2", path = "lib/emscripten", optional = true }
|
||||
wasmer-engine = { version = "0.16.2", path = "lib/engine" }
|
||||
wasmer-engine-jit = { version = "0.16.2", path = "lib/engine-jit", optional = true }
|
||||
wasmer-engine-native = { version = "0.16.2", path = "lib/engine-native", optional = true }
|
||||
wasmer-wasi = { version = "0.16.2", path = "lib/wasi", optional = true }
|
||||
wasmer-wasi-experimental-io-devices = { version = "0.16.2", path = "lib/wasi-experimental-io-devices", optional = true }
|
||||
wasmer-wast = { version = "0.16.2", path = "tests/lib/wast", optional = true }
|
||||
wasmer-cache = { version = "0.16.2", path = "lib/cache", optional = true }
|
||||
wasm-common = { version = "0.16.2", path = "lib/wasm-common" }
|
||||
wasmer = { version = "1.0.0-alpha.1", path = "lib/api", default-features = false }
|
||||
wasmer-compiler = { version = "1.0.0-alpha.1", path = "lib/compiler" }
|
||||
wasmer-compiler-cranelift = { version = "1.0.0-alpha.1", path = "lib/compiler-cranelift", optional = true }
|
||||
wasmer-compiler-singlepass = { version = "1.0.0-alpha.1", path = "lib/compiler-singlepass", optional = true }
|
||||
wasmer-compiler-llvm = { version = "1.0.0-alpha.1", path = "lib/compiler-llvm", optional = true }
|
||||
#wasmer-emscripten = { version = "1.0.0-alpha.1", path = "lib/emscripten", optional = true }
|
||||
wasmer-engine = { version = "1.0.0-alpha.1", path = "lib/engine" }
|
||||
wasmer-engine-jit = { version = "1.0.0-alpha.1", path = "lib/engine-jit", optional = true }
|
||||
wasmer-engine-native = { version = "1.0.0-alpha.1", path = "lib/engine-native", optional = true }
|
||||
wasmer-wasi = { version = "1.0.0-alpha.1", path = "lib/wasi", optional = true }
|
||||
wasmer-wasi-experimental-io-devices = { version = "1.0.0-alpha.1", path = "lib/wasi-experimental-io-devices", optional = true }
|
||||
wasmer-wast = { version = "1.0.0-alpha.1", path = "tests/lib/wast", optional = true }
|
||||
wasmer-cache = { version = "1.0.0-alpha.1", path = "lib/cache", optional = true }
|
||||
wasm-common = { version = "1.0.0-alpha.1", path = "lib/wasm-common" }
|
||||
atty = "0.2"
|
||||
colored = "1.9"
|
||||
anyhow = "1.0"
|
||||
@@ -63,6 +63,8 @@ rustc_version = "0.2"
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0"
|
||||
blake3 = "0.3"
|
||||
criterion = "0.3"
|
||||
lazy_static = "1.4"
|
||||
test-utils = { path = "tests/lib/test-utils" }
|
||||
wasmer-engine-dummy = { path = "tests/lib/engine-dummy" }
|
||||
|
||||
@@ -105,5 +107,20 @@ llvm = [
|
||||
"compiler",
|
||||
]
|
||||
|
||||
# Testing features
|
||||
test-singlepass = [
|
||||
"singlepass",
|
||||
]
|
||||
test-cranelift = [
|
||||
"cranelift",
|
||||
]
|
||||
test-llvm = [
|
||||
"llvm",
|
||||
]
|
||||
|
||||
# [profile.release]
|
||||
# lto = "fat"
|
||||
|
||||
[[bench]]
|
||||
name = "static_and_dynamic_functions"
|
||||
harness = false
|
||||
|
||||
31
Makefile
31
Makefile
@@ -59,6 +59,9 @@ compiler_features := --features "$(compiler_features_spaced)"
|
||||
# Building #
|
||||
############
|
||||
|
||||
bench:
|
||||
cargo bench $(compiler_features)
|
||||
|
||||
build-wasmer:
|
||||
cargo build --release $(compiler_features)
|
||||
|
||||
@@ -93,8 +96,21 @@ build-capi-llvm:
|
||||
# Testing #
|
||||
###########
|
||||
|
||||
test:
|
||||
cargo test --release $(compiler_features)
|
||||
test: $(foreach compiler,$(compilers),test-$(compiler)) test-packages
|
||||
|
||||
test-singlepass:
|
||||
cargo test --release $(compiler_features) --features "test-singlepass"
|
||||
|
||||
test-cranelift:
|
||||
cargo test --release $(compiler_features) --features "test-cranelift"
|
||||
|
||||
test-llvm:
|
||||
cargo test --release $(compiler_features) --features "test-llvm"
|
||||
|
||||
test-packages:
|
||||
cargo test -p wasmer --release
|
||||
cargo test -p wasmer-runtime --release
|
||||
cargo test -p wasm-common --release
|
||||
|
||||
test-capi-singlepass: build-capi-singlepass
|
||||
cargo test --manifest-path lib/c-api/Cargo.toml --release \
|
||||
@@ -114,6 +130,15 @@ test-capi: test-capi-singlepass test-capi-cranelift test-capi-llvm test-capi-ems
|
||||
# Packaging #
|
||||
#############
|
||||
|
||||
package-wapm:
|
||||
mkdir -p "package/bin"
|
||||
ifeq ($(OS), Windows_NT)
|
||||
echo ""
|
||||
else
|
||||
echo "#!/bin/bash\nwapm execute \"\$$@\"" > package/bin/wax
|
||||
chmod +x package/bin/wax
|
||||
endif
|
||||
|
||||
package-wasmer:
|
||||
mkdir -p "package/bin"
|
||||
ifeq ($(OS), Windows_NT)
|
||||
@@ -155,7 +180,7 @@ package-docs: build-docs build-docs-capi
|
||||
echo '<!-- Build $(SOURCE_VERSION) --><meta http-equiv="refresh" content="0; url=rust/wasmer_runtime/index.html">' > package/docs/index.html
|
||||
echo '<!-- Build $(SOURCE_VERSION) --><meta http-equiv="refresh" content="0; url=wasmer_runtime/index.html">' > package/docs/crates/index.html
|
||||
|
||||
package: package-wasmer package-capi
|
||||
package: package-wapm package-wasmer package-capi
|
||||
cp LICENSE package/LICENSE
|
||||
cp ATTRIBUTIONS.md package/ATTRIBUTIONS
|
||||
mkdir -p dist
|
||||
|
||||
14
README.md
14
README.md
@@ -8,12 +8,12 @@
|
||||
<a href="https://dev.azure.com/wasmerio/wasmer/_build/latest?definitionId=3&branchName=master">
|
||||
<img src="https://img.shields.io/azure-devops/build/wasmerio/wasmer/3.svg?style=flat-square" alt="Build Status">
|
||||
</a>
|
||||
<a href="https://slack.wasmer.io">
|
||||
<img src="https://img.shields.io/static/v1?label=Slack&message=join%20chat&color=brighgreen&style=flat-square" alt="Slack channel">
|
||||
</a>
|
||||
<a href="https://github.com/wasmerio/wasmer/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/github/license/wasmerio/wasmer.svg?style=flat-square" alt="License">
|
||||
</a>
|
||||
<a href="https://slack.wasmer.io">
|
||||
<img src="https://img.shields.io/static/v1?label=Slack&message=join%20chat&color=brighgreen&style=flat-square" alt="Slack channel">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h3>
|
||||
@@ -21,18 +21,14 @@
|
||||
<span> • </span>
|
||||
<a href="https://docs.wasmer.io">Docs</a>
|
||||
<span> • </span>
|
||||
<a href="https://medium.com/wasmer/">Blog</a>
|
||||
<span> • </span>
|
||||
<a href="https://slack.wasmer.io/">Slack</a>
|
||||
<span> • </span>
|
||||
<a href="https://twitter.com/wasmerio">Twitter</a>
|
||||
<a href="https://slack.wasmer.io/">Chat</a>
|
||||
</h3>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
[Wasmer](https://wasmer.io/) is a standalone [WebAssembly](https://webassembly.org/) runtime:
|
||||
[Wasmer](https://wasmer.io/) is the fastest and most popular [WebAssembly](https://webassembly.org/) runtime:
|
||||
* **Universal**: Wasmer is available in *Linux, macOS and Windows* (for both Desktop and [ARM](https://medium.com/wasmer/running-webassembly-on-arm-7d365ed0e50c))
|
||||
* **Fast**: Wasmer aims to run WebAssembly at near-native speed
|
||||
* **Pluggable**: Wasmer can be used from almost **any programming language**
|
||||
|
||||
193
benches/static_and_dynamic_functions.rs
Normal file
193
benches/static_and_dynamic_functions.rs
Normal file
@@ -0,0 +1,193 @@
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use test_utils::get_compiler_config_from_str;
|
||||
|
||||
use wasmer::*;
|
||||
use wasmer_engine_jit::JITEngine;
|
||||
|
||||
static BASIC_WAT: &str = r#"(module
|
||||
(func $multiply (import "env" "multiply") (param i32 i32) (result i32))
|
||||
(func (export "add") (param i32 i32) (result i32)
|
||||
(i32.add (local.get 0)
|
||||
(local.get 1)))
|
||||
(func (export "add20") (param i32 i32 i32 i32 i32
|
||||
i32 i32 i32 i32 i32
|
||||
i32 i32 i32 i32 i32
|
||||
i32 i32 i32 i32 i32) (result i32)
|
||||
(i32.add
|
||||
(i32.add
|
||||
(i32.add (i32.add (i32.add (local.get 0) (local.get 1))
|
||||
(i32.add (local.get 2) (local.get 3)))
|
||||
(i32.add (i32.add (local.get 4) (local.get 5))
|
||||
(i32.add (local.get 6) (local.get 7))))
|
||||
(i32.add
|
||||
(i32.add (i32.add (local.get 8) (local.get 9))
|
||||
(i32.add (local.get 10) (local.get 11)))
|
||||
(i32.add (i32.add (local.get 12) (local.get 13))
|
||||
(i32.add (local.get 14) (local.get 15)))))
|
||||
|
||||
(i32.add (i32.add (local.get 16) (local.get 17))
|
||||
(i32.add (local.get 18) (local.get 19))))
|
||||
)
|
||||
(func (export "double_then_add") (param i32 i32) (result i32)
|
||||
(i32.add (call $multiply (local.get 0) (i32.const 2))
|
||||
(call $multiply (local.get 1) (i32.const 2))))
|
||||
)"#;
|
||||
|
||||
pub fn run_basic_static_function(store: &Store, compiler_name: &str, c: &mut Criterion) {
|
||||
let module = Module::new(&store, BASIC_WAT).unwrap();
|
||||
let import_object = imports! {
|
||||
"env" => {
|
||||
"multiply" => Function::new(&store, |a: i32, b: i32| a * b),
|
||||
},
|
||||
};
|
||||
let instance = Instance::new(&module, &import_object).unwrap();
|
||||
let dyn_f: &Function = instance.exports.get("add").unwrap();
|
||||
let f: NativeFunc<(i32, i32), i32> = dyn_f.native().unwrap();
|
||||
|
||||
c.bench_function(&format!("basic static func {}", compiler_name), |b| {
|
||||
b.iter(|| {
|
||||
let result = black_box(f.call(4, 6).unwrap());
|
||||
assert_eq!(result, 10);
|
||||
})
|
||||
});
|
||||
|
||||
let dyn_f_many: &Function = instance.exports.get("add20").unwrap();
|
||||
let f_many: NativeFunc<
|
||||
(
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
i32,
|
||||
),
|
||||
i32,
|
||||
> = dyn_f_many.native().unwrap();
|
||||
c.bench_function(
|
||||
&format!("basic static func with many args {}", compiler_name),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
let result = black_box(
|
||||
f_many
|
||||
.call(
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
assert_eq!(result, 210);
|
||||
})
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
pub fn run_basic_dynamic_function(store: &Store, compiler_name: &str, c: &mut Criterion) {
|
||||
let module = Module::new(&store, BASIC_WAT).unwrap();
|
||||
let import_object = imports! {
|
||||
"env" => {
|
||||
"multiply" => Function::new(&store, |a: i32, b: i32| a * b),
|
||||
},
|
||||
};
|
||||
let instance = Instance::new(&module, &import_object).unwrap();
|
||||
|
||||
let dyn_f: &Function = instance.exports.get("add").unwrap();
|
||||
c.bench_function(&format!("basic dynfunc {}", compiler_name), |b| {
|
||||
b.iter(|| {
|
||||
let dyn_result = black_box(dyn_f.call(&[Val::I32(4), Val::I32(6)]).unwrap());
|
||||
assert_eq!(dyn_result[0], Val::I32(10));
|
||||
})
|
||||
});
|
||||
|
||||
let dyn_f_many: &Function = instance.exports.get("add20").unwrap();
|
||||
c.bench_function(
|
||||
&format!("basic dynfunc with many args {}", compiler_name),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
let dyn_result = black_box(
|
||||
dyn_f_many
|
||||
.call(&[
|
||||
Val::I32(1),
|
||||
Val::I32(2),
|
||||
Val::I32(3),
|
||||
Val::I32(4),
|
||||
Val::I32(5),
|
||||
Val::I32(6),
|
||||
Val::I32(7),
|
||||
Val::I32(8),
|
||||
Val::I32(9),
|
||||
Val::I32(10),
|
||||
Val::I32(11),
|
||||
Val::I32(12),
|
||||
Val::I32(13),
|
||||
Val::I32(14),
|
||||
Val::I32(15),
|
||||
Val::I32(16),
|
||||
Val::I32(17),
|
||||
Val::I32(18),
|
||||
Val::I32(19),
|
||||
Val::I32(20),
|
||||
])
|
||||
.unwrap(),
|
||||
);
|
||||
assert_eq!(dyn_result[0], Val::I32(210));
|
||||
})
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn run_static_benchmarks(c: &mut Criterion) {
|
||||
#[cfg(feature = "llvm")]
|
||||
{
|
||||
let store = test_utils::get_default_llvm_store();
|
||||
run_basic_static_function(&store, "llvm", c);
|
||||
}
|
||||
|
||||
#[cfg(feature = "cranelift")]
|
||||
{
|
||||
let store = test_utils::get_default_cranelift_store();
|
||||
run_basic_static_function(&store, "cranelift", c);
|
||||
}
|
||||
|
||||
#[cfg(feature = "singlepass")]
|
||||
{
|
||||
let store = test_utils::get_default_singlepass_store();
|
||||
run_basic_static_function(&store, "singlepass", c);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_dynamic_benchmarks(c: &mut Criterion) {
|
||||
#[cfg(feature = "llvm")]
|
||||
{
|
||||
let store = test_utils::get_default_llvm_store();
|
||||
run_basic_dynamic_function(&store, "llvm", c);
|
||||
}
|
||||
|
||||
#[cfg(feature = "cranelift")]
|
||||
{
|
||||
let store = test_utils::get_default_cranelift_store();
|
||||
run_basic_dynamic_function(&store, "cranelift", c);
|
||||
}
|
||||
|
||||
#[cfg(feature = "singlepass")]
|
||||
{
|
||||
let store = test_utils::get_default_singlepass_store();
|
||||
run_basic_dynamic_function(&store, "singlepass", c);
|
||||
}
|
||||
}
|
||||
|
||||
criterion_group!(benches, run_static_benchmarks, run_dynamic_benchmarks);
|
||||
|
||||
criterion_main!(benches);
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
description = "Wasmer runtime API"
|
||||
license = "(Apache-2.0 WITH LLVM-exception) OR MIT"
|
||||
@@ -9,15 +9,15 @@ readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
|
||||
wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "0.16.2", optional = true }
|
||||
wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "0.16.2", optional = true }
|
||||
wasmer-compiler-llvm = { path = "../compiler-llvm", version = "0.16.2", optional = true }
|
||||
wasmer-compiler = { path = "../compiler", version = "0.16.2" }
|
||||
wasmer-engine = { path = "../engine", version = "0.16.2" }
|
||||
wasmer-engine-jit = { path = "../engine-jit", version = "0.16.2", optional = true }
|
||||
wasmer-engine-native = { path = "../engine-native", version = "0.16.2", optional = true }
|
||||
wasm-common = { path = "../wasm-common", version = "0.16.2" }
|
||||
wasmer-runtime = { path = "../runtime", version = "1.0.0-alpha.1" }
|
||||
wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "1.0.0-alpha.1", optional = true }
|
||||
wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "1.0.0-alpha.1", optional = true }
|
||||
wasmer-compiler-llvm = { path = "../compiler-llvm", version = "1.0.0-alpha.1", optional = true }
|
||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha.1" }
|
||||
wasmer-engine = { path = "../engine", version = "1.0.0-alpha.1" }
|
||||
wasmer-engine-jit = { path = "../engine-jit", version = "1.0.0-alpha.1", optional = true }
|
||||
wasmer-engine-native = { path = "../engine-native", version = "1.0.0-alpha.1", optional = true }
|
||||
wasm-common = { path = "../wasm-common", version = "1.0.0-alpha.1" }
|
||||
indexmap = { version = "1.3", features = ["serde-1"] }
|
||||
cfg-if = "0.1"
|
||||
wat = { version = "1.0", optional = true }
|
||||
@@ -30,7 +30,7 @@ winapi = "0.3"
|
||||
|
||||
[dev-dependencies]
|
||||
# for the binary wasmer.rs
|
||||
wasmer-engine-dummy = { path = "../../tests/lib/engine-dummy", version = "0.16.2" }
|
||||
wasmer-engine-dummy = { path = "../../tests/lib/engine-dummy", version = "1.0.0-alpha.1" }
|
||||
libc = { version = "0.2", default-features = false }
|
||||
wat = "1.0"
|
||||
tempfile = "3.1"
|
||||
|
||||
@@ -12,11 +12,11 @@ Add to your `Cargo.toml`
|
||||
|
||||
```
|
||||
[dependencies]
|
||||
wasmer = "0.16.2"
|
||||
wasmer = "1.0.0-alpha.1"
|
||||
```
|
||||
|
||||
```rust
|
||||
use wasmer::{Instance, Function, Value, imports, DefaultStore as _};
|
||||
use wasmer::{Store, Module, Instance, Value, imports};
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let module_wat = r#"
|
||||
@@ -28,10 +28,11 @@ fn main() -> anyhow::Result<()> {
|
||||
i32.add))
|
||||
"#;
|
||||
|
||||
let module = Module::new(&module_wat);
|
||||
let store = Store::default();
|
||||
let module = Module::new(&store, &module_wat);
|
||||
// The module doesn't import anything, so we create an empty import object.
|
||||
let import_object = imports! {};
|
||||
let instance = Instance::new(module, &import_object)?;
|
||||
let instance = Instance::new(&module, &import_object)?;
|
||||
|
||||
let add_one = instance.exports.get_function("add_one")?;
|
||||
let result = add_one.call([Value::I32(42)])?;
|
||||
@@ -58,11 +59,15 @@ Wasmer has the following configuration flags:
|
||||
*This feature is normally used only in development environments*
|
||||
* Compilers (mutually exclusive):
|
||||
- `singlepass`: it will use `wasmer-compiler-singlepass` as the default
|
||||
compiler.
|
||||
compiler (ideal for **blockchains**).
|
||||
- `cranelift`: it will use `wasmer-compiler-cranelift` as the default
|
||||
compiler.
|
||||
compiler (ideal for **development**).
|
||||
- `llvm`: it will use `wasmer-compiler-llvm` as the default
|
||||
compiler.
|
||||
compiler (ideal for **production**).
|
||||
|
||||
Wasmer ships by default with the `cranelift` compiler as its great for development proposes.
|
||||
However, we strongly encourage to use the `llvm` backend in production as it performs
|
||||
about 50% faster, achieving near-native speeds.
|
||||
|
||||
> Note: if you want to use multiple compilers at the same time, it's also possible!
|
||||
> You will need to import them directly via each of the compiler crates.
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
use crate::externals::{Extern, Function, Global, Memory, Table};
|
||||
use crate::import_object::LikeNamespace;
|
||||
use crate::native::NativeFunc;
|
||||
use indexmap::IndexMap;
|
||||
use std::{
|
||||
iter::{ExactSizeIterator, FromIterator},
|
||||
sync::Arc,
|
||||
};
|
||||
use thiserror::Error;
|
||||
use wasm_common::WasmTypeList;
|
||||
use wasmer_runtime::Export;
|
||||
|
||||
/// The `ExportError` can happen when trying to get a specific
|
||||
@@ -37,7 +39,7 @@ pub enum ExportError {
|
||||
|
||||
/// Exports is a special kind of map that allows easily unwrapping
|
||||
/// the types of instances.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Exports {
|
||||
map: Arc<IndexMap<String, Extern>>,
|
||||
}
|
||||
@@ -45,9 +47,7 @@ pub struct Exports {
|
||||
impl Exports {
|
||||
/// Creates a new `Exports`.
|
||||
pub fn new() -> Self {
|
||||
Exports {
|
||||
map: Arc::new(IndexMap::new()),
|
||||
}
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// Creates a new `Exports` with capacity `n`.
|
||||
@@ -89,7 +89,7 @@ impl Exports {
|
||||
///
|
||||
/// If you want to get an export dynamically handling manually
|
||||
/// type checking manually, please use `get_extern`.
|
||||
pub fn get<'a, T: Exportable<'a>>(&'a self, name: &str) -> Result<&T, ExportError> {
|
||||
pub fn get<'a, T: Exportable<'a>>(&'a self, name: &str) -> Result<&'a T, ExportError> {
|
||||
match self.map.get(name) {
|
||||
None => Err(ExportError::Missing(name.to_string())),
|
||||
Some(extern_) => T::get_self_from_extern(extern_),
|
||||
@@ -116,6 +116,20 @@ impl Exports {
|
||||
self.get(name)
|
||||
}
|
||||
|
||||
/// Get an export as a `NativeFunc`.
|
||||
pub fn get_native_function<Args, Rets>(
|
||||
&self,
|
||||
name: &str,
|
||||
) -> Result<NativeFunc<Args, Rets>, ExportError>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
self.get_function(name)?
|
||||
.native()
|
||||
.ok_or(ExportError::IncompatibleType)
|
||||
}
|
||||
|
||||
/// Get an export as an `Extern`.
|
||||
pub fn get_extern(&self, name: &str) -> Option<&Extern> {
|
||||
self.map.get(name)
|
||||
@@ -130,9 +144,7 @@ impl Exports {
|
||||
}
|
||||
|
||||
/// Get an iterator over the exports.
|
||||
pub fn iter<'a>(
|
||||
&'a self,
|
||||
) -> ExportsIterator<'a, impl Iterator<Item = (&'a String, &'a Extern)>> {
|
||||
pub fn iter(&self) -> ExportsIterator<impl Iterator<Item = (&String, &Extern)>> {
|
||||
ExportsIterator {
|
||||
iter: self.map.iter(),
|
||||
}
|
||||
|
||||
51
lib/api/src/externals/function.rs
vendored
51
lib/api/src/externals/function.rs
vendored
@@ -3,6 +3,7 @@ use crate::externals::Extern;
|
||||
use crate::store::Store;
|
||||
use crate::types::Val;
|
||||
use crate::FunctionType;
|
||||
use crate::NativeFunc;
|
||||
use crate::RuntimeError;
|
||||
use std::cmp::max;
|
||||
use wasm_common::{HostFunction, WasmTypeList, WithEnv, WithoutEnv};
|
||||
@@ -15,7 +16,7 @@ use wasmer_runtime::{
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct WasmFunctionDefinition {
|
||||
// The trampoline to do the call
|
||||
trampoline: VMTrampoline,
|
||||
pub(crate) trampoline: VMTrampoline,
|
||||
}
|
||||
|
||||
/// The inner helper
|
||||
@@ -30,11 +31,11 @@ pub enum FunctionDefinition {
|
||||
/// A WebAssembly `function`.
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Function {
|
||||
store: Store,
|
||||
definition: FunctionDefinition,
|
||||
pub(crate) store: Store,
|
||||
pub(crate) definition: FunctionDefinition,
|
||||
// If the Function is owned by the Store, not the instance
|
||||
owned_by_store: bool,
|
||||
exported: ExportFunction,
|
||||
pub(crate) owned_by_store: bool,
|
||||
pub(crate) exported: ExportFunction,
|
||||
}
|
||||
|
||||
impl Function {
|
||||
@@ -176,18 +177,14 @@ impl Function {
|
||||
let signature = self.ty();
|
||||
if signature.params().len() != params.len() {
|
||||
return Err(RuntimeError::new(format!(
|
||||
"expected {} arguments, got {}: Parameters of type [{}] did not match signature {}",
|
||||
signature.params().len(),
|
||||
params.len(),
|
||||
"Parameters of type [{}] did not match signature {}",
|
||||
format_types_for_error_message(params),
|
||||
&signature
|
||||
)));
|
||||
}
|
||||
if signature.results().len() != results.len() {
|
||||
return Err(RuntimeError::new(format!(
|
||||
"expected {} results, got {}: Results of type [{}] did not match signature {}",
|
||||
signature.results().len(),
|
||||
results.len(),
|
||||
"Results of type [{}] did not match signature {}",
|
||||
format_types_for_error_message(results),
|
||||
&signature,
|
||||
)));
|
||||
@@ -198,7 +195,7 @@ impl Function {
|
||||
// Store the argument values into `values_vec`.
|
||||
let param_tys = signature.params().iter();
|
||||
for ((arg, slot), ty) in params.iter().zip(&mut values_vec).zip(param_tys) {
|
||||
if arg.ty() != ty.clone() {
|
||||
if arg.ty() != *ty {
|
||||
let param_types = format_types_for_error_message(params);
|
||||
return Err(RuntimeError::new(format!(
|
||||
"Parameters of type [{}] did not match signature {}",
|
||||
@@ -252,12 +249,14 @@ impl Function {
|
||||
/// call the trampoline.
|
||||
pub fn call(&self, params: &[Val]) -> Result<Box<[Val]>, RuntimeError> {
|
||||
let mut results = vec![Val::null(); self.result_arity()];
|
||||
|
||||
match &self.definition {
|
||||
FunctionDefinition::Wasm(wasm) => {
|
||||
self.call_wasm(&wasm, params, &mut results)?;
|
||||
}
|
||||
_ => {} // _ => unimplemented!("The host is unimplemented"),
|
||||
_ => unimplemented!("The function definition isn't supported for the moment"),
|
||||
}
|
||||
|
||||
Ok(results.into_boxed_slice())
|
||||
}
|
||||
|
||||
@@ -286,6 +285,30 @@ impl Function {
|
||||
vmctx: self.exported.vmctx,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn native<'a, Args, Rets>(&self) -> Option<NativeFunc<'a, Args, Rets>>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
// type check
|
||||
if self.exported.signature.params() != Args::wasm_types() {
|
||||
// todo: error param types don't match
|
||||
return None;
|
||||
}
|
||||
if self.exported.signature.results() != Rets::wasm_types() {
|
||||
// todo: error result types don't match
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(NativeFunc::new(
|
||||
self.store.clone(),
|
||||
self.exported.address,
|
||||
self.exported.vmctx,
|
||||
self.exported.kind,
|
||||
self.definition.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Exportable<'a> for Function {
|
||||
@@ -313,6 +336,7 @@ trait VMDynamicFunction {
|
||||
}
|
||||
|
||||
struct VMDynamicFunctionWithoutEnv {
|
||||
#[allow(clippy::type_complexity)]
|
||||
func: Box<dyn Fn(&[Val]) -> Result<Vec<Val>, RuntimeError> + 'static>,
|
||||
function_type: FunctionType,
|
||||
}
|
||||
@@ -330,6 +354,7 @@ struct VMDynamicFunctionWithEnv<Env>
|
||||
where
|
||||
Env: Sized,
|
||||
{
|
||||
#[allow(clippy::type_complexity)]
|
||||
func: Box<dyn Fn(&mut Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static>,
|
||||
env: *mut Env,
|
||||
function_type: FunctionType,
|
||||
|
||||
9
lib/api/src/externals/memory.rs
vendored
9
lib/api/src/externals/memory.rs
vendored
@@ -45,12 +45,21 @@ impl Memory {
|
||||
&self.store
|
||||
}
|
||||
|
||||
/// TODO: document this function.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
pub unsafe fn data_unchecked(&self) -> &[u8] {
|
||||
self.data_unchecked_mut()
|
||||
}
|
||||
|
||||
/// TODO: document this function, it's trivial to cause UB/break soundness with this
|
||||
/// method.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] {
|
||||
let definition = self.definition();
|
||||
|
||||
2
lib/api/src/externals/mod.rs
vendored
2
lib/api/src/externals/mod.rs
vendored
@@ -1,4 +1,4 @@
|
||||
mod function;
|
||||
pub(crate) mod function;
|
||||
mod global;
|
||||
mod memory;
|
||||
mod table;
|
||||
|
||||
@@ -42,9 +42,10 @@ pub trait LikeNamespace {
|
||||
/// n
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct ImportObject {
|
||||
map: Arc<Mutex<HashMap<String, Box<dyn LikeNamespace>>>>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) state_creator: Option<Arc<dyn Fn() -> (*mut c_void, fn(*mut c_void)) + 'static>>,
|
||||
/// Allow missing functions to be generated and instantiation to continue when required
|
||||
/// functions are not provided.
|
||||
@@ -54,11 +55,7 @@ pub struct ImportObject {
|
||||
impl ImportObject {
|
||||
/// Create a new `ImportObject`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
map: Arc::new(Mutex::new(HashMap::new())),
|
||||
state_creator: None,
|
||||
allow_missing_functions: false,
|
||||
}
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// Gets an export given a module and a name
|
||||
@@ -97,6 +94,7 @@ impl ImportObject {
|
||||
}
|
||||
|
||||
/// Calls the state creator
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn call_state_creator(&self) -> Option<(*mut c_void, fn(*mut c_void))> {
|
||||
self.state_creator.as_ref().map(|state_gen| state_gen())
|
||||
}
|
||||
@@ -186,8 +184,8 @@ impl IntoIterator for ImportObject {
|
||||
///
|
||||
/// [`ImportObject`]: struct.ImportObject.html
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// # Usage:
|
||||
/// ```
|
||||
/// # use wasmer::{Function, Store};
|
||||
/// # let store = Store::default();
|
||||
@@ -196,7 +194,7 @@ impl IntoIterator for ImportObject {
|
||||
/// let import_object = imports! {
|
||||
/// "env" => {
|
||||
/// "foo" => Function::new(&store, foo)
|
||||
/// }
|
||||
/// },
|
||||
/// };
|
||||
///
|
||||
/// fn foo(n: i32) -> i32 {
|
||||
@@ -204,43 +202,45 @@ impl IntoIterator for ImportObject {
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
// TOOD: port of lost fixes of imports macro from wasmer master/imports macro tests
|
||||
macro_rules! imports {
|
||||
( $( $ns_name:expr => $ns:tt ),* $(,)? ) => {{
|
||||
use $crate::ImportObject;
|
||||
|
||||
let mut import_object = ImportObject::new();
|
||||
( $( $ns_name:expr => $ns:tt ),* $(,)? ) => {
|
||||
{
|
||||
let mut import_object = $crate::ImportObject::new();
|
||||
|
||||
$({
|
||||
let ns = $crate::import_namespace!($ns);
|
||||
let namespace = $crate::import_namespace!($ns);
|
||||
|
||||
import_object.register($ns_name, ns);
|
||||
import_object.register($ns_name, namespace);
|
||||
})*
|
||||
|
||||
import_object
|
||||
}};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! namespace {
|
||||
($( $imp_name:expr => $import_item:expr ),* $(,)? ) => {
|
||||
$crate::import_namespace!({ $( $imp_name => $import_item, )* })
|
||||
($( $import_name:expr => $import_item:expr ),* $(,)? ) => {
|
||||
$crate::import_namespace!( { $( $import_name => $import_item, )* } )
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! import_namespace {
|
||||
( { $( $imp_name:expr => $import_item:expr ),* $(,)? } ) => {{
|
||||
let mut ns = $crate::Exports::new();
|
||||
( { $( $import_name:expr => $import_item:expr ),* $(,)? } ) => {{
|
||||
let mut namespace = $crate::Exports::new();
|
||||
|
||||
$(
|
||||
ns.insert($imp_name, $import_item);
|
||||
namespace.insert($import_name, $import_item);
|
||||
)*
|
||||
ns
|
||||
|
||||
namespace
|
||||
}};
|
||||
($ns:ident) => {
|
||||
$ns
|
||||
|
||||
( $namespace:ident ) => {
|
||||
$namespace
|
||||
};
|
||||
}
|
||||
|
||||
@@ -356,4 +356,56 @@ mod test {
|
||||
false
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn imports_macro_allows_trailing_comma_and_none() {
|
||||
use crate::Function;
|
||||
|
||||
let store = Default::default();
|
||||
|
||||
fn func(arg: i32) -> i32 {
|
||||
arg + 1
|
||||
}
|
||||
|
||||
let _ = imports! {
|
||||
"env" => {
|
||||
"func" => Function::new(&store, func),
|
||||
},
|
||||
};
|
||||
let _ = imports! {
|
||||
"env" => {
|
||||
"func" => Function::new(&store, func),
|
||||
}
|
||||
};
|
||||
let _ = imports! {
|
||||
"env" => {
|
||||
"func" => Function::new(&store, func),
|
||||
},
|
||||
"abc" => {
|
||||
"def" => Function::new(&store, func),
|
||||
}
|
||||
};
|
||||
let _ = imports! {
|
||||
"env" => {
|
||||
"func" => Function::new(&store, func)
|
||||
},
|
||||
};
|
||||
let _ = imports! {
|
||||
"env" => {
|
||||
"func" => Function::new(&store, func)
|
||||
}
|
||||
};
|
||||
let _ = imports! {
|
||||
"env" => {
|
||||
"func1" => Function::new(&store, func),
|
||||
"func2" => Function::new(&store, func)
|
||||
}
|
||||
};
|
||||
let _ = imports! {
|
||||
"env" => {
|
||||
"func1" => Function::new(&store, func),
|
||||
"func2" => Function::new(&store, func),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,13 @@ mod import_object;
|
||||
mod instance;
|
||||
mod memory_view;
|
||||
mod module;
|
||||
mod native;
|
||||
mod ordered_resolver;
|
||||
mod ptr;
|
||||
mod store;
|
||||
mod tunables;
|
||||
mod types;
|
||||
mod utils;
|
||||
|
||||
pub use crate::exports::{ExportError, Exportable, Exports};
|
||||
pub use crate::externals::{Extern, Function, Global, Memory, Table};
|
||||
@@ -19,6 +21,7 @@ pub use crate::import_object::{ImportObject, ImportObjectIterator, LikeNamespace
|
||||
pub use crate::instance::Instance;
|
||||
pub use crate::memory_view::{Atomically, MemoryView};
|
||||
pub use crate::module::Module;
|
||||
pub use crate::native::NativeFunc;
|
||||
pub use crate::ordered_resolver::OrderedResolver;
|
||||
pub use crate::ptr::{Array, Item, WasmPtr};
|
||||
pub use crate::store::{Store, StoreObject};
|
||||
@@ -28,6 +31,7 @@ pub use crate::types::{
|
||||
MemoryType, Mutability, TableType, Val, ValType,
|
||||
};
|
||||
pub use crate::types::{Val as Value, ValType as Type};
|
||||
pub use crate::utils::is_wasm;
|
||||
|
||||
pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST};
|
||||
pub use wasm_common::{Bytes, Pages, ValueType, WasmExternType, WasmTypeList};
|
||||
@@ -39,6 +43,8 @@ pub use wasmer_engine::{
|
||||
NamedResolverChain, Resolver, RuntimeError, SerializeError,
|
||||
};
|
||||
pub use wasmer_runtime::{raise_user_trap, MemoryError};
|
||||
#[cfg(feature = "wat")]
|
||||
pub use wat::parse_bytes as wat2wasm;
|
||||
|
||||
// The compilers are mutually exclusive
|
||||
#[cfg(any(
|
||||
|
||||
@@ -33,11 +33,6 @@ pub enum IoCompileError {
|
||||
pub struct Module {
|
||||
store: Store,
|
||||
artifact: Arc<dyn Artifact>,
|
||||
|
||||
#[cfg(feature = "wat")]
|
||||
#[doc(hidden)]
|
||||
// If the module was compiled from a wat file.
|
||||
pub from_wat: bool,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
@@ -103,20 +98,12 @@ impl Module {
|
||||
#[allow(unreachable_code)]
|
||||
pub fn new(store: &Store, bytes: impl AsRef<[u8]>) -> Result<Module, CompileError> {
|
||||
#[cfg(feature = "wat")]
|
||||
{
|
||||
let might_be_wat = !bytes.as_ref().starts_with(b"\0asm");
|
||||
let bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| {
|
||||
CompileError::Wasm(WasmError::Generic(format!(
|
||||
"Error when converting wat: {}",
|
||||
e
|
||||
)))
|
||||
})?;
|
||||
let mut module = Module::from_binary(store, bytes.as_ref())?;
|
||||
// We can assume it was a wat file if is not "wasm" looking
|
||||
// and the previous step succeeded.
|
||||
module.from_wat = might_be_wat;
|
||||
return Ok(module);
|
||||
}
|
||||
|
||||
Module::from_binary(store, bytes.as_ref())
|
||||
}
|
||||
@@ -145,6 +132,8 @@ impl Module {
|
||||
|
||||
/// Creates a new WebAssembly module skipping any kind of validation.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This can speed up compilation time a bit, but it should be only used
|
||||
/// in environments where the WebAssembly modules are trusted and validated
|
||||
/// beforehand.
|
||||
@@ -264,8 +253,6 @@ impl Module {
|
||||
Module {
|
||||
store: store.clone(),
|
||||
artifact,
|
||||
#[cfg(feature = "wat")]
|
||||
from_wat: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
190
lib/api/src/native.rs
Normal file
190
lib/api/src/native.rs
Normal file
@@ -0,0 +1,190 @@
|
||||
// Native Funcs
|
||||
// use wasmer_runtime::ExportFunction;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::externals::function::{FunctionDefinition, WasmFunctionDefinition};
|
||||
use crate::{Function, FunctionType, RuntimeError, Store};
|
||||
use wasm_common::{NativeWasmType, WasmExternType, WasmTypeList};
|
||||
use wasmer_runtime::{
|
||||
wasmer_call_trampoline, ExportFunction, VMContext, VMFunctionBody, VMFunctionKind,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UnprovidedArgs;
|
||||
#[derive(Clone)]
|
||||
pub struct UnprovidedRets;
|
||||
|
||||
pub struct NativeFunc<'a, Args = UnprovidedArgs, Rets = UnprovidedRets> {
|
||||
definition: FunctionDefinition,
|
||||
store: Store,
|
||||
address: *const VMFunctionBody,
|
||||
vmctx: *mut VMContext,
|
||||
arg_kind: VMFunctionKind,
|
||||
// exported: ExportFunction,
|
||||
_phantom: PhantomData<(&'a (), Args, Rets)>,
|
||||
}
|
||||
|
||||
unsafe impl<'a, Args, Rets> Send for NativeFunc<'a, Args, Rets> {}
|
||||
|
||||
impl<'a, Args, Rets> NativeFunc<'a, Args, Rets>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
pub(crate) fn new(
|
||||
store: Store,
|
||||
address: *const VMFunctionBody,
|
||||
vmctx: *mut VMContext,
|
||||
arg_kind: VMFunctionKind,
|
||||
definition: FunctionDefinition,
|
||||
) -> Self {
|
||||
Self {
|
||||
definition,
|
||||
store,
|
||||
address,
|
||||
vmctx,
|
||||
arg_kind,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Args, Rets> From<&NativeFunc<'a, Args, Rets>> for ExportFunction
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
fn from(other: &NativeFunc<'a, Args, Rets>) -> Self {
|
||||
let signature = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
|
||||
Self {
|
||||
address: other.address,
|
||||
vmctx: other.vmctx,
|
||||
signature,
|
||||
kind: other.arg_kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Args, Rets> From<NativeFunc<'a, Args, Rets>> for Function
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
fn from(other: NativeFunc<'a, Args, Rets>) -> Self {
|
||||
let signature = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
|
||||
Self {
|
||||
store: other.store,
|
||||
definition: other.definition,
|
||||
owned_by_store: true, // todo
|
||||
exported: ExportFunction {
|
||||
address: other.address,
|
||||
vmctx: other.vmctx,
|
||||
signature,
|
||||
kind: other.arg_kind,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_native_traits {
|
||||
( $( $x:ident ),* ) => {
|
||||
#[allow(unused_parens, non_snake_case)]
|
||||
impl<'a $( , $x )*, Rets> NativeFunc<'a, ( $( $x, )* ), Rets>
|
||||
where
|
||||
$( $x: WasmExternType, )*
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
/// Call the typed func and return results.
|
||||
pub fn call(&self, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
|
||||
// TODO: when `const fn` related features mature more, we can declare a single array
|
||||
// of the correct size here.
|
||||
let mut params_list = [ $( $x.to_native().to_binary() ),* ];
|
||||
let mut rets_list_array = Rets::empty_array();
|
||||
let rets_list = rets_list_array.as_mut();
|
||||
let using_rets_array;
|
||||
let args_rets: &mut [i128] = if params_list.len() > rets_list.len() {
|
||||
using_rets_array = false;
|
||||
params_list.as_mut()
|
||||
} else {
|
||||
using_rets_array = true;
|
||||
for (i, &arg) in params_list.iter().enumerate() {
|
||||
rets_list[i] = arg;
|
||||
}
|
||||
rets_list.as_mut()
|
||||
};
|
||||
|
||||
match self.definition {
|
||||
FunctionDefinition::Wasm(WasmFunctionDefinition {
|
||||
trampoline
|
||||
}) => {
|
||||
unsafe {
|
||||
wasmer_call_trampoline(
|
||||
self.vmctx,
|
||||
trampoline,
|
||||
self.address,
|
||||
args_rets.as_mut_ptr() as *mut u8,
|
||||
)
|
||||
}?;
|
||||
let num_rets = rets_list.len();
|
||||
if !using_rets_array && num_rets > 0 {
|
||||
let src_pointer = params_list.as_ptr();
|
||||
let rets_list = &mut rets_list_array.as_mut()[0] as *mut i128;
|
||||
unsafe {
|
||||
// TODO: we can probably remove this copy by doing some clever `transmute`s.
|
||||
// we know it's not overlapping because `using_rets_array` is false
|
||||
std::ptr::copy_nonoverlapping(src_pointer,
|
||||
rets_list,
|
||||
num_rets);
|
||||
}
|
||||
}
|
||||
return Ok(Rets::from_array(rets_list_array));
|
||||
}
|
||||
FunctionDefinition::Host => {
|
||||
if self.arg_kind == VMFunctionKind::Static {
|
||||
unsafe {
|
||||
let f = std::mem::transmute::<_, unsafe fn( *mut VMContext, $( $x, )*) -> Rets>(self.address);
|
||||
|
||||
let results = f( self.vmctx, $( $x, )* );
|
||||
return Ok(results);
|
||||
}
|
||||
} else {
|
||||
todo!("dynamic host functions not yet implemented")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// impl_native_traits!();
|
||||
impl_native_traits!();
|
||||
impl_native_traits!(A1);
|
||||
impl_native_traits!(A1, A2);
|
||||
impl_native_traits!(A1, A2, A3);
|
||||
impl_native_traits!(A1, A2, A3, A4);
|
||||
impl_native_traits!(A1, A2, A3, A4, A5);
|
||||
impl_native_traits!(A1, A2, A3, A4, A5, A6);
|
||||
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7);
|
||||
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8);
|
||||
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9);
|
||||
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
|
||||
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
|
||||
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
|
||||
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
|
||||
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
|
||||
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15);
|
||||
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16);
|
||||
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17);
|
||||
impl_native_traits!(
|
||||
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18
|
||||
);
|
||||
impl_native_traits!(
|
||||
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19
|
||||
);
|
||||
impl_native_traits!(
|
||||
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20
|
||||
);
|
||||
|
||||
// impl_native_traits!(A1, A2, A3);
|
||||
@@ -21,7 +21,7 @@ impl Store {
|
||||
}
|
||||
|
||||
pub fn same(a: &Store, b: &Store) -> bool {
|
||||
Arc::ptr_eq(&a.engine, &b.engine)
|
||||
a.engine.id() == b.engine.id()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,15 +41,12 @@ impl Tunables {
|
||||
// wasting too much memory.
|
||||
let dynamic_memory_offset_guard_size: u64 = 0x1_0000;
|
||||
|
||||
match triple.operating_system {
|
||||
OperatingSystem::Windows => {
|
||||
if let OperatingSystem::Windows = triple.operating_system {
|
||||
// For now, use a smaller footprint on Windows so that we don't
|
||||
// don't outstrip the paging file.
|
||||
// outstrip the paging file.
|
||||
static_memory_bound = min(static_memory_bound, 0x100.into());
|
||||
static_memory_offset_guard_size = min(static_memory_offset_guard_size, 0x10000);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Self {
|
||||
static_memory_bound,
|
||||
@@ -66,7 +63,7 @@ impl BaseTunables for Tunables {
|
||||
// tunables make it static.
|
||||
//
|
||||
// If the module doesn't declare an explicit maximum treat it as 4GiB.
|
||||
let maximum = memory.maximum.unwrap_or(Pages::max_value());
|
||||
let maximum = memory.maximum.unwrap_or_else(Pages::max_value);
|
||||
if maximum <= self.static_memory_bound {
|
||||
assert_ge!(self.static_memory_bound, memory.minimum);
|
||||
MemoryPlan {
|
||||
|
||||
4
lib/api/src/utils.rs
Normal file
4
lib/api/src/utils.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
/// Check if the provided bytes are wasm-like
|
||||
pub fn is_wasm(bytes: impl AsRef<[u8]>) -> bool {
|
||||
bytes.as_ref().starts_with(b"\0asm")
|
||||
}
|
||||
@@ -117,13 +117,12 @@ fn table_grow() -> Result<()> {
|
||||
let f = Function::new(&store, |num: i32| num + 1);
|
||||
let table = Table::new(&store, table_type, Value::FuncRef(f.clone()))?;
|
||||
// Growing to a bigger maximum should return None
|
||||
let new_len = table.grow(12, Value::FuncRef(f.clone()));
|
||||
assert!(new_len.is_err());
|
||||
let old_len = table.grow(12, Value::FuncRef(f.clone()));
|
||||
assert!(old_len.is_err());
|
||||
|
||||
// Growing to a bigger maximum should return None
|
||||
let new_len = table.grow(5, Value::FuncRef(f.clone()))?;
|
||||
// TODO: new len should be instead previous length, similarly to memory
|
||||
assert_eq!(new_len, 5);
|
||||
let old_len = table.grow(5, Value::FuncRef(f.clone()))?;
|
||||
assert_eq!(old_len, 0);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -330,3 +329,41 @@ fn function_new_dynamic_env() -> Result<()> {
|
||||
assert_eq!(function.ty().clone(), function_type);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn native_function_works() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let function = Function::new(&store, || {});
|
||||
let native_function: NativeFunc<(), ()> = function.native().unwrap();
|
||||
let result = native_function.call();
|
||||
assert!(result.is_ok());
|
||||
|
||||
// TODO:
|
||||
/*let function = Function::new(&store, |a: i32| -> i32 { a + 1 });
|
||||
let native_function: NativeFunc<i32, i32> = function.native().unwrap();
|
||||
assert!(native_function.call(3).unwrap(), 4);
|
||||
*/
|
||||
|
||||
fn rust_abi(a: i32, b: i64, c: f32, d: f64) -> u64 {
|
||||
(a as u64 * 1000) + (b as u64 * 100) + (c as u64 * 10) + (d as u64)
|
||||
}
|
||||
let function = Function::new(&store, rust_abi);
|
||||
let native_function: NativeFunc<(i32, i64, f32, f64), u64> = function.native().unwrap();
|
||||
assert_eq!(native_function.call(8, 4, 1.5, 5.).unwrap(), 8415);
|
||||
|
||||
let function = Function::new(&store, || -> i32 { 1 });
|
||||
let native_function: NativeFunc<(), i32> = function.native().unwrap();
|
||||
assert_eq!(native_function.call().unwrap(), 1);
|
||||
|
||||
// TODO:
|
||||
/*let function = Function::new(&store, |_a: i32| {});
|
||||
let native_function: NativeFunc<i32, ()> = function.native().unwrap();
|
||||
assert!(native_function.call(4).is_ok());*/
|
||||
|
||||
// TODO:
|
||||
/*let function = Function::new(&store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
|
||||
let native_function: NativeFunc<(), (i32, i64, f32, f64)> = function.native().unwrap();
|
||||
assert_eq!(native_function.call().unwrap(), (1, 2, 3.0, 4.0));
|
||||
*/
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-c-api"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
description = "Wasmer C API library"
|
||||
documentation = "https://wasmerio.github.io/wasmer/c-api/"
|
||||
license = "MIT"
|
||||
@@ -23,28 +23,28 @@ thiserror = "1"
|
||||
paste = "0.1"
|
||||
# for generating code in the same way thot the wasm-c-api does
|
||||
# Commented out for now until we can find a solution to the exported function problem
|
||||
# wasmer-wasm-c-api = { version = "0.16.2", path = "crates/wasm-c-api" }
|
||||
# wasmer-wasm-c-api = { version = "1.0.0-alpha.1", path = "crates/wasm-c-api" }
|
||||
|
||||
[dependencies.wasmer]
|
||||
default-features = false
|
||||
features = ["compiler", "engine", "jit"]
|
||||
path = "../api"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
|
||||
[dependencies.wasm-common]
|
||||
default-features = false
|
||||
path = "../wasm-common"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
|
||||
[dependencies.wasmer-wasi]
|
||||
default-features = false
|
||||
path = "../wasi"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
optional = true
|
||||
|
||||
#[dependencies.wasmer-emscripten]
|
||||
#path = "../emscripten"
|
||||
#version = "0.16.2"
|
||||
#version = "1.0.0-alpha.1"
|
||||
#optional = true
|
||||
|
||||
[features]
|
||||
|
||||
@@ -50,7 +50,7 @@ int main()
|
||||
int error_result = wasmer_last_error_message(error_str, error_len);
|
||||
assert(error_len == error_result);
|
||||
printf("Error str: `%s`\n", error_str);
|
||||
assert(0 == strcmp(error_str, "RuntimeError: expected 2 arguments, got 1: Parameters of type [I32] did not match signature [I32, I32] -> [I32]"));
|
||||
assert(0 == strcmp(error_str, "RuntimeError: Parameters of type [I32] did not match signature [I32, I32] -> [I32]"));
|
||||
free(error_str);
|
||||
|
||||
printf("Destroy instance\n");
|
||||
|
||||
4
lib/cache/Cargo.toml
vendored
4
lib/cache/Cargo.toml
vendored
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-cache"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
description = "Cache system for WebAssembly"
|
||||
license = "MIT"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@@ -11,7 +11,7 @@ keywords = ["webassembly", "wasm", "cache"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasmer = { path = "../api", version = "0.16.2", default-features = false }
|
||||
wasmer = { path = "../api", version = "1.0.0-alpha.1", default-features = false }
|
||||
memmap = "0.7"
|
||||
hex = "0.4"
|
||||
thiserror = "1"
|
||||
|
||||
2
lib/cache/src/cache.rs
vendored
2
lib/cache/src/cache.rs
vendored
@@ -20,5 +20,5 @@ pub trait Cache {
|
||||
unsafe fn load(&self, store: &Store, key: WasmHash) -> Result<Module, Self::DeserializeError>;
|
||||
|
||||
/// Store a [`Module`] into the cache with the given [`WasmHash`].
|
||||
fn store(&mut self, key: WasmHash, module: Module) -> Result<(), Self::SerializeError>;
|
||||
fn store(&mut self, key: WasmHash, module: &Module) -> Result<(), Self::SerializeError>;
|
||||
}
|
||||
|
||||
2
lib/cache/src/filesystem.rs
vendored
2
lib/cache/src/filesystem.rs
vendored
@@ -78,7 +78,7 @@ impl Cache for FileSystemCache {
|
||||
Module::deserialize_from_file(&store, new_path_buf)
|
||||
}
|
||||
|
||||
fn store(&mut self, key: WasmHash, module: Module) -> Result<(), Self::SerializeError> {
|
||||
fn store(&mut self, key: WasmHash, module: &Module) -> Result<(), Self::SerializeError> {
|
||||
let filename = key.to_string();
|
||||
let mut new_path_buf = self.path.clone();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-compiler-cranelift"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
description = "Standalone environment support for WebAsssembly code in Cranelift"
|
||||
license = "MIT OR (Apache-2.0 WITH LLVM-exception)"
|
||||
@@ -12,9 +12,9 @@ readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasmer-compiler = { path = "../compiler", version = "0.16.2", features = ["translator"], default-features = false }
|
||||
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
|
||||
wasm-common = { path = "../wasm-common", version = "0.16.2", default-features = false }
|
||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha.1", features = ["translator"], default-features = false }
|
||||
wasmer-runtime = { path = "../runtime", version = "1.0.0-alpha.1" }
|
||||
wasm-common = { path = "../wasm-common", version = "1.0.0-alpha.1", default-features = false }
|
||||
cranelift-codegen = { version = "0.62", default-features = false }
|
||||
cranelift-frontend = { version = "0.62", default-features = false }
|
||||
tracing = "0.1"
|
||||
|
||||
@@ -81,7 +81,7 @@ impl Compiler for CraneliftCompiler {
|
||||
let signatures = module
|
||||
.signatures
|
||||
.iter()
|
||||
.map(|(_sig_index, func_type)| signature_to_cranelift_ir(func_type, &frontend_config))
|
||||
.map(|(_sig_index, func_type)| signature_to_cranelift_ir(func_type, frontend_config))
|
||||
.collect::<PrimaryMap<SignatureIndex, ir::Signature>>();
|
||||
|
||||
let functions = function_body_inputs
|
||||
|
||||
@@ -715,7 +715,7 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
|
||||
Ok(GlobalVariable::Memory {
|
||||
gv: ptr,
|
||||
offset: offset.into(),
|
||||
ty: type_to_irtype(self.module.globals[index].ty, &self.target_config())?,
|
||||
ty: type_to_irtype(self.module.globals[index].ty, self.target_config())?,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ pub fn make_trampoline_dynamic_function(
|
||||
) -> Result<FunctionBody, CompileError> {
|
||||
let pointer_type = isa.pointer_type();
|
||||
let frontend_config = isa.frontend_config();
|
||||
let signature = signature_to_cranelift_ir(func_type, &frontend_config);
|
||||
let signature = signature_to_cranelift_ir(func_type, frontend_config);
|
||||
let mut stub_sig = ir::Signature::new(frontend_config.default_call_conv);
|
||||
// Add the caller `vmctx` parameter.
|
||||
stub_sig.params.push(ir::AbiParam::special(
|
||||
|
||||
@@ -27,7 +27,7 @@ pub fn make_trampoline_function_call(
|
||||
) -> Result<FunctionBody, CompileError> {
|
||||
let pointer_type = isa.pointer_type();
|
||||
let frontend_config = isa.frontend_config();
|
||||
let signature = signature_to_cranelift_ir(func_type, &frontend_config);
|
||||
let signature = signature_to_cranelift_ir(func_type, frontend_config);
|
||||
let mut wrapper_sig = ir::Signature::new(frontend_config.default_call_conv);
|
||||
|
||||
// Add the callee `vmctx` parameter.
|
||||
|
||||
@@ -66,7 +66,7 @@ pub trait TargetEnvironment {
|
||||
///
|
||||
/// This returns `R64` for 64-bit architectures and `R32` for 32-bit architectures.
|
||||
fn reference_type(&self) -> ir::Type {
|
||||
reference_type(&self.target_config()).expect("expected reference type")
|
||||
reference_type(self.target_config()).expect("expected reference type")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ use wasmer_runtime::libcalls::LibCall;
|
||||
/// Helper function translate a Function signature into Cranelift Ir
|
||||
pub fn signature_to_cranelift_ir(
|
||||
signature: &FunctionType,
|
||||
target_config: &TargetFrontendConfig,
|
||||
target_config: TargetFrontendConfig,
|
||||
) -> ir::Signature {
|
||||
let mut sig = ir::Signature::new(target_config.default_call_conv);
|
||||
sig.params.extend(signature.params().iter().map(|&ty| {
|
||||
@@ -40,7 +40,7 @@ pub fn signature_to_cranelift_ir(
|
||||
}
|
||||
|
||||
/// Helper function translating wasmparser types to Cranelift types when possible.
|
||||
pub fn reference_type(target_config: &TargetFrontendConfig) -> WasmResult<ir::Type> {
|
||||
pub fn reference_type(target_config: TargetFrontendConfig) -> WasmResult<ir::Type> {
|
||||
match target_config.pointer_type() {
|
||||
ir::types::I32 => Ok(ir::types::R32),
|
||||
ir::types::I64 => Ok(ir::types::R64),
|
||||
@@ -51,7 +51,7 @@ pub fn reference_type(target_config: &TargetFrontendConfig) -> WasmResult<ir::Ty
|
||||
}
|
||||
|
||||
/// Helper function translating wasmparser types to Cranelift types when possible.
|
||||
pub fn type_to_irtype(ty: Type, target_config: &TargetFrontendConfig) -> WasmResult<ir::Type> {
|
||||
pub fn type_to_irtype(ty: Type, target_config: TargetFrontendConfig) -> WasmResult<ir::Type> {
|
||||
match ty {
|
||||
Type::I32 => Ok(ir::types::I32),
|
||||
Type::I64 => Ok(ir::types::I64),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-compiler-llvm"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
license = "MIT"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
repository = "https://github.com/wasmerio/wasmer"
|
||||
@@ -10,9 +10,9 @@ edition = "2018"
|
||||
readme = "README.md"
|
||||
|
||||
[dependencies]
|
||||
wasmer-compiler = { path = "../compiler", version = "0.16.2", features = ["translator"] }
|
||||
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
|
||||
wasm-common = { path = "../wasm-common", version = "0.16.2" }
|
||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha.1", features = ["translator"] }
|
||||
wasmer-runtime = { path = "../runtime", version = "1.0.0-alpha.1" }
|
||||
wasm-common = { path = "../wasm-common", version = "1.0.0-alpha.1" }
|
||||
target-lexicon = { version = "0.10", default-features = false }
|
||||
smallvec = "1"
|
||||
goblin = "0.2"
|
||||
|
||||
@@ -69,26 +69,6 @@ impl LLVMConfig {
|
||||
/// Creates a new configuration object with the default configuration
|
||||
/// specified.
|
||||
pub fn new(features: Features, target: Target) -> Self {
|
||||
let operating_system =
|
||||
if target.triple().operating_system == wasmer_compiler::OperatingSystem::Darwin {
|
||||
// LLVM detects static relocation + darwin + 64-bit and
|
||||
// force-enables PIC because MachO doesn't support that
|
||||
// combination. They don't check whether they're targeting
|
||||
// MachO, they check whether the OS is set to Darwin.
|
||||
//
|
||||
// Since both linux and darwin use SysV ABI, this should work.
|
||||
wasmer_compiler::OperatingSystem::Linux
|
||||
} else {
|
||||
target.triple().operating_system
|
||||
};
|
||||
let triple = Triple {
|
||||
architecture: target.triple().architecture,
|
||||
vendor: target.triple().vendor.clone(),
|
||||
operating_system,
|
||||
environment: target.triple().environment,
|
||||
binary_format: target_lexicon::BinaryFormat::Elf,
|
||||
};
|
||||
let target = Target::new(triple, *target.cpu_features());
|
||||
Self {
|
||||
enable_nan_canonicalization: true,
|
||||
enable_verifier: false,
|
||||
@@ -112,7 +92,27 @@ impl LLVMConfig {
|
||||
}
|
||||
|
||||
pub fn target_triple(&self) -> TargetTriple {
|
||||
TargetTriple::create(&self.target().triple().to_string())
|
||||
let target = self.target();
|
||||
let operating_system =
|
||||
if target.triple().operating_system == wasmer_compiler::OperatingSystem::Darwin {
|
||||
// LLVM detects static relocation + darwin + 64-bit and
|
||||
// force-enables PIC because MachO doesn't support that
|
||||
// combination. They don't check whether they're targeting
|
||||
// MachO, they check whether the OS is set to Darwin.
|
||||
//
|
||||
// Since both linux and darwin use SysV ABI, this should work.
|
||||
wasmer_compiler::OperatingSystem::Linux
|
||||
} else {
|
||||
target.triple().operating_system
|
||||
};
|
||||
let triple = Triple {
|
||||
architecture: target.triple().architecture,
|
||||
vendor: target.triple().vendor.clone(),
|
||||
operating_system,
|
||||
environment: target.triple().environment,
|
||||
binary_format: target_lexicon::BinaryFormat::Elf,
|
||||
};
|
||||
TargetTriple::create(&triple.to_string())
|
||||
}
|
||||
|
||||
/// Generates the target machine for the current target
|
||||
@@ -149,10 +149,11 @@ impl LLVMConfig {
|
||||
.map(|feature| format!("+{}", feature.to_string()))
|
||||
.join(",");
|
||||
|
||||
let llvm_target = InkwellTarget::from_triple(&self.target_triple()).unwrap();
|
||||
let target_triple = self.target_triple();
|
||||
let llvm_target = InkwellTarget::from_triple(&target_triple).unwrap();
|
||||
llvm_target
|
||||
.create_target_machine(
|
||||
&self.target_triple(),
|
||||
&target_triple,
|
||||
"generic",
|
||||
&llvm_cpu_features,
|
||||
self.opt_level,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use crate::config::{CompiledFunctionKind, LLVMConfig};
|
||||
use crate::object_file::load_object_file;
|
||||
use crate::translator::abi::{func_type_to_llvm, is_sret, rets_from_call};
|
||||
use crate::translator::abi::{
|
||||
func_type_to_llvm, get_vmctx_ptr_param, is_sret, pack_values_for_register_return,
|
||||
rets_from_call,
|
||||
};
|
||||
use crate::translator::intrinsics::{type_to_llvm, type_to_llvm_ptr, Intrinsics};
|
||||
use inkwell::{
|
||||
attributes::{Attribute, AttributeLoc},
|
||||
@@ -14,7 +17,6 @@ use inkwell::{
|
||||
};
|
||||
use std::cmp;
|
||||
use std::convert::TryInto;
|
||||
use std::iter;
|
||||
use wasm_common::{FunctionType, Type};
|
||||
use wasmer_compiler::{CompileError, FunctionBody};
|
||||
|
||||
@@ -48,7 +50,7 @@ impl FuncTrampoline {
|
||||
let (callee_ty, callee_attrs) = func_type_to_llvm(&self.ctx, &intrinsics, ty)?;
|
||||
let trampoline_ty = intrinsics.void_ty.fn_type(
|
||||
&[
|
||||
intrinsics.ctx_ptr_ty.as_basic_type_enum(), // callee_vmctx ptr
|
||||
intrinsics.ctx_ptr_ty.as_basic_type_enum(), // vmctx ptr
|
||||
callee_ty
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.as_basic_type_enum(), // callee function address
|
||||
@@ -134,16 +136,11 @@ impl FuncTrampoline {
|
||||
module.set_data_layout(&target_machine.get_target_data().get_data_layout());
|
||||
let intrinsics = Intrinsics::declare(&module, &self.ctx);
|
||||
|
||||
let params = iter::once(Ok(intrinsics.ctx_ptr_ty.as_basic_type_enum()))
|
||||
.chain(
|
||||
ty.params()
|
||||
.iter()
|
||||
.map(|param_ty| type_to_llvm(&intrinsics, *param_ty)),
|
||||
)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let trampoline_ty = intrinsics.void_ty.fn_type(params.as_slice(), false);
|
||||
|
||||
let (trampoline_ty, trampoline_attrs) = func_type_to_llvm(&self.ctx, &intrinsics, ty)?;
|
||||
let trampoline_func = module.add_function("", trampoline_ty, Some(Linkage::External));
|
||||
for (attr, attr_loc) in trampoline_attrs {
|
||||
trampoline_func.add_attribute(attr_loc, attr);
|
||||
}
|
||||
trampoline_func
|
||||
.as_global_value()
|
||||
.set_section(FUNCTION_SECTION);
|
||||
@@ -311,14 +308,6 @@ fn generate_dynamic_trampoline<'ctx>(
|
||||
let builder = context.create_builder();
|
||||
builder.position_at_end(entry_block);
|
||||
|
||||
/*
|
||||
// TODO: remove debugging
|
||||
builder.build_call(
|
||||
intrinsics.debug_trap,
|
||||
&[],
|
||||
"");
|
||||
*/
|
||||
|
||||
// Allocate stack space for the params and results.
|
||||
let values = builder.build_alloca(
|
||||
intrinsics.i128_ty.array_type(cmp::max(
|
||||
@@ -329,6 +318,7 @@ fn generate_dynamic_trampoline<'ctx>(
|
||||
);
|
||||
|
||||
// Copy params to 'values'.
|
||||
let first_user_param = if is_sret(func_sig)? { 2 } else { 1 };
|
||||
for i in 0..func_sig.params().len() {
|
||||
let ptr = unsafe {
|
||||
builder.build_in_bounds_gep(
|
||||
@@ -343,57 +333,99 @@ fn generate_dynamic_trampoline<'ctx>(
|
||||
let ptr = builder
|
||||
.build_bitcast(ptr, type_to_llvm_ptr(intrinsics, func_sig.params()[i])?, "")
|
||||
.into_pointer_value();
|
||||
builder.build_store(ptr, trampoline_func.get_nth_param(i as u32 + 1).unwrap());
|
||||
builder.build_store(
|
||||
ptr,
|
||||
trampoline_func
|
||||
.get_nth_param(i as u32 + first_user_param)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
let callee_ty = intrinsics
|
||||
.void_ty
|
||||
.fn_type(
|
||||
&[
|
||||
intrinsics.ctx_ptr_ty.as_basic_type_enum(),
|
||||
intrinsics.i128_ptr_ty.as_basic_type_enum(),
|
||||
intrinsics.ctx_ptr_ty.as_basic_type_enum(), // vmctx ptr
|
||||
intrinsics.i128_ptr_ty.as_basic_type_enum(), // in/out values ptr
|
||||
],
|
||||
false,
|
||||
)
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let vmctx = trampoline_func.get_nth_param(0).unwrap();
|
||||
let vmctx = get_vmctx_ptr_param(&trampoline_func);
|
||||
let callee = builder
|
||||
.build_load(
|
||||
builder
|
||||
.build_bitcast(vmctx, callee_ty, "")
|
||||
.build_bitcast(vmctx, callee_ty.ptr_type(AddressSpace::Generic), "")
|
||||
.into_pointer_value(),
|
||||
"",
|
||||
)
|
||||
.into_pointer_value();
|
||||
|
||||
let values_ptr = builder.build_pointer_cast(values, intrinsics.i128_ptr_ty, "");
|
||||
builder.build_call(
|
||||
callee,
|
||||
&[vmctx.as_basic_value_enum(), values.as_basic_value_enum()],
|
||||
&[
|
||||
vmctx.as_basic_value_enum(),
|
||||
values_ptr.as_basic_value_enum(),
|
||||
],
|
||||
"",
|
||||
);
|
||||
|
||||
match func_sig.results() {
|
||||
[] => {
|
||||
if func_sig.results().is_empty() {
|
||||
builder.build_return(None);
|
||||
}
|
||||
[ty] => {
|
||||
} else {
|
||||
let results = func_sig
|
||||
.results()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, ty)| {
|
||||
let ptr = unsafe {
|
||||
builder.build_in_bounds_gep(
|
||||
builder.build_gep(
|
||||
values,
|
||||
&[intrinsics.i32_zero, intrinsics.i32_ty.const_int(0, false)],
|
||||
&[
|
||||
intrinsics.i32_ty.const_zero(),
|
||||
intrinsics.i32_ty.const_int(idx.try_into().unwrap(), false),
|
||||
],
|
||||
"",
|
||||
)
|
||||
};
|
||||
let ptr = builder
|
||||
.build_bitcast(ptr, type_to_llvm_ptr(intrinsics, *ty)?, "")
|
||||
let ptr = builder.build_pointer_cast(ptr, type_to_llvm_ptr(intrinsics, *ty)?, "");
|
||||
Ok(builder.build_load(ptr, ""))
|
||||
})
|
||||
.collect::<Result<Vec<_>, CompileError>>()?;
|
||||
|
||||
if is_sret(func_sig)? {
|
||||
let sret = trampoline_func
|
||||
.get_first_param()
|
||||
.unwrap()
|
||||
.into_pointer_value();
|
||||
let ret = builder.build_load(ptr, "");
|
||||
builder.build_return(Some(&ret));
|
||||
let mut struct_value = sret
|
||||
.get_type()
|
||||
.get_element_type()
|
||||
.into_struct_type()
|
||||
.get_undef();
|
||||
for (idx, value) in results.iter().enumerate() {
|
||||
let value = builder.build_bitcast(
|
||||
*value,
|
||||
type_to_llvm(&intrinsics, func_sig.results()[idx])?,
|
||||
"",
|
||||
);
|
||||
struct_value = builder
|
||||
.build_insert_value(struct_value, value, idx as u32, "")
|
||||
.unwrap()
|
||||
.into_struct_value();
|
||||
}
|
||||
builder.build_store(sret, struct_value);
|
||||
builder.build_return(None);
|
||||
} else {
|
||||
builder.build_return(Some(&pack_values_for_register_return(
|
||||
&intrinsics,
|
||||
&builder,
|
||||
&results.as_slice(),
|
||||
&trampoline_func.get_type(),
|
||||
)?));
|
||||
}
|
||||
}
|
||||
_ => unimplemented!("multi-value return is not yet implemented"),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -110,10 +110,12 @@ impl FuncTranslator {
|
||||
let entry = self.ctx.append_basic_block(func, "entry");
|
||||
let start_of_code = self.ctx.append_basic_block(func, "start_of_code");
|
||||
let return_ = self.ctx.append_basic_block(func, "return");
|
||||
let alloca_builder = self.ctx.create_builder();
|
||||
let cache_builder = self.ctx.create_builder();
|
||||
let builder = self.ctx.create_builder();
|
||||
cache_builder.position_at_end(entry);
|
||||
let br = cache_builder.build_unconditional_branch(start_of_code);
|
||||
alloca_builder.position_before(&br);
|
||||
cache_builder.position_before(&br);
|
||||
builder.position_at_end(start_of_code);
|
||||
|
||||
@@ -139,14 +141,23 @@ impl FuncTranslator {
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let mut is_first_alloca = true;
|
||||
let mut insert_alloca = |ty, name| {
|
||||
let alloca = alloca_builder.build_alloca(ty, name);
|
||||
if is_first_alloca {
|
||||
alloca_builder.position_at(entry, &alloca.as_instruction_value().unwrap());
|
||||
is_first_alloca = false;
|
||||
}
|
||||
alloca
|
||||
};
|
||||
|
||||
for idx in 0..wasm_fn_type.params().len() {
|
||||
let ty = wasm_fn_type.params()[idx];
|
||||
let ty = type_to_llvm(&intrinsics, ty)?;
|
||||
let value = func
|
||||
.get_nth_param((idx as u32).checked_add(first_param).unwrap())
|
||||
.unwrap();
|
||||
// TODO: don't interleave allocas and stores.
|
||||
let alloca = cache_builder.build_alloca(ty, "param");
|
||||
let alloca = insert_alloca(ty, "param");
|
||||
cache_builder.build_store(alloca, value);
|
||||
params.push(alloca);
|
||||
}
|
||||
@@ -160,9 +171,8 @@ impl FuncTranslator {
|
||||
.map_err(to_wasm_error)?;
|
||||
let ty = wptype_to_type(ty).map_err(to_compile_error)?;
|
||||
let ty = type_to_llvm(&intrinsics, ty)?;
|
||||
// TODO: don't interleave allocas and stores.
|
||||
for _ in 0..count {
|
||||
let alloca = cache_builder.build_alloca(ty, "local");
|
||||
let alloca = insert_alloca(ty, "local");
|
||||
cache_builder.build_store(alloca, const_zero(ty));
|
||||
locals.push(alloca);
|
||||
}
|
||||
@@ -174,6 +184,7 @@ impl FuncTranslator {
|
||||
let mut fcg = LLVMFunctionCodeGenerator {
|
||||
context: &self.ctx,
|
||||
builder,
|
||||
alloca_builder,
|
||||
intrinsics: &intrinsics,
|
||||
state,
|
||||
function: func,
|
||||
@@ -608,7 +619,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
||||
let divisor_is_zero = self.builder.build_int_compare(
|
||||
IntPredicate::EQ,
|
||||
right,
|
||||
int_type.const_int(0, false),
|
||||
int_type.const_zero(),
|
||||
"divisor_is_zero",
|
||||
);
|
||||
let should_trap = self.builder.build_or(
|
||||
@@ -633,10 +644,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
||||
self.intrinsics.expect_i1,
|
||||
&[
|
||||
should_trap.as_basic_value_enum(),
|
||||
self.intrinsics
|
||||
.i1_ty
|
||||
.const_int(0, false)
|
||||
.as_basic_value_enum(),
|
||||
self.intrinsics.i1_ty.const_zero().as_basic_value_enum(),
|
||||
],
|
||||
"should_trap_expect",
|
||||
)
|
||||
@@ -671,7 +679,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
||||
let should_trap = self.builder.build_int_compare(
|
||||
IntPredicate::EQ,
|
||||
value,
|
||||
int_type.const_int(0, false),
|
||||
int_type.const_zero(),
|
||||
"divisor_is_zero",
|
||||
);
|
||||
|
||||
@@ -681,10 +689,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
||||
self.intrinsics.expect_i1,
|
||||
&[
|
||||
should_trap.as_basic_value_enum(),
|
||||
self.intrinsics
|
||||
.i1_ty
|
||||
.const_int(0, false)
|
||||
.as_basic_value_enum(),
|
||||
self.intrinsics.i1_ty.const_zero().as_basic_value_enum(),
|
||||
],
|
||||
"should_trap_expect",
|
||||
)
|
||||
@@ -1179,7 +1184,7 @@ fn emit_stack_map<'ctx>(
|
||||
.const_int(stackmap_id as u64, false)
|
||||
.as_basic_value_enum(),
|
||||
);
|
||||
params.push(intrinsics.i32_ty.const_int(0, false).as_basic_value_enum());
|
||||
params.push(intrinsics.i32_ty.const_zero().as_basic_value_enum());
|
||||
|
||||
let locals: Vec<_> = locals.iter().map(|x| x.as_basic_value_enum()).collect();
|
||||
let mut value_semantics: Vec<ValueSemantic> =
|
||||
@@ -1226,7 +1231,7 @@ fn finalize_opcode_stack_map<'ctx>(
|
||||
.i64_ty
|
||||
.const_int(stackmap_id as u64, false)
|
||||
.as_basic_value_enum(),
|
||||
intrinsics.i32_ty.const_int(0, false).as_basic_value_enum(),
|
||||
intrinsics.i32_ty.const_zero().as_basic_value_enum(),
|
||||
],
|
||||
"opcode_stack_map_end",
|
||||
);
|
||||
@@ -1245,6 +1250,7 @@ fn finalize_opcode_stack_map<'ctx>(
|
||||
pub struct LLVMFunctionCodeGenerator<'ctx, 'a> {
|
||||
context: &'ctx Context,
|
||||
builder: Builder<'ctx>,
|
||||
alloca_builder: Builder<'ctx>,
|
||||
intrinsics: &'a Intrinsics<'ctx>,
|
||||
state: State<'ctx>,
|
||||
function: FunctionValue<'ctx>,
|
||||
@@ -1390,7 +1396,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
||||
);
|
||||
let signal_mem = ctx.signal_mem();
|
||||
let iv = self.builder
|
||||
.build_store(signal_mem, self.context.i8_type().const_int(0 as u64, false));
|
||||
.build_store(signal_mem, self.context.i8_type().const_zero());
|
||||
// Any 'store' can be made volatile.
|
||||
iv.set_volatile(true).unwrap();
|
||||
finalize_opcode_stack_map(
|
||||
@@ -1617,14 +1623,13 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
||||
let current_block = self.builder.get_insert_block().ok_or_else(|| {
|
||||
CompileError::Codegen("not currently in a block".to_string())
|
||||
})?;
|
||||
self.builder.build_unconditional_branch(*frame.code_after());
|
||||
|
||||
for phi in frame.phis().to_vec().iter().rev() {
|
||||
let (value, info) = self.state.pop1_extra()?;
|
||||
let value = self.apply_pending_canonicalization(value, info);
|
||||
phi.add_incoming(&[(&value, current_block)])
|
||||
}
|
||||
let frame = self.state.frame_at_depth(0)?;
|
||||
self.builder.build_unconditional_branch(*frame.code_after());
|
||||
}
|
||||
|
||||
let (if_else_block, if_else_state) = if let ControlFrame::IfElse {
|
||||
@@ -1696,19 +1701,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
||||
self.state.push1(phi.as_basic_value());
|
||||
} else {
|
||||
let basic_ty = phi.as_basic_value().get_type();
|
||||
let placeholder_value = match basic_ty {
|
||||
BasicTypeEnum::IntType(int_ty) => {
|
||||
int_ty.const_int(0, false).as_basic_value_enum()
|
||||
}
|
||||
BasicTypeEnum::FloatType(float_ty) => {
|
||||
float_ty.const_float(0.0).as_basic_value_enum()
|
||||
}
|
||||
_ => {
|
||||
return Err(CompileError::Codegen(
|
||||
"Operator::End phi type unimplemented".to_string(),
|
||||
));
|
||||
}
|
||||
};
|
||||
let placeholder_value = const_zero(basic_ty);
|
||||
self.state.push1(placeholder_value);
|
||||
phi.as_instruction().erase_from_basic_block();
|
||||
}
|
||||
@@ -1721,15 +1714,13 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
||||
.ok_or_else(|| CompileError::Codegen("not currently in a block".to_string()))?;
|
||||
|
||||
let frame = self.state.outermost_frame()?;
|
||||
self.builder.build_unconditional_branch(*frame.br_dest());
|
||||
for phi in frame.phis().to_vec().iter().rev() {
|
||||
let (arg, info) = self.state.pop1_extra()?;
|
||||
let arg = self.apply_pending_canonicalization(arg, info);
|
||||
phi.add_incoming(&[(&arg, current_block)]);
|
||||
}
|
||||
|
||||
let frame = self.state.outermost_frame()?;
|
||||
self.builder.build_unconditional_branch(*frame.br_dest());
|
||||
|
||||
self.state.reachable = false;
|
||||
}
|
||||
|
||||
@@ -2090,8 +2081,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
||||
});
|
||||
|
||||
let params = abi::args_to_call(
|
||||
// TODO: should be an alloca_builder.
|
||||
&self.builder,
|
||||
&self.alloca_builder,
|
||||
func_type,
|
||||
callee_vmctx.into_pointer_value(),
|
||||
&func.get_type().get_element_type().into_function_type(),
|
||||
@@ -2334,8 +2324,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
|
||||
});
|
||||
|
||||
let params = abi::args_to_call(
|
||||
// TODO: should be an alloca_builder.
|
||||
&self.builder,
|
||||
&self.alloca_builder,
|
||||
func_type,
|
||||
ctx_ptr.into_pointer_value(),
|
||||
&llvm_func_type,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-compiler-singlepass"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
description = "Standalone environment support for WebAsssembly code in Singlepass"
|
||||
license = "MIT OR (Apache-2.0 WITH LLVM-exception)"
|
||||
@@ -12,9 +12,9 @@ readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasmer-compiler = { path = "../compiler", version = "0.16.2", features = ["translator"], default-features = false }
|
||||
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
|
||||
wasm-common = { path = "../wasm-common", version = "0.16.2", default-features = false }
|
||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha.1", features = ["translator"], default-features = false }
|
||||
wasmer-runtime = { path = "../runtime", version = "1.0.0-alpha.1" }
|
||||
wasm-common = { path = "../wasm-common", version = "1.0.0-alpha.1", default-features = false }
|
||||
rayon = "1.3"
|
||||
hashbrown = { version = "0.7", optional = true }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
@@ -1236,7 +1236,6 @@ impl<'a> FuncGen<'a> {
|
||||
MemoryStyle::Dynamic => true,
|
||||
};
|
||||
let tmp_addr = self.machine.acquire_temp_gpr().unwrap();
|
||||
let tmp_base = self.machine.acquire_temp_gpr().unwrap();
|
||||
|
||||
// Reusing `tmp_addr` for temporary indirection here, since it's not used before the last reference to `{base,bound}_loc`.
|
||||
let (base_loc, bound_loc) = if self.module.num_imported_memories != 0 {
|
||||
@@ -1261,15 +1260,36 @@ impl<'a> FuncGen<'a> {
|
||||
)
|
||||
};
|
||||
|
||||
let tmp_base = self.machine.acquire_temp_gpr().unwrap();
|
||||
let tmp_bound = self.machine.acquire_temp_gpr().unwrap();
|
||||
|
||||
// Load base into temporary register.
|
||||
self.assembler
|
||||
.emit_mov(Size::S64, base_loc, Location::GPR(tmp_base));
|
||||
|
||||
// Load bound into temporary register, if needed.
|
||||
if need_check {
|
||||
let tmp_bound = self.machine.acquire_temp_gpr().unwrap();
|
||||
|
||||
self.assembler
|
||||
.emit_mov(Size::S32, bound_loc, Location::GPR(tmp_bound));
|
||||
|
||||
// Wasm -> Effective.
|
||||
// Assuming we never underflow - should always be true on Linux/macOS and Windows >=8,
|
||||
// since the first page from 0x0 to 0x1000 is not accepted by mmap.
|
||||
|
||||
// This `lea` calculates the upper bound allowed for the beginning of the word.
|
||||
// Since the upper bound of the memory is (exclusively) `tmp_bound + tmp_base`,
|
||||
// the maximum allowed beginning of word is (inclusively)
|
||||
// `tmp_bound + tmp_base - value_size`.
|
||||
self.assembler.emit_lea(
|
||||
Size::S64,
|
||||
Location::MemoryAddTriple(tmp_bound, tmp_base, -(value_size as i32)),
|
||||
Location::GPR(tmp_bound),
|
||||
);
|
||||
}
|
||||
|
||||
// Load effective address.
|
||||
// `base_loc` and `bound_loc` becomes INVALID after this line, because `tmp_addr`
|
||||
// might be reused.
|
||||
self.assembler
|
||||
.emit_mov(Size::S32, addr, Location::GPR(tmp_addr));
|
||||
|
||||
@@ -1280,51 +1300,27 @@ impl<'a> FuncGen<'a> {
|
||||
Location::Imm32(memarg.offset),
|
||||
Location::GPR(tmp_addr),
|
||||
);
|
||||
// Overflow is checked outside the `need_check` block, so we don't need to check it here.
|
||||
}
|
||||
|
||||
// Trap if the start address of the requested area is equal to or above that of the linear memory.
|
||||
self.assembler
|
||||
.emit_cmp(Size::S32, Location::GPR(tmp_bound), Location::GPR(tmp_addr));
|
||||
self.assembler
|
||||
.emit_jmp(Condition::AboveEqual, self.special_labels.heap_access_oob);
|
||||
|
||||
// Calculate end of word.
|
||||
if value_size != 0 {
|
||||
self.assembler.emit_add(
|
||||
Size::S32,
|
||||
Location::Imm32(value_size as u32),
|
||||
Location::GPR(tmp_addr),
|
||||
);
|
||||
self.assembler
|
||||
.emit_jmp(Condition::Carry, self.special_labels.heap_access_oob);
|
||||
}
|
||||
|
||||
// Trap if the end address of the requested area is above that of the linear memory.
|
||||
self.assembler
|
||||
.emit_cmp(Size::S64, Location::GPR(tmp_bound), Location::GPR(tmp_addr));
|
||||
self.assembler
|
||||
.emit_jmp(Condition::Above, self.special_labels.heap_access_oob);
|
||||
|
||||
self.machine.release_temp_gpr(tmp_bound);
|
||||
}
|
||||
|
||||
// Calculates the real address, and loads from it.
|
||||
self.assembler
|
||||
.emit_mov(Size::S32, addr, Location::GPR(tmp_addr));
|
||||
if memarg.offset != 0 {
|
||||
self.assembler.emit_add(
|
||||
Size::S64,
|
||||
Location::Imm32(memarg.offset as u32),
|
||||
Location::GPR(tmp_addr),
|
||||
);
|
||||
|
||||
// Trap if offset calculation overflowed.
|
||||
self.assembler
|
||||
.emit_jmp(Condition::Carry, self.special_labels.heap_access_oob);
|
||||
}
|
||||
|
||||
// Wasm linear memory -> real memory
|
||||
self.assembler
|
||||
.emit_add(Size::S64, Location::GPR(tmp_base), Location::GPR(tmp_addr));
|
||||
|
||||
if need_check {
|
||||
// Trap if the end address of the requested area is above that of the linear memory.
|
||||
self.assembler
|
||||
.emit_cmp(Size::S64, Location::GPR(tmp_bound), Location::GPR(tmp_addr));
|
||||
|
||||
// `tmp_bound` is inclusive. So trap only if `tmp_addr > tmp_bound`.
|
||||
self.assembler
|
||||
.emit_jmp(Condition::Above, self.special_labels.heap_access_oob);
|
||||
}
|
||||
|
||||
self.machine.release_temp_gpr(tmp_bound);
|
||||
self.machine.release_temp_gpr(tmp_base);
|
||||
|
||||
let align = match memarg.flags & 3 {
|
||||
|
||||
@@ -20,6 +20,7 @@ pub enum Location {
|
||||
GPR(GPR),
|
||||
XMM(XMM),
|
||||
Memory(GPR, i32),
|
||||
MemoryAddTriple(GPR, GPR, i32),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
@@ -796,6 +797,12 @@ impl Emitter for Assembler {
|
||||
(Size::S64, Location::Memory(src, disp), Location::GPR(dst)) => {
|
||||
dynasm!(self ; lea Rq(dst as u8), [Rq(src as u8) + disp]);
|
||||
}
|
||||
(Size::S32, Location::MemoryAddTriple(src1, src2, disp), Location::GPR(dst)) => {
|
||||
dynasm!(self ; lea Rd(dst as u8), [Rq(src1 as u8) + Rq(src2 as u8) + disp]);
|
||||
}
|
||||
(Size::S64, Location::MemoryAddTriple(src1, src2, disp), Location::GPR(dst)) => {
|
||||
dynasm!(self ; lea Rq(dst as u8), [Rq(src1 as u8) + Rq(src2 as u8) + disp]);
|
||||
}
|
||||
_ => panic!("singlepass can't emit LEA {:?} {:?} {:?}", sz, src, dst),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-compiler"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
description = "Base compiler abstraction for WebAssembly"
|
||||
license = "MIT OR (Apache-2.0 WITH LLVM-exception)"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@@ -11,8 +11,8 @@ keywords = ["webassembly", "wasm", "compiler"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
|
||||
wasm-common = { path = "../wasm-common", version = "0.16.2" }
|
||||
wasmer-runtime = { path = "../runtime", version = "1.0.0-alpha.1" }
|
||||
wasm-common = { path = "../wasm-common", version = "1.0.0-alpha.1" }
|
||||
wasmparser = { version = "0.51", optional = true, default-features = false }
|
||||
target-lexicon = { version = "0.10", default-features = false }
|
||||
enumset = "1.0"
|
||||
|
||||
@@ -129,19 +129,19 @@ impl FromStr for CpuFeature {
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"sse2" => Ok(CpuFeature::SSE2),
|
||||
"sse3" => Ok(CpuFeature::SSE3),
|
||||
"ssse3" => Ok(CpuFeature::SSSE3),
|
||||
"sse4.1" => Ok(CpuFeature::SSE41),
|
||||
"sse4.2" => Ok(CpuFeature::SSE42),
|
||||
"popcnt" => Ok(CpuFeature::POPCNT),
|
||||
"avx" => Ok(CpuFeature::AVX),
|
||||
"bmi" => Ok(CpuFeature::BMI1),
|
||||
"bmi2" => Ok(CpuFeature::BMI2),
|
||||
"avx2" => Ok(CpuFeature::AVX2),
|
||||
"avx512dq" => Ok(CpuFeature::AVX512DQ),
|
||||
"avx512vl" => Ok(CpuFeature::AVX512VL),
|
||||
"lzcnt" => Ok(CpuFeature::LZCNT),
|
||||
"sse2" => Ok(Self::SSE2),
|
||||
"sse3" => Ok(Self::SSE3),
|
||||
"ssse3" => Ok(Self::SSSE3),
|
||||
"sse4.1" => Ok(Self::SSE41),
|
||||
"sse4.2" => Ok(Self::SSE42),
|
||||
"popcnt" => Ok(Self::POPCNT),
|
||||
"avx" => Ok(Self::AVX),
|
||||
"bmi" => Ok(Self::BMI1),
|
||||
"bmi2" => Ok(Self::BMI2),
|
||||
"avx2" => Ok(Self::AVX2),
|
||||
"avx512dq" => Ok(Self::AVX512DQ),
|
||||
"avx512vl" => Ok(Self::AVX512VL),
|
||||
"lzcnt" => Ok(Self::LZCNT),
|
||||
_ => Err(ParseCpuFeatureError::Missing(s.to_string())),
|
||||
}
|
||||
}
|
||||
@@ -150,19 +150,19 @@ impl FromStr for CpuFeature {
|
||||
impl ToString for CpuFeature {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
CpuFeature::SSE2 => "sse2",
|
||||
CpuFeature::SSE3 => "sse3",
|
||||
CpuFeature::SSSE3 => "ssse3",
|
||||
CpuFeature::SSE41 => "sse4.1",
|
||||
CpuFeature::SSE42 => "sse4.2",
|
||||
CpuFeature::POPCNT => "popcnt",
|
||||
CpuFeature::AVX => "avx",
|
||||
CpuFeature::BMI1 => "bmi",
|
||||
CpuFeature::BMI2 => "bmi2",
|
||||
CpuFeature::AVX2 => "avx2",
|
||||
CpuFeature::AVX512DQ => "avx512dq",
|
||||
CpuFeature::AVX512VL => "avx512vl",
|
||||
CpuFeature::LZCNT => "lzcnt",
|
||||
Self::SSE2 => "sse2",
|
||||
Self::SSE3 => "sse3",
|
||||
Self::SSSE3 => "ssse3",
|
||||
Self::SSE41 => "sse4.1",
|
||||
Self::SSE42 => "sse4.2",
|
||||
Self::POPCNT => "popcnt",
|
||||
Self::AVX => "avx",
|
||||
Self::BMI1 => "bmi",
|
||||
Self::BMI2 => "bmi2",
|
||||
Self::AVX2 => "avx2",
|
||||
Self::AVX512DQ => "avx512dq",
|
||||
Self::AVX512VL => "avx512vl",
|
||||
Self::LZCNT => "lzcnt",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ use crate::{wasm_unsupported, WasmResult};
|
||||
use std::boxed::Box;
|
||||
use wasm_common::entity::PrimaryMap;
|
||||
use wasm_common::SignatureIndex;
|
||||
use wasmparser;
|
||||
|
||||
/// Map of signatures to a function's parameter and return types.
|
||||
pub(crate) type WasmTypes =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-emscripten"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
description = "Wasmer runtime emscripten implementation library"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@@ -15,7 +15,7 @@ lazy_static = "1.4"
|
||||
libc = "0.2.60"
|
||||
log = "0.4"
|
||||
time = "0.1"
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.16.2" }
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "1.0.0-alpha.1" }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
getrandom = "0.1"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-engine-jit"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
description = "Wasmer JIT Engine"
|
||||
license = "(Apache-2.0 WITH LLVM-exception) or MIT"
|
||||
@@ -11,10 +11,10 @@ readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasm-common = { path = "../wasm-common", version = "0.16.2" }
|
||||
wasmer-compiler = { path = "../compiler", version = "0.16.2", default-features = false }
|
||||
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
|
||||
wasmer-engine = { path = "../engine", version = "0.16.2" }
|
||||
wasm-common = { path = "../wasm-common", version = "1.0.0-alpha.1" }
|
||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha.1", default-features = false }
|
||||
wasmer-runtime = { path = "../runtime", version = "1.0.0-alpha.1" }
|
||||
wasmer-engine = { path = "../engine", version = "1.0.0-alpha.1" }
|
||||
# flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" }
|
||||
region = "2.1"
|
||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
use crate::engine::{JITEngine, JITEngineInner};
|
||||
use crate::link::link_module;
|
||||
use crate::serialize::{SerializableCompilation, SerializableModule};
|
||||
#[cfg(feature = "compiler")]
|
||||
use crate::serialize::SerializableCompilation;
|
||||
use crate::serialize::SerializableModule;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use wasm_common::entity::{BoxedSlice, PrimaryMap};
|
||||
use wasm_common::{
|
||||
@@ -14,12 +16,11 @@ use wasm_common::{
|
||||
use wasmer_compiler::ModuleEnvironment;
|
||||
use wasmer_compiler::{CompileError, Features};
|
||||
use wasmer_engine::{
|
||||
register_frame_info, Artifact, DeserializeError, Engine, GlobalFrameInfoRegistration,
|
||||
SerializableFunctionFrameInfo, SerializeError,
|
||||
register_frame_info, Artifact, DeserializeError, GlobalFrameInfoRegistration, SerializeError,
|
||||
};
|
||||
use wasmer_runtime::{ModuleInfo, VMFunctionBody, VMSharedSignatureIndex};
|
||||
|
||||
use wasmer_runtime::{MemoryPlan, TablePlan};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_engine::{Engine, SerializableFunctionFrameInfo};
|
||||
use wasmer_runtime::{MemoryPlan, ModuleInfo, TablePlan, VMFunctionBody, VMSharedSignatureIndex};
|
||||
|
||||
/// A compiled wasm module, ready to be instantiated.
|
||||
pub struct JITArtifact {
|
||||
@@ -28,7 +29,7 @@ pub struct JITArtifact {
|
||||
finished_functions: BoxedSlice<LocalFunctionIndex, *mut [VMFunctionBody]>,
|
||||
finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, *const VMFunctionBody>,
|
||||
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
||||
frame_info_registration: Mutex<Option<Option<GlobalFrameInfoRegistration>>>,
|
||||
frame_info_registration: Mutex<Option<GlobalFrameInfoRegistration>>,
|
||||
}
|
||||
|
||||
impl JITArtifact {
|
||||
@@ -132,7 +133,7 @@ impl JITArtifact {
|
||||
|
||||
/// Compile a data buffer into a `JITArtifact`, which may then be instantiated.
|
||||
#[cfg(not(feature = "compiler"))]
|
||||
pub fn new(jit: &JITEngine, data: &[u8]) -> Result<Self, CompileError> {
|
||||
pub fn new(_jit: &JITEngine, _data: &[u8]) -> Result<Self, CompileError> {
|
||||
Err(CompileError::Codegen(
|
||||
"Compilation is not enabled in the engine".to_string(),
|
||||
))
|
||||
@@ -224,16 +225,18 @@ impl Artifact for JITArtifact {
|
||||
|
||||
fn register_frame_info(&self) {
|
||||
let mut info = self.frame_info_registration.lock().unwrap();
|
||||
|
||||
if info.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
let frame_infos = &self.serializable.compilation.function_frame_info;
|
||||
let finished_functions = &self.finished_functions;
|
||||
*info = Some(register_frame_info(
|
||||
*info = register_frame_info(
|
||||
self.serializable.module.clone(),
|
||||
finished_functions,
|
||||
frame_infos.clone(),
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
fn features(&self) -> &Features {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
//! Memory management for executable code.
|
||||
use crate::function_table::FunctionTable;
|
||||
use region;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::{cmp, mem};
|
||||
use wasm_common::entity::PrimaryMap;
|
||||
|
||||
@@ -10,7 +10,7 @@ use wasmer_compiler::{
|
||||
};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::{Compiler, CompilerConfig};
|
||||
use wasmer_engine::{Artifact, DeserializeError, Engine, Tunables};
|
||||
use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables};
|
||||
use wasmer_runtime::{
|
||||
ModuleInfo, SignatureRegistry, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline,
|
||||
};
|
||||
@@ -20,6 +20,7 @@ use wasmer_runtime::{
|
||||
pub struct JITEngine {
|
||||
inner: Arc<Mutex<JITEngineInner>>,
|
||||
tunables: Arc<dyn Tunables + Send + Sync>,
|
||||
engine_id: EngineId,
|
||||
}
|
||||
|
||||
impl JITEngine {
|
||||
@@ -38,6 +39,7 @@ impl JITEngine {
|
||||
signatures: SignatureRegistry::new(),
|
||||
})),
|
||||
tunables: Arc::new(tunables),
|
||||
engine_id: EngineId::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +66,7 @@ impl JITEngine {
|
||||
signatures: SignatureRegistry::new(),
|
||||
})),
|
||||
tunables: Arc::new(tunables),
|
||||
engine_id: EngineId::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +116,10 @@ impl Engine for JITEngine {
|
||||
unsafe fn deserialize(&self, bytes: &[u8]) -> Result<Arc<dyn Artifact>, DeserializeError> {
|
||||
Ok(Arc::new(JITArtifact::deserialize(&self, &bytes)?))
|
||||
}
|
||||
|
||||
fn id(&self) -> &EngineId {
|
||||
&self.engine_id
|
||||
}
|
||||
}
|
||||
|
||||
/// The inner contents of `JITEngine`
|
||||
@@ -131,7 +138,7 @@ pub struct JITEngineInner {
|
||||
}
|
||||
|
||||
impl JITEngineInner {
|
||||
/// Gets the compiler associated to this JIT
|
||||
/// Gets the compiler associated to this engine.
|
||||
#[cfg(feature = "compiler")]
|
||||
pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> {
|
||||
if self.compiler.is_none() {
|
||||
@@ -148,9 +155,10 @@ impl JITEngineInner {
|
||||
|
||||
/// Validate the module
|
||||
#[cfg(not(feature = "compiler"))]
|
||||
pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> {
|
||||
pub fn validate<'data>(&self, _data: &'data [u8]) -> Result<(), CompileError> {
|
||||
Err(CompileError::Validate(
|
||||
"Validation is only enabled with the compiler feature".to_string(),
|
||||
"The JITEngine is not compiled with compiler support, which is required for validating"
|
||||
.to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -178,6 +186,7 @@ impl JITEngineInner {
|
||||
}
|
||||
|
||||
/// Compile the given function bodies.
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) fn allocate(
|
||||
&mut self,
|
||||
module: &ModuleInfo,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-engine-native"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
description = "Wasmer JIT Engine"
|
||||
license = "(Apache-2.0 WITH LLVM-exception) or MIT"
|
||||
@@ -11,10 +11,10 @@ readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasm-common = { path = "../wasm-common", version = "0.16.2" }
|
||||
wasmer-compiler = { path = "../compiler", version = "0.16.2", default-features = false }
|
||||
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
|
||||
wasmer-engine = { path = "../engine", version = "0.16.2" }
|
||||
wasm-common = { path = "../wasm-common", version = "1.0.0-alpha.1" }
|
||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha.1", default-features = false }
|
||||
wasmer-runtime = { path = "../runtime", version = "1.0.0-alpha.1" }
|
||||
wasmer-engine = { path = "../engine", version = "1.0.0-alpha.1" }
|
||||
faerie = "0.15"
|
||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||
serde_bytes = { version = "0.11" }
|
||||
|
||||
@@ -3,25 +3,31 @@
|
||||
|
||||
use crate::engine::{NativeEngine, NativeEngineInner};
|
||||
use crate::serialize::ModuleMetadata;
|
||||
#[cfg(feature = "compiler")]
|
||||
use faerie::{ArtifactBuilder, Decl, Link};
|
||||
use libloading::{Library, Symbol};
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
#[cfg(feature = "compiler")]
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use tempfile::NamedTempFile;
|
||||
#[cfg(feature = "compiler")]
|
||||
use tracing::trace;
|
||||
use wasm_common::entity::{BoxedSlice, EntityRef, PrimaryMap};
|
||||
use wasm_common::{
|
||||
FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex,
|
||||
TableIndex,
|
||||
};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::ModuleEnvironment;
|
||||
use wasmer_compiler::{BinaryFormat, CompileError, Features, RelocationTarget, Triple};
|
||||
use wasmer_compiler::{BinaryFormat, ModuleEnvironment, RelocationTarget, Triple};
|
||||
use wasmer_compiler::{CompileError, Features};
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_engine::Engine;
|
||||
use wasmer_engine::{
|
||||
Artifact, DeserializeError, Engine, InstantiationError, LinkError, RuntimeError, SerializeError,
|
||||
Artifact, DeserializeError, InstantiationError, LinkError, RuntimeError, SerializeError,
|
||||
};
|
||||
use wasmer_runtime::{MemoryPlan, TablePlan};
|
||||
use wasmer_runtime::{ModuleInfo, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline};
|
||||
@@ -61,13 +67,13 @@ impl NativeArtifact {
|
||||
pub fn is_deserializable(bytes: &[u8]) -> bool {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(target_pointer_width = "64", target_os="macos"))] {
|
||||
return bytes.starts_with(Self::MAGIC_HEADER_MH_CIGAM_64);
|
||||
bytes.starts_with(Self::MAGIC_HEADER_MH_CIGAM_64)
|
||||
}
|
||||
else if #[cfg(all(target_pointer_width = "64", target_os="linux"))] {
|
||||
return bytes.starts_with(Self::MAGIC_HEADER_ELF_64);
|
||||
bytes.starts_with(Self::MAGIC_HEADER_ELF_64)
|
||||
}
|
||||
else if #[cfg(all(target_pointer_width = "32", target_os="linux"))] {
|
||||
return bytes.starts_with(Self::MAGIC_HEADER_ELF_32);
|
||||
bytes.starts_with(Self::MAGIC_HEADER_ELF_32)
|
||||
}
|
||||
else {
|
||||
false
|
||||
@@ -82,9 +88,7 @@ impl NativeArtifact {
|
||||
let mut engine_inner = engine.inner_mut();
|
||||
let tunables = engine.tunables();
|
||||
|
||||
let translation = environ
|
||||
.translate(data)
|
||||
.map_err(|error| CompileError::Wasm(error))?;
|
||||
let translation = environ.translate(data).map_err(CompileError::Wasm)?;
|
||||
|
||||
let memory_plans: PrimaryMap<MemoryIndex, MemoryPlan> = translation
|
||||
.module
|
||||
@@ -290,38 +294,38 @@ impl NativeArtifact {
|
||||
|
||||
let shared_file = NamedTempFile::new().map_err(to_compile_error)?;
|
||||
let (_file, shared_filepath) = shared_file.keep().map_err(to_compile_error)?;
|
||||
let wasmer_symbols = libcalls
|
||||
.iter()
|
||||
.map(|libcall| {
|
||||
match target_triple.binary_format {
|
||||
BinaryFormat::Macho => format!("-Wl,-U,_{}", libcall),
|
||||
BinaryFormat::Elf => format!("-Wl,--undefined={}", libcall),
|
||||
_ => {
|
||||
// We should already be filtering only valid binary formats before
|
||||
// so this should never happen.
|
||||
unreachable!("Incorrect binary format")
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let is_cross_compiling = target_triple != Triple::host();
|
||||
let host_target = Triple::host();
|
||||
let is_cross_compiling = target_triple != host_target;
|
||||
let cross_compiling_args = if is_cross_compiling {
|
||||
vec![
|
||||
format!("--target={}", target_triple),
|
||||
"-fuse-ld=lld".to_string(),
|
||||
"-nodefaultlibs".to_string(),
|
||||
"-nostdlib".to_string(),
|
||||
]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
let output = Command::new("gcc")
|
||||
trace!(
|
||||
"Compiling for target {} from host {}",
|
||||
target_triple.to_string(),
|
||||
host_target.to_string()
|
||||
);
|
||||
|
||||
let linker = if is_cross_compiling {
|
||||
"clang-10"
|
||||
} else {
|
||||
"gcc"
|
||||
};
|
||||
|
||||
let output = Command::new(linker)
|
||||
.arg(&filepath)
|
||||
.arg("-nostartfiles")
|
||||
.arg("-nodefaultlibs")
|
||||
.arg("-nostdlib")
|
||||
.arg("-o")
|
||||
.arg(&shared_filepath)
|
||||
.args(&wasmer_symbols)
|
||||
.arg("-Wl,-undefined,dynamic_lookup")
|
||||
// .args(&wasmer_symbols)
|
||||
.arg("-shared")
|
||||
.args(&cross_compiling_args)
|
||||
.arg("-v")
|
||||
@@ -415,7 +419,7 @@ impl NativeArtifact {
|
||||
// implemented in this engine.
|
||||
let func_pointer =
|
||||
std::slice::from_raw_parts(raw as *const (), *function_len as usize);
|
||||
let func_pointer = std::mem::transmute::<_, *mut [VMFunctionBody]>(func_pointer);
|
||||
let func_pointer = func_pointer as *const [()] as *mut [VMFunctionBody];
|
||||
finished_functions.push(func_pointer);
|
||||
}
|
||||
}
|
||||
@@ -489,17 +493,21 @@ impl NativeArtifact {
|
||||
|
||||
/// Compile a data buffer into a `NativeArtifact`, which may then be instantiated.
|
||||
#[cfg(not(feature = "compiler"))]
|
||||
pub fn new(engine: &NativeEngine, data: &[u8]) -> Result<Self, CompileError> {
|
||||
pub fn new(_engine: &NativeEngine, _data: &[u8]) -> Result<Self, CompileError> {
|
||||
Err(CompileError::Codegen(
|
||||
"Compilation is not enabled in the engine".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Deserialize a `NativeArtifact` from bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The bytes must represent a serialized WebAssembly module.
|
||||
pub unsafe fn deserialize(
|
||||
engine: &NativeEngine,
|
||||
bytes: &[u8],
|
||||
) -> Result<NativeArtifact, DeserializeError> {
|
||||
) -> Result<Self, DeserializeError> {
|
||||
if !Self::is_deserializable(&bytes) {
|
||||
return Err(DeserializeError::Incompatible(
|
||||
"The provided bytes are not in any native format Wasmer can understand".to_string(),
|
||||
@@ -515,10 +523,14 @@ impl NativeArtifact {
|
||||
}
|
||||
|
||||
/// Deserialize a `NativeArtifact` from a file path.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The file's content must represent a serialized WebAssembly module.
|
||||
pub unsafe fn deserialize_from_file(
|
||||
engine: &NativeEngine,
|
||||
path: &Path,
|
||||
) -> Result<NativeArtifact, DeserializeError> {
|
||||
) -> Result<Self, DeserializeError> {
|
||||
let mut file = File::open(&path)?;
|
||||
let mut buffer = [0; 5];
|
||||
// read up to 5 bytes
|
||||
@@ -532,10 +544,14 @@ impl NativeArtifact {
|
||||
}
|
||||
|
||||
/// Deserialize a `NativeArtifact` from a file path (unchecked).
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The file's content must represent a serialized WebAssembly module.
|
||||
pub unsafe fn deserialize_from_file_unchecked(
|
||||
engine: &NativeEngine,
|
||||
path: &Path,
|
||||
) -> Result<NativeArtifact, DeserializeError> {
|
||||
) -> Result<Self, DeserializeError> {
|
||||
let lib = Library::new(&path).map_err(|e| {
|
||||
DeserializeError::CorruptedBinary(format!("Library loading failed: {}", e))
|
||||
})?;
|
||||
@@ -565,7 +581,7 @@ impl NativeArtifact {
|
||||
let mut engine_inner = engine.inner_mut();
|
||||
|
||||
Self::from_parts(&mut engine_inner, metadata, shared_path, lib)
|
||||
.map_err(|e| DeserializeError::Compiler(e))
|
||||
.map_err(DeserializeError::Compiler)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use wasm_common::FunctionType;
|
||||
use wasmer_compiler::CompileError;
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::{Compiler, CompilerConfig};
|
||||
use wasmer_engine::{Artifact, DeserializeError, Engine, Tunables};
|
||||
use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables};
|
||||
use wasmer_runtime::{SignatureRegistry, VMSharedSignatureIndex, VMTrampoline};
|
||||
|
||||
/// A WebAssembly `Native` Engine.
|
||||
@@ -17,6 +17,7 @@ use wasmer_runtime::{SignatureRegistry, VMSharedSignatureIndex, VMTrampoline};
|
||||
pub struct NativeEngine {
|
||||
inner: Arc<Mutex<NativeEngineInner>>,
|
||||
tunables: Arc<dyn Tunables + Send + Sync>,
|
||||
engine_id: EngineId,
|
||||
}
|
||||
|
||||
impl NativeEngine {
|
||||
@@ -36,6 +37,7 @@ impl NativeEngine {
|
||||
prefixer: None,
|
||||
})),
|
||||
tunables: Arc::new(tunables),
|
||||
engine_id: EngineId::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +64,7 @@ impl NativeEngine {
|
||||
prefixer: None,
|
||||
})),
|
||||
tunables: Arc::new(tunables),
|
||||
engine_id: EngineId::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +143,10 @@ impl Engine for NativeEngine {
|
||||
&self, &file_ref,
|
||||
)?))
|
||||
}
|
||||
|
||||
fn id(&self) -> &EngineId {
|
||||
&self.engine_id
|
||||
}
|
||||
}
|
||||
|
||||
/// The inner contents of `NativeEngine`
|
||||
@@ -159,7 +166,7 @@ pub struct NativeEngineInner {
|
||||
}
|
||||
|
||||
impl NativeEngineInner {
|
||||
/// Gets the compiler associated to this JIT
|
||||
/// Gets the compiler associated to this engine.
|
||||
#[cfg(feature = "compiler")]
|
||||
pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> {
|
||||
if self.compiler.is_none() {
|
||||
@@ -187,9 +194,9 @@ impl NativeEngineInner {
|
||||
|
||||
/// Validate the module
|
||||
#[cfg(not(feature = "compiler"))]
|
||||
pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> {
|
||||
pub fn validate<'data>(&self, _data: &'data [u8]) -> Result<(), CompileError> {
|
||||
Err(CompileError::Validate(
|
||||
"Validation is only enabled with the compiler feature".to_string(),
|
||||
"The NativeEngine is not compiled with compiler support, which is required for validating".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
)
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate tracing;
|
||||
|
||||
mod artifact;
|
||||
mod engine;
|
||||
mod serialize;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-engine"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
description = "Wasmer Engine abstraction"
|
||||
license = "(Apache-2.0 WITH LLVM-exception) or MIT"
|
||||
@@ -11,9 +11,9 @@ readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasm-common = { path = "../wasm-common", version = "0.16.2" }
|
||||
wasmer-compiler = { path = "../compiler", version = "0.16.2", default-features = false }
|
||||
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
|
||||
wasm-common = { path = "../wasm-common", version = "1.0.0-alpha.1" }
|
||||
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha.1", default-features = false }
|
||||
wasmer-runtime = { path = "../runtime", version = "1.0.0-alpha.1" }
|
||||
target-lexicon = { version = "0.10", default-features = false }
|
||||
# flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" }
|
||||
backtrace = "0.3"
|
||||
|
||||
@@ -80,7 +80,7 @@ pub trait Artifact {
|
||||
|
||||
/// Crate an `Instance` from this `Artifact`.
|
||||
///
|
||||
/// # Unsafety
|
||||
/// # Safety
|
||||
///
|
||||
/// See [`InstanceHandle::new`].
|
||||
unsafe fn instantiate(
|
||||
@@ -89,7 +89,8 @@ pub trait Artifact {
|
||||
resolver: &dyn Resolver,
|
||||
host_state: Box<dyn Any>,
|
||||
) -> Result<InstanceHandle, InstantiationError> {
|
||||
let _ = self.preinstantiate()?;
|
||||
self.preinstantiate()?;
|
||||
|
||||
let module = self.module();
|
||||
let imports = resolve_imports(
|
||||
&module,
|
||||
@@ -129,7 +130,7 @@ pub trait Artifact {
|
||||
|
||||
/// Finishes the instantiation of a just created `InstanceHandle`.
|
||||
///
|
||||
/// # Unsafety
|
||||
/// # Safety
|
||||
///
|
||||
/// See [`InstanceHandle::finish_instantiation`].
|
||||
unsafe fn finish_instantiation(
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use crate::tunables::Tunables;
|
||||
use crate::{Artifact, DeserializeError};
|
||||
use std::path::Path;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
||||
use std::sync::Arc;
|
||||
use wasm_common::FunctionType;
|
||||
use wasmer_compiler::CompileError;
|
||||
@@ -34,9 +35,17 @@ pub trait Engine {
|
||||
fn compile(&self, binary: &[u8]) -> Result<Arc<dyn Artifact>, CompileError>;
|
||||
|
||||
/// Deserializes a WebAssembly module
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The serialized content must represent a serialized WebAssembly module.
|
||||
unsafe fn deserialize(&self, bytes: &[u8]) -> Result<Arc<dyn Artifact>, DeserializeError>;
|
||||
|
||||
/// Deserializes a WebAssembly module from a path
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The file's content must represent a serialized WebAssembly module.
|
||||
unsafe fn deserialize_from_file(
|
||||
&self,
|
||||
file_ref: &Path,
|
||||
@@ -44,4 +53,40 @@ pub trait Engine {
|
||||
let bytes = std::fs::read(file_ref)?;
|
||||
self.deserialize(&bytes)
|
||||
}
|
||||
|
||||
/// A unique identifier for this object.
|
||||
///
|
||||
/// This exists to allow us to compare two Engines for equality. Otherwise,
|
||||
/// comparing two trait objects unsafely relies on implementation details
|
||||
/// of trait representation.
|
||||
fn id(&self) -> &EngineId;
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[repr(transparent)]
|
||||
/// A unique identifier for an Engine.
|
||||
pub struct EngineId {
|
||||
id: usize,
|
||||
}
|
||||
|
||||
impl EngineId {
|
||||
/// Format this identifier as a string.
|
||||
pub fn id(&self) -> String {
|
||||
format!("{}", &self.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for EngineId {
|
||||
fn clone(&self) -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EngineId {
|
||||
fn default() -> Self {
|
||||
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
|
||||
Self {
|
||||
id: NEXT_ID.fetch_add(1, SeqCst),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ mod trap;
|
||||
mod tunables;
|
||||
|
||||
pub use crate::artifact::Artifact;
|
||||
pub use crate::engine::Engine;
|
||||
pub use crate::engine::{Engine, EngineId};
|
||||
pub use crate::error::{
|
||||
DeserializeError, ImportError, InstantiationError, LinkError, SerializeError,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-runtime"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
description = "Runtime library support for Wasmer"
|
||||
license = "MIT OR (Apache-2.0 WITH LLVM-exception)"
|
||||
@@ -11,7 +11,7 @@ readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasm-common = { path = "../wasm-common", version = "0.16.2", features = ["enable-serde"] }
|
||||
wasm-common = { path = "../wasm-common", version = "1.0.0-alpha.1", features = ["enable-serde"] }
|
||||
region = "2.1"
|
||||
libc = { version = "0.2", default-features = false }
|
||||
memoffset = "0.5"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use crate::memory::LinearMemory;
|
||||
use crate::module::{MemoryPlan, TablePlan};
|
||||
use crate::table::Table;
|
||||
use crate::memory::{LinearMemory, MemoryPlan};
|
||||
use crate::table::{Table, TablePlan};
|
||||
use crate::vmcontext::{
|
||||
VMContext, VMFunctionBody, VMFunctionKind, VMGlobalDefinition, VMMemoryDefinition,
|
||||
VMTableDefinition,
|
||||
@@ -85,7 +84,7 @@ impl ExportMemory {
|
||||
}
|
||||
|
||||
/// Returns whether or not the two `ExportMemory`s refer to the same Memory.
|
||||
pub fn same(&self, other: &ExportMemory) -> bool {
|
||||
pub fn same(&self, other: &Self) -> bool {
|
||||
self.definition == other.definition && self.from == other.from
|
||||
}
|
||||
}
|
||||
@@ -107,7 +106,7 @@ pub struct ExportGlobal {
|
||||
|
||||
impl ExportGlobal {
|
||||
/// Returns whether or not the two `ExportGlobal`s refer to the same Global.
|
||||
pub fn same(&self, other: &ExportGlobal) -> bool {
|
||||
pub fn same(&self, other: &Self) -> bool {
|
||||
self.definition == other.definition && self.global == other.global
|
||||
}
|
||||
}
|
||||
|
||||
@@ -587,8 +587,7 @@ impl Instance {
|
||||
let passive_elements = self.passive_elements.borrow();
|
||||
let elem = passive_elements
|
||||
.get(&elem_index)
|
||||
.map(|e| &**e)
|
||||
.unwrap_or_else(|| &[]);
|
||||
.map_or_else(|| -> &[VMCallerCheckedAnyfunc] { &[] }, |e| &**e);
|
||||
|
||||
if src
|
||||
.checked_add(len)
|
||||
@@ -765,7 +764,7 @@ pub struct InstanceHandle {
|
||||
impl InstanceHandle {
|
||||
/// Create a new `InstanceHandle` pointing at a new `Instance`.
|
||||
///
|
||||
/// # Unsafety
|
||||
/// # Safety
|
||||
///
|
||||
/// This method is not necessarily inherently unsafe to call, but in general
|
||||
/// the APIs of an `Instance` are quite unsafe and have not been really
|
||||
@@ -778,6 +777,7 @@ impl InstanceHandle {
|
||||
/// internally if you'd like to do so. If possible it's recommended to use
|
||||
/// the `wasmer` crate API rather than this type since that is vetted for
|
||||
/// safety.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub unsafe fn new(
|
||||
module: Arc<ModuleInfo>,
|
||||
finished_functions: BoxedSlice<LocalFunctionIndex, *mut [VMFunctionBody]>,
|
||||
@@ -890,6 +890,8 @@ impl InstanceHandle {
|
||||
|
||||
/// Finishes the instantiation process started by `Instance::new`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Only safe to call immediately after instantiation.
|
||||
pub unsafe fn finish_instantiation(
|
||||
&self,
|
||||
@@ -922,7 +924,8 @@ impl InstanceHandle {
|
||||
/// This is unsafe because it doesn't work on just any `VMContext`, it must
|
||||
/// be a `VMContext` allocated as part of an `Instance`.
|
||||
pub unsafe fn from_vmctx(vmctx: *mut VMContext) -> Self {
|
||||
let instance = (&mut *vmctx).instance();
|
||||
let instance = (&*vmctx).instance();
|
||||
|
||||
Self {
|
||||
instance: instance as *const Instance as *mut Instance,
|
||||
}
|
||||
@@ -1040,9 +1043,11 @@ impl InstanceHandle {
|
||||
|
||||
/// Deallocates memory associated with this instance.
|
||||
///
|
||||
/// Note that this is unsafe because there might be other handles to this
|
||||
/// `InstanceHandle` elsewhere, and there's nothing preventing usage of
|
||||
/// this handle after this function is called.
|
||||
/// # Safety
|
||||
///
|
||||
/// This is unsafe because there might be other handles to this
|
||||
/// `InstanceHandle` elsewhere, and there's nothing preventing
|
||||
/// usage of this handle after this function is called.
|
||||
pub unsafe fn dealloc(&self) {
|
||||
let instance = self.instance();
|
||||
let layout = instance.alloc_layout();
|
||||
|
||||
@@ -39,15 +39,12 @@ pub mod libcalls;
|
||||
pub use crate::export::*;
|
||||
pub use crate::imports::Imports;
|
||||
pub use crate::instance::InstanceHandle;
|
||||
pub use crate::memory::{LinearMemory, MemoryError};
|
||||
pub use crate::memory::{LinearMemory, MemoryError, MemoryPlan, MemoryStyle};
|
||||
pub use crate::mmap::Mmap;
|
||||
pub use crate::module::{
|
||||
ExportsIterator, ImportsIterator, MemoryPlan, MemoryStyle, ModuleInfo, TableElements,
|
||||
TablePlan, TableStyle,
|
||||
};
|
||||
pub use crate::module::{ExportsIterator, ImportsIterator, ModuleInfo};
|
||||
pub use crate::probestack::PROBESTACK;
|
||||
pub use crate::sig_registry::SignatureRegistry;
|
||||
pub use crate::table::Table;
|
||||
pub use crate::table::{Table, TableElements, TablePlan, TableStyle};
|
||||
pub use crate::trap::*;
|
||||
pub use crate::vmcontext::{
|
||||
VMBuiltinFunctionIndex, VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionImportContext,
|
||||
|
||||
@@ -131,12 +131,16 @@ pub extern "C" fn wasmer_f64_nearest(x: f64) -> f64 {
|
||||
}
|
||||
|
||||
/// Implementation of memory.grow for locally-defined 32-bit memories.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `vmctx` must be valid and not null.
|
||||
pub unsafe extern "C" fn wasmer_memory32_grow(
|
||||
vmctx: *mut VMContext,
|
||||
delta: u32,
|
||||
memory_index: u32,
|
||||
) -> u32 {
|
||||
let instance = (&mut *vmctx).instance();
|
||||
let instance = (&*vmctx).instance();
|
||||
let memory_index = LocalMemoryIndex::from_u32(memory_index);
|
||||
|
||||
instance
|
||||
@@ -146,12 +150,16 @@ pub unsafe extern "C" fn wasmer_memory32_grow(
|
||||
}
|
||||
|
||||
/// Implementation of memory.grow for imported 32-bit memories.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `vmctx` must be valid and not null.
|
||||
pub unsafe extern "C" fn wasmer_imported_memory32_grow(
|
||||
vmctx: *mut VMContext,
|
||||
delta: u32,
|
||||
memory_index: u32,
|
||||
) -> u32 {
|
||||
let instance = (&mut *vmctx).instance();
|
||||
let instance = (&*vmctx).instance();
|
||||
let memory_index = MemoryIndex::from_u32(memory_index);
|
||||
|
||||
instance
|
||||
@@ -161,25 +169,37 @@ pub unsafe extern "C" fn wasmer_imported_memory32_grow(
|
||||
}
|
||||
|
||||
/// Implementation of memory.size for locally-defined 32-bit memories.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `vmctx` must be valid and not null.
|
||||
pub unsafe extern "C" fn wasmer_memory32_size(vmctx: *mut VMContext, memory_index: u32) -> u32 {
|
||||
let instance = (&mut *vmctx).instance();
|
||||
let instance = (&*vmctx).instance();
|
||||
let memory_index = LocalMemoryIndex::from_u32(memory_index);
|
||||
|
||||
instance.memory_size(memory_index).0
|
||||
}
|
||||
|
||||
/// Implementation of memory.size for imported 32-bit memories.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `vmctx` must be valid and not null.
|
||||
pub unsafe extern "C" fn wasmer_imported_memory32_size(
|
||||
vmctx: *mut VMContext,
|
||||
memory_index: u32,
|
||||
) -> u32 {
|
||||
let instance = (&mut *vmctx).instance();
|
||||
let instance = (&*vmctx).instance();
|
||||
let memory_index = MemoryIndex::from_u32(memory_index);
|
||||
|
||||
instance.imported_memory_size(memory_index).0
|
||||
}
|
||||
|
||||
/// Implementation of `table.copy`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `vmctx` must be valid and not null.
|
||||
pub unsafe extern "C" fn wasmer_table_copy(
|
||||
vmctx: *mut VMContext,
|
||||
dst_table_index: u32,
|
||||
@@ -191,7 +211,7 @@ pub unsafe extern "C" fn wasmer_table_copy(
|
||||
let result = {
|
||||
let dst_table_index = TableIndex::from_u32(dst_table_index);
|
||||
let src_table_index = TableIndex::from_u32(src_table_index);
|
||||
let instance = (&mut *vmctx).instance();
|
||||
let instance = (&*vmctx).instance();
|
||||
let dst_table = instance.get_table(dst_table_index);
|
||||
let src_table = instance.get_table(src_table_index);
|
||||
Table::copy(dst_table, src_table, dst, src, len)
|
||||
@@ -202,6 +222,10 @@ pub unsafe extern "C" fn wasmer_table_copy(
|
||||
}
|
||||
|
||||
/// Implementation of `table.init`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `vmctx` must be valid and not null.
|
||||
pub unsafe extern "C" fn wasmer_table_init(
|
||||
vmctx: *mut VMContext,
|
||||
table_index: u32,
|
||||
@@ -213,7 +237,7 @@ pub unsafe extern "C" fn wasmer_table_init(
|
||||
let result = {
|
||||
let table_index = TableIndex::from_u32(table_index);
|
||||
let elem_index = ElemIndex::from_u32(elem_index);
|
||||
let instance = (&mut *vmctx).instance();
|
||||
let instance = (&*vmctx).instance();
|
||||
instance.table_init(table_index, elem_index, dst, src, len)
|
||||
};
|
||||
if let Err(trap) = result {
|
||||
@@ -222,13 +246,21 @@ pub unsafe extern "C" fn wasmer_table_init(
|
||||
}
|
||||
|
||||
/// Implementation of `elem.drop`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `vmctx` must be valid and not null.
|
||||
pub unsafe extern "C" fn wasmer_elem_drop(vmctx: *mut VMContext, elem_index: u32) {
|
||||
let elem_index = ElemIndex::from_u32(elem_index);
|
||||
let instance = (&mut *vmctx).instance();
|
||||
let instance = (&*vmctx).instance();
|
||||
instance.elem_drop(elem_index);
|
||||
}
|
||||
|
||||
/// Implementation of `memory.copy` for locally defined memories.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `vmctx` must be valid and not null.
|
||||
pub unsafe extern "C" fn wasmer_local_memory_copy(
|
||||
vmctx: *mut VMContext,
|
||||
memory_index: u32,
|
||||
@@ -238,7 +270,7 @@ pub unsafe extern "C" fn wasmer_local_memory_copy(
|
||||
) {
|
||||
let result = {
|
||||
let memory_index = LocalMemoryIndex::from_u32(memory_index);
|
||||
let instance = (&mut *vmctx).instance();
|
||||
let instance = (&*vmctx).instance();
|
||||
instance.local_memory_copy(memory_index, dst, src, len)
|
||||
};
|
||||
if let Err(trap) = result {
|
||||
@@ -247,6 +279,10 @@ pub unsafe extern "C" fn wasmer_local_memory_copy(
|
||||
}
|
||||
|
||||
/// Implementation of `memory.copy` for imported memories.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `vmctx` must be valid and not null.
|
||||
pub unsafe extern "C" fn wasmer_imported_memory_copy(
|
||||
vmctx: *mut VMContext,
|
||||
memory_index: u32,
|
||||
@@ -256,7 +292,7 @@ pub unsafe extern "C" fn wasmer_imported_memory_copy(
|
||||
) {
|
||||
let result = {
|
||||
let memory_index = MemoryIndex::from_u32(memory_index);
|
||||
let instance = (&mut *vmctx).instance();
|
||||
let instance = (&*vmctx).instance();
|
||||
instance.imported_memory_copy(memory_index, dst, src, len)
|
||||
};
|
||||
if let Err(trap) = result {
|
||||
@@ -265,6 +301,10 @@ pub unsafe extern "C" fn wasmer_imported_memory_copy(
|
||||
}
|
||||
|
||||
/// Implementation of `memory.fill` for locally defined memories.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `vmctx` must be valid and not null.
|
||||
pub unsafe extern "C" fn wasmer_memory_fill(
|
||||
vmctx: *mut VMContext,
|
||||
memory_index: u32,
|
||||
@@ -274,7 +314,7 @@ pub unsafe extern "C" fn wasmer_memory_fill(
|
||||
) {
|
||||
let result = {
|
||||
let memory_index = LocalMemoryIndex::from_u32(memory_index);
|
||||
let instance = (&mut *vmctx).instance();
|
||||
let instance = (&*vmctx).instance();
|
||||
instance.local_memory_fill(memory_index, dst, val, len)
|
||||
};
|
||||
if let Err(trap) = result {
|
||||
@@ -283,6 +323,10 @@ pub unsafe extern "C" fn wasmer_memory_fill(
|
||||
}
|
||||
|
||||
/// Implementation of `memory.fill` for imported memories.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `vmctx` must be valid and not null.
|
||||
pub unsafe extern "C" fn wasmer_imported_memory_fill(
|
||||
vmctx: *mut VMContext,
|
||||
memory_index: u32,
|
||||
@@ -292,7 +336,7 @@ pub unsafe extern "C" fn wasmer_imported_memory_fill(
|
||||
) {
|
||||
let result = {
|
||||
let memory_index = MemoryIndex::from_u32(memory_index);
|
||||
let instance = (&mut *vmctx).instance();
|
||||
let instance = (&*vmctx).instance();
|
||||
instance.imported_memory_fill(memory_index, dst, val, len)
|
||||
};
|
||||
if let Err(trap) = result {
|
||||
@@ -301,6 +345,10 @@ pub unsafe extern "C" fn wasmer_imported_memory_fill(
|
||||
}
|
||||
|
||||
/// Implementation of `memory.init`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `vmctx` must be valid and not null.
|
||||
pub unsafe extern "C" fn wasmer_memory_init(
|
||||
vmctx: *mut VMContext,
|
||||
memory_index: u32,
|
||||
@@ -312,7 +360,7 @@ pub unsafe extern "C" fn wasmer_memory_init(
|
||||
let result = {
|
||||
let memory_index = MemoryIndex::from_u32(memory_index);
|
||||
let data_index = DataIndex::from_u32(data_index);
|
||||
let instance = (&mut *vmctx).instance();
|
||||
let instance = (&*vmctx).instance();
|
||||
instance.memory_init(memory_index, data_index, dst, src, len)
|
||||
};
|
||||
if let Err(trap) = result {
|
||||
@@ -321,13 +369,21 @@ pub unsafe extern "C" fn wasmer_memory_init(
|
||||
}
|
||||
|
||||
/// Implementation of `data.drop`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `vmctx` must be valid and not null.
|
||||
pub unsafe extern "C" fn wasmer_data_drop(vmctx: *mut VMContext, data_index: u32) {
|
||||
let data_index = DataIndex::from_u32(data_index);
|
||||
let instance = (&mut *vmctx).instance();
|
||||
let instance = (&*vmctx).instance();
|
||||
instance.data_drop(data_index)
|
||||
}
|
||||
|
||||
/// Implementation for raising a trap
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO)
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_raise_trap(trap_code: TrapCode) -> ! {
|
||||
let trap = Trap::wasm(trap_code);
|
||||
@@ -335,6 +391,10 @@ pub unsafe extern "C" fn wasmer_raise_trap(trap_code: TrapCode) -> ! {
|
||||
}
|
||||
|
||||
/// Probestack check
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO)
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wasmer_probestack() {
|
||||
PROBESTACK();
|
||||
@@ -345,53 +405,68 @@ pub unsafe extern "C" fn wasmer_probestack() {
|
||||
/// This list is likely to grow over time.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum LibCall {
|
||||
/// ceil.f32
|
||||
CeilF32,
|
||||
|
||||
/// ceil.f64
|
||||
CeilF64,
|
||||
|
||||
/// floor.f32
|
||||
FloorF32,
|
||||
|
||||
/// floor.f64
|
||||
FloorF64,
|
||||
|
||||
/// nearest.f32
|
||||
NearestF32,
|
||||
|
||||
/// nearest.f64
|
||||
NearestF64,
|
||||
|
||||
/// probe for stack overflow. These are emitted for functions which need
|
||||
/// when the `enable_probestack` setting is true.
|
||||
Probestack,
|
||||
/// ceil.f32
|
||||
CeilF32,
|
||||
/// ceil.f64
|
||||
CeilF64,
|
||||
/// floor.f32
|
||||
FloorF32,
|
||||
/// floor.f64
|
||||
FloorF64,
|
||||
/// trunc.f32
|
||||
TruncF32,
|
||||
/// frunc.f64
|
||||
TruncF64,
|
||||
/// nearest.f32
|
||||
NearestF32,
|
||||
/// nearest.f64
|
||||
NearestF64,
|
||||
|
||||
/// A custom trap
|
||||
RaiseTrap,
|
||||
// /// libc.memcpy
|
||||
// Memcpy,
|
||||
// /// libc.memset
|
||||
// Memset,
|
||||
// /// libc.memmove
|
||||
// Memmove,
|
||||
|
||||
// /// Elf __tls_get_addr
|
||||
// ElfTlsGetAddr,
|
||||
/// trunc.f32
|
||||
TruncF32,
|
||||
|
||||
/// frunc.f64
|
||||
TruncF64,
|
||||
}
|
||||
|
||||
impl LibCall {
|
||||
/// The function pointer to a libcall
|
||||
pub fn function_pointer(&self) -> usize {
|
||||
match &self {
|
||||
pub fn function_pointer(self) -> usize {
|
||||
match self {
|
||||
Self::CeilF32 => wasmer_f32_ceil as usize,
|
||||
Self::FloorF32 => wasmer_f32_floor as usize,
|
||||
Self::TruncF32 => wasmer_f32_trunc as usize,
|
||||
Self::NearestF32 => wasmer_f32_nearest as usize,
|
||||
Self::CeilF64 => wasmer_f64_ceil as usize,
|
||||
Self::FloorF32 => wasmer_f32_floor as usize,
|
||||
Self::FloorF64 => wasmer_f64_floor as usize,
|
||||
Self::TruncF64 => wasmer_f64_trunc as usize,
|
||||
Self::NearestF32 => wasmer_f32_nearest as usize,
|
||||
Self::NearestF64 => wasmer_f64_nearest as usize,
|
||||
Self::Probestack => wasmer_probestack as usize,
|
||||
Self::RaiseTrap => wasmer_raise_trap as usize,
|
||||
Self::Probestack => PROBESTACK as usize,
|
||||
// other => panic!("unexpected libcall: {}", other),
|
||||
Self::TruncF32 => wasmer_f32_trunc as usize,
|
||||
Self::TruncF64 => wasmer_f64_trunc as usize,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the function name associated to the libcall.
|
||||
pub fn to_function_name(&self) -> &str {
|
||||
match self {
|
||||
Self::CeilF32 => "wasmer_f32_ceil",
|
||||
Self::CeilF64 => "wasmer_f64_ceil",
|
||||
Self::FloorF32 => "wasmer_f32_floor",
|
||||
Self::FloorF64 => "wasmer_f64_floor",
|
||||
Self::NearestF32 => "wasmer_f32_nearest",
|
||||
Self::NearestF64 => "wasmer_f64_nearest",
|
||||
Self::Probestack => "wasmer_probestack",
|
||||
Self::RaiseTrap => "wasmer_raise_trap",
|
||||
Self::TruncF32 => "wasmer_f32_trunc",
|
||||
Self::TruncF64 => "wasmer_f64_trunc",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
//! `LinearMemory` is to WebAssembly linear memories what `Table` is to WebAssembly tables.
|
||||
|
||||
use crate::mmap::Mmap;
|
||||
use crate::module::{MemoryPlan, MemoryStyle};
|
||||
use crate::vmcontext::VMMemoryDefinition;
|
||||
use more_asserts::{assert_ge, assert_le};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cell::RefCell;
|
||||
use thiserror::Error;
|
||||
use wasm_common::{Bytes, Pages};
|
||||
use wasm_common::{Bytes, MemoryType, Pages};
|
||||
|
||||
/// Error type describing things that can go wrong when operating on Wasm Memories.
|
||||
#[derive(Error, Debug, Clone, PartialEq, Hash)]
|
||||
@@ -36,6 +36,30 @@ pub enum MemoryError {
|
||||
Generic(String),
|
||||
}
|
||||
|
||||
/// Implementation styles for WebAssembly linear memory.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum MemoryStyle {
|
||||
/// The actual memory can be resized and moved.
|
||||
Dynamic,
|
||||
/// Address space is allocated up front.
|
||||
Static {
|
||||
/// The number of mapped and unmapped pages.
|
||||
bound: Pages,
|
||||
},
|
||||
}
|
||||
|
||||
/// A WebAssembly linear memory description along with our chosen style for
|
||||
/// implementing it.
|
||||
#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
|
||||
pub struct MemoryPlan {
|
||||
/// The WebAssembly linear memory description.
|
||||
pub memory: MemoryType,
|
||||
/// Our chosen implementation style.
|
||||
pub style: MemoryStyle,
|
||||
/// Our chosen offset-guard size.
|
||||
pub offset_guard_size: u64,
|
||||
}
|
||||
|
||||
/// A linear memory instance.
|
||||
#[derive(Debug)]
|
||||
pub struct LinearMemory {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! Data structure for representing WebAssembly modules
|
||||
//! in a [`Module`].
|
||||
|
||||
use crate::table::TableElements;
|
||||
use indexmap::IndexMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
@@ -12,64 +13,10 @@ use wasm_common::entity::{EntityRef, PrimaryMap};
|
||||
use wasm_common::{
|
||||
CustomSectionIndex, DataIndex, ElemIndex, ExportIndex, ExportType, ExternType, FunctionIndex,
|
||||
FunctionType, GlobalIndex, GlobalInit, GlobalType, ImportIndex, ImportType, LocalFunctionIndex,
|
||||
LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, MemoryType, Pages,
|
||||
SignatureIndex, TableIndex, TableType,
|
||||
LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, MemoryType, SignatureIndex,
|
||||
TableIndex, TableType,
|
||||
};
|
||||
|
||||
/// A WebAssembly table initializer.
|
||||
#[derive(Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub struct TableElements {
|
||||
/// The index of a table to initialize.
|
||||
pub table_index: TableIndex,
|
||||
/// Optionally, a global variable giving a base index.
|
||||
pub base: Option<GlobalIndex>,
|
||||
/// The offset to add to the base.
|
||||
pub offset: usize,
|
||||
/// The values to write into the table elements.
|
||||
pub elements: Box<[FunctionIndex]>,
|
||||
}
|
||||
|
||||
/// Implementation styles for WebAssembly linear memory.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum MemoryStyle {
|
||||
/// The actual memory can be resized and moved.
|
||||
Dynamic,
|
||||
/// Address space is allocated up front.
|
||||
Static {
|
||||
/// The number of mapped and unmapped pages.
|
||||
bound: Pages,
|
||||
},
|
||||
}
|
||||
|
||||
/// A WebAssembly linear memory description along with our chosen style for
|
||||
/// implementing it.
|
||||
#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
|
||||
pub struct MemoryPlan {
|
||||
/// The WebAssembly linear memory description.
|
||||
pub memory: MemoryType,
|
||||
/// Our chosen implementation style.
|
||||
pub style: MemoryStyle,
|
||||
/// Our chosen offset-guard size.
|
||||
pub offset_guard_size: u64,
|
||||
}
|
||||
|
||||
/// Implementation styles for WebAssembly tables.
|
||||
#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
|
||||
pub enum TableStyle {
|
||||
/// Signatures are stored in the table and checked in the caller.
|
||||
CallerChecksSignature,
|
||||
}
|
||||
|
||||
/// A WebAssembly table description along with our chosen style for
|
||||
/// implementing it.
|
||||
#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
|
||||
pub struct TablePlan {
|
||||
/// The WebAssembly table description.
|
||||
pub table: TableType,
|
||||
/// Our chosen implementation style.
|
||||
pub style: TableStyle,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ModuleId {
|
||||
id: usize,
|
||||
@@ -237,7 +184,7 @@ impl ModuleInfo {
|
||||
}
|
||||
ExportIndex::Global(i) => {
|
||||
let global_type = self.globals.get(i.clone()).unwrap();
|
||||
ExternType::Global(global_type.clone())
|
||||
ExternType::Global(*global_type)
|
||||
}
|
||||
};
|
||||
ExportType::new(name, extern_type)
|
||||
|
||||
@@ -2,12 +2,42 @@
|
||||
//!
|
||||
//! `Table` is to WebAssembly tables what `LinearMemory` is to WebAssembly linear memories.
|
||||
|
||||
use crate::module::{TablePlan, TableStyle};
|
||||
use crate::trap::{Trap, TrapCode};
|
||||
use crate::vmcontext::{VMCallerCheckedAnyfunc, VMTableDefinition};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cell::RefCell;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use wasm_common::Type;
|
||||
use wasm_common::{FunctionIndex, GlobalIndex, TableIndex, TableType, Type};
|
||||
|
||||
/// A WebAssembly table initializer.
|
||||
#[derive(Clone, Debug, Hash, Serialize, Deserialize)]
|
||||
pub struct TableElements {
|
||||
/// The index of a table to initialize.
|
||||
pub table_index: TableIndex,
|
||||
/// Optionally, a global variable giving a base index.
|
||||
pub base: Option<GlobalIndex>,
|
||||
/// The offset to add to the base.
|
||||
pub offset: usize,
|
||||
/// The values to write into the table elements.
|
||||
pub elements: Box<[FunctionIndex]>,
|
||||
}
|
||||
|
||||
/// Implementation styles for WebAssembly tables.
|
||||
#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
|
||||
pub enum TableStyle {
|
||||
/// Signatures are stored in the table and checked in the caller.
|
||||
CallerChecksSignature,
|
||||
}
|
||||
|
||||
/// A WebAssembly table description along with our chosen style for
|
||||
/// implementing it.
|
||||
#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
|
||||
pub struct TablePlan {
|
||||
/// The WebAssembly table description.
|
||||
pub table: TableType,
|
||||
/// Our chosen implementation style.
|
||||
pub style: TableStyle,
|
||||
}
|
||||
|
||||
/// A table instance.
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -415,6 +415,8 @@ impl Trap {
|
||||
/// * `values_vec` - points to a buffer which holds the incoming arguments, and to
|
||||
/// which the outgoing return values will be written.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Wildly unsafe because it calls raw function pointers and reads/writes raw
|
||||
/// function pointers.
|
||||
pub unsafe fn wasmer_call_trampoline(
|
||||
@@ -433,7 +435,9 @@ pub unsafe fn wasmer_call_trampoline(
|
||||
/// Catches any wasm traps that happen within the execution of `closure`,
|
||||
/// returning them as a `Result`.
|
||||
///
|
||||
/// Highly unsafe since `closure` won't have any dtors run.
|
||||
/// # Safety
|
||||
///
|
||||
/// Highly unsafe since `closure` won't have any destructors run.
|
||||
pub unsafe fn catch_traps<F>(vmctx: *mut VMContext, mut closure: F) -> Result<(), Trap>
|
||||
where
|
||||
F: FnMut(),
|
||||
@@ -582,7 +586,7 @@ impl CallThreadState {
|
||||
// First up see if any instance registered has a custom trap handler,
|
||||
// in which case run them all. If anything handles the trap then we
|
||||
// return that the trap was handled.
|
||||
if self.any_instance(|i| {
|
||||
let any_instance = self.any_instance(|i| {
|
||||
let handler = match i.instance().signal_handler.replace(None) {
|
||||
Some(handler) => handler,
|
||||
None => return false,
|
||||
@@ -590,7 +594,9 @@ impl CallThreadState {
|
||||
let result = call_handler(&handler);
|
||||
i.instance().signal_handler.set(Some(handler));
|
||||
result
|
||||
}) {
|
||||
});
|
||||
|
||||
if any_instance {
|
||||
self.handling_trap.set(false);
|
||||
return 1 as *const _;
|
||||
}
|
||||
|
||||
@@ -433,120 +433,200 @@ impl VMGlobalDefinition {
|
||||
}
|
||||
|
||||
/// Return a reference to the value as an i32.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_i32(&self) -> &i32 {
|
||||
&*(self.storage.as_ref().as_ptr() as *const i32)
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the value as an i32.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_i32_mut(&mut self) -> &mut i32 {
|
||||
&mut *(self.storage.as_mut().as_mut_ptr() as *mut i32)
|
||||
}
|
||||
|
||||
/// Return a reference to the value as a u32.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_u32(&self) -> &u32 {
|
||||
&*(self.storage.as_ref().as_ptr() as *const u32)
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the value as an u32.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_u32_mut(&mut self) -> &mut u32 {
|
||||
&mut *(self.storage.as_mut().as_mut_ptr() as *mut u32)
|
||||
}
|
||||
|
||||
/// Return a reference to the value as an i64.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_i64(&self) -> &i64 {
|
||||
&*(self.storage.as_ref().as_ptr() as *const i64)
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the value as an i64.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_i64_mut(&mut self) -> &mut i64 {
|
||||
&mut *(self.storage.as_mut().as_mut_ptr() as *mut i64)
|
||||
}
|
||||
|
||||
/// Return a reference to the value as an u64.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_u64(&self) -> &u64 {
|
||||
&*(self.storage.as_ref().as_ptr() as *const u64)
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the value as an u64.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_u64_mut(&mut self) -> &mut u64 {
|
||||
&mut *(self.storage.as_mut().as_mut_ptr() as *mut u64)
|
||||
}
|
||||
|
||||
/// Return a reference to the value as an f32.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_f32(&self) -> &f32 {
|
||||
&*(self.storage.as_ref().as_ptr() as *const f32)
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the value as an f32.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_f32_mut(&mut self) -> &mut f32 {
|
||||
&mut *(self.storage.as_mut().as_mut_ptr() as *mut f32)
|
||||
}
|
||||
|
||||
/// Return a reference to the value as f32 bits.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_f32_bits(&self) -> &u32 {
|
||||
&*(self.storage.as_ref().as_ptr() as *const u32)
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the value as f32 bits.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_f32_bits_mut(&mut self) -> &mut u32 {
|
||||
&mut *(self.storage.as_mut().as_mut_ptr() as *mut u32)
|
||||
}
|
||||
|
||||
/// Return a reference to the value as an f64.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_f64(&self) -> &f64 {
|
||||
&*(self.storage.as_ref().as_ptr() as *const f64)
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the value as an f64.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_f64_mut(&mut self) -> &mut f64 {
|
||||
&mut *(self.storage.as_mut().as_mut_ptr() as *mut f64)
|
||||
}
|
||||
|
||||
/// Return a reference to the value as f64 bits.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_f64_bits(&self) -> &u64 {
|
||||
&*(self.storage.as_ref().as_ptr() as *const u64)
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the value as f64 bits.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_f64_bits_mut(&mut self) -> &mut u64 {
|
||||
&mut *(self.storage.as_mut().as_mut_ptr() as *mut u64)
|
||||
}
|
||||
|
||||
/// Return a reference to the value as an u128.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_u128(&self) -> &u128 {
|
||||
&*(self.storage.as_ref().as_ptr() as *const u128)
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the value as an u128.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_u128_mut(&mut self) -> &mut u128 {
|
||||
&mut *(self.storage.as_mut().as_mut_ptr() as *mut u128)
|
||||
}
|
||||
|
||||
/// Return a reference to the value as u128 bits.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_u128_bits(&self) -> &[u8; 16] {
|
||||
&*(self.storage.as_ref().as_ptr() as *const [u8; 16])
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the value as u128 bits.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// To be defined (TODO).
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub unsafe fn as_u128_bits_mut(&mut self) -> &mut [u8; 16] {
|
||||
&mut *(self.storage.as_mut().as_mut_ptr() as *mut [u8; 16])
|
||||
@@ -721,7 +801,7 @@ impl VMBuiltinFunctionIndex {
|
||||
}
|
||||
|
||||
/// Return the index as an u32 number.
|
||||
pub const fn index(&self) -> u32 {
|
||||
pub const fn index(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-wasi-experimental-io-devices"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
edition = "2018"
|
||||
repository = "https://github.com/wasmerio/wasmer"
|
||||
@@ -12,7 +12,7 @@ license = "MIT"
|
||||
maintenance = { status = "experimental" }
|
||||
|
||||
[dependencies]
|
||||
wasmer-wasi = { version = "0.16.2", path = "../wasi" }
|
||||
wasmer-wasi = { version = "1.0.0-alpha.1", path = "../wasi" }
|
||||
tracing = "0.1"
|
||||
minifb = "0.16"
|
||||
ref_thread_local = "0.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-wasi"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
description = "Wasmer runtime WASI implementation library"
|
||||
license = "MIT"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@@ -20,7 +20,7 @@ getrandom = "0.1"
|
||||
time = "0.1"
|
||||
typetag = "0.1"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
wasmer = { path = "../api", version = "0.16.2", default-features = false }
|
||||
wasmer = { path = "../api", version = "1.0.0-alpha.1", default-features = false }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = "0.3"
|
||||
|
||||
@@ -26,7 +26,7 @@ pub use crate::syscalls::types;
|
||||
pub use crate::utils::{get_wasi_version, is_wasi_module, WasiVersion};
|
||||
|
||||
use thiserror::Error;
|
||||
use wasmer::{imports, Function, ImportObject, Memory, Store};
|
||||
use wasmer::{imports, Function, ImportObject, Memory, Module, Store};
|
||||
|
||||
/// This is returned in `RuntimeError`.
|
||||
/// Use `downcast` or `downcast_ref` to retrieve the `ExitCode`.
|
||||
@@ -34,6 +34,8 @@ use wasmer::{imports, Function, ImportObject, Memory, Store};
|
||||
pub enum WasiError {
|
||||
#[error("WASI exited with code: {0}")]
|
||||
Exit(syscalls::types::__wasi_exitcode_t),
|
||||
#[error("The WASI version could not be determined")]
|
||||
UnknownWasiVersion,
|
||||
}
|
||||
|
||||
/// The environment provided to the WASI imports.
|
||||
@@ -51,6 +53,15 @@ impl<'a> WasiEnv<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn import_object(&mut self, module: &Module) -> Result<ImportObject, WasiError> {
|
||||
let wasi_version = get_wasi_version(module, false).ok_or(WasiError::UnknownWasiVersion)?;
|
||||
Ok(generate_import_object_from_env(
|
||||
module.store(),
|
||||
self,
|
||||
wasi_version,
|
||||
))
|
||||
}
|
||||
|
||||
/// Set the state
|
||||
pub fn set_memory(&mut self, memory: &'a Memory) {
|
||||
self.memory = Some(memory);
|
||||
|
||||
@@ -13,6 +13,7 @@ impl<T: Copy, Ty> Copy for WasmPtr<T, Ty> {}
|
||||
|
||||
impl<T: Copy, Ty> Clone for WasmPtr<T, Ty> {
|
||||
fn clone(&self) -> Self {
|
||||
#[allow(clippy::clone_on_copy)]
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
@@ -73,7 +74,7 @@ impl<T: Copy + ValueType> WasmPtr<T, Array> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_utf8_string<'a>(self, memory: &'a Memory, str_len: u32) -> Option<&'a str> {
|
||||
pub fn get_utf8_string(self, memory: &Memory, str_len: u32) -> Option<&str> {
|
||||
self.0.get_utf8_string(memory, str_len)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use crate::state::{WasiFile, WasiFs, WasiFsError, WasiState};
|
||||
use crate::syscalls::types::{__WASI_STDERR_FILENO, __WASI_STDIN_FILENO, __WASI_STDOUT_FILENO};
|
||||
use crate::WasiEnv;
|
||||
use std::path::{Path, PathBuf};
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -36,6 +37,7 @@ pub struct WasiStateBuilder {
|
||||
args: Vec<Vec<u8>>,
|
||||
envs: Vec<Vec<u8>>,
|
||||
preopens: Vec<PreopenedDir>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
setup_fs_fn: Option<Box<dyn Fn(&mut WasiFs) -> Result<(), String> + Send>>,
|
||||
stdout_override: Option<Box<dyn WasiFile>>,
|
||||
stderr_override: Option<Box<dyn WasiFile>>,
|
||||
@@ -78,16 +80,11 @@ pub enum WasiStateCreationError {
|
||||
}
|
||||
|
||||
fn validate_mapped_dir_alias(alias: &str) -> Result<(), WasiStateCreationError> {
|
||||
for byte in alias.bytes() {
|
||||
match byte {
|
||||
b'\0' => {
|
||||
if !alias.bytes().all(|b| b != b'\0') {
|
||||
return Err(WasiStateCreationError::MappedDirAliasFormattingError(
|
||||
format!("Alias \"{}\" contains a nul byte", alias),
|
||||
));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -392,6 +389,14 @@ impl WasiStateBuilder {
|
||||
envs: self.envs.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Consumes the [`WasiStateBuilder`] and produces a [`WasiEnv`]
|
||||
///
|
||||
/// Returns the error from `WasiFs::new` if there's an error
|
||||
pub fn finalize(&mut self) -> Result<WasiEnv, WasiStateCreationError> {
|
||||
let state = self.build()?;
|
||||
Ok(WasiEnv::new(state))
|
||||
}
|
||||
}
|
||||
|
||||
/// Builder for preopened directories.
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
//! You can implement `WasiFile` for your own types to get custom behavior and extend WASI, see the
|
||||
//! [WASI plugin example](https://github.com/wasmerio/wasmer/blob/master/examples/plugin.rs).
|
||||
|
||||
#![allow(clippy::cognitive_complexity, clippy::too_many_arguments)]
|
||||
|
||||
mod builder;
|
||||
mod types;
|
||||
|
||||
@@ -1357,7 +1359,7 @@ impl WasiFs {
|
||||
_ => unreachable!("Symlink pointing to something that's not a directory as its base preopened directory"),
|
||||
}
|
||||
}
|
||||
__ => return None,
|
||||
_ => return None,
|
||||
};
|
||||
Some(__wasi_filestat_t {
|
||||
st_filetype: host_file_type_to_wasi_file_type(md.file_type()),
|
||||
@@ -1401,7 +1403,7 @@ impl WasiFs {
|
||||
.ok_or(__WASI_EINVAL)?
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
if let Some(p) = parent.clone() {
|
||||
if let Some(p) = *parent {
|
||||
match &mut self.inodes[p].kind {
|
||||
Kind::Dir { entries, .. } | Kind::Root { entries } => {
|
||||
self.fd_map.remove(&fd).unwrap();
|
||||
@@ -1478,8 +1480,9 @@ pub struct WasiState {
|
||||
impl WasiState {
|
||||
/// Create a [`WasiStateBuilder`] to construct a validated instance of
|
||||
/// [`WasiState`].
|
||||
pub fn new(program_name: &str) -> WasiStateBuilder {
|
||||
create_wasi_state(program_name)
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new(program_name: impl AsRef<str>) -> WasiStateBuilder {
|
||||
create_wasi_state(program_name.as_ref())
|
||||
}
|
||||
|
||||
/// Turn the WasiState into bytes
|
||||
|
||||
@@ -22,6 +22,7 @@ pub fn fd_filestat_get(
|
||||
let new_buf: WasmPtr<types::__wasi_filestat_t> = unsafe { std::mem::transmute(buf) };
|
||||
|
||||
// Copy the data including the extra data
|
||||
#[allow(clippy::clone_on_copy)]
|
||||
let new_filestat_setup: types::__wasi_filestat_t =
|
||||
wasi_try!(new_buf.deref(memory)).get().clone();
|
||||
|
||||
@@ -71,6 +72,7 @@ pub fn path_filestat_get(
|
||||
let memory = env.memory();
|
||||
|
||||
let new_buf: WasmPtr<types::__wasi_filestat_t> = unsafe { std::mem::transmute(buf) };
|
||||
#[allow(clippy::clone_on_copy)]
|
||||
let new_filestat_setup: types::__wasi_filestat_t =
|
||||
wasi_try!(new_buf.deref(memory)).get().clone();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#![allow(unused, clippy::too_many_arguments)]
|
||||
#![allow(unused, clippy::too_many_arguments, clippy::cognitive_complexity)]
|
||||
|
||||
pub mod types;
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
@@ -596,14 +597,11 @@ pub fn fd_filestat_set_times(
|
||||
};
|
||||
inode.stat.st_atim = time_to_set;
|
||||
// TODO: set it for more than just files
|
||||
match &mut inode.kind {
|
||||
Kind::File { handle, .. } => {
|
||||
if let Kind::File { handle, .. } = &mut inode.kind {
|
||||
if let Some(handle) = handle {
|
||||
handle.set_last_accessed(time_to_set);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if fst_flags & __WASI_FILESTAT_SET_MTIM != 0 || fst_flags & __WASI_FILESTAT_SET_MTIM_NOW != 0 {
|
||||
@@ -614,14 +612,11 @@ pub fn fd_filestat_set_times(
|
||||
};
|
||||
inode.stat.st_mtim = time_to_set;
|
||||
// TODO: set it for more than just files
|
||||
match &mut inode.kind {
|
||||
Kind::File { handle, .. } => {
|
||||
if let Kind::File { handle, .. } = &mut inode.kind {
|
||||
if let Some(handle) = handle {
|
||||
handle.set_last_modified(time_to_set);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
__WASI_ESUCCESS
|
||||
@@ -688,8 +683,7 @@ pub fn fd_pread(
|
||||
h.seek(std::io::SeekFrom::Start(offset as u64)).ok(),
|
||||
__WASI_EIO
|
||||
);
|
||||
let bytes_read = wasi_try!(read_bytes(h, memory, iov_cells));
|
||||
bytes_read
|
||||
wasi_try!(read_bytes(h, memory, iov_cells))
|
||||
} else {
|
||||
return __WASI_EINVAL;
|
||||
}
|
||||
@@ -836,7 +830,7 @@ pub fn fd_pwrite(
|
||||
|
||||
let inode = &mut state.fs.inodes[fd_entry.inode];
|
||||
|
||||
let bytes_written = match &mut inode.kind {
|
||||
match &mut inode.kind {
|
||||
Kind::File { handle, .. } => {
|
||||
if let Some(handle) = handle {
|
||||
handle.seek(std::io::SeekFrom::Start(offset as u64));
|
||||
@@ -855,9 +849,7 @@ pub fn fd_pwrite(
|
||||
memory,
|
||||
iovs_arr_cell
|
||||
)),
|
||||
};
|
||||
|
||||
bytes_written
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1534,14 +1526,11 @@ pub fn path_filestat_set_times(
|
||||
};
|
||||
inode.stat.st_atim = time_to_set;
|
||||
// TODO: set it for more than just files
|
||||
match &mut inode.kind {
|
||||
Kind::File { handle, .. } => {
|
||||
if let Kind::File { handle, .. } = &mut inode.kind {
|
||||
if let Some(handle) = handle {
|
||||
handle.set_last_accessed(time_to_set);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if fst_flags & __WASI_FILESTAT_SET_MTIM != 0 || fst_flags & __WASI_FILESTAT_SET_MTIM_NOW != 0 {
|
||||
let time_to_set = if fst_flags & __WASI_FILESTAT_SET_MTIM != 0 {
|
||||
@@ -1551,14 +1540,11 @@ pub fn path_filestat_set_times(
|
||||
};
|
||||
inode.stat.st_mtim = time_to_set;
|
||||
// TODO: set it for more than just files
|
||||
match &mut inode.kind {
|
||||
Kind::File { handle, .. } => {
|
||||
if let Kind::File { handle, .. } = &mut inode.kind {
|
||||
if let Some(handle) = handle {
|
||||
handle.set_last_modified(time_to_set);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
__WASI_ESUCCESS
|
||||
@@ -1734,11 +1720,9 @@ pub fn path_open(
|
||||
if o_flags & __WASI_O_DIRECTORY != 0 {
|
||||
return __WASI_ENOTDIR;
|
||||
}
|
||||
if o_flags & __WASI_O_EXCL != 0 {
|
||||
if path.exists() {
|
||||
if o_flags & __WASI_O_EXCL != 0 && path.exists() {
|
||||
return __WASI_EEXIST;
|
||||
}
|
||||
}
|
||||
let mut open_options = std::fs::OpenOptions::new();
|
||||
let write_permission = adjusted_rights & __WASI_RIGHT_FD_WRITE != 0;
|
||||
// append, truncate, and create all require the permission to write
|
||||
@@ -1780,12 +1764,10 @@ pub fn path_open(
|
||||
Kind::Buffer { .. } => unimplemented!("wasi::path_open for Buffer type files"),
|
||||
Kind::Dir { .. } | Kind::Root { .. } => {
|
||||
// TODO: adjust these to be correct
|
||||
if o_flags & __WASI_O_EXCL != 0 {
|
||||
if path_arg.exists() {
|
||||
if o_flags & __WASI_O_EXCL != 0 && path_arg.exists() {
|
||||
return __WASI_EEXIST;
|
||||
}
|
||||
}
|
||||
}
|
||||
Kind::Symlink {
|
||||
base_po_dir,
|
||||
path_to_symlink,
|
||||
@@ -1971,12 +1953,10 @@ pub fn path_remove_directory(
|
||||
|
||||
let host_path_to_remove = match &state.fs.inodes[inode].kind {
|
||||
Kind::Dir { entries, path, .. } => {
|
||||
if !entries.is_empty() {
|
||||
if !entries.is_empty()
|
||||
|| wasi_try!(std::fs::read_dir(path).ok(), __WASI_EIO).count() != 0
|
||||
{
|
||||
return __WASI_ENOTEMPTY;
|
||||
} else {
|
||||
if wasi_try!(std::fs::read_dir(path).ok(), __WASI_EIO).count() != 0 {
|
||||
return __WASI_ENOTEMPTY;
|
||||
}
|
||||
}
|
||||
path.clone()
|
||||
}
|
||||
|
||||
@@ -290,6 +290,7 @@ impl PrestatEnum {
|
||||
}
|
||||
|
||||
impl __wasi_prestat_t {
|
||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||
pub fn tagged(&self) -> Option<PrestatEnum> {
|
||||
match self.pr_type {
|
||||
__WASI_PREOPENTYPE_DIR => Some(PrestatEnum::Dir {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasm-common"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
description = "WebAssembly Common Types"
|
||||
license = "MIT OR (Apache-2.0 WITH LLVM-exception)"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
|
||||
@@ -138,8 +138,8 @@ impl Features {
|
||||
}
|
||||
|
||||
impl Default for Features {
|
||||
fn default() -> Features {
|
||||
Features::new()
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ mod test_features {
|
||||
reference_types: false,
|
||||
simd: false,
|
||||
bulk_memory: false,
|
||||
multi_value: false,
|
||||
multi_value: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#![deny(missing_docs, unused_extern_crates)]
|
||||
#![warn(unused_import_braces)]
|
||||
#![cfg_attr(feature = "std", deny(unstable_features))]
|
||||
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
|
||||
#![cfg_attr(
|
||||
|
||||
@@ -30,12 +30,16 @@ pub trait NativeWasmType {
|
||||
|
||||
#[doc(hidden)]
|
||||
fn into_abi(self) -> Self::Abi;
|
||||
|
||||
/// Convert self to i128 binary representation.
|
||||
fn to_binary(self) -> i128;
|
||||
|
||||
/// Convert to self from i128 binary representation.
|
||||
fn from_binary(binary: i128) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! wasm_native_type {
|
||||
($type:ty => $native_type:expr) => {
|
||||
impl NativeWasmType for $type {
|
||||
const WASM_TYPE: Type = $native_type;
|
||||
impl NativeWasmType for i32 {
|
||||
const WASM_TYPE: Type = Type::I32;
|
||||
type Abi = Self;
|
||||
|
||||
#[inline]
|
||||
@@ -47,14 +51,81 @@ macro_rules! wasm_native_type {
|
||||
fn into_abi(self) -> Self::Abi {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn to_binary(self) -> i128 {
|
||||
self as _
|
||||
}
|
||||
|
||||
wasm_native_type!(i32 => Type::I32);
|
||||
wasm_native_type!(i64 => Type::I64);
|
||||
wasm_native_type!(f32 => Type::F32);
|
||||
wasm_native_type!(f64 => Type::F64);
|
||||
fn from_binary(bits: i128) -> Self {
|
||||
bits as _
|
||||
}
|
||||
}
|
||||
impl NativeWasmType for i64 {
|
||||
const WASM_TYPE: Type = Type::I64;
|
||||
type Abi = Self;
|
||||
|
||||
#[inline]
|
||||
fn from_abi(abi: Self::Abi) -> Self {
|
||||
abi
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_abi(self) -> Self::Abi {
|
||||
self
|
||||
}
|
||||
|
||||
fn to_binary(self) -> i128 {
|
||||
self as _
|
||||
}
|
||||
|
||||
fn from_binary(bits: i128) -> Self {
|
||||
bits as _
|
||||
}
|
||||
}
|
||||
impl NativeWasmType for f32 {
|
||||
const WASM_TYPE: Type = Type::F32;
|
||||
type Abi = Self;
|
||||
|
||||
#[inline]
|
||||
fn from_abi(abi: Self::Abi) -> Self {
|
||||
abi
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_abi(self) -> Self::Abi {
|
||||
self
|
||||
}
|
||||
|
||||
fn to_binary(self) -> i128 {
|
||||
self.to_bits() as _
|
||||
}
|
||||
|
||||
fn from_binary(bits: i128) -> Self {
|
||||
Self::from_bits(bits as _)
|
||||
}
|
||||
}
|
||||
impl NativeWasmType for f64 {
|
||||
const WASM_TYPE: Type = Type::F64;
|
||||
type Abi = Self;
|
||||
|
||||
#[inline]
|
||||
fn from_abi(abi: Self::Abi) -> Self {
|
||||
abi
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_abi(self) -> Self::Abi {
|
||||
self
|
||||
}
|
||||
|
||||
fn to_binary(self) -> i128 {
|
||||
self.to_bits() as _
|
||||
}
|
||||
|
||||
fn from_binary(bits: i128) -> Self {
|
||||
Self::from_bits(bits as _)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_native_type {
|
||||
@@ -87,6 +158,7 @@ where
|
||||
|
||||
macro_rules! wasm_extern_type {
|
||||
($type:ty => $native_type:ty) => {
|
||||
#[allow(clippy::use_self)]
|
||||
unsafe impl WasmExternType for $type {
|
||||
type Native = $native_type;
|
||||
|
||||
@@ -147,18 +219,15 @@ where
|
||||
{
|
||||
}
|
||||
|
||||
macro_rules! convert_value_impl {
|
||||
($t:ty) => {
|
||||
unsafe impl ValueType for $t {}
|
||||
};
|
||||
( $($t:ty),* ) => {
|
||||
macro_rules! impl_value_type_for {
|
||||
( $($type:ty),* ) => {
|
||||
$(
|
||||
convert_value_impl!($t);
|
||||
unsafe impl ValueType for $type {}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
convert_value_impl!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
|
||||
impl_value_type_for!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
|
||||
|
||||
/// Represents a list of WebAssembly values.
|
||||
pub trait WasmTypeList {
|
||||
@@ -166,7 +235,7 @@ pub trait WasmTypeList {
|
||||
type CStruct;
|
||||
|
||||
/// Array of return values.
|
||||
type Array: AsMut<[u64]>;
|
||||
type Array: AsMut<[i128]>;
|
||||
|
||||
/// Construct `Self` based on an array of returned values.
|
||||
fn from_array(array: Self::Array) -> Self;
|
||||
@@ -195,6 +264,7 @@ where
|
||||
{
|
||||
/// The error type for this trait.
|
||||
type Error: Send + 'static;
|
||||
|
||||
/// Get returns or error result.
|
||||
fn report(self) -> Result<Rets, Self::Error>;
|
||||
}
|
||||
@@ -204,7 +274,8 @@ where
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
type Error = Infallible;
|
||||
fn report(self) -> Result<Rets, Infallible> {
|
||||
|
||||
fn report(self) -> Result<Self, Infallible> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
@@ -215,7 +286,8 @@ where
|
||||
E: Send + 'static,
|
||||
{
|
||||
type Error = E;
|
||||
fn report(self) -> Result<Rets, E> {
|
||||
|
||||
fn report(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -299,7 +371,7 @@ where
|
||||
|
||||
impl WasmTypeList for Infallible {
|
||||
type CStruct = Self;
|
||||
type Array = [u64; 0];
|
||||
type Array = [i128; 0];
|
||||
|
||||
fn from_array(_: Self::Array) -> Self {
|
||||
unreachable!()
|
||||
@@ -351,20 +423,19 @@ macro_rules! impl_traits {
|
||||
{
|
||||
type CStruct = $struct_name<$( $x ),*>;
|
||||
|
||||
type Array = [u64; count_idents!( $( $x ),* )];
|
||||
type Array = [i128; count_idents!( $( $x ),* )];
|
||||
|
||||
fn from_array(_array: Self::Array) -> Self {
|
||||
unimplemented!("from array");
|
||||
// #[allow(non_snake_case)]
|
||||
// let [ $( $x ),* ] = array;
|
||||
fn from_array(array: Self::Array) -> Self {
|
||||
#[allow(non_snake_case)]
|
||||
let [ $( $x ),* ] = array;
|
||||
|
||||
// ( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* )
|
||||
( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* )
|
||||
}
|
||||
|
||||
fn into_array(self) -> Self::Array {
|
||||
unimplemented!("into array");
|
||||
// let ( $( $x ),* ) = self;
|
||||
// [ $( WasmExternType::to_native($x).to_binary() ),* ]
|
||||
#[allow(non_snake_case)]
|
||||
let ( $( $x ),* ) = self;
|
||||
[ $( WasmExternType::to_native($x).to_binary() ),* ]
|
||||
}
|
||||
|
||||
fn empty_array() -> Self::Array {
|
||||
@@ -409,7 +480,7 @@ macro_rules! impl_traits {
|
||||
// println!("WRAP");
|
||||
// println!("Struct {:?}", (($( $x ),*) as WasmTypeList).into_c_struct());
|
||||
// $( println!("X: {:?}", $x); )*
|
||||
let f: &FN = unsafe { std::mem::transmute(&()) };
|
||||
let f: &FN = unsafe { &*(&() as *const () as *const FN) };
|
||||
f( $( WasmExternType::from_native($x) ),* ).into_c_struct()
|
||||
}
|
||||
wrap::<$( $x, )* Rets, Self> as *const FunctionBody
|
||||
@@ -486,7 +557,7 @@ macro_rules! impl_traits {
|
||||
T: Sized,
|
||||
FN: Fn(&mut T, $( $x ),* ) -> Rets + 'static
|
||||
{
|
||||
let f: &FN = unsafe { std::mem::transmute(&()) };
|
||||
let f: &FN = unsafe { &*(&() as *const () as *const FN) };
|
||||
f(ctx, $( WasmExternType::from_native($x) ),* ).into_c_struct()
|
||||
}
|
||||
wrap::<$( $x, )* Rets, Self, T> as *const FunctionBody
|
||||
@@ -520,11 +591,11 @@ impl_traits!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
|
||||
impl_traits!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
|
||||
impl_traits!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
|
||||
impl_traits!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15);
|
||||
// impl_traits!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16);
|
||||
// impl_traits!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17);
|
||||
// impl_traits!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18);
|
||||
// impl_traits!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19);
|
||||
// impl_traits!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20);
|
||||
impl_traits!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16);
|
||||
impl_traits!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17);
|
||||
impl_traits!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18);
|
||||
impl_traits!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19);
|
||||
impl_traits!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20);
|
||||
// impl_traits!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21);
|
||||
// impl_traits!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22);
|
||||
// impl_traits!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23);
|
||||
@@ -593,6 +664,7 @@ mod test_wasm_type_list {
|
||||
mod test_func {
|
||||
use super::*;
|
||||
use crate::types::Type;
|
||||
use std::ptr;
|
||||
// WasmTypeList
|
||||
|
||||
fn func() {}
|
||||
@@ -615,64 +687,44 @@ mod test_func {
|
||||
|
||||
#[test]
|
||||
fn test_function_types() {
|
||||
assert_eq!(Function::new(func).ty(), FunctionType::new(vec![], vec![]));
|
||||
assert_eq!(Func::new(func).ty(), FunctionType::new(vec![], vec![]));
|
||||
assert_eq!(
|
||||
Function::new(func__i32).ty(),
|
||||
Func::new(func__i32).ty(),
|
||||
FunctionType::new(vec![], vec![Type::I32])
|
||||
);
|
||||
assert_eq!(
|
||||
Function::new(func_i32).ty(),
|
||||
Func::new(func_i32).ty(),
|
||||
FunctionType::new(vec![Type::I32], vec![])
|
||||
);
|
||||
assert_eq!(
|
||||
Function::new(func_i32__i32).ty(),
|
||||
Func::new(func_i32__i32).ty(),
|
||||
FunctionType::new(vec![Type::I32], vec![Type::I32])
|
||||
);
|
||||
assert_eq!(
|
||||
Function::new(func_i32_i32__i32).ty(),
|
||||
Func::new(func_i32_i32__i32).ty(),
|
||||
FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32])
|
||||
);
|
||||
assert_eq!(
|
||||
Function::new(func_i32_i32__i32_i32).ty(),
|
||||
Func::new(func_i32_i32__i32_i32).ty(),
|
||||
FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32, Type::I32])
|
||||
);
|
||||
assert_eq!(
|
||||
Function::new(func_f32_i32__i32_f32).ty(),
|
||||
Func::new(func_f32_i32__i32_f32).ty(),
|
||||
FunctionType::new(vec![Type::F32, Type::I32], vec![Type::I32, Type::F32])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_function_pointer() {
|
||||
let f = Function::new(func_i32__i32);
|
||||
let function = unsafe {
|
||||
std::mem::transmute::<*const FunctionBody, fn(i32, i32, i32) -> i32>(f.address)
|
||||
};
|
||||
assert_eq!(function(1, 2, 3), 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_function_env_pointer() {
|
||||
fn func_i32__i32_env(env: &mut Env, a: i32) -> i32 {
|
||||
let result = env.num * a;
|
||||
env.num = 10;
|
||||
return result;
|
||||
}
|
||||
struct Env {
|
||||
pub num: i32,
|
||||
};
|
||||
let mut my_env = Env { num: 2 };
|
||||
let f = Function::new_env(&mut my_env, func_i32__i32_env);
|
||||
let function = unsafe {
|
||||
std::mem::transmute::<*const FunctionBody, fn(&mut Env, i32) -> i32>(f.address)
|
||||
};
|
||||
assert_eq!(function(&mut my_env, 3), 6);
|
||||
assert_eq!(my_env.num, 10);
|
||||
let f = Func::new(func_i32__i32);
|
||||
let function =
|
||||
unsafe { std::mem::transmute::<*const FunctionBody, fn(usize, i32) -> i32>(f.address) };
|
||||
assert_eq!(function(0, 3), 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_function_call() {
|
||||
let f = Function::new(func_i32__i32);
|
||||
let f = Func::new(func_i32__i32);
|
||||
let x = |args: <(i32, i32) as WasmTypeList>::Array,
|
||||
rets: &mut <(i32, i32) as WasmTypeList>::Array| {
|
||||
let result = func_i32_i32__i32_i32(args[0] as _, args[1] as _);
|
||||
|
||||
@@ -100,9 +100,9 @@ impl AnyRef {
|
||||
|
||||
/// Returns true if the two `AnyRef<T>`'s point to the same value (not just
|
||||
/// values that compare as equal).
|
||||
pub fn ptr_eq(&self, other: &AnyRef) -> bool {
|
||||
pub fn ptr_eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Null, AnyRef::Null) => true,
|
||||
(Self::Null, Self::Null) => true,
|
||||
(Self::Ref(InternalRef(ref a)), Self::Ref(InternalRef(ref b))) => a.ptr_eq(b.as_ref()),
|
||||
(Self::Other(OtherRef(ref a)), Self::Other(OtherRef(ref b))) => Rc::ptr_eq(a, b),
|
||||
_ => false,
|
||||
|
||||
@@ -32,7 +32,7 @@ pub enum Type {
|
||||
impl Type {
|
||||
/// Returns true if `Type` matches any of the numeric types. (e.g. `I32`,
|
||||
/// `I64`, `F32`, `F64`, `V128`).
|
||||
pub fn is_num(&self) -> bool {
|
||||
pub fn is_num(self) -> bool {
|
||||
match self {
|
||||
Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128 => true,
|
||||
_ => false,
|
||||
@@ -40,7 +40,7 @@ impl Type {
|
||||
}
|
||||
|
||||
/// Returns true if `Type` matches either of the reference types.
|
||||
pub fn is_ref(&self) -> bool {
|
||||
pub fn is_ref(self) -> bool {
|
||||
match self {
|
||||
Self::AnyRef | Self::FuncRef => true,
|
||||
_ => false,
|
||||
@@ -109,7 +109,7 @@ pub enum ExternType {
|
||||
Memory(MemoryType),
|
||||
}
|
||||
|
||||
fn is_global_compatible(exported: &GlobalType, imported: &GlobalType) -> bool {
|
||||
fn is_global_compatible(exported: GlobalType, imported: GlobalType) -> bool {
|
||||
let GlobalType {
|
||||
ty: exported_ty,
|
||||
mutability: exported_mutability,
|
||||
@@ -118,6 +118,7 @@ fn is_global_compatible(exported: &GlobalType, imported: &GlobalType) -> bool {
|
||||
ty: imported_ty,
|
||||
mutability: imported_mutability,
|
||||
} = imported;
|
||||
|
||||
exported_ty == imported_ty && imported_mutability == exported_mutability
|
||||
}
|
||||
|
||||
@@ -201,7 +202,7 @@ impl ExternType {
|
||||
pub fn is_compatible_with(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Function(a), Self::Function(b)) => a == b,
|
||||
(Self::Global(a), Self::Global(b)) => is_global_compatible(a, b),
|
||||
(Self::Global(a), Self::Global(b)) => is_global_compatible(*a, *b),
|
||||
(Self::Table(a), Self::Table(b)) => is_table_compatible(a, b),
|
||||
(Self::Memory(a), Self::Memory(b)) => is_memory_compatible(a, b),
|
||||
// The rest of possibilities, are not compatible
|
||||
@@ -289,25 +290,26 @@ pub enum Mutability {
|
||||
|
||||
impl Mutability {
|
||||
/// Returns a boolean indicating if the enum is set to mutable.
|
||||
pub fn is_mutable(&self) -> bool {
|
||||
(*self).into()
|
||||
pub fn is_mutable(self) -> bool {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for Mutability {
|
||||
fn from(val: bool) -> Self {
|
||||
match val {
|
||||
false => Self::Const,
|
||||
true => Self::Var,
|
||||
fn from(value: bool) -> Self {
|
||||
if value {
|
||||
Self::Var
|
||||
} else {
|
||||
Self::Const
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Mutability> for bool {
|
||||
fn from(val: Mutability) -> Self {
|
||||
match val {
|
||||
Mutability::Const => false,
|
||||
fn from(value: Mutability) -> Self {
|
||||
match value {
|
||||
Mutability::Var => true,
|
||||
Mutability::Const => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -550,7 +552,7 @@ impl<T> ExportType<T> {
|
||||
/// Creates a new export which is exported with the given `name` and has the
|
||||
/// given `ty`.
|
||||
pub fn new(name: &str, ty: T) -> Self {
|
||||
ExportType {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
ty,
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ impl<T> Value<T> {
|
||||
/// `p` must be:
|
||||
/// - Properly aligned to the specified `ty`'s Rust equivalent
|
||||
/// - Non-null and pointing to valid memory
|
||||
pub unsafe fn read_value_from(p: *const i128, ty: Type) -> Value<T> {
|
||||
pub unsafe fn read_value_from(p: *const i128, ty: Type) -> Self {
|
||||
match ty {
|
||||
Type::I32 => Self::I32(ptr::read(p as *const i32)),
|
||||
Type::I64 => Self::I64(ptr::read(p as *const i64)),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# A script to update the version of all the crates at the same time
|
||||
PREVIOUS_VERSION='0.16.2'
|
||||
NEXT_VERSION='0.17.0'
|
||||
PREVIOUS_VERSION='1.0.0-alpha.1'
|
||||
NEXT_VERSION='1.0.0-alpha.2'
|
||||
|
||||
# quick hack
|
||||
fd Cargo.toml --exec sed -i '' "s/version = \"$PREVIOUS_VERSION\"/version = \"$NEXT_VERSION\"/"
|
||||
|
||||
@@ -26,7 +26,14 @@ impl Inspect {
|
||||
let (store, _engine_type, _compiler_type) = self.store.get_store()?;
|
||||
let module_contents = std::fs::read(&self.path)?;
|
||||
let module = Module::new(&store, &module_contents)?;
|
||||
println!("Type: {}", if module.from_wat { "wat" } else { "wasm" });
|
||||
println!(
|
||||
"Type: {}",
|
||||
if !is_wasm(&module_contents) {
|
||||
"wat"
|
||||
} else {
|
||||
"wasm"
|
||||
}
|
||||
);
|
||||
println!("Size: {}", ByteSize(module_contents.len() as _));
|
||||
println!("Imports:");
|
||||
println!(" Functions:");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::common::get_cache_dir;
|
||||
use crate::store::StoreOptions;
|
||||
use crate::store::{CompilerType, EngineType, StoreOptions};
|
||||
use crate::suggestions::suggest_function_exports;
|
||||
use crate::warning;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
@@ -68,23 +68,27 @@ pub struct Run {
|
||||
}
|
||||
|
||||
impl Run {
|
||||
#[cfg(feature = "cache")]
|
||||
/// Get the Compiler Filesystem cache
|
||||
fn get_cache(&self, engine_name: String, compiler_name: String) -> Result<FileSystemCache> {
|
||||
let mut cache_dir_root = get_cache_dir();
|
||||
cache_dir_root.push(engine_name);
|
||||
cache_dir_root.push(compiler_name);
|
||||
Ok(FileSystemCache::new(cache_dir_root)?)
|
||||
}
|
||||
/// Execute the run command
|
||||
pub fn execute(&self) -> Result<()> {
|
||||
self.inner_execute()
|
||||
.context(format!("failed to run `{}`", self.path.display()))
|
||||
self.inner_execute().with_context(|| {
|
||||
let compilers = CompilerType::enabled()
|
||||
.iter()
|
||||
.map(|c| c.to_string())
|
||||
.collect::<Vec<String>>();
|
||||
format!(
|
||||
"failed to run `{}`{}",
|
||||
self.path.display(),
|
||||
if compilers.len() > 0 {
|
||||
""
|
||||
} else {
|
||||
" (no compilers enabled)"
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn inner_execute(&self) -> Result<()> {
|
||||
let module = self
|
||||
.get_module()
|
||||
.with_context(|| "module instantiation failed")?;
|
||||
let module = self.get_module()?;
|
||||
// Do we want to invoke a function?
|
||||
if let Some(ref invoke) = self.invoke {
|
||||
let imports = imports! {};
|
||||
@@ -105,7 +109,7 @@ impl Run {
|
||||
#[cfg(feature = "wasi")]
|
||||
{
|
||||
let wasi_version = Wasi::get_version(&module);
|
||||
if let Some(version) = wasi_version {
|
||||
if wasi_version.is_some() {
|
||||
let program_name = self
|
||||
.command_name
|
||||
.clone()
|
||||
@@ -117,7 +121,7 @@ impl Run {
|
||||
.unwrap_or_default();
|
||||
return self
|
||||
.wasi
|
||||
.execute(module, version, program_name, self.args.clone())
|
||||
.execute(module, program_name, self.args.clone())
|
||||
.with_context(|| "WASI execution failed");
|
||||
}
|
||||
}
|
||||
@@ -154,14 +158,41 @@ impl Run {
|
||||
}
|
||||
}
|
||||
let (store, engine_type, compiler_type) = self.store.get_store()?;
|
||||
#[cfg(feature = "cache")]
|
||||
let module_result: Result<Module> = if !self.disable_cache && contents.len() > 0x1000 {
|
||||
self.get_module_from_cache(&store, &contents, &engine_type, &compiler_type)
|
||||
} else {
|
||||
Module::new(&store, &contents).map_err(|e| e.into())
|
||||
};
|
||||
#[cfg(not(feature = "cache"))]
|
||||
let module_result = Module::new(&store, &contents);
|
||||
|
||||
let mut module = module_result.with_context(|| {
|
||||
format!(
|
||||
"module instantiation failed (engine: {}, compiler: {})",
|
||||
engine_type.to_string(),
|
||||
compiler_type.to_string()
|
||||
)
|
||||
})?;
|
||||
// We set the name outside the cache, to make sure we dont cache the name
|
||||
module.set_name(&self.path.file_name().unwrap_or_default().to_string_lossy());
|
||||
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
#[cfg(feature = "cache")]
|
||||
fn get_module_from_cache(
|
||||
&self,
|
||||
store: &Store,
|
||||
contents: &[u8],
|
||||
engine_type: &EngineType,
|
||||
compiler_type: &CompilerType,
|
||||
) -> Result<Module> {
|
||||
// We try to get it from cache, in case caching is enabled
|
||||
// and the file length is greater than 4KB.
|
||||
// For files smaller than 4KB caching is not worth,
|
||||
// as it takes space and the speedup is minimal.
|
||||
let mut module =
|
||||
if cfg!(feature = "cache") && !self.disable_cache && contents.len() > 0x1000 {
|
||||
let mut cache =
|
||||
self.get_cache(engine_type.to_string(), compiler_type.to_string())?;
|
||||
let mut cache = self.get_cache(engine_type.to_string(), compiler_type.to_string())?;
|
||||
// Try to get the hash from the provided `--cache-key`, otherwise
|
||||
// generate one from the provided file `.wasm` contents.
|
||||
let hash = self
|
||||
@@ -170,7 +201,7 @@ impl Run {
|
||||
.and_then(|key| WasmHash::from_str(&key).ok())
|
||||
.unwrap_or_else(|| WasmHash::generate(&contents));
|
||||
match unsafe { cache.load(&store, hash) } {
|
||||
Ok(module) => module,
|
||||
Ok(module) => Ok(module),
|
||||
Err(e) => {
|
||||
match e {
|
||||
DeserializeError::Io(_) => {
|
||||
@@ -182,18 +213,20 @@ impl Run {
|
||||
}
|
||||
let module = Module::new(&store, &contents)?;
|
||||
// Store the compiled Module in cache
|
||||
cache.store(hash, module.clone())?;
|
||||
module
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Module::new(&store, &contents)?
|
||||
};
|
||||
// We set the name outside the cache, to make sure we dont cache the name
|
||||
module.set_name(&self.path.file_name().unwrap_or_default().to_string_lossy());
|
||||
|
||||
cache.store(hash, &module)?;
|
||||
Ok(module)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "cache")]
|
||||
/// Get the Compiler Filesystem cache
|
||||
fn get_cache(&self, engine_name: String, compiler_name: String) -> Result<FileSystemCache> {
|
||||
let mut cache_dir_root = get_cache_dir();
|
||||
cache_dir_root.push(engine_name);
|
||||
cache_dir_root.push(compiler_name);
|
||||
Ok(FileSystemCache::new(cache_dir_root)?)
|
||||
}
|
||||
|
||||
fn try_find_function(
|
||||
&self,
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use crate::utils::{parse_envvar, parse_mapdir};
|
||||
use anyhow::{Context, Result};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use wasmer::{Function, Instance, Memory, Module};
|
||||
use wasmer_wasi::{
|
||||
generate_import_object_from_env, get_wasi_version, WasiEnv, WasiState, WasiVersion,
|
||||
};
|
||||
use wasmer::{Instance, Module};
|
||||
use wasmer_wasi::{get_wasi_version, WasiState, WasiVersion};
|
||||
|
||||
use structopt::StructOpt;
|
||||
|
||||
@@ -12,16 +10,16 @@ use structopt::StructOpt;
|
||||
/// WASI Options
|
||||
pub struct Wasi {
|
||||
/// WASI pre-opened directory
|
||||
#[structopt(long = "dir", multiple = true, group = "wasi")]
|
||||
#[structopt(long = "dir", name = "DIR", multiple = true, group = "wasi")]
|
||||
pre_opened_directories: Vec<PathBuf>,
|
||||
|
||||
/// Map a host directory to a different location for the wasm module
|
||||
#[structopt(long = "mapdir", multiple = true)]
|
||||
mapped_dirs: Vec<String>,
|
||||
#[structopt(long = "mapdir", name = "GUEST_DIR:HOST_DIR", multiple = true, parse(try_from_str = parse_mapdir))]
|
||||
mapped_dirs: Vec<(String, PathBuf)>,
|
||||
|
||||
/// Pass custom environment variables
|
||||
#[structopt(long = "env", multiple = true)]
|
||||
env_vars: Vec<String>,
|
||||
#[structopt(long = "env", name = "KEY=VALUE", multiple = true, parse(try_from_str = parse_envvar))]
|
||||
env_vars: Vec<(String, String)>,
|
||||
|
||||
/// Enable experimental IO devices
|
||||
#[cfg(feature = "experimental-io-devices")]
|
||||
@@ -30,44 +28,6 @@ pub struct Wasi {
|
||||
}
|
||||
|
||||
impl Wasi {
|
||||
fn get_mapped_dirs(&self) -> Result<Vec<(String, PathBuf)>> {
|
||||
let mut md = vec![];
|
||||
for entry in self.mapped_dirs.iter() {
|
||||
if let [alias, real_dir] = entry.split(':').collect::<Vec<&str>>()[..] {
|
||||
let pb = PathBuf::from(&real_dir);
|
||||
if let Ok(pb_metadata) = pb.metadata() {
|
||||
if !pb_metadata.is_dir() {
|
||||
bail!("\"{}\" exists, but it is not a directory", &real_dir);
|
||||
}
|
||||
} else {
|
||||
bail!("Directory \"{}\" does not exist", &real_dir);
|
||||
}
|
||||
md.push((alias.to_string(), pb));
|
||||
continue;
|
||||
}
|
||||
bail!(
|
||||
"Directory mappings must consist of two paths separate by a colon. Found {}",
|
||||
&entry
|
||||
);
|
||||
}
|
||||
Ok(md)
|
||||
}
|
||||
|
||||
fn get_env_vars(&self) -> Result<Vec<(&str, &str)>> {
|
||||
let mut env = vec![];
|
||||
for entry in self.env_vars.iter() {
|
||||
if let [env_var, value] = entry.split('=').collect::<Vec<&str>>()[..] {
|
||||
env.push((env_var, value));
|
||||
} else {
|
||||
bail!(
|
||||
"Env vars must be of the form <var_name>=<value>. Found {}",
|
||||
&entry
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(env)
|
||||
}
|
||||
|
||||
/// Gets the WASI version (if any) for the provided module
|
||||
pub fn get_version(module: &Module) -> Option<WasiVersion> {
|
||||
// Get the wasi version on strict mode, so no other imports are
|
||||
@@ -76,25 +36,15 @@ impl Wasi {
|
||||
}
|
||||
|
||||
/// Helper function for executing Wasi from the `Run` command.
|
||||
pub fn execute(
|
||||
&self,
|
||||
module: Module,
|
||||
wasi_version: WasiVersion,
|
||||
program_name: String,
|
||||
args: Vec<String>,
|
||||
) -> Result<()> {
|
||||
let mut wasi_state_builder = WasiState::new(&program_name);
|
||||
|
||||
pub fn execute(&self, module: Module, program_name: String, args: Vec<String>) -> Result<()> {
|
||||
let args = args.iter().cloned().map(|arg| arg.into_bytes());
|
||||
let env_vars = self.get_env_vars()?;
|
||||
let preopened_files = self.pre_opened_directories.clone();
|
||||
let mapped_dirs = self.get_mapped_dirs()?;
|
||||
|
||||
let mut wasi_state_builder = WasiState::new(program_name);
|
||||
wasi_state_builder
|
||||
.args(args)
|
||||
.envs(env_vars)
|
||||
.preopen_dirs(preopened_files)?
|
||||
.map_dirs(mapped_dirs)?;
|
||||
.envs(self.env_vars.clone())
|
||||
.preopen_dirs(self.pre_opened_directories.clone())?
|
||||
.map_dirs(self.mapped_dirs.clone())?;
|
||||
|
||||
#[cfg(feature = "experimental-io-devices")]
|
||||
{
|
||||
@@ -104,18 +54,13 @@ impl Wasi {
|
||||
}
|
||||
}
|
||||
|
||||
let wasi_state = wasi_state_builder.build()?;
|
||||
let mut wasi_env = WasiEnv::new(wasi_state);
|
||||
let import_object =
|
||||
generate_import_object_from_env(module.store(), &mut wasi_env, wasi_version);
|
||||
|
||||
let mut wasi_env = wasi_state_builder.finalize()?;
|
||||
let import_object = wasi_env.import_object(&module)?;
|
||||
let instance = Instance::new(&module, &import_object)?;
|
||||
|
||||
let memory: &Memory = instance.exports.get("memory")?;
|
||||
wasi_env.set_memory(memory);
|
||||
|
||||
let start: &Function = instance.exports.get("_start")?;
|
||||
wasi_env.set_memory(instance.exports.get_memory("memory")?);
|
||||
|
||||
let start = instance.exports.get_function("_start")?;
|
||||
start
|
||||
.call(&[])
|
||||
.with_context(|| "failed to run WASI `_start` function")?;
|
||||
|
||||
25
src/store.rs
25
src/store.rs
@@ -9,6 +9,7 @@ use std::string::ToString;
|
||||
use std::sync::Arc;
|
||||
use structopt::StructOpt;
|
||||
use wasmer::*;
|
||||
#[cfg(feature = "compiler")]
|
||||
use wasmer_compiler::CompilerConfig;
|
||||
|
||||
#[derive(Debug, Clone, StructOpt)]
|
||||
@@ -61,6 +62,20 @@ pub enum CompilerType {
|
||||
Headless,
|
||||
}
|
||||
|
||||
impl CompilerType {
|
||||
/// Return all enabled compilers
|
||||
pub fn enabled() -> Vec<CompilerType> {
|
||||
vec![
|
||||
#[cfg(feature = "singlepass")]
|
||||
Self::Singlepass,
|
||||
#[cfg(feature = "cranelift")]
|
||||
Self::Cranelift,
|
||||
#[cfg(feature = "llvm")]
|
||||
Self::LLVM,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for CompilerType {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
@@ -104,13 +119,13 @@ impl StoreOptions {
|
||||
// Auto mode, we choose the best compiler for that platform
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(feature = "cranelift", target_arch = "x86_64"))] {
|
||||
return Ok(CompilerType::Cranelift);
|
||||
Ok(CompilerType::Cranelift)
|
||||
}
|
||||
else if #[cfg(all(feature = "singlepass", target_arch = "x86_64"))] {
|
||||
return Ok(CompilerType::Singlepass);
|
||||
Ok(CompilerType::Singlepass)
|
||||
}
|
||||
else if #[cfg(feature = "llvm")] {
|
||||
return Ok(CompilerType::LLVM);
|
||||
Ok(CompilerType::LLVM)
|
||||
} else {
|
||||
bail!("There are no available compilers for your architecture");
|
||||
}
|
||||
@@ -303,7 +318,7 @@ impl StoreOptions {
|
||||
engine.to_string()
|
||||
),
|
||||
};
|
||||
return Ok((engine, engine_type));
|
||||
Ok((engine, engine_type))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,7 +378,7 @@ impl StoreOptions {
|
||||
engine.to_string()
|
||||
),
|
||||
};
|
||||
return Ok((engine, engine_type));
|
||||
Ok((engine, engine_type))
|
||||
}
|
||||
|
||||
/// Get the store (headless engine)
|
||||
|
||||
33
src/utils.rs
33
src/utils.rs
@@ -1,5 +1,7 @@
|
||||
//! Utility functions for the WebAssembly module
|
||||
use anyhow::{bail, Result};
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Whether or not Wasmer should print with color
|
||||
pub fn wasmer_should_print_color() -> bool {
|
||||
@@ -8,3 +10,34 @@ pub fn wasmer_should_print_color() -> bool {
|
||||
.and_then(|inner| inner.parse::<bool>().ok())
|
||||
.unwrap_or_else(|| atty::is(atty::Stream::Stdout))
|
||||
}
|
||||
|
||||
/// Parses a mapdir from a string
|
||||
pub fn parse_mapdir(entry: &str) -> Result<(String, PathBuf)> {
|
||||
if let [alias, real_dir] = entry.split(':').collect::<Vec<&str>>()[..] {
|
||||
let pb = PathBuf::from(&real_dir);
|
||||
if let Ok(pb_metadata) = pb.metadata() {
|
||||
if !pb_metadata.is_dir() {
|
||||
bail!("\"{}\" exists, but it is not a directory", &real_dir);
|
||||
}
|
||||
} else {
|
||||
bail!("Directory \"{}\" does not exist", &real_dir);
|
||||
}
|
||||
return Ok((alias.to_string(), pb));
|
||||
}
|
||||
bail!(
|
||||
"Directory mappings must consist of two paths separate by a colon. Found {}",
|
||||
&entry
|
||||
)
|
||||
}
|
||||
|
||||
/// Parses a mapdir from an env var
|
||||
pub fn parse_envvar(entry: &str) -> Result<(String, String)> {
|
||||
if let [env_var, value] = entry.split('=').collect::<Vec<&str>>()[..] {
|
||||
return Ok((env_var.to_string(), value.to_string()));
|
||||
} else {
|
||||
bail!(
|
||||
"Env vars must be of the form <var_name>=<value>. Found {}",
|
||||
&entry
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[Setup]
|
||||
AppName=Wasmer
|
||||
AppVersion=0.16.2
|
||||
AppVersion=1.0.0-alpha.1
|
||||
DefaultDirName={pf}\Wasmer
|
||||
DefaultGroupName=Wasmer
|
||||
Compression=lzma2
|
||||
|
||||
41
tests/compilers/functions.rs
Normal file
41
tests/compilers/functions.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use crate::utils::get_store;
|
||||
use anyhow::Result;
|
||||
|
||||
use wasmer::*;
|
||||
|
||||
#[test]
|
||||
fn native_function_works_for_wasm() -> Result<()> {
|
||||
let store = get_store();
|
||||
let wat = r#"(module
|
||||
(func $multiply (import "env" "multiply") (param i32 i32) (result i32))
|
||||
(func (export "add") (param i32 i32) (result i32)
|
||||
(i32.add (local.get 0)
|
||||
(local.get 1)))
|
||||
(func (export "double_then_add") (param i32 i32) (result i32)
|
||||
(i32.add (call $multiply (local.get 0) (i32.const 2))
|
||||
(call $multiply (local.get 1) (i32.const 2))))
|
||||
)"#;
|
||||
let module = Module::new(&store, wat).unwrap();
|
||||
|
||||
let import_object = imports! {
|
||||
"env" => {
|
||||
"multiply" => Function::new(&store, |a: i32, b: i32| a * b),
|
||||
},
|
||||
};
|
||||
|
||||
let instance = Instance::new(&module, &import_object)?;
|
||||
|
||||
let f: NativeFunc<(i32, i32), i32> = instance.exports.get_native_function("add")?;
|
||||
let result = f.call(4, 6)?;
|
||||
assert_eq!(result, 10);
|
||||
|
||||
let dyn_f: &Function = instance.exports.get("double_then_add")?;
|
||||
let dyn_result = dyn_f.call(&[Val::I32(4), Val::I32(6)])?;
|
||||
assert_eq!(dyn_result[0], Val::I32(20));
|
||||
|
||||
let f: NativeFunc<(i32, i32), i32> = dyn_f.native().unwrap();
|
||||
|
||||
let result = f.call(4, 6)?;
|
||||
assert_eq!(result, 20);
|
||||
Ok(())
|
||||
}
|
||||
@@ -2,10 +2,10 @@
|
||||
//! This tests checks that the provided functions (both native and
|
||||
//! dynamic ones) work properly.
|
||||
|
||||
wasmer_compilers! {
|
||||
use wasmer::*;
|
||||
use crate::utils::get_store;
|
||||
use anyhow::Result;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
||||
use wasmer::*;
|
||||
|
||||
fn get_module(store: &Store) -> Result<Module> {
|
||||
let wat = r#"
|
||||
@@ -77,7 +77,6 @@ wasmer_compilers! {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn dynamic_function_with_env() -> Result<()> {
|
||||
let store = get_store();
|
||||
@@ -194,4 +193,3 @@ wasmer_compilers! {
|
||||
assert_eq!(env.load(SeqCst), 4);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
#[macro_export]
|
||||
macro_rules! wasmer_compilers {
|
||||
{ $($code:item)* } => {
|
||||
#[cfg(feature = "singlepass")]
|
||||
#[cfg(test)]
|
||||
mod singlepass {
|
||||
use std::sync::Arc;
|
||||
use wasmer::{Features, Store, Tunables};
|
||||
use wasmer_engine_jit::JITEngine;
|
||||
use test_utils::get_compiler_config_from_str;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn get_store() -> Store {
|
||||
let features = Features::default();
|
||||
let try_nan_canonicalization = false;
|
||||
let compiler_config =
|
||||
get_compiler_config_from_str("singlepass", try_nan_canonicalization, features);
|
||||
let tunables = Tunables::for_target(compiler_config.target().triple());
|
||||
let store = Store::new(Arc::new(JITEngine::new(compiler_config, tunables)));
|
||||
store
|
||||
}
|
||||
$($code)*
|
||||
}
|
||||
|
||||
#[cfg(feature = "cranelift")]
|
||||
#[cfg(test)]
|
||||
mod cranelift {
|
||||
use std::sync::Arc;
|
||||
use wasmer::{Features, Store, Tunables};
|
||||
use wasmer_engine_jit::JITEngine;
|
||||
use test_utils::get_compiler_config_from_str;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn get_store() -> Store {
|
||||
let features = Features::default();
|
||||
let try_nan_canonicalization = false;
|
||||
let compiler_config =
|
||||
get_compiler_config_from_str("cranelift", try_nan_canonicalization, features);
|
||||
let tunables = Tunables::for_target(compiler_config.target().triple());
|
||||
let store = Store::new(Arc::new(JITEngine::new(compiler_config, tunables)));
|
||||
store
|
||||
}
|
||||
$($code)*
|
||||
}
|
||||
#[cfg(feature = "llvm")]
|
||||
#[cfg(test)]
|
||||
mod llvm {
|
||||
use std::sync::Arc;
|
||||
use wasmer::{Features, Store, Tunables};
|
||||
use wasmer_engine_jit::JITEngine;
|
||||
use test_utils::get_compiler_config_from_str;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn get_store() -> Store {
|
||||
let features = Features::default();
|
||||
let try_nan_canonicalization = false;
|
||||
let compiler_config =
|
||||
get_compiler_config_from_str("llvm", try_nan_canonicalization, features);
|
||||
let tunables = Tunables::for_target(compiler_config.target().triple());
|
||||
let store = Store::new(Arc::new(JITEngine::new(compiler_config, tunables)));
|
||||
store
|
||||
}
|
||||
$($code)*
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
#![cfg(feature = "compiler")]
|
||||
|
||||
//! This test suite does all the tests that involve any compiler
|
||||
//! implementation, such as: singlepass, cranelift or llvm depending
|
||||
//! on what's available on the target.
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
mod functions;
|
||||
mod imports;
|
||||
mod wast;
|
||||
mod multi_value_imports;
|
||||
mod serialize;
|
||||
mod traps;
|
||||
mod utils;
|
||||
|
||||
207
tests/compilers/multi_value_imports.rs
Normal file
207
tests/compilers/multi_value_imports.rs
Normal file
@@ -0,0 +1,207 @@
|
||||
//! Testing the imports with different provided functions.
|
||||
//! This tests checks that the provided functions (both native and
|
||||
//! dynamic ones) work properly.
|
||||
|
||||
use crate::utils::get_store;
|
||||
use wasmer::*;
|
||||
|
||||
macro_rules! mvr_test {
|
||||
($test_name:ident, $( $result_type:ty ),* ) => {
|
||||
mod $test_name {
|
||||
use super::*;
|
||||
|
||||
fn get_module(store: &Store) -> anyhow::Result<wasmer::Module> {
|
||||
let wat: String = r#"
|
||||
(type $type (func (param i32) (result
|
||||
"#.to_string() +
|
||||
&stringify!( $( $result_type ),* ).replace(",", "").replace("(", "").replace(")", "") + &r#")))
|
||||
(import "host" "callback_fn" (func $callback_fn (type $type)))
|
||||
(func (export "test_call") (type $type)
|
||||
get_local 0
|
||||
call $callback_fn)
|
||||
(func (export "test_call_indirect") (type $type)
|
||||
(i32.const 1)
|
||||
(call_indirect (type $type) (i32.const 0))
|
||||
)
|
||||
(table funcref
|
||||
(elem
|
||||
$callback_fn
|
||||
)
|
||||
)
|
||||
"#.to_string();
|
||||
Ok(wasmer::Module::new(&store, &wat)?)
|
||||
}
|
||||
|
||||
fn callback_fn(n: i32) -> ( $( $result_type ),* ) {
|
||||
( $( <$result_type>::expected_value(n) ),* )
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(any(feature = "test-cranelift", feature="test-singlepass"), ignore)]
|
||||
fn native() -> anyhow::Result<()> {
|
||||
let store = get_store();
|
||||
let module = get_module(&store)?;
|
||||
let instance = wasmer::Instance::new(
|
||||
&module,
|
||||
&wasmer::imports! {
|
||||
"host" => {
|
||||
"callback_fn" => wasmer::Function::new(&store, callback_fn)
|
||||
}
|
||||
}
|
||||
)?;
|
||||
let expected_value = vec![ $( <$result_type>::expected_val(1) ),* ].into_boxed_slice();
|
||||
assert_eq!(instance.exports.get_function("test_call")?.call(&[wasmer::Val::I32(1)])?,
|
||||
expected_value);
|
||||
assert_eq!(instance.exports.get_function("test_call_indirect")?.call(&[wasmer::Val::I32(1)])?,
|
||||
expected_value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn dynamic_callback_fn(values: &[wasmer::Value]) -> Result<Vec<wasmer::Val>, wasmer::RuntimeError> {
|
||||
assert_eq!(values[0], wasmer::Value::I32(1));
|
||||
Ok(vec![ $( <$result_type>::expected_val(1) ),* ])
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(feature="test-singlepass", ignore)]
|
||||
fn dynamic() -> anyhow::Result<()> {
|
||||
let store = get_store();
|
||||
let module = get_module(&store)?;
|
||||
let instance = wasmer::Instance::new(
|
||||
&module,
|
||||
&wasmer::imports! {
|
||||
"host" => {
|
||||
"callback_fn" => wasmer::Function::new_dynamic(&store, &wasmer::FunctionType::new(vec![wasmer::ValType::I32], vec![ $( <$result_type>::expected_valtype() ),* ]), dynamic_callback_fn)
|
||||
}
|
||||
}
|
||||
)?;
|
||||
let expected_value = vec![ $( <$result_type>::expected_val(1) ),* ].into_boxed_slice();
|
||||
assert_eq!(instance.exports.get_function("test_call")?.call(&[wasmer::Val::I32(1)])?,
|
||||
expected_value);
|
||||
assert_eq!(instance.exports.get_function("test_call_indirect")?.call(&[wasmer::Val::I32(1)])?,
|
||||
expected_value);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait ExpectedExpr {
|
||||
fn expected_value(n: i32) -> Self;
|
||||
fn expected_val(n: i32) -> wasmer::Val;
|
||||
fn expected_valtype() -> wasmer::ValType;
|
||||
}
|
||||
impl ExpectedExpr for i32 {
|
||||
fn expected_value(n: i32) -> i32 {
|
||||
n + 1
|
||||
}
|
||||
fn expected_val(n: i32) -> wasmer::Val {
|
||||
wasmer::Val::I32(Self::expected_value(n))
|
||||
}
|
||||
fn expected_valtype() -> wasmer::ValType {
|
||||
wasmer::ValType::I32
|
||||
}
|
||||
}
|
||||
impl ExpectedExpr for i64 {
|
||||
fn expected_value(n: i32) -> i64 {
|
||||
n as i64 + 2i64
|
||||
}
|
||||
fn expected_val(n: i32) -> wasmer::Val {
|
||||
wasmer::Val::I64(Self::expected_value(n))
|
||||
}
|
||||
fn expected_valtype() -> wasmer::ValType {
|
||||
wasmer::ValType::I64
|
||||
}
|
||||
}
|
||||
impl ExpectedExpr for f32 {
|
||||
fn expected_value(n: i32) -> f32 {
|
||||
n as f32 * 0.1
|
||||
}
|
||||
fn expected_val(n: i32) -> wasmer::Val {
|
||||
wasmer::Val::F32(Self::expected_value(n))
|
||||
}
|
||||
fn expected_valtype() -> wasmer::ValType {
|
||||
wasmer::ValType::F32
|
||||
}
|
||||
}
|
||||
impl ExpectedExpr for f64 {
|
||||
fn expected_value(n: i32) -> f64 {
|
||||
n as f64 * 0.12
|
||||
}
|
||||
fn expected_val(n: i32) -> wasmer::Val {
|
||||
wasmer::Val::F64(Self::expected_value(n))
|
||||
}
|
||||
fn expected_valtype() -> wasmer::ValType {
|
||||
wasmer::ValType::F64
|
||||
}
|
||||
}
|
||||
|
||||
mvr_test!(test_mvr_i32_i32, i32, i32);
|
||||
mvr_test!(test_mvr_i32_f32, i32, f32);
|
||||
mvr_test!(test_mvr_f32_i32, f32, i32);
|
||||
mvr_test!(test_mvr_f32_f32, f32, f32);
|
||||
|
||||
mvr_test!(test_mvr_i64_i32, i64, i32);
|
||||
mvr_test!(test_mvr_i64_f32, i64, f32);
|
||||
mvr_test!(test_mvr_f64_i32, f64, i32);
|
||||
mvr_test!(test_mvr_f64_f32, f64, f32);
|
||||
|
||||
mvr_test!(test_mvr_i32_i64, i32, i64);
|
||||
mvr_test!(test_mvr_f32_i64, f32, i64);
|
||||
mvr_test!(test_mvr_i32_f64, i32, f64);
|
||||
mvr_test!(test_mvr_f32_f64, f32, f64);
|
||||
|
||||
mvr_test!(test_mvr_i32_i32_i32, i32, i32, i32);
|
||||
mvr_test!(test_mvr_i32_i32_f32, i32, i32, f32);
|
||||
mvr_test!(test_mvr_i32_f32_i32, i32, f32, i32);
|
||||
mvr_test!(test_mvr_i32_f32_f32, i32, f32, f32);
|
||||
mvr_test!(test_mvr_f32_i32_i32, f32, i32, i32);
|
||||
mvr_test!(test_mvr_f32_i32_f32, f32, i32, f32);
|
||||
mvr_test!(test_mvr_f32_f32_i32, f32, f32, i32);
|
||||
mvr_test!(test_mvr_f32_f32_f32, f32, f32, f32);
|
||||
|
||||
mvr_test!(test_mvr_i32_i32_i64, i32, i32, i64);
|
||||
mvr_test!(test_mvr_i32_f32_i64, i32, f32, i64);
|
||||
mvr_test!(test_mvr_f32_i32_i64, f32, i32, i64);
|
||||
mvr_test!(test_mvr_f32_f32_i64, f32, f32, i64);
|
||||
mvr_test!(test_mvr_i32_i32_f64, i32, i32, f64);
|
||||
mvr_test!(test_mvr_i32_f32_f64, i32, f32, f64);
|
||||
mvr_test!(test_mvr_f32_i32_f64, f32, i32, f64);
|
||||
mvr_test!(test_mvr_f32_f32_f64, f32, f32, f64);
|
||||
|
||||
mvr_test!(test_mvr_i32_i64_i32, i32, i64, i32);
|
||||
mvr_test!(test_mvr_i32_i64_f32, i32, i64, f32);
|
||||
mvr_test!(test_mvr_f32_i64_i32, f32, i64, i32);
|
||||
mvr_test!(test_mvr_f32_i64_f32, f32, i64, f32);
|
||||
mvr_test!(test_mvr_i32_f64_i32, i32, f64, i32);
|
||||
mvr_test!(test_mvr_i32_f64_f32, i32, f64, f32);
|
||||
mvr_test!(test_mvr_f32_f64_i32, f32, f64, i32);
|
||||
mvr_test!(test_mvr_f32_f64_f32, f32, f64, f32);
|
||||
|
||||
mvr_test!(test_mvr_i64_i32_i32, i64, i32, i32);
|
||||
mvr_test!(test_mvr_i64_i32_f32, i64, i32, f32);
|
||||
mvr_test!(test_mvr_i64_f32_i32, i64, f32, i32);
|
||||
mvr_test!(test_mvr_i64_f32_f32, i64, f32, f32);
|
||||
mvr_test!(test_mvr_f64_i32_i32, f64, i32, i32);
|
||||
mvr_test!(test_mvr_f64_i32_f32, f64, i32, f32);
|
||||
mvr_test!(test_mvr_f64_f32_i32, f64, f32, i32);
|
||||
mvr_test!(test_mvr_f64_f32_f32, f64, f32, f32);
|
||||
|
||||
mvr_test!(test_mvr_i32_i32_i32_i32, i32, i32, i32, i32);
|
||||
mvr_test!(test_mvr_i32_i32_i32_f32, i32, i32, i32, f32);
|
||||
mvr_test!(test_mvr_i32_i32_f32_i32, i32, i32, f32, i32);
|
||||
mvr_test!(test_mvr_i32_i32_f32_f32, i32, i32, f32, f32);
|
||||
mvr_test!(test_mvr_i32_f32_i32_i32, i32, f32, i32, i32);
|
||||
mvr_test!(test_mvr_i32_f32_i32_f32, i32, f32, i32, f32);
|
||||
mvr_test!(test_mvr_i32_f32_f32_i32, i32, f32, f32, i32);
|
||||
mvr_test!(test_mvr_i32_f32_f32_f32, i32, f32, f32, f32);
|
||||
mvr_test!(test_mvr_f32_i32_i32_i32, f32, i32, i32, i32);
|
||||
mvr_test!(test_mvr_f32_i32_i32_f32, f32, i32, i32, f32);
|
||||
mvr_test!(test_mvr_f32_i32_f32_i32, f32, i32, f32, i32);
|
||||
mvr_test!(test_mvr_f32_i32_f32_f32, f32, i32, f32, f32);
|
||||
mvr_test!(test_mvr_f32_f32_i32_i32, f32, f32, i32, i32);
|
||||
mvr_test!(test_mvr_f32_f32_i32_f32, f32, f32, i32, f32);
|
||||
mvr_test!(test_mvr_f32_f32_f32_i32, f32, f32, f32, i32);
|
||||
mvr_test!(test_mvr_f32_f32_f32_f32, f32, f32, f32, f32);
|
||||
|
||||
mvr_test!(test_mvr_i32_i32_i32_i32_i32, i32, i32, i32, i32, i32);
|
||||
77
tests/compilers/serialize.rs
Normal file
77
tests/compilers/serialize.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
use crate::utils::{get_headless_store, get_store};
|
||||
use anyhow::Result;
|
||||
use wasmer::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialize() -> Result<()> {
|
||||
let store = get_store();
|
||||
let wat = r#"
|
||||
(module
|
||||
(func $hello (import "" "hello"))
|
||||
(func (export "run") (call $hello))
|
||||
)
|
||||
"#;
|
||||
|
||||
let module = Module::new(&store, wat)?;
|
||||
let serialized_bytes = module.serialize()?;
|
||||
assert!(!serialized_bytes.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize() -> Result<()> {
|
||||
let store = get_store();
|
||||
let wat = r#"
|
||||
(module $name
|
||||
(import "host" "sum_part" (func (param i32 i64 i32 f32 f64) (result i64)))
|
||||
(func (export "test_call") (result i64)
|
||||
i32.const 100
|
||||
i64.const 200
|
||||
i32.const 300
|
||||
f32.const 400
|
||||
f64.const 500
|
||||
call 0
|
||||
)
|
||||
)
|
||||
"#;
|
||||
|
||||
let module = Module::new(&store, wat)?;
|
||||
let serialized_bytes = module.serialize()?;
|
||||
|
||||
let headless_store = get_headless_store();
|
||||
let deserialized_module = unsafe { Module::deserialize(&headless_store, &serialized_bytes)? };
|
||||
assert_eq!(deserialized_module.name(), Some("name"));
|
||||
assert_eq!(
|
||||
deserialized_module.exports().collect::<Vec<_>>(),
|
||||
module.exports().collect::<Vec<_>>()
|
||||
);
|
||||
assert_eq!(
|
||||
deserialized_module.imports().collect::<Vec<_>>(),
|
||||
module.imports().collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
let func_type = FunctionType::new(
|
||||
vec![Type::I32, Type::I64, Type::I32, Type::F32, Type::F64],
|
||||
vec![Type::I64],
|
||||
);
|
||||
let instance = Instance::new(
|
||||
&module,
|
||||
&imports! {
|
||||
"host" => {
|
||||
"sum_part" => Function::new_dynamic(&store, &func_type, |params| {
|
||||
let param_0: i64 = params[0].unwrap_i32() as i64;
|
||||
let param_1: i64 = params[1].unwrap_i64() as i64;
|
||||
let param_2: i64 = params[2].unwrap_i32() as i64;
|
||||
let param_3: i64 = params[3].unwrap_f32() as i64;
|
||||
let param_4: i64 = params[4].unwrap_f64() as i64;
|
||||
Ok(vec![Value::I64(param_0 + param_1 + param_2 + param_3 + param_4)])
|
||||
})
|
||||
}
|
||||
},
|
||||
)?;
|
||||
|
||||
let test_call = instance.exports.get_function("test_call")?;
|
||||
let result = test_call.call(&[])?;
|
||||
assert_eq!(result.to_vec(), vec![Value::I64(1500)]);
|
||||
Ok(())
|
||||
}
|
||||
473
tests/compilers/traps.rs
Normal file
473
tests/compilers/traps.rs
Normal file
@@ -0,0 +1,473 @@
|
||||
use crate::utils::get_store;
|
||||
use anyhow::Result;
|
||||
use std::panic::{self, AssertUnwindSafe};
|
||||
use wasmer::*;
|
||||
|
||||
#[test]
|
||||
fn test_trap_return() -> Result<()> {
|
||||
let store = get_store();
|
||||
let wat = r#"
|
||||
(module
|
||||
(func $hello (import "" "hello"))
|
||||
(func (export "run") (call $hello))
|
||||
)
|
||||
"#;
|
||||
|
||||
let module = Module::new(&store, wat)?;
|
||||
let hello_type = FunctionType::new(vec![], vec![]);
|
||||
let hello_func =
|
||||
Function::new_dynamic(&store, &hello_type, |_| Err(RuntimeError::new("test 123")));
|
||||
|
||||
let instance = Instance::new(
|
||||
&module,
|
||||
&imports! {
|
||||
"" => {
|
||||
"hello" => hello_func
|
||||
}
|
||||
},
|
||||
)?;
|
||||
let run_func = instance
|
||||
.exports
|
||||
.get_function("run")
|
||||
.expect("expected function export");
|
||||
|
||||
let e = run_func.call(&[]).err().expect("error calling function");
|
||||
|
||||
assert_eq!(e.message(), "test 123");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)]
|
||||
fn test_trap_trace() -> Result<()> {
|
||||
let store = get_store();
|
||||
let wat = r#"
|
||||
(module $hello_mod
|
||||
(func (export "run") (call $hello))
|
||||
(func $hello (unreachable))
|
||||
)
|
||||
"#;
|
||||
|
||||
let module = Module::new(&store, wat)?;
|
||||
let instance = Instance::new(&module, &imports! {})?;
|
||||
let run_func = instance
|
||||
.exports
|
||||
.get_function("run")
|
||||
.expect("expected function export");
|
||||
|
||||
let e = run_func.call(&[]).err().expect("error calling function");
|
||||
|
||||
let trace = e.trace();
|
||||
assert_eq!(trace.len(), 2);
|
||||
assert_eq!(trace[0].module_name(), "hello_mod");
|
||||
assert_eq!(trace[0].func_index(), 1);
|
||||
assert_eq!(trace[0].func_name(), Some("hello"));
|
||||
assert_eq!(trace[1].module_name(), "hello_mod");
|
||||
assert_eq!(trace[1].func_index(), 0);
|
||||
assert_eq!(trace[1].func_name(), None);
|
||||
assert!(
|
||||
e.message().contains("unreachable"),
|
||||
"wrong message: {}",
|
||||
e.message()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trap_trace_cb() -> Result<()> {
|
||||
let store = get_store();
|
||||
let wat = r#"
|
||||
(module $hello_mod
|
||||
(import "" "throw" (func $throw))
|
||||
(func (export "run") (call $hello))
|
||||
(func $hello (call $throw))
|
||||
)
|
||||
"#;
|
||||
|
||||
let fn_type = FunctionType::new(vec![], vec![]);
|
||||
let fn_func = Function::new_dynamic(&store, &fn_type, |_| Err(RuntimeError::new("cb throw")));
|
||||
|
||||
let module = Module::new(&store, wat)?;
|
||||
let instance = Instance::new(
|
||||
&module,
|
||||
&imports! {
|
||||
"" => {
|
||||
"throw" => fn_func
|
||||
}
|
||||
},
|
||||
)?;
|
||||
let run_func = instance
|
||||
.exports
|
||||
.get_function("run")
|
||||
.expect("expected function export");
|
||||
|
||||
let e = run_func.call(&[]).err().expect("error calling function");
|
||||
|
||||
let trace = e.trace();
|
||||
println!("Trace {:?}", trace);
|
||||
// TODO: Reenable this (disabled as it was not working with llvm/singlepass)
|
||||
// assert_eq!(trace.len(), 2);
|
||||
// assert_eq!(trace[0].module_name(), "hello_mod");
|
||||
// assert_eq!(trace[0].func_index(), 2);
|
||||
// assert_eq!(trace[1].module_name(), "hello_mod");
|
||||
// assert_eq!(trace[1].func_index(), 1);
|
||||
assert_eq!(e.message(), "cb throw");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)]
|
||||
fn test_trap_stack_overflow() -> Result<()> {
|
||||
let store = get_store();
|
||||
let wat = r#"
|
||||
(module $rec_mod
|
||||
(func $run (export "run") (call $run))
|
||||
)
|
||||
"#;
|
||||
|
||||
let module = Module::new(&store, wat)?;
|
||||
let instance = Instance::new(&module, &imports! {})?;
|
||||
let run_func = instance
|
||||
.exports
|
||||
.get_function("run")
|
||||
.expect("expected function export");
|
||||
|
||||
let e = run_func.call(&[]).err().expect("error calling function");
|
||||
|
||||
let trace = e.trace();
|
||||
assert!(trace.len() >= 32);
|
||||
for i in 0..trace.len() {
|
||||
assert_eq!(trace[i].module_name(), "rec_mod");
|
||||
assert_eq!(trace[i].func_index(), 0);
|
||||
assert_eq!(trace[i].func_name(), Some("run"));
|
||||
}
|
||||
assert!(e.message().contains("call stack exhausted"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)]
|
||||
fn trap_display_pretty() -> Result<()> {
|
||||
let store = get_store();
|
||||
let wat = r#"
|
||||
(module $m
|
||||
(func $die unreachable)
|
||||
(func call $die)
|
||||
(func $foo call 1)
|
||||
(func (export "bar") call $foo)
|
||||
)
|
||||
"#;
|
||||
|
||||
let module = Module::new(&store, wat)?;
|
||||
let instance = Instance::new(&module, &imports! {})?;
|
||||
let run_func = instance
|
||||
.exports
|
||||
.get_function("bar")
|
||||
.expect("expected function export");
|
||||
|
||||
let e = run_func.call(&[]).err().expect("error calling function");
|
||||
assert_eq!(
|
||||
e.to_string(),
|
||||
"\
|
||||
RuntimeError: unreachable
|
||||
at die (m[0]:0x23)
|
||||
at <unnamed> (m[1]:0x27)
|
||||
at foo (m[2]:0x2c)
|
||||
at <unnamed> (m[3]:0x31)"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)]
|
||||
fn trap_display_multi_module() -> Result<()> {
|
||||
let store = get_store();
|
||||
let wat = r#"
|
||||
(module $a
|
||||
(func $die unreachable)
|
||||
(func call $die)
|
||||
(func $foo call 1)
|
||||
(func (export "bar") call $foo)
|
||||
)
|
||||
"#;
|
||||
|
||||
let module = Module::new(&store, wat)?;
|
||||
let instance = Instance::new(&module, &imports! {})?;
|
||||
let bar = instance.exports.get_function("bar")?.clone();
|
||||
|
||||
let wat = r#"
|
||||
(module $b
|
||||
(import "" "" (func $bar))
|
||||
(func $middle call $bar)
|
||||
(func (export "bar2") call $middle)
|
||||
)
|
||||
"#;
|
||||
let module = Module::new(&store, wat)?;
|
||||
let instance = Instance::new(
|
||||
&module,
|
||||
&imports! {
|
||||
"" => {
|
||||
"" => bar
|
||||
}
|
||||
},
|
||||
)?;
|
||||
let bar2 = instance
|
||||
.exports
|
||||
.get_function("bar2")
|
||||
.expect("expected function export");
|
||||
|
||||
let e = bar2.call(&[]).err().expect("error calling function");
|
||||
assert_eq!(
|
||||
e.to_string(),
|
||||
"\
|
||||
RuntimeError: unreachable
|
||||
at die (a[0]:0x23)
|
||||
at <unnamed> (a[1]:0x27)
|
||||
at foo (a[2]:0x2c)
|
||||
at <unnamed> (a[3]:0x31)
|
||||
at middle (b[1]:0x29)
|
||||
at <unnamed> (b[2]:0x2e)"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trap_start_function_import() -> Result<()> {
|
||||
let store = get_store();
|
||||
let binary = r#"
|
||||
(module $a
|
||||
(import "" "" (func $foo))
|
||||
(start $foo)
|
||||
)
|
||||
"#;
|
||||
|
||||
let module = Module::new(&store, &binary)?;
|
||||
let sig = FunctionType::new(vec![], vec![]);
|
||||
let func = Function::new_dynamic(&store, &sig, |_| Err(RuntimeError::new("user trap")));
|
||||
let err = Instance::new(
|
||||
&module,
|
||||
&imports! {
|
||||
"" => {
|
||||
"" => func
|
||||
}
|
||||
},
|
||||
)
|
||||
.err()
|
||||
.unwrap();
|
||||
match err {
|
||||
InstantiationError::Link(_) => panic!("It should be a start error"),
|
||||
InstantiationError::Start(err) => {
|
||||
assert_eq!(err.message(), "user trap");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rust_panic_import() -> Result<()> {
|
||||
let store = get_store();
|
||||
let binary = r#"
|
||||
(module $a
|
||||
(import "" "foo" (func $foo))
|
||||
(import "" "bar" (func $bar))
|
||||
(func (export "foo") call $foo)
|
||||
(func (export "bar") call $bar)
|
||||
)
|
||||
"#;
|
||||
|
||||
let module = Module::new(&store, &binary)?;
|
||||
let sig = FunctionType::new(vec![], vec![]);
|
||||
let func = Function::new_dynamic(&store, &sig, |_| panic!("this is a panic"));
|
||||
let instance = Instance::new(
|
||||
&module,
|
||||
&imports! {
|
||||
"" => {
|
||||
"foo" => func,
|
||||
"bar" => Function::new(&store, || panic!("this is another panic"))
|
||||
}
|
||||
},
|
||||
)?;
|
||||
let func = instance.exports.get_function("foo")?.clone();
|
||||
let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
drop(func.call(&[]));
|
||||
}))
|
||||
.unwrap_err();
|
||||
assert_eq!(err.downcast_ref::<&'static str>(), Some(&"this is a panic"));
|
||||
|
||||
// TODO: Reenable this (disabled as it was not working with llvm/singlepass)
|
||||
// It doesn't work either with cranelift and `--test-threads=1`.
|
||||
// let func = instance.exports.get_function("bar")?.clone();
|
||||
// let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
// drop(func.call(&[]));
|
||||
// }))
|
||||
// .unwrap_err();
|
||||
// assert_eq!(
|
||||
// err.downcast_ref::<&'static str>(),
|
||||
// Some(&"this is another panic")
|
||||
// );
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rust_panic_start_function() -> Result<()> {
|
||||
let store = get_store();
|
||||
let binary = r#"
|
||||
(module $a
|
||||
(import "" "" (func $foo))
|
||||
(start $foo)
|
||||
)
|
||||
"#;
|
||||
|
||||
let module = Module::new(&store, &binary)?;
|
||||
let sig = FunctionType::new(vec![], vec![]);
|
||||
let func = Function::new_dynamic(&store, &sig, |_| panic!("this is a panic"));
|
||||
let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
drop(Instance::new(
|
||||
&module,
|
||||
&imports! {
|
||||
"" => {
|
||||
"" => func
|
||||
}
|
||||
},
|
||||
));
|
||||
}))
|
||||
.unwrap_err();
|
||||
assert_eq!(err.downcast_ref::<&'static str>(), Some(&"this is a panic"));
|
||||
|
||||
let func = Function::new(&store, || panic!("this is another panic"));
|
||||
let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
drop(Instance::new(
|
||||
&module,
|
||||
&imports! {
|
||||
"" => {
|
||||
"" => func
|
||||
}
|
||||
},
|
||||
));
|
||||
}))
|
||||
.unwrap_err();
|
||||
assert_eq!(
|
||||
err.downcast_ref::<&'static str>(),
|
||||
Some(&"this is another panic")
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mismatched_arguments() -> Result<()> {
|
||||
let store = get_store();
|
||||
let binary = r#"
|
||||
(module $a
|
||||
(func (export "foo") (param i32))
|
||||
)
|
||||
"#;
|
||||
|
||||
let module = Module::new(&store, &binary)?;
|
||||
let instance = Instance::new(&module, &imports! {})?;
|
||||
let func: &Function = instance.exports.get("foo")?;
|
||||
assert_eq!(
|
||||
func.call(&[]).unwrap_err().message(),
|
||||
"Parameters of type [] did not match signature [I32] -> []"
|
||||
);
|
||||
assert_eq!(
|
||||
func.call(&[Val::F32(0.0)]).unwrap_err().message(),
|
||||
"Parameters of type [F32] did not match signature [I32] -> []",
|
||||
);
|
||||
assert_eq!(
|
||||
func.call(&[Val::I32(0), Val::I32(1)])
|
||||
.unwrap_err()
|
||||
.message(),
|
||||
"Parameters of type [I32, I32] did not match signature [I32] -> []"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)]
|
||||
fn call_signature_mismatch() -> Result<()> {
|
||||
let store = get_store();
|
||||
let binary = r#"
|
||||
(module $a
|
||||
(func $foo
|
||||
i32.const 0
|
||||
call_indirect)
|
||||
(func $bar (param i32))
|
||||
(start $foo)
|
||||
|
||||
(table 1 anyfunc)
|
||||
(elem (i32.const 0) 1)
|
||||
)
|
||||
"#;
|
||||
|
||||
let module = Module::new(&store, &binary)?;
|
||||
let err = Instance::new(&module, &imports! {})
|
||||
.err()
|
||||
.expect("expected error");
|
||||
assert_eq!(
|
||||
format!("{}", err),
|
||||
"\
|
||||
RuntimeError: indirect call type mismatch
|
||||
at foo (a[0]:0x30)\
|
||||
"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[ignore]
|
||||
#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)]
|
||||
fn start_trap_pretty() -> Result<()> {
|
||||
let store = get_store();
|
||||
let wat = r#"
|
||||
(module $m
|
||||
(func $die unreachable)
|
||||
(func call $die)
|
||||
(func $foo call 1)
|
||||
(func $start call $foo)
|
||||
(start $start)
|
||||
)
|
||||
"#;
|
||||
|
||||
let module = Module::new(&store, wat)?;
|
||||
let err = Instance::new(&module, &imports! {})
|
||||
.err()
|
||||
.expect("expected error");
|
||||
|
||||
assert_eq!(
|
||||
format!("{}", err),
|
||||
"\
|
||||
RuntimeError: unreachable
|
||||
at die (m[0]:0x1d)
|
||||
at <unnamed> (m[1]:0x21)
|
||||
at foo (m[2]:0x26)
|
||||
at start (m[3]:0x2b)\
|
||||
"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn present_after_module_drop() -> Result<()> {
|
||||
let store = get_store();
|
||||
let module = Module::new(&store, r#"(func (export "foo") unreachable)"#)?;
|
||||
let instance = Instance::new(&module, &imports! {})?;
|
||||
let func: Function = instance.exports.get_function("foo")?.clone();
|
||||
|
||||
println!("asserting before we drop modules");
|
||||
assert_trap(func.call(&[]).unwrap_err());
|
||||
drop((instance, module));
|
||||
|
||||
println!("asserting after drop");
|
||||
assert_trap(func.call(&[]).unwrap_err());
|
||||
return Ok(());
|
||||
|
||||
fn assert_trap(t: RuntimeError) {
|
||||
println!("{}", t);
|
||||
// assert_eq!(t.trace().len(), 1);
|
||||
// assert_eq!(t.trace()[0].func_index(), 0);
|
||||
}
|
||||
}
|
||||
39
tests/compilers/utils.rs
Normal file
39
tests/compilers/utils.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
use std::sync::Arc;
|
||||
use test_utils::get_compiler_config_from_str;
|
||||
use wasmer::{Features, Store, Triple, Tunables};
|
||||
use wasmer_engine_jit::JITEngine;
|
||||
|
||||
fn get_compiler_str() -> &'static str {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(
|
||||
all(feature = "test-llvm", any(feature = "test-cranelift", feature = "test-singlepass")),
|
||||
all(feature = "test-cranelift", feature = "test-singlepass")
|
||||
))] {
|
||||
compile_error!("Only one compiler can be selected")
|
||||
} else if #[cfg(feature = "test-cranelift")] {
|
||||
"cranelift"
|
||||
} else if #[cfg(feature = "test-llvm")] {
|
||||
"llvm"
|
||||
} else if #[cfg(feature = "test-singlepass")] {
|
||||
"singlepass"
|
||||
} else {
|
||||
compile_error!("No compiler chosen for the tests")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_store() -> Store {
|
||||
let features = Features::default();
|
||||
let try_nan_canonicalization = false;
|
||||
let compiler_config =
|
||||
get_compiler_config_from_str(get_compiler_str(), try_nan_canonicalization, features);
|
||||
let tunables = Tunables::for_target(compiler_config.target().triple());
|
||||
let store = Store::new(Arc::new(JITEngine::new(compiler_config, tunables)));
|
||||
store
|
||||
}
|
||||
|
||||
pub fn get_headless_store() -> Store {
|
||||
let tunables = Tunables::for_target(&Triple::host());
|
||||
let store = Store::new(Arc::new(JITEngine::headless(tunables)));
|
||||
store
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
[package]
|
||||
name = "wasmer-engine-dummy"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
description = "wasmer testing utils"
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
wasm-common = { path = "../../../lib/wasm-common", version = "0.16.2" }
|
||||
wasmer-compiler = { path = "../../../lib/compiler", version = "0.16.2" }
|
||||
wasmer-runtime = { path = "../../../lib/runtime", version = "0.16.2" }
|
||||
wasmer-engine = { path = "../../../lib/engine", version = "0.16.2" }
|
||||
wasm-common = { path = "../../../lib/wasm-common", version = "1.0.0-alpha.1" }
|
||||
wasmer-compiler = { path = "../../../lib/compiler", version = "1.0.0-alpha.1" }
|
||||
wasmer-runtime = { path = "../../../lib/runtime", version = "1.0.0-alpha.1" }
|
||||
wasmer-engine = { path = "../../../lib/engine", version = "1.0.0-alpha.1" }
|
||||
serde = { version = "1.0", features = ["derive", "rc"], optional = true }
|
||||
serde_bytes = { version = "0.11", optional = true }
|
||||
bincode = { version = "1.2", optional = true }
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::DummyArtifact;
|
||||
use std::sync::Arc;
|
||||
use wasm_common::FunctionType;
|
||||
use wasmer_compiler::{CompileError, Features};
|
||||
use wasmer_engine::{Artifact, DeserializeError, Engine, Tunables};
|
||||
use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables};
|
||||
use wasmer_runtime::{
|
||||
SignatureRegistry, VMContext, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline,
|
||||
};
|
||||
@@ -23,6 +23,7 @@ pub struct DummyEngine {
|
||||
signatures: Arc<SignatureRegistry>,
|
||||
features: Arc<Features>,
|
||||
tunables: Arc<dyn Tunables + Send + Sync>,
|
||||
engine_id: EngineId,
|
||||
}
|
||||
|
||||
impl DummyEngine {
|
||||
@@ -32,6 +33,7 @@ impl DummyEngine {
|
||||
signatures: Arc::new(SignatureRegistry::new()),
|
||||
tunables: Arc::new(tunables),
|
||||
features: Arc::new(Default::default()),
|
||||
engine_id: EngineId::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,4 +99,8 @@ impl Engine for DummyEngine {
|
||||
unsafe fn deserialize(&self, bytes: &[u8]) -> Result<Arc<dyn Artifact>, DeserializeError> {
|
||||
Ok(Arc::new(DummyArtifact::deserialize(&self, &bytes)?))
|
||||
}
|
||||
|
||||
fn id(&self) -> &EngineId {
|
||||
&self.engine_id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ pub fn with_features(
|
||||
f: impl Fn(&mut Testsuite) -> anyhow::Result<()> + Copy,
|
||||
) -> anyhow::Result<()> {
|
||||
for compiler in features.iter() {
|
||||
writeln!(out.buffer, "#[cfg(feature=\"{}\")]", compiler)?;
|
||||
writeln!(out.buffer, "#[cfg(feature=\"test-{}\")]", compiler)?;
|
||||
writeln!(out.buffer, "#[cfg(test)]")?;
|
||||
writeln!(out.buffer, "#[allow(non_snake_case)]")?;
|
||||
with_test_module(&mut out, &compiler, f)?;
|
||||
|
||||
@@ -20,11 +20,7 @@ pub fn wast_processor(out: &mut Testsuite, p: PathBuf) -> Option<Test> {
|
||||
let compiler = out.path.get(0).unwrap();
|
||||
|
||||
// The implementation of `run_wast` lives in /tests/spectest.rs
|
||||
let body = format!(
|
||||
"crate::wast::run_wast(r#\"{}\"#, \"{}\")",
|
||||
p.display(),
|
||||
compiler
|
||||
);
|
||||
let body = format!("crate::run_wast(r#\"{}\"#, \"{}\")", p.display(), compiler);
|
||||
|
||||
Some(Test {
|
||||
name: testname,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "test-utils"
|
||||
version = "0.16.2"
|
||||
version = "1.0.0-alpha.1"
|
||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
description = "wasmer testing utils"
|
||||
edition = "2018"
|
||||
@@ -9,12 +9,12 @@ publish = false
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
wasmer-compiler = { path = "../../../lib/compiler", version = "0.16.2" }
|
||||
wasmer-compiler-singlepass = { path = "../../../lib/compiler-singlepass", version = "0.16.2", optional = true }
|
||||
wasmer-compiler-cranelift = { path = "../../../lib/compiler-cranelift", version = "0.16.2", optional = true }
|
||||
wasmer-compiler-llvm = { path = "../../../lib/compiler-llvm", version = "0.16.2", optional = true }
|
||||
wasmer-engine-jit = { path = "../../../lib/engine-jit", version = "0.16.2" }
|
||||
wasmer = { path = "../../../lib/api", version = "0.16.2", default-features = false }
|
||||
wasmer-compiler = { path = "../../../lib/compiler", version = "1.0.0-alpha.1" }
|
||||
wasmer-compiler-singlepass = { path = "../../../lib/compiler-singlepass", version = "1.0.0-alpha.1", optional = true }
|
||||
wasmer-compiler-cranelift = { path = "../../../lib/compiler-cranelift", version = "1.0.0-alpha.1", optional = true }
|
||||
wasmer-compiler-llvm = { path = "../../../lib/compiler-llvm", version = "1.0.0-alpha.1", optional = true }
|
||||
wasmer-engine-jit = { path = "../../../lib/engine-jit", version = "1.0.0-alpha.1" }
|
||||
wasmer = { path = "../../../lib/api", version = "1.0.0-alpha.1", default-features = false }
|
||||
|
||||
[features]
|
||||
compiler = []
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user