Merge remote-tracking branch 'upstream/master' into poll

This commit is contained in:
Marcin Mielniczuk
2020-01-14 16:40:23 +01:00
104 changed files with 2056 additions and 1607 deletions

2
.gitmodules vendored
View File

@@ -5,5 +5,5 @@
path = crates/api/c-examples/wasm-c-api path = crates/api/c-examples/wasm-c-api
url = https://github.com/WebAssembly/wasm-c-api url = https://github.com/WebAssembly/wasm-c-api
[submodule "crates/wasi-common/WASI"] [submodule "crates/wasi-common/WASI"]
path = crates/wasi-common/WASI path = crates/wasi-common/wig/WASI
url = https://github.com/WebAssembly/WASI url = https://github.com/WebAssembly/WASI

383
Cargo.lock generated
View File

@@ -20,9 +20,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.25" version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14" checksum = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c"
[[package]] [[package]]
name = "arbitrary" name = "arbitrary"
@@ -53,10 +53,11 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.13" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [ dependencies = [
"hermit-abi",
"libc", "libc",
"winapi", "winapi",
] ]
@@ -67,6 +68,12 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
[[package]]
name = "autocfg"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.40" version = "0.3.40"
@@ -119,7 +126,7 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "440d600bca1c3b3982dd2533518e15ba73d051b532768804aa3c06ae52f4ce44" checksum = "440d600bca1c3b3982dd2533518e15ba73d051b532768804aa3c06ae52f4ce44"
dependencies = [ dependencies = [
"bindgen 0.52.0", "bindgen",
"cc", "cc",
"cmake", "cmake",
"heck", "heck",
@@ -136,29 +143,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "bindgen"
version = "0.51.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebd71393f1ec0509b553aa012b9b58e81dadbdff7130bd3b8cba576e69b32f75"
dependencies = [
"bitflags",
"cexpr",
"cfg-if",
"clang-sys",
"clap",
"env_logger 0.6.2",
"lazy_static",
"log",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"which",
]
[[package]] [[package]]
name = "bindgen" name = "bindgen"
version = "0.52.0" version = "0.52.0"
@@ -191,9 +175,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]] [[package]]
name = "blake2b_simd" name = "blake2b_simd"
version = "0.5.9" version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b83b7baab1e671718d78204225800d6b170e648188ac7dc992e9d6bddf87d0c0" checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
dependencies = [ dependencies = [
"arrayref", "arrayref",
"arrayvec 0.5.1", "arrayvec 0.5.1",
@@ -262,12 +246,11 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.48" version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76" checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
dependencies = [ dependencies = [
"jobserver", "jobserver",
"num_cpus",
] ]
[[package]] [[package]]
@@ -358,18 +341,18 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-bforest" name = "cranelift-bforest"
version = "0.52.0" version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56aa72ef104c5d634f2f9e84ef2c47e116c1d185fae13f196b97ca84b0a514f1" checksum = "bd3225fff1be118941c5fb66f1fb1f7f3e86468fac0e7364713c4fb99b72632b"
dependencies = [ dependencies = [
"cranelift-entity", "cranelift-entity",
] ]
[[package]] [[package]]
name = "cranelift-codegen" name = "cranelift-codegen"
version = "0.52.0" version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "460b9d20793543599308d22f5a1172c196e63a780c4e9aacb0b3f4f63d63ffe1" checksum = "f3e3e6679892029f76a99b9059d2b74e77ac03637d573bb014bc21579ec1b7da"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"cranelift-bforest", "cranelift-bforest",
@@ -385,9 +368,9 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-codegen-meta" name = "cranelift-codegen-meta"
version = "0.52.0" version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc70e4e8ccebd53a4f925147def857c9e9f7fe0fdbef4bb645a420473e012f50" checksum = "3cabe691548e28ca82ebd218f2fe76eec4c5629b64ef3db8b58443b7d9047275"
dependencies = [ dependencies = [
"cranelift-codegen-shared", "cranelift-codegen-shared",
"cranelift-entity", "cranelift-entity",
@@ -395,24 +378,24 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-codegen-shared" name = "cranelift-codegen-shared"
version = "0.52.0" version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3992000be4d18df0fe332b7c42c120de896e8ec54cd7b6cfa050910a8c9f6e2f" checksum = "d173252ffade4aa6e929090977b9a4cd5ac28e15a42626f878be3844b3000ad9"
[[package]] [[package]]
name = "cranelift-entity" name = "cranelift-entity"
version = "0.52.0" version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "722957e05064d97a3157bf0976deed0f3e8ee4f8a4ce167a7c724ca63a4e8bd9" checksum = "3498ad9ba021715716a1c52e2b31d7829a149913fb0d88493e4b07d3b772b656"
dependencies = [ dependencies = [
"serde", "serde",
] ]
[[package]] [[package]]
name = "cranelift-frontend" name = "cranelift-frontend"
version = "0.52.0" version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13051964302dc7948e8869735de42591559ea55e319b9b92da5b38f8e6a75cb7" checksum = "521a30773b8de74345c807a38853f055aca8fecaa39a0fc7698bfebc5a3da515"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"log", "log",
@@ -422,9 +405,9 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-native" name = "cranelift-native"
version = "0.52.0" version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21398a0bc6ba389ea86964ac4a495426dd61080f2ddd306184777a8560fe9976" checksum = "624e755cbe984e437308968239736e7f9aa3193e99928fb76eec7a1946627b34"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"raw-cpuid", "raw-cpuid",
@@ -433,9 +416,9 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-wasm" name = "cranelift-wasm"
version = "0.52.0" version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b72b7b10c09f70a604122fab76e6c4411255cf35403b68c3285566cc9d21c486" checksum = "0320733e518ab9e0e2d1a22034d40e2851fb403ed14db5220cf9b86576b9cfd4"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"cranelift-entity", "cranelift-entity",
@@ -443,7 +426,7 @@ dependencies = [
"log", "log",
"serde", "serde",
"thiserror", "thiserror",
"wasmparser 0.45.1", "wasmparser 0.45.2",
] ]
[[package]] [[package]]
@@ -462,7 +445,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" checksum = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
dependencies = [ dependencies = [
"autocfg", "autocfg 0.1.7",
"cfg-if", "cfg-if",
"crossbeam-utils 0.7.0", "crossbeam-utils 0.7.0",
"lazy_static", "lazy_static",
@@ -472,10 +455,11 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-queue" name = "crossbeam-queue"
version = "0.2.0" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfd6515864a82d2f877b42813d4553292c6659498c9a2aa31bab5a15243c2700" checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
dependencies = [ dependencies = [
"cfg-if",
"crossbeam-utils 0.7.0", "crossbeam-utils 0.7.0",
] ]
@@ -495,7 +479,7 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" checksum = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
dependencies = [ dependencies = [
"autocfg", "autocfg 0.1.7",
"cfg-if", "cfg-if",
"lazy_static", "lazy_static",
] ]
@@ -630,9 +614,9 @@ dependencies = [
[[package]] [[package]]
name = "faerie" name = "faerie"
version = "0.13.0" version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f902f2af041f6c7177a2a04f805687cdc71e69c7cbef059a2755d8923f4cd7a8" checksum = "74b9ed6159e4a6212c61d9c6a86bee01876b192a64accecf58d5b5ae3b667b52"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"goblin", "goblin",
@@ -723,9 +707,9 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.1.13" version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@@ -764,9 +748,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]] [[package]]
name = "goblin" name = "goblin"
version = "0.1.2" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88a79ef1f0dad46fd78075b6f80f92d97710eddf87b3e18a15a66761e8942672" checksum = "3081214398d39e4bd7f2c1975f0488ed04614ffdd976c6fc7a0708278552c0da"
dependencies = [ dependencies = [
"log", "log",
"plain", "plain",
@@ -784,9 +768,9 @@ dependencies = [
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.3" version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" checksum = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@@ -812,7 +796,7 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2" checksum = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2"
dependencies = [ dependencies = [
"autocfg", "autocfg 0.1.7",
] ]
[[package]] [[package]]
@@ -840,9 +824,9 @@ dependencies = [
[[package]] [[package]]
name = "inventory" name = "inventory"
version = "0.1.4" version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4cece20baea71d9f3435e7bbe9adf4765f091c5fe404975f844006964a71299" checksum = "2bf98296081bd2cb540acc09ef9c97f22b7e487841520350293605db1b2c7a27"
dependencies = [ dependencies = [
"ctor", "ctor",
"ghost", "ghost",
@@ -851,9 +835,9 @@ dependencies = [
[[package]] [[package]]
name = "inventory-impl" name = "inventory-impl"
version = "0.1.4" version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2869bf972e998977b1cb87e60df70341d48e48dca0823f534feb91ea44adaf9" checksum = "0a8e30575afe28eea36a9a39136b70b2fb6b0dd0a212a5bd1f30a498395c0274"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -877,13 +861,11 @@ checksum = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
[[package]] [[package]]
name = "jobserver" name = "jobserver"
version = "0.1.17" version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2b1d42ef453b30b7387e113da1c83ab1605d90c5b4e0eb8e96d016ed3b8c160" checksum = "230ae9adf468173aecd4176c7233bddc84a15871a586c5971ace9a55f881c075"
dependencies = [ dependencies = [
"getrandom",
"libc", "libc",
"log",
] ]
[[package]] [[package]]
@@ -931,7 +913,7 @@ dependencies = [
[[package]] [[package]]
name = "lightbeam" name = "lightbeam"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"capstone", "capstone",
@@ -948,7 +930,7 @@ dependencies = [
"smallvec", "smallvec",
"thiserror", "thiserror",
"typemap", "typemap",
"wasmparser 0.45.1", "wasmparser 0.47.0",
"wat", "wat",
] ]
@@ -1025,9 +1007,9 @@ dependencies = [
[[package]] [[package]]
name = "num" name = "num"
version = "0.2.0" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db" checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36"
dependencies = [ dependencies = [
"num-complex", "num-complex",
"num-integer", "num-integer",
@@ -1038,53 +1020,53 @@ dependencies = [
[[package]] [[package]]
name = "num-complex" name = "num-complex"
version = "0.2.3" version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb0cf31fb3ff77e6d2a6ebd6800df7fdcd106f2ad89113c9130bcd07f93dffc" checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95"
dependencies = [ dependencies = [
"autocfg", "autocfg 1.0.0",
"num-traits", "num-traits",
] ]
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.41" version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
dependencies = [ dependencies = [
"autocfg", "autocfg 1.0.0",
"num-traits", "num-traits",
] ]
[[package]] [[package]]
name = "num-iter" name = "num-iter"
version = "0.1.39" version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" checksum = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00"
dependencies = [ dependencies = [
"autocfg", "autocfg 1.0.0",
"num-integer", "num-integer",
"num-traits", "num-traits",
] ]
[[package]] [[package]]
name = "num-rational" name = "num-rational"
version = "0.2.2" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454" checksum = "da4dc79f9e6c81bef96148c8f6b8e72ad4541caa4a24373e900a36da07de03a3"
dependencies = [ dependencies = [
"autocfg", "autocfg 1.0.0",
"num-integer", "num-integer",
"num-traits", "num-traits",
] ]
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.10" version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
dependencies = [ dependencies = [
"autocfg", "autocfg 1.0.0",
] ]
[[package]] [[package]]
@@ -1175,13 +1157,28 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro-error" name = "proc-macro-error"
version = "0.2.6" version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097" checksum = "53c98547ceaea14eeb26fcadf51dc70d01a2479a7839170eae133721105e4428"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "proc-macro-error-attr"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2bf5d493cf5d3e296beccfd61794e445e830dfc8070a9c248ad3ee071392c6c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustversion",
"syn", "syn",
"syn-mid",
] ]
[[package]] [[package]]
@@ -1197,18 +1194,18 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.6" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" checksum = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc"
dependencies = [ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]] [[package]]
name = "pyo3" name = "pyo3"
version = "0.8.3" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b338139584e698b341996e4f453c71fa937daa408aaf301e042383724e0caca" checksum = "e1bfe257586436fbe1296d917f14a167d4253d0873bf43e2c9b9bdd58a3f9f35"
dependencies = [ dependencies = [
"indoc", "indoc",
"inventory", "inventory",
@@ -1227,9 +1224,9 @@ dependencies = [
[[package]] [[package]]
name = "pyo3-derive-backend" name = "pyo3-derive-backend"
version = "0.8.3" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b8c805249a82c04a00d96f562e66537e8ddfe5d895bc2a414a8e6b6ae3d53be" checksum = "4882d8237fd8c7373cc25cb802fe0dab9ff70830fd56f47ef6c7f3f287fcc057"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1238,9 +1235,9 @@ dependencies = [
[[package]] [[package]]
name = "pyo3cls" name = "pyo3cls"
version = "0.8.3" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3575ad614aa547044119f3ff78aff7bdcba6bcde53fcd67065611546d2b8a122" checksum = "fdf321cfab555f7411298733c86d21e5136f5ded13f5872fabf9de3337beecda"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"pyo3-derive-backend", "pyo3-derive-backend",
@@ -1250,9 +1247,9 @@ dependencies = [
[[package]] [[package]]
name = "quick-error" name = "quick-error"
version = "1.2.2" version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]] [[package]]
name = "quickcheck" name = "quickcheck"
@@ -1368,9 +1365,9 @@ dependencies = [
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.2.1" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43739f8831493b276363637423d3622d4bd6394ab6f0a9c4a552e208aeb7fddd" checksum = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
dependencies = [ dependencies = [
"crossbeam-deque", "crossbeam-deque",
"either", "either",
@@ -1379,9 +1376,9 @@ dependencies = [
[[package]] [[package]]
name = "rayon-core" name = "rayon-core"
version = "1.6.1" version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8bf17de6f23b05473c437eb958b9c850bfc8af0961fe17b4cc92d5a627b4791" checksum = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
dependencies = [ dependencies = [
"crossbeam-deque", "crossbeam-deque",
"crossbeam-queue", "crossbeam-queue",
@@ -1419,9 +1416,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.3.1" version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" checksum = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -1431,9 +1428,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.12" version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" checksum = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90"
[[package]] [[package]]
name = "region" name = "region"
@@ -1491,6 +1488,17 @@ dependencies = [
"semver", "semver",
] ]
[[package]]
name = "rustversion"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a0538bd897e17257b0128d2fd95c2ed6df939374073a36166051a79e2eb7986"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.2" version = "1.0.2"
@@ -1540,18 +1548,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.103" version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" checksum = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.103" version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8c6faef9a2e64b0064f48570289b4bf8823b7581f1d6157c1b52152306651d0" checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1571,9 +1579,9 @@ dependencies = [
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.8.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" checksum = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0"
dependencies = [ dependencies = [
"block-buffer", "block-buffer",
"digest", "digest",
@@ -1589,9 +1597,9 @@ checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.0.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86" checksum = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4"
[[package]] [[package]]
name = "spin" name = "spin"
@@ -1622,9 +1630,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]] [[package]]
name = "structopt" name = "structopt"
version = "0.3.5" version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30b3a3e93f5ad553c38b3301c8a0a0cec829a36783f6a0c467fc4bf553a5f5bf" checksum = "884ae79d6aad1e738f4a70dff314203fd498490a63ebc4d03ea83323c40b7b72"
dependencies = [ dependencies = [
"clap", "clap",
"structopt-derive", "structopt-derive",
@@ -1632,9 +1640,9 @@ dependencies = [
[[package]] [[package]]
name = "structopt-derive" name = "structopt-derive"
version = "0.3.5" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea692d40005b3ceba90a9fe7a78fa8d4b82b0ce627eebbffc329aab850f3410e" checksum = "0a97f829a34a0a9d5b353a881025a23b8c9fd09d46be6045df6b22920dbd7a93"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro-error", "proc-macro-error",
@@ -1645,15 +1653,26 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.11" version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238" checksum = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"unicode-xid", "unicode-xid",
] ]
[[package]]
name = "syn-mid"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fd3937748a7eccff61ba5b90af1a20dbf610858923a9192ea0ecb0cb77db1d0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "synstructure" name = "synstructure"
version = "0.12.3" version = "0.12.3"
@@ -1668,9 +1687,9 @@ dependencies = [
[[package]] [[package]]
name = "target-lexicon" name = "target-lexicon"
version = "0.9.0" version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f4c118a7a38378f305a9e111fcb2f7f838c0be324bfb31a77ea04f7f6e684b4" checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"
[[package]] [[package]]
name = "tempfile" name = "tempfile"
@@ -1697,7 +1716,7 @@ dependencies = [
[[package]] [[package]]
name = "test-programs" name = "test-programs"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cfg-if", "cfg-if",
@@ -1745,9 +1764,9 @@ dependencies = [
[[package]] [[package]]
name = "thread_local" name = "thread_local"
version = "0.3.6" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" checksum = "88ddf1ad580c7e3d1efff877d972bcc93f995556b9087a5a259630985c88ceab"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
] ]
@@ -1780,9 +1799,9 @@ checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
[[package]] [[package]]
name = "trybuild" name = "trybuild"
version = "1.0.18" version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b75e31d624df08744532e935f1d4bfedd319a277d5a162c5b15f6ced59307575" checksum = "987d6fdc45ddd7f3be5aa7386c8c8a844d1655c95b9ed948a9cd9cded8f2b79f"
dependencies = [ dependencies = [
"glob", "glob",
"lazy_static", "lazy_static",
@@ -1886,13 +1905,13 @@ dependencies = [
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.7.0" version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]] [[package]]
name = "wasi-common" name = "wasi-common"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cfg-if", "cfg-if",
@@ -1913,7 +1932,7 @@ dependencies = [
[[package]] [[package]]
name = "wasi-common-cbindgen" name = "wasi-common-cbindgen"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1947,9 +1966,15 @@ checksum = "1527c84a5bd585215f29c06b0e2a5274e478ad4dfc970d26ffad66fdc6cb311d"
[[package]] [[package]]
name = "wasmparser" name = "wasmparser"
version = "0.45.1" version = "0.45.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ee23c9b67aa5d7a2381ae56805ced08960d21b7cf6ca11f78b42d68e698d03b" checksum = "8b4eab1d9971d0803729cba3617b56eb04fcb4bd25361cb63880ed41a42f20d5"
[[package]]
name = "wasmparser"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1add8db5a53a2f64f13418b241982c4ab533d7a9e1e8a5dcadccce633d8d393b"
[[package]] [[package]]
name = "wasmprinter" name = "wasmprinter"
@@ -1963,27 +1988,28 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime" name = "wasmtime"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cfg-if",
"file-per-thread-logger", "file-per-thread-logger",
"libc",
"pretty_env_logger", "pretty_env_logger",
"rayon", "rayon",
"region", "region",
"target-lexicon", "target-lexicon",
"wasi-common", "wasi-common",
"wasmparser 0.45.1", "wasmparser 0.47.0",
"wasmtime-environ", "wasmtime-environ",
"wasmtime-jit", "wasmtime-jit",
"wasmtime-runtime", "wasmtime-runtime",
"wasmtime-wasi",
"wasmtime-wast",
"wat", "wat",
"winapi",
] ]
[[package]] [[package]]
name = "wasmtime-cli" name = "wasmtime-cli"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"faerie", "faerie",
@@ -2003,6 +2029,7 @@ dependencies = [
"wasmtime-interface-types", "wasmtime-interface-types",
"wasmtime-jit", "wasmtime-jit",
"wasmtime-obj", "wasmtime-obj",
"wasmtime-runtime",
"wasmtime-wasi", "wasmtime-wasi",
"wasmtime-wasi-c", "wasmtime-wasi-c",
"wasmtime-wast", "wasmtime-wast",
@@ -2011,7 +2038,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-debug" name = "wasmtime-debug"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"faerie", "faerie",
@@ -2019,13 +2046,13 @@ dependencies = [
"more-asserts", "more-asserts",
"target-lexicon", "target-lexicon",
"thiserror", "thiserror",
"wasmparser 0.45.1", "wasmparser 0.47.0",
"wasmtime-environ", "wasmtime-environ",
] ]
[[package]] [[package]]
name = "wasmtime-environ" name = "wasmtime-environ"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64 0.11.0", "base64 0.11.0",
@@ -2053,14 +2080,14 @@ dependencies = [
"tempfile", "tempfile",
"thiserror", "thiserror",
"toml", "toml",
"wasmparser 0.45.1", "wasmparser 0.47.0",
"winapi", "winapi",
"zstd", "zstd",
] ]
[[package]] [[package]]
name = "wasmtime-fuzz" name = "wasmtime-fuzz"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"arbitrary", "arbitrary",
"env_logger 0.7.1", "env_logger 0.7.1",
@@ -2073,14 +2100,14 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-fuzzing" name = "wasmtime-fuzzing"
version = "0.1.0" version = "0.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"arbitrary", "arbitrary",
"binaryen", "binaryen",
"env_logger 0.7.1", "env_logger 0.7.1",
"log", "log",
"wasmparser 0.45.1", "wasmparser 0.47.0",
"wasmprinter", "wasmprinter",
"wasmtime", "wasmtime",
"wasmtime-environ", "wasmtime-environ",
@@ -2090,12 +2117,12 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-interface-types" name = "wasmtime-interface-types"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"walrus", "walrus",
"wasm-webidl-bindings", "wasm-webidl-bindings",
"wasmparser 0.45.1", "wasmparser 0.47.0",
"wasmtime", "wasmtime",
"wasmtime-environ", "wasmtime-environ",
"wasmtime-jit", "wasmtime-jit",
@@ -2105,7 +2132,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-jit" name = "wasmtime-jit"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cranelift-codegen", "cranelift-codegen",
@@ -2117,7 +2144,7 @@ dependencies = [
"region", "region",
"target-lexicon", "target-lexicon",
"thiserror", "thiserror",
"wasmparser 0.45.1", "wasmparser 0.47.0",
"wasmtime-debug", "wasmtime-debug",
"wasmtime-environ", "wasmtime-environ",
"wasmtime-runtime", "wasmtime-runtime",
@@ -2126,7 +2153,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-obj" name = "wasmtime-obj"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"faerie", "faerie",
@@ -2136,13 +2163,13 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-py" name = "wasmtime-py"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"pyo3", "pyo3",
"region", "region",
"target-lexicon", "target-lexicon",
"wasmparser 0.45.1", "wasmparser 0.47.0",
"wasmtime", "wasmtime",
"wasmtime-environ", "wasmtime-environ",
"wasmtime-interface-types", "wasmtime-interface-types",
@@ -2152,9 +2179,10 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-runtime" name = "wasmtime-runtime"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"cc", "cc",
"cfg-if",
"indexmap", "indexmap",
"lazy_static", "lazy_static",
"libc", "libc",
@@ -2168,7 +2196,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-rust" name = "wasmtime-rust"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"wasmtime", "wasmtime",
@@ -2179,7 +2207,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-rust-macro" name = "wasmtime-rust-macro"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -2188,7 +2216,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-wasi" name = "wasmtime-wasi"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"cranelift-entity", "cranelift-entity",
@@ -2205,9 +2233,9 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-wasi-c" name = "wasmtime-wasi-c"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"bindgen 0.51.1", "bindgen",
"cmake", "cmake",
"cranelift-codegen", "cranelift-codegen",
"cranelift-entity", "cranelift-entity",
@@ -2223,11 +2251,11 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-wast" name = "wasmtime-wast"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"wasmtime", "wasmtime",
"wast 5.0.1", "wast 6.0.0",
] ]
[[package]] [[package]]
@@ -2241,29 +2269,20 @@ dependencies = [
[[package]] [[package]]
name = "wast" name = "wast"
version = "4.0.0" version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdd03645007fe5c76cdacbcf51c145db79ab82756e977f7ed051b7cf896dc7df" checksum = "3ed3db7029d1d31a15c10126e78b58e51781faefafbc8afb20fb01291b779984"
dependencies = [
"leb128",
]
[[package]]
name = "wast"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d1de68310854a9840d39487701a8c1acccb5c9f9f2650d5fce3cdfe6650c372"
dependencies = [ dependencies = [
"leb128", "leb128",
] ]
[[package]] [[package]]
name = "wat" name = "wat"
version = "1.0.5" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ba86afa8d9f69291394de512e10e5ca6788998f4c426a56113770048826dc9" checksum = "9d59ba5b224f5507d55e4f89d0b18cc6452d84640ab11b4c9086d61a3ee62d03"
dependencies = [ dependencies = [
"wast 4.0.0", "wast 6.0.0",
] ]
[[package]] [[package]]
@@ -2277,7 +2296,7 @@ dependencies = [
[[package]] [[package]]
name = "wig" name = "wig"
version = "0.7.0" version = "0.9.2"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
@@ -2328,7 +2347,7 @@ dependencies = [
[[package]] [[package]]
name = "winx" name = "winx"
version = "0.7.0" version = "0.9.0"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cvt", "cvt",
@@ -2338,6 +2357,8 @@ dependencies = [
[[package]] [[package]]
name = "witx" name = "witx"
version = "0.6.0" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abc432537dbc9940e06816ebc3e1c4694fc835b90720615c32038769d7b2967d"
dependencies = [ dependencies = [
"clap", "clap",
"thiserror", "thiserror",
@@ -2346,7 +2367,7 @@ dependencies = [
[[package]] [[package]]
name = "yanix" name = "yanix"
version = "0.1.0" version = "0.9.0"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg-if", "cfg-if",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime-cli" name = "wasmtime-cli"
version = "0.7.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
description = "Command-line interface for Wasmtime" description = "Command-line interface for Wasmtime"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -29,9 +29,9 @@ wasmtime-wasi = { path = "crates/wasi" }
wasmtime-wasi-c = { path = "crates/wasi-c", optional = true } wasmtime-wasi-c = { path = "crates/wasi-c", optional = true }
wasi-common = { path = "crates/wasi-common" } wasi-common = { path = "crates/wasi-common" }
structopt = { version = "0.3.5", features = ["color", "suggestions"] } structopt = { version = "0.3.5", features = ["color", "suggestions"] }
faerie = "0.13.0" faerie = "0.14.0"
anyhow = "1.0.19" anyhow = "1.0.19"
target-lexicon = { version = "0.9.0", default-features = false } target-lexicon = { version = "0.10.0", default-features = false }
pretty_env_logger = "0.3.0" pretty_env_logger = "0.3.0"
file-per-thread-logger = "0.1.1" file-per-thread-logger = "0.1.1"
wat = "1.0.2" wat = "1.0.2"
@@ -40,6 +40,7 @@ rayon = "1.2.1"
wasm-webidl-bindings = "0.6" wasm-webidl-bindings = "0.6"
[dev-dependencies] [dev-dependencies]
wasmtime-runtime = { path = "crates/runtime" }
more-asserts = "0.2.1" more-asserts = "0.2.1"
# This feature requires the wasm32-wasi target be installed. It enables # This feature requires the wasm32-wasi target be installed. It enables
# wasm32-wasi integration tests. To enable, run # wasm32-wasi integration tests. To enable, run

View File

@@ -30,26 +30,8 @@ fn main() -> anyhow::Result<()> {
// Skip running spec_testsuite tests if the submodule isn't checked // Skip running spec_testsuite tests if the submodule isn't checked
// out. // out.
if spec_tests > 0 { if spec_tests > 0 {
start_test_module(&mut out, "simd")?; test_directory(&mut out, "tests/spec_testsuite/proposals/simd", strategy)
write_testsuite_tests( .expect("generating tests");
&mut out,
"tests/spec_testsuite/proposals/simd/simd_address.wast",
"simd",
strategy,
)?;
write_testsuite_tests(
&mut out,
"tests/spec_testsuite/proposals/simd/simd_align.wast",
"simd",
strategy,
)?;
write_testsuite_tests(
&mut out,
"tests/spec_testsuite/proposals/simd/simd_const.wast",
"simd",
strategy,
)?;
finish_test_module(&mut out)?;
test_directory( test_directory(
&mut out, &mut out,
@@ -139,7 +121,6 @@ fn write_testsuite_tests(
strategy: &str, strategy: &str,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let path = path.as_ref(); let path = path.as_ref();
println!("cargo:rerun-if-changed={}", path.display());
let testname = extract_name(path); let testname = extract_name(path);
writeln!(out, "#[test]")?; writeln!(out, "#[test]")?;
@@ -165,9 +146,23 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
"Lightbeam" => match (testsuite, testname) { "Lightbeam" => match (testsuite, testname) {
(_, _) if testname.starts_with("simd") => return true, (_, _) if testname.starts_with("simd") => return true,
(_, _) if testsuite.ends_with("multi_value") => return true, (_, _) if testsuite.ends_with("multi_value") => return true,
// Lightbeam doesn't support float arguments on the stack.
("spec_testsuite", "call") => return true,
_ => (), _ => (),
}, },
"Cranelift" => match (testsuite, testname) { "Cranelift" => match (testsuite, testname) {
("simd", "simd_bit_shift") => return true, // FIXME Unsupported feature: proposed SIMD operator I8x16Shl
("simd", "simd_const") => return true, // FIXME Invalid input WebAssembly code at offset 474: Unexpected data at the end of the section
("simd", "simd_conversions") => return true, // FIXME Unsupported feature: proposed SIMD operator I16x8NarrowI32x4S
("simd", "simd_f32x4") => return true, // FIXME expected V128(F32x4([CanonicalNan, CanonicalNan, Value(Float32 { bits: 0 }), Value(Float32 { bits: 0 })])), got V128(18428729675200069632)
("simd", "simd_f64x2") => return true, // FIXME expected V128(F64x2([Value(Float64 { bits: 9221120237041090560 }), Value(Float64 { bits: 0 })])), got V128(0)
("simd", "simd_f64x2_arith") => return true, // FIXME expected V128(F64x2([Value(Float64 { bits: 9221120237041090560 }), Value(Float64 { bits: 13835058055282163712 })])), got V128(255211775190703847615975447847722024960)
("simd", "simd_i64x2_arith") => return true, // FIXME Unsupported feature: proposed SIMD operator I64x2Mul
("simd", "simd_lane") => return true, // FIXME invalid u8 number: constant out of range: (v8x16.shuffle -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14...
("simd", "simd_load") => return true, // FIXME Unsupported feature: proposed SIMD operator I8x16Shl
("simd", "simd_load_extend") => return true, // FIXME Unsupported feature: proposed SIMD operator I16x8Load8x8S { memarg: MemoryImmediate { flags: 0, offset: 0 } }
("simd", "simd_load_splat") => return true, // FIXME Unsupported feature: proposed SIMD operator V8x16LoadSplat { memarg: MemoryImmediate { flags: 0, offset: 0 } }
("simd", "simd_splat") => return true, // FIXME Unsupported feature: proposed SIMD operator I8x16ShrS
_ => {} _ => {}
}, },
_ => panic!("unrecognized strategy"), _ => panic!("unrecognized strategy"),

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime" name = "wasmtime"
version = "0.7.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
description = "High-level API to expose the Wasmtime runtime" description = "High-level API to expose the Wasmtime runtime"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -13,11 +13,11 @@ name = "wasmtime"
crate-type = ["lib", "staticlib", "cdylib"] crate-type = ["lib", "staticlib", "cdylib"]
[dependencies] [dependencies]
wasmtime-runtime = { path = "../runtime" } wasmtime-runtime = { path = "../runtime", version = "0.9.0" }
wasmtime-environ = { path = "../environ" } wasmtime-environ = { path = "../environ", version = "0.9.0" }
wasmtime-jit = { path = "../jit" } wasmtime-jit = { path = "../jit", version = "0.9.0" }
wasmparser = { version = "0.45.1", default-features = false } wasmparser = { version = "0.47.0", default-features = false }
target-lexicon = { version = "0.9.0", default-features = false } target-lexicon = { version = "0.10.0", default-features = false }
anyhow = "1.0.19" anyhow = "1.0.19"
region = "2.0.0" region = "2.0.0"
libc = "0.2" libc = "0.2"
@@ -28,10 +28,8 @@ winapi = "0.3.7"
[dev-dependencies] [dev-dependencies]
# for wasmtime.rs # for wasmtime.rs
wasi-common = { path = "../wasi-common" } wasi-common = { path = "../wasi-common", version = "0.9.0" }
pretty_env_logger = "0.3.0" pretty_env_logger = "0.3.0"
wasmtime-wast = { path = "../wast" }
wasmtime-wasi = { path = "../wasi" }
rayon = "1.2.1" rayon = "1.2.1"
file-per-thread-logger = "0.1.1" file-per-thread-logger = "0.1.1"
wat = "1.0" wat = "1.0"

View File

@@ -50,11 +50,11 @@ fn main() -> anyhow::Result<()> {
.0; .0;
// Instantiate the module. // Instantiate the module.
let instance = Instance::new(&store, &module, &[])?; let instance = Instance::new(&module, &[])?;
// Invoke `gcd` export // Invoke `gcd` export
let gcd = instance.exports()[gcd_index].func().expect("gcd"); let gcd = instance.exports()[gcd_index].func().expect("gcd");
let result = gcd.borrow().call(&[Val::from(6i32), Val::from(27i32)])?; let result = gcd.call(&[Val::from(6i32), Val::from(27i32)])?;
println!("{:?}", result); println!("{:?}", result);
Ok(()) Ok(())

View File

@@ -41,15 +41,14 @@ fn main() -> Result<()> {
// `HelloCallback` type and its associated implementation of `Callback. // `HelloCallback` type and its associated implementation of `Callback.
println!("Creating callback..."); println!("Creating callback...");
let hello_type = FuncType::new(Box::new([]), Box::new([])); let hello_type = FuncType::new(Box::new([]), Box::new([]));
let hello_func = HostRef::new(Func::new(&store, hello_type, Rc::new(HelloCallback))); let hello_func = Func::new(&store, hello_type, Rc::new(HelloCallback));
// Once we've got that all set up we can then move to the instantiation // Once we've got that all set up we can then move to the instantiation
// phase, pairing together a compiled module as well as a set of imports. // phase, pairing together a compiled module as well as a set of imports.
// Note that this is where the wasm `start` function, if any, would run. // Note that this is where the wasm `start` function, if any, would run.
println!("Instantiating module..."); println!("Instantiating module...");
let imports = vec![hello_func.into()]; let imports = vec![hello_func.into()];
let instance = Instance::new(&store, &module, imports.as_slice()) let instance = Instance::new(&module, &imports).context("> Error instantiating module!")?;
.context("> Error instantiating module!")?;
// Next we poke around a bit to extract the `run` function from the module. // Next we poke around a bit to extract the `run` function from the module.
println!("Extracting export..."); println!("Extracting export...");
@@ -59,7 +58,7 @@ fn main() -> Result<()> {
// And last but not least we can call it! // And last but not least we can call it!
println!("Calling export..."); println!("Calling export...");
run_func.borrow().call(&[])?; run_func.call(&[])?;
println!("Done."); println!("Done.");
Ok(()) Ok(())

View File

@@ -3,7 +3,7 @@
use anyhow::{bail, ensure, Context as _, Error}; use anyhow::{bail, ensure, Context as _, Error};
use wasmtime::*; use wasmtime::*;
fn get_export_memory(exports: &[Extern], i: usize) -> Result<HostRef<Memory>, Error> { fn get_export_memory(exports: &[Extern], i: usize) -> Result<Memory, Error> {
if exports.len() <= i { if exports.len() <= i {
bail!("> Error accessing memory export {}!", i); bail!("> Error accessing memory export {}!", i);
} }
@@ -13,7 +13,7 @@ fn get_export_memory(exports: &[Extern], i: usize) -> Result<HostRef<Memory>, Er
.clone()) .clone())
} }
fn get_export_func(exports: &[Extern], i: usize) -> Result<HostRef<Func>, Error> { fn get_export_func(exports: &[Extern], i: usize) -> Result<Func, Error> {
if exports.len() <= i { if exports.len() <= i {
bail!("> Error accessing function export {}!", i); bail!("> Error accessing function export {}!", i);
} }
@@ -33,7 +33,7 @@ macro_rules! check {
macro_rules! check_ok { macro_rules! check_ok {
($func:expr, $($p:expr),*) => { ($func:expr, $($p:expr),*) => {
if let Err(_) = $func.borrow().call(&[$($p.into()),*]) { if let Err(_) = $func.call(&[$($p.into()),*]) {
bail!("> Error on result, expected return"); bail!("> Error on result, expected return");
} }
} }
@@ -41,7 +41,7 @@ macro_rules! check_ok {
macro_rules! check_trap { macro_rules! check_trap {
($func:expr, $($p:expr),*) => { ($func:expr, $($p:expr),*) => {
if let Ok(_) = $func.borrow().call(&[$($p.into()),*]) { if let Ok(_) = $func.call(&[$($p.into()),*]) {
bail!("> Error on result, expected trap"); bail!("> Error on result, expected trap");
} }
} }
@@ -49,7 +49,7 @@ macro_rules! check_trap {
macro_rules! call { macro_rules! call {
($func:expr, $($p:expr),*) => { ($func:expr, $($p:expr),*) => {
match $func.borrow().call(&[$($p.into()),*]) { match $func.call(&[$($p.into()),*]) {
Ok(result) => { Ok(result) => {
let result: i32 = result[0].unwrap_i32(); let result: i32 = result[0].unwrap_i32();
result result
@@ -90,7 +90,7 @@ fn main() -> Result<(), Error> {
// Instantiate. // Instantiate.
println!("Instantiating module..."); println!("Instantiating module...");
let instance = Instance::new(&store, &module, &[]).context("> Error instantiating module!")?; let instance = Instance::new(&module, &[]).context("> Error instantiating module!")?;
// Extract export. // Extract export.
println!("Extracting export..."); println!("Extracting export...");
@@ -101,16 +101,13 @@ fn main() -> Result<(), Error> {
let load_func = get_export_func(&exports, 2)?; let load_func = get_export_func(&exports, 2)?;
let store_func = get_export_func(&exports, 3)?; let store_func = get_export_func(&exports, 3)?;
// Try cloning.
check!(memory.clone().ptr_eq(&memory), true);
// Check initial memory. // Check initial memory.
println!("Checking memory..."); println!("Checking memory...");
check!(memory.borrow().size(), 2u32); check!(memory.size(), 2u32);
check!(memory.borrow().data_size(), 0x20000usize); check!(memory.data_size(), 0x20000usize);
check!(unsafe { memory.borrow().data()[0] }, 0); check!(unsafe { memory.data()[0] }, 0);
check!(unsafe { memory.borrow().data()[0x1000] }, 1); check!(unsafe { memory.data()[0x1000] }, 1);
check!(unsafe { memory.borrow().data()[0x1003] }, 4); check!(unsafe { memory.data()[0x1003] }, 4);
check!(call!(size_func,), 2); check!(call!(size_func,), 2);
check!(call!(load_func, 0), 0); check!(call!(load_func, 0), 0);
@@ -122,36 +119,36 @@ fn main() -> Result<(), Error> {
// Mutate memory. // Mutate memory.
println!("Mutating memory..."); println!("Mutating memory...");
unsafe { unsafe {
memory.borrow_mut().data()[0x1003] = 5; memory.data()[0x1003] = 5;
} }
check_ok!(store_func, 0x1002, 6); check_ok!(store_func, 0x1002, 6);
check_trap!(store_func, 0x20000, 0); check_trap!(store_func, 0x20000, 0);
check!(unsafe { memory.borrow().data()[0x1002] }, 6); check!(unsafe { memory.data()[0x1002] }, 6);
check!(unsafe { memory.borrow().data()[0x1003] }, 5); check!(unsafe { memory.data()[0x1003] }, 5);
check!(call!(load_func, 0x1002), 6); check!(call!(load_func, 0x1002), 6);
check!(call!(load_func, 0x1003), 5); check!(call!(load_func, 0x1003), 5);
// Grow memory. // Grow memory.
println!("Growing memory..."); println!("Growing memory...");
check!(memory.borrow_mut().grow(1), true); check!(memory.grow(1), true);
check!(memory.borrow().size(), 3u32); check!(memory.size(), 3u32);
check!(memory.borrow().data_size(), 0x30000usize); check!(memory.data_size(), 0x30000usize);
check!(call!(load_func, 0x20000), 0); check!(call!(load_func, 0x20000), 0);
check_ok!(store_func, 0x20000, 0); check_ok!(store_func, 0x20000, 0);
check_trap!(load_func, 0x30000); check_trap!(load_func, 0x30000);
check_trap!(store_func, 0x30000, 0); check_trap!(store_func, 0x30000, 0);
check!(memory.borrow_mut().grow(1), false); check!(memory.grow(1), false);
check!(memory.borrow_mut().grow(0), true); check!(memory.grow(0), true);
// Create stand-alone memory. // Create stand-alone memory.
// TODO(wasm+): Once Wasm allows multiple memories, turn this into import. // TODO(wasm+): Once Wasm allows multiple memories, turn this into import.
println!("Creating stand-alone memory..."); println!("Creating stand-alone memory...");
let memorytype = MemoryType::new(Limits::new(5, Some(5))); let memorytype = MemoryType::new(Limits::new(5, Some(5)));
let mut memory2 = Memory::new(&store, memorytype); let memory2 = Memory::new(&store, memorytype);
check!(memory2.size(), 5u32); check!(memory2.size(), 5u32);
check!(memory2.grow(1), false); check!(memory2.grow(1), false);
check!(memory2.grow(0), true); check!(memory2.grow(0), true);

View File

@@ -62,13 +62,13 @@ fn main() -> Result<()> {
Box::new([ValType::I32, ValType::I64]), Box::new([ValType::I32, ValType::I64]),
Box::new([ValType::I64, ValType::I32]), Box::new([ValType::I64, ValType::I32]),
); );
let callback_func = HostRef::new(Func::new(&store, callback_type, Rc::new(Callback))); let callback_func = Func::new(&store, callback_type, Rc::new(Callback));
// Instantiate. // Instantiate.
println!("Instantiating module..."); println!("Instantiating module...");
let imports = vec![callback_func.into()]; let imports = vec![callback_func.into()];
let instance = Instance::new(&store, &module, imports.as_slice()) let instance =
.context("Error instantiating module!")?; Instance::new(&module, imports.as_slice()).context("Error instantiating module!")?;
// Extract exports. // Extract exports.
println!("Extracting export..."); println!("Extracting export...");
@@ -83,7 +83,6 @@ fn main() -> Result<()> {
println!("Calling export \"g\"..."); println!("Calling export \"g\"...");
let args = vec![Val::I32(1), Val::I64(3)]; let args = vec![Val::I32(1), Val::I64(3)];
let results = g let results = g
.borrow()
.call(&args) .call(&args)
.map_err(|e| format_err!("> Error calling g! {:?}", e))?; .map_err(|e| format_err!("> Error calling g! {:?}", e))?;
@@ -108,7 +107,6 @@ fn main() -> Result<()> {
Val::I64(9), Val::I64(9),
]; ];
let results = round_trip_many let results = round_trip_many
.borrow()
.call(&args) .call(&args)
.map_err(|e| format_err!("> Error calling round_trip_many! {:?}", e))?; .map_err(|e| format_err!("> Error calling round_trip_many! {:?}", e))?;

View File

@@ -12,7 +12,7 @@ use wasmtime_runtime::Export;
/// WebAssembly. /// WebAssembly.
/// # Example /// # Example
/// ``` /// ```
/// use wasmtime::{HostRef, Val}; /// use wasmtime::Val;
/// ///
/// struct TimesTwo; /// struct TimesTwo;
/// ///
@@ -54,13 +54,11 @@ use wasmtime_runtime::Export;
/// ); /// );
/// ///
/// // Build a reference to the "times_two" function that can be used. /// // Build a reference to the "times_two" function that can be used.
/// let times_two_function = HostRef::new( /// let times_two_function =
/// wasmtime::Func::new(&store, times_two_type, std::rc::Rc::new(TimesTwo)) /// wasmtime::Func::new(&store, times_two_type, std::rc::Rc::new(TimesTwo));
/// );
/// ///
/// // Create module instance that imports our function /// // Create module instance that imports our function
/// let instance = wasmtime::Instance::new( /// let instance = wasmtime::Instance::new(
/// &store,
/// &module, /// &module,
/// &[times_two_function.into()] /// &[times_two_function.into()]
/// )?; /// )?;
@@ -71,7 +69,6 @@ use wasmtime_runtime::Export;
/// // Borrow and call "run". Returning any error message from Wasm as a string. /// // Borrow and call "run". Returning any error message from Wasm as a string.
/// let original = 5i32; /// let original = 5i32;
/// let results = run_function /// let results = run_function
/// .borrow()
/// .call(&[original.into()]) /// .call(&[original.into()])
/// .map_err(|trap| trap.to_string())?; /// .map_err(|trap| trap.to_string())?;
/// ///

View File

@@ -1,5 +1,5 @@
use crate::callable::{Callable, NativeCallable, WasmtimeFn, WrappedCallable}; use crate::callable::{Callable, NativeCallable, WasmtimeFn, WrappedCallable};
use crate::r#ref::{AnyRef, HostRef}; use crate::r#ref::AnyRef;
use crate::runtime::Store; use crate::runtime::Store;
use crate::trampoline::{generate_global_export, generate_memory_export, generate_table_export}; use crate::trampoline::{generate_global_export, generate_memory_export, generate_table_export};
use crate::trap::Trap; use crate::trap::Trap;
@@ -15,53 +15,53 @@ use wasmtime_runtime::InstanceHandle;
#[derive(Clone)] #[derive(Clone)]
pub enum Extern { pub enum Extern {
Func(HostRef<Func>), Func(Func),
Global(HostRef<Global>), Global(Global),
Table(HostRef<Table>), Table(Table),
Memory(HostRef<Memory>), Memory(Memory),
} }
impl Extern { impl Extern {
pub fn func(&self) -> Option<&HostRef<Func>> { pub fn func(&self) -> Option<&Func> {
match self { match self {
Extern::Func(func) => Some(func), Extern::Func(func) => Some(func),
_ => None, _ => None,
} }
} }
pub fn global(&self) -> Option<&HostRef<Global>> { pub fn global(&self) -> Option<&Global> {
match self { match self {
Extern::Global(global) => Some(global), Extern::Global(global) => Some(global),
_ => None, _ => None,
} }
} }
pub fn table(&self) -> Option<&HostRef<Table>> { pub fn table(&self) -> Option<&Table> {
match self { match self {
Extern::Table(table) => Some(table), Extern::Table(table) => Some(table),
_ => None, _ => None,
} }
} }
pub fn memory(&self) -> Option<&HostRef<Memory>> { pub fn memory(&self) -> Option<&Memory> {
match self { match self {
Extern::Memory(memory) => Some(memory), Extern::Memory(memory) => Some(memory),
_ => None, _ => None,
} }
} }
pub fn r#type(&self) -> ExternType { pub fn ty(&self) -> ExternType {
match self { match self {
Extern::Func(ft) => ExternType::Func(ft.borrow().r#type().clone()), Extern::Func(ft) => ExternType::Func(ft.ty().clone()),
Extern::Memory(ft) => ExternType::Memory(ft.borrow().r#type().clone()), Extern::Memory(ft) => ExternType::Memory(ft.ty().clone()),
Extern::Table(tt) => ExternType::Table(tt.borrow().r#type().clone()), Extern::Table(tt) => ExternType::Table(tt.ty().clone()),
Extern::Global(gt) => ExternType::Global(gt.borrow().r#type().clone()), Extern::Global(gt) => ExternType::Global(gt.ty().clone()),
} }
} }
pub(crate) fn get_wasmtime_export(&mut self) -> wasmtime_runtime::Export { pub(crate) fn get_wasmtime_export(&self) -> wasmtime_runtime::Export {
match self { match self {
Extern::Func(f) => f.borrow().wasmtime_export().clone(), Extern::Func(f) => f.wasmtime_export().clone(),
Extern::Global(g) => g.borrow().wasmtime_export().clone(), Extern::Global(g) => g.wasmtime_export().clone(),
Extern::Memory(m) => m.borrow().wasmtime_export().clone(), Extern::Memory(m) => m.wasmtime_export().clone(),
Extern::Table(t) => t.borrow().wasmtime_export().clone(), Extern::Table(t) => t.wasmtime_export().clone(),
} }
} }
@@ -71,50 +71,51 @@ impl Extern {
export: wasmtime_runtime::Export, export: wasmtime_runtime::Export,
) -> Extern { ) -> Extern {
match export { match export {
wasmtime_runtime::Export::Function { .. } => Extern::Func(HostRef::new( wasmtime_runtime::Export::Function { .. } => {
Func::from_wasmtime_function(export, store, instance_handle), Extern::Func(Func::from_wasmtime_function(export, store, instance_handle))
)), }
wasmtime_runtime::Export::Memory { .. } => Extern::Memory(HostRef::new( wasmtime_runtime::Export::Memory { .. } => {
Memory::from_wasmtime_memory(export, store, instance_handle), Extern::Memory(Memory::from_wasmtime_memory(export, store, instance_handle))
)), }
wasmtime_runtime::Export::Global { .. } => { wasmtime_runtime::Export::Global { .. } => {
Extern::Global(HostRef::new(Global::from_wasmtime_global(export, store))) Extern::Global(Global::from_wasmtime_global(export, store))
}
wasmtime_runtime::Export::Table { .. } => {
Extern::Table(Table::from_wasmtime_table(export, store, instance_handle))
} }
wasmtime_runtime::Export::Table { .. } => Extern::Table(HostRef::new(
Table::from_wasmtime_table(export, store, instance_handle),
)),
} }
} }
} }
impl From<HostRef<Func>> for Extern { impl From<Func> for Extern {
fn from(r: HostRef<Func>) -> Self { fn from(r: Func) -> Self {
Extern::Func(r) Extern::Func(r)
} }
} }
impl From<HostRef<Global>> for Extern { impl From<Global> for Extern {
fn from(r: HostRef<Global>) -> Self { fn from(r: Global) -> Self {
Extern::Global(r) Extern::Global(r)
} }
} }
impl From<HostRef<Memory>> for Extern { impl From<Memory> for Extern {
fn from(r: HostRef<Memory>) -> Self { fn from(r: Memory) -> Self {
Extern::Memory(r) Extern::Memory(r)
} }
} }
impl From<HostRef<Table>> for Extern { impl From<Table> for Extern {
fn from(r: HostRef<Table>) -> Self { fn from(r: Table) -> Self {
Extern::Table(r) Extern::Table(r)
} }
} }
#[derive(Clone)]
pub struct Func { pub struct Func {
_store: Store, _store: Store,
callable: Rc<dyn WrappedCallable + 'static>, callable: Rc<dyn WrappedCallable + 'static>,
r#type: FuncType, ty: FuncType,
} }
impl Func { impl Func {
@@ -125,26 +126,26 @@ impl Func {
fn from_wrapped( fn from_wrapped(
store: &Store, store: &Store,
r#type: FuncType, ty: FuncType,
callable: Rc<dyn WrappedCallable + 'static>, callable: Rc<dyn WrappedCallable + 'static>,
) -> Func { ) -> Func {
Func { Func {
_store: store.clone(), _store: store.clone(),
callable, callable,
r#type, ty,
} }
} }
pub fn r#type(&self) -> &FuncType { pub fn ty(&self) -> &FuncType {
&self.r#type &self.ty
} }
pub fn param_arity(&self) -> usize { pub fn param_arity(&self) -> usize {
self.r#type.params().len() self.ty.params().len()
} }
pub fn result_arity(&self) -> usize { pub fn result_arity(&self) -> usize {
self.r#type.results().len() self.ty.results().len()
} }
pub fn call(&self, params: &[Val]) -> Result<Box<[Val]>, Trap> { pub fn call(&self, params: &[Val]) -> Result<Box<[Val]>, Trap> {
@@ -162,8 +163,12 @@ impl Func {
store: &Store, store: &Store,
instance_handle: InstanceHandle, instance_handle: InstanceHandle,
) -> Self { ) -> Self {
// This is only called with `Export::Function`, and since it's coming
// from wasmtime_runtime itself we should support all the types coming
// out of it, so assert such here.
let ty = if let wasmtime_runtime::Export::Function { signature, .. } = &export { let ty = if let wasmtime_runtime::Export::Function { signature, .. } = &export {
FuncType::from_wasmtime_signature(signature.clone()) FuncType::from_wasmtime_signature(signature.clone())
.expect("core wasm signature should be supported")
} else { } else {
panic!("expected function export") panic!("expected function export")
}; };
@@ -178,32 +183,39 @@ impl fmt::Debug for Func {
} }
} }
#[derive(Clone)]
pub struct Global { pub struct Global {
inner: Rc<GlobalInner>,
}
struct GlobalInner {
_store: Store, _store: Store,
r#type: GlobalType, ty: GlobalType,
wasmtime_export: wasmtime_runtime::Export, wasmtime_export: wasmtime_runtime::Export,
#[allow(dead_code)] #[allow(dead_code)]
wasmtime_state: Option<crate::trampoline::GlobalState>, wasmtime_state: Option<crate::trampoline::GlobalState>,
} }
impl Global { impl Global {
pub fn new(store: &Store, r#type: GlobalType, val: Val) -> Global { pub fn new(store: &Store, ty: GlobalType, val: Val) -> Global {
let (wasmtime_export, wasmtime_state) = let (wasmtime_export, wasmtime_state) =
generate_global_export(&r#type, val).expect("generated global"); generate_global_export(&ty, val).expect("generated global");
Global { Global {
inner: Rc::new(GlobalInner {
_store: store.clone(), _store: store.clone(),
r#type, ty,
wasmtime_export, wasmtime_export,
wasmtime_state: Some(wasmtime_state), wasmtime_state: Some(wasmtime_state),
}),
} }
} }
pub fn r#type(&self) -> &GlobalType { pub fn ty(&self) -> &GlobalType {
&self.r#type &self.inner.ty
} }
fn wasmtime_global_definition(&self) -> *mut wasmtime_runtime::VMGlobalDefinition { fn wasmtime_global_definition(&self) -> *mut wasmtime_runtime::VMGlobalDefinition {
match self.wasmtime_export { match self.inner.wasmtime_export {
wasmtime_runtime::Export::Global { definition, .. } => definition, wasmtime_runtime::Export::Global { definition, .. } => definition,
_ => panic!("global definition not found"), _ => panic!("global definition not found"),
} }
@@ -212,22 +224,22 @@ impl Global {
pub fn get(&self) -> Val { pub fn get(&self) -> Val {
let definition = unsafe { &mut *self.wasmtime_global_definition() }; let definition = unsafe { &mut *self.wasmtime_global_definition() };
unsafe { unsafe {
match self.r#type().content() { match self.ty().content() {
ValType::I32 => Val::from(*definition.as_i32()), ValType::I32 => Val::from(*definition.as_i32()),
ValType::I64 => Val::from(*definition.as_i64()), ValType::I64 => Val::from(*definition.as_i64()),
ValType::F32 => Val::F32(*definition.as_u32()), ValType::F32 => Val::F32(*definition.as_u32()),
ValType::F64 => Val::F64(*definition.as_u64()), ValType::F64 => Val::F64(*definition.as_u64()),
_ => unimplemented!("Global::get for {:?}", self.r#type().content()), _ => unimplemented!("Global::get for {:?}", self.ty().content()),
} }
} }
} }
pub fn set(&mut self, val: Val) { pub fn set(&self, val: Val) {
if val.r#type() != *self.r#type().content() { if val.ty() != *self.ty().content() {
panic!( panic!(
"global of type {:?} cannot be set to {:?}", "global of type {:?} cannot be set to {:?}",
self.r#type().content(), self.ty().content(),
val.r#type() val.ty()
); );
} }
let definition = unsafe { &mut *self.wasmtime_global_definition() }; let definition = unsafe { &mut *self.wasmtime_global_definition() };
@@ -237,34 +249,40 @@ impl Global {
Val::I64(i) => *definition.as_i64_mut() = i, Val::I64(i) => *definition.as_i64_mut() = i,
Val::F32(f) => *definition.as_u32_mut() = f, Val::F32(f) => *definition.as_u32_mut() = f,
Val::F64(f) => *definition.as_u64_mut() = f, Val::F64(f) => *definition.as_u64_mut() = f,
_ => unimplemented!("Global::set for {:?}", val.r#type()), _ => unimplemented!("Global::set for {:?}", val.ty()),
} }
} }
} }
pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::Export { pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::Export {
&self.wasmtime_export &self.inner.wasmtime_export
} }
pub(crate) fn from_wasmtime_global(export: wasmtime_runtime::Export, store: &Store) -> Global { pub(crate) fn from_wasmtime_global(export: wasmtime_runtime::Export, store: &Store) -> Global {
let global = if let wasmtime_runtime::Export::Global { ref global, .. } = export { let global = if let wasmtime_runtime::Export::Global { ref global, .. } = export {
global global
} else { } else {
panic!("wasmtime export is not memory") panic!("wasmtime export is not global")
}; };
let ty = GlobalType::from_wasmtime_global(&global); // The original export is coming from wasmtime_runtime itself we should
// support all the types coming out of it, so assert such here.
let ty = GlobalType::from_wasmtime_global(&global)
.expect("core wasm global type should be supported");
Global { Global {
inner: Rc::new(GlobalInner {
_store: store.clone(), _store: store.clone(),
r#type: ty, ty: ty,
wasmtime_export: export, wasmtime_export: export,
wasmtime_state: None, wasmtime_state: None,
}),
} }
} }
} }
#[derive(Clone)]
pub struct Table { pub struct Table {
store: Store, store: Store,
r#type: TableType, ty: TableType,
wasmtime_handle: InstanceHandle, wasmtime_handle: InstanceHandle,
wasmtime_export: wasmtime_runtime::Export, wasmtime_export: wasmtime_runtime::Export,
} }
@@ -299,13 +317,13 @@ fn set_table_item(
} }
impl Table { impl Table {
pub fn new(store: &Store, r#type: TableType, init: Val) -> Table { pub fn new(store: &Store, ty: TableType, init: Val) -> Table {
match r#type.element() { match ty.element() {
ValType::FuncRef => (), ValType::FuncRef => (),
_ => panic!("table is not for funcref"), _ => panic!("table is not for funcref"),
} }
let (mut wasmtime_handle, wasmtime_export) = let (mut wasmtime_handle, wasmtime_export) =
generate_table_export(&r#type).expect("generated table"); generate_table_export(&ty).expect("generated table");
// Initialize entries with the init value. // Initialize entries with the init value.
match wasmtime_export { match wasmtime_export {
@@ -323,14 +341,14 @@ impl Table {
Table { Table {
store: store.clone(), store: store.clone(),
r#type, ty,
wasmtime_handle, wasmtime_handle,
wasmtime_export, wasmtime_export,
} }
} }
pub fn r#type(&self) -> &TableType { pub fn ty(&self) -> &TableType {
&self.r#type &self.ty
} }
fn wasmtime_table_index(&self) -> wasm::DefinedTableIndex { fn wasmtime_table_index(&self) -> wasm::DefinedTableIndex {
@@ -362,9 +380,9 @@ impl Table {
} }
} }
pub fn grow(&mut self, delta: u32, init: Val) -> bool { pub fn grow(&self, delta: u32, init: Val) -> bool {
let index = self.wasmtime_table_index(); let index = self.wasmtime_table_index();
if let Some(len) = self.wasmtime_handle.table_grow(index, delta) { if let Some(len) = self.wasmtime_handle.clone().table_grow(index, delta) {
let mut wasmtime_handle = self.wasmtime_handle.clone(); let mut wasmtime_handle = self.wasmtime_handle.clone();
for i in 0..delta { for i in 0..delta {
let i = len - (delta - i); let i = len - (delta - i);
@@ -395,34 +413,35 @@ impl Table {
let ty = TableType::from_wasmtime_table(&table.table); let ty = TableType::from_wasmtime_table(&table.table);
Table { Table {
store: store.clone(), store: store.clone(),
r#type: ty, ty: ty,
wasmtime_handle: instance_handle, wasmtime_handle: instance_handle,
wasmtime_export: export, wasmtime_export: export,
} }
} }
} }
#[derive(Clone)]
pub struct Memory { pub struct Memory {
_store: Store, _store: Store,
r#type: MemoryType, ty: MemoryType,
wasmtime_handle: InstanceHandle, wasmtime_handle: InstanceHandle,
wasmtime_export: wasmtime_runtime::Export, wasmtime_export: wasmtime_runtime::Export,
} }
impl Memory { impl Memory {
pub fn new(store: &Store, r#type: MemoryType) -> Memory { pub fn new(store: &Store, ty: MemoryType) -> Memory {
let (wasmtime_handle, wasmtime_export) = let (wasmtime_handle, wasmtime_export) =
generate_memory_export(&r#type).expect("generated memory"); generate_memory_export(&ty).expect("generated memory");
Memory { Memory {
_store: store.clone(), _store: store.clone(),
r#type, ty,
wasmtime_handle, wasmtime_handle,
wasmtime_export, wasmtime_export,
} }
} }
pub fn r#type(&self) -> &MemoryType { pub fn ty(&self) -> &MemoryType {
&self.r#type &self.ty
} }
fn wasmtime_memory_definition(&self) -> *mut wasmtime_runtime::VMMemoryDefinition { fn wasmtime_memory_definition(&self) -> *mut wasmtime_runtime::VMMemoryDefinition {
@@ -453,12 +472,15 @@ impl Memory {
(self.data_size() / wasmtime_environ::WASM_PAGE_SIZE as usize) as u32 (self.data_size() / wasmtime_environ::WASM_PAGE_SIZE as usize) as u32
} }
pub fn grow(&mut self, delta: u32) -> bool { pub fn grow(&self, delta: u32) -> bool {
match self.wasmtime_export { match self.wasmtime_export {
wasmtime_runtime::Export::Memory { definition, .. } => { wasmtime_runtime::Export::Memory { definition, .. } => {
let definition = unsafe { &(*definition) }; let definition = unsafe { &(*definition) };
let index = self.wasmtime_handle.memory_index(definition); let index = self.wasmtime_handle.memory_index(definition);
self.wasmtime_handle.memory_grow(index, delta).is_some() self.wasmtime_handle
.clone()
.memory_grow(index, delta)
.is_some()
} }
_ => panic!("memory definition not found"), _ => panic!("memory definition not found"),
} }
@@ -481,7 +503,7 @@ impl Memory {
let ty = MemoryType::from_wasmtime_memory(&memory.memory); let ty = MemoryType::from_wasmtime_memory(&memory.memory);
Memory { Memory {
_store: store.clone(), _store: store.clone(),
r#type: ty, ty: ty,
wasmtime_handle: instance_handle, wasmtime_handle: instance_handle,
wasmtime_export: export, wasmtime_export: export,
} }

View File

@@ -9,45 +9,50 @@ use anyhow::{Error, Result};
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::rc::Rc; use std::rc::Rc;
use wasmtime_jit::{instantiate, Resolver, SetupError}; use wasmtime_jit::{CompiledModule, Resolver};
use wasmtime_runtime::{Export, InstanceHandle, InstantiationError}; use wasmtime_runtime::{Export, InstanceHandle, InstantiationError};
struct SimpleResolver { struct SimpleResolver<'a> {
imports: Vec<(String, String, Extern)>, imports: &'a [Extern],
} }
impl Resolver for SimpleResolver { impl Resolver for SimpleResolver<'_> {
fn resolve(&mut self, name: &str, field: &str) -> Option<Export> { fn resolve(&mut self, idx: u32, _name: &str, _field: &str) -> Option<Export> {
// TODO speedup lookup
self.imports self.imports
.iter_mut() .get(idx as usize)
.find(|(n, f, _)| name == n && field == f) .map(|i| i.get_wasmtime_export())
.map(|(_, _, e)| e.get_wasmtime_export())
} }
} }
pub fn instantiate_in_context( fn instantiate_in_context(
store: &Store,
data: &[u8], data: &[u8],
imports: Vec<(String, String, Extern)>, imports: &[Extern],
module_name: Option<String>, module_name: Option<&str>,
context: Context, context: Context,
exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>>, exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>>,
) -> Result<(InstanceHandle, HashSet<Context>), Error> { ) -> Result<(InstanceHandle, HashSet<Context>), Error> {
let mut contexts = HashSet::new(); let mut contexts = HashSet::new();
let debug_info = context.debug_info(); let debug_info = context.debug_info();
let mut resolver = SimpleResolver { imports }; let mut resolver = SimpleResolver { imports };
let instance = instantiate( let mut compiled_module = CompiledModule::new(
&mut context.compiler(), &mut context.compiler(),
data, data,
module_name, module_name,
&mut resolver, &mut resolver,
exports, exports,
debug_info, debug_info,
) )?;
.map_err(|e| -> Error {
// Register all module signatures
for signature in compiled_module.module().signatures.values() {
store.register_wasmtime_signature(signature);
}
let instance = compiled_module.instantiate().map_err(|e| -> Error {
if let Some(trap) = take_api_trap() { if let Some(trap) = take_api_trap() {
trap.into() trap.into()
} else if let SetupError::Instantiate(InstantiationError::StartTrap(msg)) = e { } else if let InstantiationError::StartTrap(msg) = e {
Trap::new(msg).into() Trap::new(msg).into()
} else { } else {
e.into() e.into()
@@ -70,19 +75,15 @@ pub struct Instance {
} }
impl Instance { impl Instance {
pub fn new(store: &Store, module: &Module, externs: &[Extern]) -> Result<Instance, Error> { pub fn new(module: &Module, externs: &[Extern]) -> Result<Instance, Error> {
let store = module.store();
let context = store.context().clone(); let context = store.context().clone();
let exports = store.global_exports().clone(); let exports = store.global_exports().clone();
let imports = module
.imports()
.iter()
.zip(externs.iter())
.map(|(i, e)| (i.module().to_string(), i.name().to_string(), e.clone()))
.collect::<Vec<_>>();
let (mut instance_handle, contexts) = instantiate_in_context( let (mut instance_handle, contexts) = instantiate_in_context(
module.store(),
module.binary().expect("binary"), module.binary().expect("binary"),
imports, externs,
module.name().cloned(), module.name(),
context, context,
exports, exports,
)?; )?;
@@ -108,14 +109,27 @@ impl Instance {
}) })
} }
pub fn exports(&self) -> &[Extern] { /// Returns the associated [`Store`] that this `Instance` is compiled into.
&self.exports ///
/// This is the [`Store`] that generally serves as a sort of global cache
/// for various instance-related things.
pub fn store(&self) -> &Store {
self.module.store()
} }
/// Returns the associated [`Module`] that this `Instance` instantiated.
///
/// The corresponding [`Module`] here is a static version of this `Instance`
/// which can be used to learn information such as naming information about
/// various functions.
pub fn module(&self) -> &Module { pub fn module(&self) -> &Module {
&self.module &self.module
} }
pub fn exports(&self) -> &[Extern] {
&self.exports
}
pub fn find_export_by_name(&self, name: &str) -> Option<&Extern> { pub fn find_export_by_name(&self, name: &str) -> Option<&Extern> {
let (i, _) = self let (i, _) = self
.module .module
@@ -140,7 +154,14 @@ impl Instance {
// imported into this store using the from_handle() method. // imported into this store using the from_handle() method.
let _ = store.register_wasmtime_signature(signature); let _ = store.register_wasmtime_signature(signature);
} }
let extern_type = ExternType::from_wasmtime_export(&export);
// We should support everything supported by wasmtime_runtime, or
// otherwise we've got a bug in this crate, so panic if anything
// fails to convert here.
let extern_type = match ExternType::from_wasmtime_export(&export) {
Some(ty) => ty,
None => panic!("unsupported core wasm external type {:?}", export),
};
exports_types.push(ExportType::new(name, extern_type)); exports_types.push(ExportType::new(name, extern_type));
exports.push(Extern::from_wasmtime_export( exports.push(Extern::from_wasmtime_export(
store, store,
@@ -175,29 +196,29 @@ cfg_if::cfg_if! {
impl Instance { impl Instance {
/// The signal handler must be /// The signal handler must be
/// [async-signal-safe](http://man7.org/linux/man-pages/man7/signal-safety.7.html). /// [async-signal-safe](http://man7.org/linux/man-pages/man7/signal-safety.7.html).
pub fn set_signal_handler<H>(&mut self, handler: H) pub fn set_signal_handler<H>(&self, handler: H)
where where
H: 'static + Fn(libc::c_int, *const libc::siginfo_t, *const libc::c_void) -> bool, H: 'static + Fn(libc::c_int, *const libc::siginfo_t, *const libc::c_void) -> bool,
{ {
self.instance_handle.set_signal_handler(handler); self.instance_handle.clone().set_signal_handler(handler);
} }
} }
} else if #[cfg(target_os = "windows")] { } else if #[cfg(target_os = "windows")] {
impl Instance { impl Instance {
pub fn set_signal_handler<H>(&mut self, handler: H) pub fn set_signal_handler<H>(&self, handler: H)
where where
H: 'static + Fn(winapi::um::winnt::EXCEPTION_POINTERS) -> bool, H: 'static + Fn(winapi::um::winnt::EXCEPTION_POINTERS) -> bool,
{ {
self.instance_handle.set_signal_handler(handler); self.instance_handle.clone().set_signal_handler(handler);
} }
} }
} else if #[cfg(target_os = "macos")] { } else if #[cfg(target_os = "macos")] {
impl Instance { impl Instance {
pub fn set_signal_handler<H>(&mut self, handler: H) pub fn set_signal_handler<H>(&self, handler: H)
where where
H: 'static + Fn(libc::c_int, *const libc::siginfo_t, *const libc::c_void) -> bool, H: 'static + Fn(libc::c_int, *const libc::siginfo_t, *const libc::c_void) -> bool,
{ {
self.instance_handle.set_signal_handler(handler); self.instance_handle.clone().set_signal_handler(handler);
} }
} }
} }

View File

@@ -6,8 +6,6 @@
//! and there to implement Rust idioms. This crate also defines the actual C API //! and there to implement Rust idioms. This crate also defines the actual C API
//! itself for consumption from other languages. //! itself for consumption from other languages.
#![allow(improper_ctypes)]
mod callable; mod callable;
mod context; mod context;
mod externals; mod externals;
@@ -26,7 +24,7 @@ pub use crate::callable::Callable;
pub use crate::externals::*; pub use crate::externals::*;
pub use crate::instance::Instance; pub use crate::instance::Instance;
pub use crate::module::Module; pub use crate::module::Module;
pub use crate::r#ref::{AnyRef, HostInfo, HostRef}; pub use crate::r#ref::AnyRef;
pub use crate::runtime::{Config, Engine, OptLevel, Store, Strategy}; pub use crate::runtime::{Config, Engine, OptLevel, Store, Strategy};
pub use crate::trap::{FrameInfo, Trap}; pub use crate::trap::{FrameInfo, Trap};
pub use crate::types::*; pub use crate::types::*;

View File

@@ -56,9 +56,210 @@ fn into_table_type(tt: wasmparser::TableType) -> TableType {
TableType::new(ty, limits) TableType::new(ty, limits)
} }
fn read_imports_and_exports( #[derive(Clone)]
binary: &[u8], pub(crate) enum ModuleCodeSource {
) -> Result<(Box<[ImportType]>, Box<[ExportType]>, Option<String>)> { Binary(Box<[u8]>),
Unknown,
}
/// A compiled WebAssembly module, ready to be instantiated.
///
/// A `Module` is a compiled in-memory representation of an input WebAssembly
/// binary. A `Module` is then used to create an [`Instance`](crate::Instance)
/// through an instantiation process. You cannot call functions or fetch
/// globals, for example, on a `Module` because it's purely a code
/// representation. Instead you'll need to create an
/// [`Instance`](crate::Instance) to interact with the wasm module.
///
/// ## Modules and `Clone`
///
/// Using `clone` on a `Module` is a cheap operation. It will not create an
/// entirely new module, but rather just a new reference to the existing module.
/// In other words it's a shallow copy, not a deep copy.
#[derive(Clone)]
pub struct Module {
// FIXME(#777) should be `Arc` and this type should be thread-safe
inner: Rc<ModuleInner>,
}
struct ModuleInner {
store: Store,
source: ModuleCodeSource,
imports: Box<[ImportType]>,
exports: Box<[ExportType]>,
name: Option<String>,
}
impl Module {
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
/// data.
///
/// The `binary` data provided must be a [binary-encoded][binary]
/// WebAssembly module. This means that the data for the wasm module must be
/// loaded in-memory if it's present elsewhere, for example on disk.
/// Additionally this requires that the entire binary is loaded into memory
/// all at once, this API does not support streaming compilation of a
/// module.
///
/// The WebAssembly binary will be decoded and validated. It will also be
/// compiled according to the configuration of the provided `store` and
/// cached in this type.
///
/// The provided `store` is a global cache for compiled resources as well as
/// configuration for what wasm features are enabled. It's recommended to
/// share a `store` among modules if possible.
///
/// # Errors
///
/// This function may fail and return an error. Errors may include
/// situations such as:
///
/// * The binary provided could not be decoded because it's not a valid
/// WebAssembly binary
/// * The WebAssembly binary may not validate (e.g. contains type errors)
/// * Implementation-specific limits were exceeded with a valid binary (for
/// example too many locals)
/// * The wasm binary may use features that are not enabled in the
/// configuration of `store`
///
/// The error returned should contain full information about why module
/// creation failed if one is returned.
///
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
pub fn new(store: &Store, binary: &[u8]) -> Result<Module> {
Module::validate(store, binary)?;
// Note that the call to `unsafe` here should be ok because we
// previously validated the binary, meaning we're guaranteed to pass a
// valid binary for `store`.
unsafe { Module::new_unchecked(store, binary) }
}
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
/// data. The provided `name` will be used in traps/backtrace details.
///
/// See [`Module::new`] for other details.
pub fn new_with_name(store: &Store, binary: &[u8], name: &str) -> Result<Module> {
let mut ret = Module::new(store, binary)?;
Rc::get_mut(&mut ret.inner).unwrap().name = Some(name.to_string());
Ok(ret)
}
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
/// data, skipping validation and asserting that `binary` is a valid
/// WebAssembly module.
///
/// This function is the same as [`Module::new`] except that it skips the
/// call to [`Module::validate`]. This means that the WebAssembly binary is
/// not validated for correctness and it is simply assumed as valid.
///
/// For more information about creation of a module and the `store` argument
/// see the documentation of [`Module::new`].
///
/// # Unsafety
///
/// This function is `unsafe` due to the unchecked assumption that the input
/// `binary` is valid. If the `binary` is not actually a valid wasm binary it
/// may cause invalid machine code to get generated, cause panics, etc.
///
/// It is only safe to call this method if [`Module::validate`] succeeds on
/// the same arguments passed to this function.
///
/// # Errors
///
/// This function may fail for many of the same reasons as [`Module::new`].
/// While this assumes that the binary is valid it still needs to actually
/// be somewhat valid for decoding purposes, and the basics of decoding can
/// still fail.
pub unsafe fn new_unchecked(store: &Store, binary: &[u8]) -> Result<Module> {
let mut ret = Module::empty(store);
ret.read_imports_and_exports(binary)?;
Ok(ret)
}
/// Validates `binary` input data as a WebAssembly binary given the
/// configuration in `store`.
///
/// This function will perform a speedy validation of the `binary` input
/// WebAssembly module (which is in [binary form][binary]) and return either
/// `Ok` or `Err` depending on the results of validation. The `store`
/// argument indicates configuration for WebAssembly features, for example,
/// which are used to indicate what should be valid and what shouldn't be.
///
/// Validation automatically happens as part of [`Module::new`], but is a
/// requirement for [`Module::new_unchecked`] to be safe.
///
/// # Errors
///
/// If validation fails for any reason (type check error, usage of a feature
/// that wasn't enabled, etc) then an error with a description of the
/// validation issue will be returned.
///
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
pub fn validate(store: &Store, binary: &[u8]) -> Result<()> {
let features = store.engine().config.features.clone();
let config = ValidatingParserConfig {
operator_config: OperatorValidatorConfig {
enable_threads: features.threads,
enable_reference_types: features.reference_types,
enable_bulk_memory: features.bulk_memory,
enable_simd: features.simd,
enable_multi_value: features.multi_value,
},
};
validate(binary, Some(config)).map_err(Error::new)
}
pub fn from_exports(store: &Store, exports: Box<[ExportType]>) -> Self {
let mut ret = Module::empty(store);
Rc::get_mut(&mut ret.inner).unwrap().exports = exports;
return ret;
}
fn empty(store: &Store) -> Self {
Module {
inner: Rc::new(ModuleInner {
store: store.clone(),
source: ModuleCodeSource::Unknown,
imports: Box::new([]),
exports: Box::new([]),
name: None,
}),
}
}
pub(crate) fn binary(&self) -> Option<&[u8]> {
match &self.inner.source {
ModuleCodeSource::Binary(b) => Some(b),
_ => None,
}
}
/// Returns identifier/name that this [`Module`] has. This name
/// is used in traps/backtrace details.
pub fn name(&self) -> Option<&str> {
self.inner.name.as_deref()
}
/// Returns the list of imports that this [`Module`] has and must be
/// satisfied.
pub fn imports(&self) -> &[ImportType] {
&self.inner.imports
}
/// Returns the list of exports that this [`Module`] has and will be
/// available after instantiation.
pub fn exports(&self) -> &[ExportType] {
&self.inner.exports
}
/// Returns the [`Store`] that this [`Module`] was compiled into.
pub fn store(&self) -> &Store {
&self.inner.store
}
fn read_imports_and_exports(&mut self, binary: &[u8]) -> Result<()> {
let inner = Rc::get_mut(&mut self.inner).unwrap();
inner.source = ModuleCodeSource::Binary(binary.into());
let mut reader = ModuleReader::new(binary)?; let mut reader = ModuleReader::new(binary)?;
let mut imports = Vec::new(); let mut imports = Vec::new();
let mut exports = Vec::new(); let mut exports = Vec::new();
@@ -67,7 +268,6 @@ fn read_imports_and_exports(
let mut func_sig = Vec::new(); let mut func_sig = Vec::new();
let mut sigs = Vec::new(); let mut sigs = Vec::new();
let mut globals = Vec::new(); let mut globals = Vec::new();
let mut module_name = None;
while !reader.eof() { while !reader.eof() {
let section = reader.read()?; let section = reader.read()?;
match section.code { match section.code {
@@ -169,7 +369,7 @@ fn read_imports_and_exports(
while let Ok(entry) = reader.read() { while let Ok(entry) = reader.read() {
if let Name::Module(name) = entry { if let Name::Module(name) = entry {
if let Ok(name) = name.get_name() { if let Ok(name) = name.get_name() {
module_name = Some(name.to_string()); inner.name = Some(name.to_string());
} }
break; break;
} }
@@ -181,219 +381,9 @@ fn read_imports_and_exports(
} }
} }
} }
Ok((
imports.into_boxed_slice(),
exports.into_boxed_slice(),
module_name,
))
}
#[derive(Clone)] inner.imports = imports.into();
pub(crate) enum ModuleCodeSource { inner.exports = exports.into();
Binary(Box<[u8]>), Ok(())
Unknown,
}
/// A compiled WebAssembly module, ready to be instantiated.
///
/// A `Module` is a compiled in-memory representation of an input WebAssembly
/// binary. A `Module` is then used to create an [`Instance`](crate::Instance)
/// through an instantiation process. You cannot call functions or fetch
/// globals, for example, on a `Module` because it's purely a code
/// representation. Instead you'll need to create an
/// [`Instance`](crate::Instance) to interact with the wasm module.
///
/// ## Modules and `Clone`
///
/// Using `clone` on a `Module` is a cheap operation. It will not create an
/// entirely new module, but rather just a new reference to the existing module.
/// In other words it's a shallow copy, not a deep copy.
#[derive(Clone)]
pub struct Module {
// FIXME(#777) should be `Arc` and this type should be thread-safe
inner: Rc<ModuleInner>,
}
struct ModuleInner {
store: Store,
source: ModuleCodeSource,
imports: Box<[ImportType]>,
exports: Box<[ExportType]>,
name: Option<String>,
}
impl Module {
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
/// data.
///
/// The `binary` data provided must be a [binary-encoded][binary]
/// WebAssembly module. This means that the data for the wasm module must be
/// loaded in-memory if it's present elsewhere, for example on disk.
/// Additionally this requires that the entire binary is loaded into memory
/// all at once, this API does not support streaming compilation of a
/// module.
///
/// The WebAssembly binary will be decoded and validated. It will also be
/// compiled according to the configuration of the provided `store` and
/// cached in this type.
///
/// The provided `store` is a global cache for compiled resources as well as
/// configuration for what wasm features are enabled. It's recommended to
/// share a `store` among modules if possible.
///
/// # Errors
///
/// This function may fail and return an error. Errors may include
/// situations such as:
///
/// * The binary provided could not be decoded because it's not a valid
/// WebAssembly binary
/// * The WebAssembly binary may not validate (e.g. contains type errors)
/// * Implementation-specific limits were exceeded with a valid binary (for
/// example too many locals)
/// * The wasm binary may use features that are not enabled in the
/// configuration of `store`
///
/// The error returned should contain full information about why module
/// creation failed if one is returned.
///
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
pub fn new(store: &Store, binary: &[u8]) -> Result<Module> {
Self::validate(store, binary)?;
// Note that the call to `unsafe` here should be ok because we
// previously validated the binary, meaning we're guaranteed to pass a
// valid binary for `store`.
unsafe { Self::create(store, binary, None) }
}
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
/// data. The provided `name` will be used in traps/backtrace details.
///
/// See [`Module::new`] for other details.
pub fn new_with_name(store: &Store, binary: &[u8], name: String) -> Result<Module> {
Self::validate(store, binary)?;
unsafe { Self::create(store, binary, Some(name)) }
}
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
/// data, skipping validation and asserting that `binary` is a valid
/// WebAssembly module.
///
/// This function is the same as [`Module::new`] except that it skips the
/// call to [`Module::validate`]. This means that the WebAssembly binary is
/// not validated for correctness and it is simply assumed as valid.
///
/// For more information about creation of a module and the `store` argument
/// see the documentation of [`Module::new`].
///
/// # Unsafety
///
/// This function is `unsafe` due to the unchecked assumption that the input
/// `binary` is valid. If the `binary` is not actually a valid wasm binary it
/// may cause invalid machine code to get generated, cause panics, etc.
///
/// It is only safe to call this method if [`Module::validate`] succeeds on
/// the same arguments passed to this function.
///
/// # Errors
///
/// This function may fail for many of the same reasons as [`Module::new`].
/// While this assumes that the binary is valid it still needs to actually
/// be somewhat valid for decoding purposes, and the basics of decoding can
/// still fail.
pub unsafe fn new_unchecked(store: &Store, binary: &[u8]) -> Result<Module> {
Self::create(store, binary, None)
}
unsafe fn create(
store: &Store,
binary: &[u8],
name_override: Option<String>,
) -> Result<Module> {
let (imports, exports, name) = read_imports_and_exports(binary)?;
Ok(Module {
inner: Rc::new(ModuleInner {
store: store.clone(),
source: ModuleCodeSource::Binary(binary.into()),
imports,
exports,
name: name_override.or(name),
}),
})
}
/// Validates `binary` input data as a WebAssembly binary given the
/// configuration in `store`.
///
/// This function will perform a speedy validation of the `binary` input
/// WebAssembly module (which is in [binary form][binary]) and return either
/// `Ok` or `Err` depending on the results of validation. The `store`
/// argument indicates configuration for WebAssembly features, for example,
/// which are used to indicate what should be valid and what shouldn't be.
///
/// Validation automatically happens as part of [`Module::new`], but is a
/// requirement for [`Module::new_unchecked`] to be safe.
///
/// # Errors
///
/// If validation fails for any reason (type check error, usage of a feature
/// that wasn't enabled, etc) then an error with a description of the
/// validation issue will be returned.
///
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
pub fn validate(store: &Store, binary: &[u8]) -> Result<()> {
let features = store.engine().config.features.clone();
let config = ValidatingParserConfig {
operator_config: OperatorValidatorConfig {
enable_threads: features.threads,
enable_reference_types: features.reference_types,
enable_bulk_memory: features.bulk_memory,
enable_simd: features.simd,
enable_multi_value: features.multi_value,
},
};
validate(binary, Some(config)).map_err(Error::new)
}
pub fn from_exports(store: &Store, exports: Box<[ExportType]>) -> Self {
Module {
inner: Rc::new(ModuleInner {
store: store.clone(),
source: ModuleCodeSource::Unknown,
imports: Box::new([]),
exports,
name: None,
}),
}
}
pub(crate) fn binary(&self) -> Option<&[u8]> {
match &self.inner.source {
ModuleCodeSource::Binary(b) => Some(b),
_ => None,
}
}
/// Returns identifier/name that this [`Module`] has. This name
/// is used in traps/backtrace details.
pub fn name(&self) -> Option<&String> {
self.inner.name.as_ref()
}
/// Returns the list of imports that this [`Module`] has and must be
/// satisfied.
pub fn imports(&self) -> &[ImportType] {
&self.inner.imports
}
/// Returns the list of exports that this [`Module`] has and will be
/// available after instantiation.
pub fn exports(&self) -> &[ExportType] {
&self.inner.exports
}
/// Returns the [`Store`] that this [`Module`] was compiled into.
pub fn store(&self) -> &Store {
&self.inner.store
} }
} }

View File

@@ -397,6 +397,10 @@ impl Store {
.get(&type_index) .get(&type_index)
.cloned() .cloned()
} }
pub(crate) fn ptr_eq(a: &Store, b: &Store) -> bool {
Rc::ptr_eq(&a.inner, &b.inner)
}
} }
impl Default for Store { impl Default for Store {

View File

@@ -3,7 +3,7 @@
use super::create_handle::create_handle; use super::create_handle::create_handle;
use super::trap::{record_api_trap, TrapSink, API_TRAP_CODE}; use super::trap::{record_api_trap, TrapSink, API_TRAP_CODE};
use crate::{Callable, FuncType, Store, Val}; use crate::{Callable, FuncType, Store, Val};
use anyhow::Result; use anyhow::{bail, Result};
use std::cmp; use std::cmp;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::rc::Rc; use std::rc::Rc;
@@ -234,7 +234,10 @@ pub fn create_handle_with_function(
func: &Rc<dyn Callable + 'static>, func: &Rc<dyn Callable + 'static>,
store: &Store, store: &Store,
) -> Result<InstanceHandle> { ) -> Result<InstanceHandle> {
let sig = ft.get_wasmtime_signature().clone(); let sig = match ft.get_wasmtime_signature() {
Some(sig) => sig.clone(),
None => bail!("not a supported core wasm signature {:?}", ft),
};
let isa = { let isa = {
let isa_builder = native::builder(); let isa_builder = native::builder();

View File

@@ -1,6 +1,6 @@
use super::create_handle::create_handle; use super::create_handle::create_handle;
use crate::{GlobalType, Mutability, Val}; use crate::{GlobalType, Mutability, Val};
use anyhow::Result; use anyhow::{bail, Result};
use wasmtime_environ::entity::PrimaryMap; use wasmtime_environ::entity::PrimaryMap;
use wasmtime_environ::{wasm, Module}; use wasmtime_environ::{wasm, Module};
use wasmtime_runtime::{InstanceHandle, VMGlobalDefinition}; use wasmtime_runtime::{InstanceHandle, VMGlobalDefinition};
@@ -24,7 +24,10 @@ pub fn create_global(gt: &GlobalType, val: Val) -> Result<(wasmtime_runtime::Exp
} }
let global = wasm::Global { let global = wasm::Global {
ty: gt.content().get_wasmtime_type(), ty: match gt.content().get_wasmtime_type() {
Some(t) => t,
None => bail!("cannot support {:?} as a wasm global type", gt.content()),
},
mutability: match gt.mutability() { mutability: match gt.mutability() {
Mutability::Const => false, Mutability::Const => false,
Mutability::Var => true, Mutability::Var => true,

View File

@@ -1,6 +1,6 @@
use super::create_handle::create_handle; use super::create_handle::create_handle;
use crate::{TableType, ValType}; use crate::{TableType, ValType};
use anyhow::Result; use anyhow::{bail, Result};
use wasmtime_environ::entity::PrimaryMap; use wasmtime_environ::entity::PrimaryMap;
use wasmtime_environ::{wasm, Module}; use wasmtime_environ::{wasm, Module};
use wasmtime_runtime::InstanceHandle; use wasmtime_runtime::InstanceHandle;
@@ -13,7 +13,10 @@ pub fn create_handle_with_table(table: &TableType) -> Result<InstanceHandle> {
maximum: table.limits().max(), maximum: table.limits().max(),
ty: match table.element() { ty: match table.element() {
ValType::FuncRef => wasm::TableElementType::Func, ValType::FuncRef => wasm::TableElementType::Func,
_ => wasm::TableElementType::Val(table.element().get_wasmtime_type()), _ => match table.element().get_wasmtime_type() {
Some(t) => wasm::TableElementType::Val(t),
None => bail!("cannot support {:?} as a table element", table.element()),
},
}, },
}; };
let tunable = Default::default(); let tunable = Default::default();

View File

@@ -84,25 +84,25 @@ impl ValType {
} }
} }
pub(crate) fn get_wasmtime_type(&self) -> ir::Type { pub(crate) fn get_wasmtime_type(&self) -> Option<ir::Type> {
match self { match self {
ValType::I32 => ir::types::I32, ValType::I32 => Some(ir::types::I32),
ValType::I64 => ir::types::I64, ValType::I64 => Some(ir::types::I64),
ValType::F32 => ir::types::F32, ValType::F32 => Some(ir::types::F32),
ValType::F64 => ir::types::F64, ValType::F64 => Some(ir::types::F64),
ValType::V128 => ir::types::I8X16, ValType::V128 => Some(ir::types::I8X16),
_ => unimplemented!("get_wasmtime_type other"), _ => None,
} }
} }
pub(crate) fn from_wasmtime_type(ty: ir::Type) -> ValType { pub(crate) fn from_wasmtime_type(ty: ir::Type) -> Option<ValType> {
match ty { match ty {
ir::types::I32 => ValType::I32, ir::types::I32 => Some(ValType::I32),
ir::types::I64 => ValType::I64, ir::types::I64 => Some(ValType::I64),
ir::types::F32 => ValType::F32, ir::types::F32 => Some(ValType::F32),
ir::types::F64 => ValType::F64, ir::types::F64 => Some(ValType::F64),
ir::types::I8X16 => ValType::V128, ir::types::I8X16 => Some(ValType::V128),
_ => unimplemented!("from_wasmtime_type other"), _ => None,
} }
} }
} }
@@ -153,26 +153,29 @@ impl ExternType {
(Table(TableType) table unwrap_table) (Table(TableType) table unwrap_table)
(Memory(MemoryType) memory unwrap_memory) (Memory(MemoryType) memory unwrap_memory)
} }
pub(crate) fn from_wasmtime_export(export: &wasmtime_runtime::Export) -> Self {
match export { /// Returns `None` if the sub-type fails to get converted, see documentation
/// for sub-types about what may fail.
pub(crate) fn from_wasmtime_export(export: &wasmtime_runtime::Export) -> Option<Self> {
Some(match export {
wasmtime_runtime::Export::Function { signature, .. } => { wasmtime_runtime::Export::Function { signature, .. } => {
ExternType::Func(FuncType::from_wasmtime_signature(signature.clone())) ExternType::Func(FuncType::from_wasmtime_signature(signature.clone())?)
} }
wasmtime_runtime::Export::Memory { memory, .. } => { wasmtime_runtime::Export::Memory { memory, .. } => {
ExternType::Memory(MemoryType::from_wasmtime_memory(&memory.memory)) ExternType::Memory(MemoryType::from_wasmtime_memory(&memory.memory))
} }
wasmtime_runtime::Export::Global { global, .. } => { wasmtime_runtime::Export::Global { global, .. } => {
ExternType::Global(GlobalType::from_wasmtime_global(&global)) ExternType::Global(GlobalType::from_wasmtime_global(&global)?)
} }
wasmtime_runtime::Export::Table { table, .. } => { wasmtime_runtime::Export::Table { table, .. } => {
ExternType::Table(TableType::from_wasmtime_table(&table.table)) ExternType::Table(TableType::from_wasmtime_table(&table.table))
} }
} })
} }
} }
// Function Types // Function Types
fn from_wasmtime_abiparam(param: &ir::AbiParam) -> ValType { fn from_wasmtime_abiparam(param: &ir::AbiParam) -> Option<ValType> {
assert_eq!(param.purpose, ir::ArgumentPurpose::Normal); assert_eq!(param.purpose, ir::ArgumentPurpose::Normal);
ValType::from_wasmtime_type(param.value_type) ValType::from_wasmtime_type(param.value_type)
} }
@@ -184,7 +187,12 @@ fn from_wasmtime_abiparam(param: &ir::AbiParam) -> ValType {
pub struct FuncType { pub struct FuncType {
params: Box<[ValType]>, params: Box<[ValType]>,
results: Box<[ValType]>, results: Box<[ValType]>,
signature: ir::Signature, // `None` if params/results aren't wasm-compatible (e.g. use wasm interface
// types), or if they're not implemented (like anyref at the time of this
// writing)
//
// `Some` if they're all wasm-compatible.
signature: Option<ir::Signature>,
} }
impl FuncType { impl FuncType {
@@ -196,15 +204,18 @@ impl FuncType {
use wasmtime_environ::ir::{types, AbiParam, ArgumentPurpose, Signature}; use wasmtime_environ::ir::{types, AbiParam, ArgumentPurpose, Signature};
use wasmtime_jit::native; use wasmtime_jit::native;
let call_conv = native::call_conv(); let call_conv = native::call_conv();
let signature: Signature = { let signature = params
let mut params = params
.iter() .iter()
.map(|p| AbiParam::new(p.get_wasmtime_type())) .map(|p| p.get_wasmtime_type().map(AbiParam::new))
.collect::<Vec<_>>(); .collect::<Option<Vec<_>>>()
let returns = results .and_then(|params| {
results
.iter() .iter()
.map(|p| AbiParam::new(p.get_wasmtime_type())) .map(|p| p.get_wasmtime_type().map(AbiParam::new))
.collect::<Vec<_>>(); .collect::<Option<Vec<_>>>()
.map(|results| (params, results))
})
.map(|(mut params, returns)| {
params.insert(0, AbiParam::special(types::I64, ArgumentPurpose::VMContext)); params.insert(0, AbiParam::special(types::I64, ArgumentPurpose::VMContext));
Signature { Signature {
@@ -212,7 +223,7 @@ impl FuncType {
returns, returns,
call_conv, call_conv,
} }
}; });
FuncType { FuncType {
params, params,
results, results,
@@ -230,27 +241,33 @@ impl FuncType {
&self.results &self.results
} }
pub(crate) fn get_wasmtime_signature(&self) -> &ir::Signature { /// Returns `Some` if this function signature was compatible with cranelift,
&self.signature /// or `None` if one of the types/results wasn't supported or compatible
/// with cranelift.
pub(crate) fn get_wasmtime_signature(&self) -> Option<&ir::Signature> {
self.signature.as_ref()
} }
pub(crate) fn from_wasmtime_signature(signature: ir::Signature) -> FuncType { /// Returns `None` if any types in the signature can't be converted to the
/// types in this crate, but that should very rarely happen and largely only
/// indicate a bug in our cranelift integration.
pub(crate) fn from_wasmtime_signature(signature: ir::Signature) -> Option<FuncType> {
let params = signature let params = signature
.params .params
.iter() .iter()
.filter(|p| p.purpose == ir::ArgumentPurpose::Normal) .filter(|p| p.purpose == ir::ArgumentPurpose::Normal)
.map(|p| from_wasmtime_abiparam(p)) .map(|p| from_wasmtime_abiparam(p))
.collect::<Vec<_>>(); .collect::<Option<Vec<_>>>()?;
let results = signature let results = signature
.returns .returns
.iter() .iter()
.map(|p| from_wasmtime_abiparam(p)) .map(|p| from_wasmtime_abiparam(p))
.collect::<Vec<_>>(); .collect::<Option<Vec<_>>>()?;
FuncType { Some(FuncType {
params: params.into_boxed_slice(), params: params.into_boxed_slice(),
results: results.into_boxed_slice(), results: results.into_boxed_slice(),
signature, signature: Some(signature),
} })
} }
} }
@@ -287,14 +304,16 @@ impl GlobalType {
self.mutability self.mutability
} }
pub(crate) fn from_wasmtime_global(global: &wasm::Global) -> GlobalType { /// Returns `None` if the wasmtime global has a type that we can't
let ty = ValType::from_wasmtime_type(global.ty); /// represent, but that should only very rarely happen and indicate a bug.
pub(crate) fn from_wasmtime_global(global: &wasm::Global) -> Option<GlobalType> {
let ty = ValType::from_wasmtime_type(global.ty)?;
let mutability = if global.mutability { let mutability = if global.mutability {
Mutability::Var Mutability::Var
} else { } else {
Mutability::Const Mutability::Const
}; };
GlobalType::new(ty, mutability) Some(GlobalType::new(ty, mutability))
} }
} }

View File

@@ -1,5 +1,5 @@
use crate::externals::Func; use crate::externals::Func;
use crate::r#ref::{AnyRef, HostRef}; use crate::r#ref::AnyRef;
use crate::runtime::Store; use crate::runtime::Store;
use crate::types::ValType; use crate::types::ValType;
use std::ptr; use std::ptr;
@@ -34,7 +34,7 @@ pub enum Val {
AnyRef(AnyRef), AnyRef(AnyRef),
/// A first-class reference to a WebAssembly function. /// A first-class reference to a WebAssembly function.
FuncRef(HostRef<Func>), FuncRef(Func),
/// A 128-bit number /// A 128-bit number
V128(u128), V128(u128),
@@ -71,7 +71,7 @@ impl Val {
} }
/// Returns the corresponding [`ValType`] for this `Val`. /// Returns the corresponding [`ValType`] for this `Val`.
pub fn r#type(&self) -> ValType { pub fn ty(&self) -> ValType {
match self { match self {
Val::I32(_) => ValType::I32, Val::I32(_) => ValType::I32,
Val::I64(_) => ValType::I64, Val::I64(_) => ValType::I64,
@@ -111,7 +111,7 @@ impl Val {
(I64(i64) i64 unwrap_i64 *e) (I64(i64) i64 unwrap_i64 *e)
(F32(f32) f32 unwrap_f32 f32::from_bits(*e)) (F32(f32) f32 unwrap_f32 f32::from_bits(*e))
(F64(f64) f64 unwrap_f64 f64::from_bits(*e)) (F64(f64) f64 unwrap_f64 f64::from_bits(*e))
(FuncRef(&HostRef<Func>) funcref unwrap_funcref e) (FuncRef(&Func) funcref unwrap_funcref e)
(V128(u128) v128 unwrap_v128 *e) (V128(u128) v128 unwrap_v128 *e)
} }
@@ -122,7 +122,6 @@ impl Val {
pub fn anyref(&self) -> Option<AnyRef> { pub fn anyref(&self) -> Option<AnyRef> {
match self { match self {
Val::AnyRef(e) => Some(e.clone()), Val::AnyRef(e) => Some(e.clone()),
Val::FuncRef(e) => Some(e.anyref()),
_ => None, _ => None,
} }
} }
@@ -164,21 +163,12 @@ impl From<f64> for Val {
impl From<AnyRef> for Val { impl From<AnyRef> for Val {
fn from(val: AnyRef) -> Val { fn from(val: AnyRef) -> Val {
match &val {
AnyRef::Ref(r) => {
if r.is_ref::<Func>() {
Val::FuncRef(r.get_ref())
} else {
Val::AnyRef(val) Val::AnyRef(val)
} }
} }
_ => unimplemented!("AnyRef::Other"),
}
}
}
impl From<HostRef<Func>> for Val { impl From<Func> for Val {
fn from(val: HostRef<Func>) -> Val { fn from(val: Func) -> Val {
Val::FuncRef(val) Val::FuncRef(val)
} }
} }
@@ -206,7 +196,6 @@ pub(crate) fn into_checked_anyfunc(
vmctx: ptr::null_mut(), vmctx: ptr::null_mut(),
}, },
Val::FuncRef(f) => { Val::FuncRef(f) => {
let f = f.borrow();
let (vmctx, func_ptr, signature) = match f.wasmtime_export() { let (vmctx, func_ptr, signature) = match f.wasmtime_export() {
wasmtime_runtime::Export::Function { wasmtime_runtime::Export::Function {
vmctx, vmctx,
@@ -243,5 +232,5 @@ pub(crate) fn from_checked_anyfunc(
vmctx: item.vmctx, vmctx: item.vmctx,
}; };
let f = Func::from_wasmtime_function(export, store, instance_handle); let f = Func::from_wasmtime_function(export, store, instance_handle);
Val::FuncRef(HostRef::new(f)) Val::FuncRef(f)
} }

View File

@@ -7,9 +7,11 @@
use super::{ use super::{
AnyRef, Callable, Engine, ExportType, Extern, ExternType, Func, FuncType, Global, GlobalType, AnyRef, Callable, Engine, ExportType, Extern, ExternType, Func, FuncType, Global, GlobalType,
HostInfo, HostRef, ImportType, Instance, Limits, Memory, MemoryType, Module, Store, Table, ImportType, Instance, Limits, Memory, MemoryType, Module, Store, Table, TableType, Trap, Val,
TableType, Trap, Val, ValType, ValType,
}; };
use crate::r#ref::{HostInfo, HostRef};
use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use std::{mem, ptr, slice}; use std::{mem, ptr, slice};
@@ -243,6 +245,12 @@ enum wasm_externtype_t_type_cache {
declare_vec!(wasm_externtype_vec_t, *mut wasm_externtype_t); declare_vec!(wasm_externtype_vec_t, *mut wasm_externtype_t);
pub type wasm_externkind_t = u8; pub type wasm_externkind_t = u8;
const WASM_EXTERN_FUNC: wasm_externkind_t = 0;
const WASM_EXTERN_GLOBAL: wasm_externkind_t = 1;
const WASM_EXTERN_TABLE: wasm_externkind_t = 2;
const WASM_EXTERN_MEMORY: wasm_externkind_t = 3;
#[repr(C)] #[repr(C)]
#[derive(Clone)] #[derive(Clone)]
pub struct wasm_importtype_t { pub struct wasm_importtype_t {
@@ -312,6 +320,7 @@ declare_vec!(wasm_frame_vec_t, *mut wasm_frame_t);
#[derive(Clone)] #[derive(Clone)]
pub struct wasm_instance_t { pub struct wasm_instance_t {
instance: HostRef<Instance>, instance: HostRef<Instance>,
exports_cache: RefCell<Option<Vec<ExternHost>>>,
} }
pub type wasm_message_t = wasm_name_t; pub type wasm_message_t = wasm_name_t;
#[repr(C)] #[repr(C)]
@@ -336,12 +345,22 @@ pub struct wasm_module_t {
pub struct wasm_shared_module_t { pub struct wasm_shared_module_t {
_unused: [u8; 0], _unused: [u8; 0],
} }
#[repr(C)]
#[derive(Clone)] #[derive(Clone)]
#[repr(transparent)]
pub struct wasm_func_t { pub struct wasm_func_t {
func: HostRef<Func>, ext: wasm_extern_t,
ext: Option<Box<wasm_extern_t>>,
} }
impl wasm_func_t {
fn func(&self) -> &HostRef<Func> {
match &self.ext.which {
ExternHost::Func(f) => f,
_ => unsafe { std::hint::unreachable_unchecked() },
}
}
}
pub type wasm_func_callback_t = std::option::Option< pub type wasm_func_callback_t = std::option::Option<
unsafe extern "C" fn(args: *const wasm_val_t, results: *mut wasm_val_t) -> *mut wasm_trap_t, unsafe extern "C" fn(args: *const wasm_val_t, results: *mut wasm_val_t) -> *mut wasm_trap_t,
>; >;
@@ -352,40 +371,67 @@ pub type wasm_func_callback_with_env_t = std::option::Option<
results: *mut wasm_val_t, results: *mut wasm_val_t,
) -> *mut wasm_trap_t, ) -> *mut wasm_trap_t,
>; >;
#[repr(C)]
#[derive(Clone)] #[derive(Clone)]
#[repr(transparent)]
pub struct wasm_global_t { pub struct wasm_global_t {
global: HostRef<Global>, ext: wasm_extern_t,
ext: Option<Box<wasm_extern_t>>,
} }
#[repr(C)]
#[derive(Clone)] impl wasm_global_t {
pub struct wasm_table_t { fn global(&self) -> &HostRef<Global> {
table: HostRef<Table>, match &self.ext.which {
ext: Option<Box<wasm_extern_t>>, ExternHost::Global(g) => g,
_ => unsafe { std::hint::unreachable_unchecked() },
} }
pub type wasm_table_size_t = u32;
#[repr(C)]
#[derive(Clone)]
pub struct wasm_memory_t {
memory: HostRef<Memory>,
ext: Option<Box<wasm_extern_t>>,
} }
pub type wasm_memory_pages_t = u32;
#[repr(C)]
#[derive(Clone)]
pub struct wasm_extern_t {
ext: Extern,
cache: wasm_extern_t_type_cache,
} }
#[derive(Clone)] #[derive(Clone)]
enum wasm_extern_t_type_cache { #[repr(transparent)]
Empty, pub struct wasm_table_t {
Func(wasm_func_t), ext: wasm_extern_t,
Global(wasm_global_t), }
Memory(wasm_memory_t),
Table(wasm_table_t), impl wasm_table_t {
fn table(&self) -> &HostRef<Table> {
match &self.ext.which {
ExternHost::Table(t) => t,
_ => unsafe { std::hint::unreachable_unchecked() },
}
}
}
pub type wasm_table_size_t = u32;
#[derive(Clone)]
#[repr(transparent)]
pub struct wasm_memory_t {
ext: wasm_extern_t,
}
impl wasm_memory_t {
fn memory(&self) -> &HostRef<Memory> {
match &self.ext.which {
ExternHost::Memory(m) => m,
_ => unsafe { std::hint::unreachable_unchecked() },
}
}
}
pub type wasm_memory_pages_t = u32;
#[derive(Clone)]
pub struct wasm_extern_t {
which: ExternHost,
}
#[derive(Clone)]
enum ExternHost {
Func(HostRef<Func>),
Global(HostRef<Global>),
Memory(HostRef<Memory>),
Table(HostRef<Table>),
} }
declare_vec!(wasm_extern_vec_t, *mut wasm_extern_t); declare_vec!(wasm_extern_vec_t, *mut wasm_extern_t);
@@ -415,16 +461,9 @@ pub unsafe extern "C" fn wasm_engine_new() -> *mut wasm_engine_t {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_as_func(e: *mut wasm_extern_t) -> *mut wasm_func_t { pub unsafe extern "C" fn wasm_extern_as_func(e: *mut wasm_extern_t) -> *mut wasm_func_t {
if let wasm_extern_t_type_cache::Empty = (*e).cache { match &(*e).which {
(*e).cache = wasm_extern_t_type_cache::Func(wasm_func_t { ExternHost::Func(_) => e.cast(),
func: (*e).ext.func().unwrap().clone(), _ => ptr::null_mut(),
ext: None,
});
}
match &mut (*e).cache {
wasm_extern_t_type_cache::Func(f) => f,
_ => panic!("wasm_extern_as_func"),
} }
} }
@@ -435,17 +474,7 @@ pub unsafe extern "C" fn wasm_extern_vec_delete(v: *mut wasm_extern_vec_t) {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_func_as_extern(f: *mut wasm_func_t) -> *mut wasm_extern_t { pub unsafe extern "C" fn wasm_func_as_extern(f: *mut wasm_func_t) -> *mut wasm_extern_t {
if (*f).ext.is_none() { &mut (*f).ext
(*f).ext = Some(Box::new(wasm_extern_t {
ext: Extern::Func((*f).func.clone()),
cache: wasm_extern_t_type_cache::Empty,
}));
}
match &mut (*f).ext {
Some(e) => e.as_mut(),
_ => panic!("wasm_func_as_extern"),
}
} }
#[no_mangle] #[no_mangle]
@@ -454,7 +483,7 @@ pub unsafe extern "C" fn wasm_func_call(
args: *const wasm_val_t, args: *const wasm_val_t,
results: *mut wasm_val_t, results: *mut wasm_val_t,
) -> *mut wasm_trap_t { ) -> *mut wasm_trap_t {
let func = (*func).func.borrow(); let func = (*func).func().borrow();
let mut params = Vec::with_capacity(func.param_arity()); let mut params = Vec::with_capacity(func.param_arity());
for i in 0..func.param_arity() { for i in 0..func.param_arity() {
let val = &(*args.add(i)); let val = &(*args.add(i));
@@ -606,8 +635,9 @@ pub unsafe extern "C" fn wasm_func_new(
let ty = (*ty).functype.clone(); let ty = (*ty).functype.clone();
let callback = Rc::new(callback); let callback = Rc::new(callback);
let func = Box::new(wasm_func_t { let func = Box::new(wasm_func_t {
func: HostRef::new(Func::new(store, ty, callback)), ext: wasm_extern_t {
ext: None, which: ExternHost::Func(HostRef::new(Func::new(store, ty, callback))),
},
}); });
Box::into_raw(func) Box::into_raw(func)
} }
@@ -656,17 +686,35 @@ pub unsafe extern "C" fn wasm_instance_new(
imports: *const *const wasm_extern_t, imports: *const *const wasm_extern_t,
result: *mut *mut wasm_trap_t, result: *mut *mut wasm_trap_t,
) -> *mut wasm_instance_t { ) -> *mut wasm_instance_t {
let store = &(*store).store.borrow();
let mut externs: Vec<Extern> = Vec::with_capacity((*module).imports.len()); let mut externs: Vec<Extern> = Vec::with_capacity((*module).imports.len());
for i in 0..(*module).imports.len() { for i in 0..(*module).imports.len() {
let import = *imports.add(i); let import = *imports.add(i);
externs.push((*import).ext.clone()); externs.push(match &(*import).which {
ExternHost::Func(e) => Extern::Func(e.borrow().clone()),
ExternHost::Table(e) => Extern::Table(e.borrow().clone()),
ExternHost::Global(e) => Extern::Global(e.borrow().clone()),
ExternHost::Memory(e) => Extern::Memory(e.borrow().clone()),
});
} }
let store = &(*store).store.borrow();
let module = &(*module).module.borrow(); let module = &(*module).module.borrow();
match Instance::new(store, module, &externs) { // FIXME(WebAssembly/wasm-c-api#126) what else can we do with the `store`
// argument?
if !Store::ptr_eq(&store, module.store()) {
if !result.is_null() {
let trap = Trap::new("wasm_store_t must match store in wasm_module_t");
let trap = Box::new(wasm_trap_t {
trap: HostRef::new(trap),
});
(*result) = Box::into_raw(trap);
}
return ptr::null_mut();
}
match Instance::new(module, &externs) {
Ok(instance) => { Ok(instance) => {
let instance = Box::new(wasm_instance_t { let instance = Box::new(wasm_instance_t {
instance: HostRef::new(instance), instance: HostRef::new(instance),
exports_cache: RefCell::new(None),
}); });
if !result.is_null() { if !result.is_null() {
(*result) = ptr::null_mut(); (*result) = ptr::null_mut();
@@ -694,14 +742,23 @@ pub unsafe extern "C" fn wasm_instance_exports(
instance: *const wasm_instance_t, instance: *const wasm_instance_t,
out: *mut wasm_extern_vec_t, out: *mut wasm_extern_vec_t,
) { ) {
let mut cache = (*instance).exports_cache.borrow_mut();
let exports = cache.get_or_insert_with(|| {
let instance = &(*instance).instance.borrow(); let instance = &(*instance).instance.borrow();
let exports = instance.exports(); instance
let mut buffer = Vec::with_capacity(exports.len()); .exports()
for e in exports.iter() { .iter()
let ext = Box::new(wasm_extern_t { .map(|e| match e {
ext: e.clone(), Extern::Func(f) => ExternHost::Func(HostRef::new(f.clone())),
cache: wasm_extern_t_type_cache::Empty, Extern::Global(f) => ExternHost::Global(HostRef::new(f.clone())),
Extern::Memory(f) => ExternHost::Memory(HostRef::new(f.clone())),
Extern::Table(f) => ExternHost::Table(HostRef::new(f.clone())),
})
.collect()
}); });
let mut buffer = Vec::with_capacity(exports.len());
for e in exports {
let ext = Box::new(wasm_extern_t { which: e.clone() });
buffer.push(Box::into_raw(ext)); buffer.push(Box::into_raw(ext));
} }
(*out).set_buffer(buffer); (*out).set_buffer(buffer);
@@ -817,8 +874,9 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
finalizer, finalizer,
}); });
let func = Box::new(wasm_func_t { let func = Box::new(wasm_func_t {
func: HostRef::new(Func::new(store, ty, callback)), ext: wasm_extern_t {
ext: None, which: ExternHost::Func(HostRef::new(Func::new(store, ty, callback))),
},
}); });
Box::into_raw(func) Box::into_raw(func)
} }
@@ -1012,24 +1070,25 @@ pub unsafe extern "C" fn wasm_exporttype_vec_delete(et: *mut wasm_exporttype_vec
(*et).uninitialize(); (*et).uninitialize();
} }
fn from_externtype(ty: &ExternType) -> wasm_externkind_t {
match ty {
ExternType::Func(_) => 0,
ExternType::Global(_) => 1,
ExternType::Table(_) => 2,
ExternType::Memory(_) => 3,
}
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_kind(e: *const wasm_extern_t) -> wasm_externkind_t { pub unsafe extern "C" fn wasm_extern_kind(e: *const wasm_extern_t) -> wasm_externkind_t {
from_externtype(&(*e).ext.r#type()) match (*e).which {
ExternHost::Func(_) => WASM_EXTERN_FUNC,
ExternHost::Global(_) => WASM_EXTERN_GLOBAL,
ExternHost::Table(_) => WASM_EXTERN_TABLE,
ExternHost::Memory(_) => WASM_EXTERN_MEMORY,
}
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_type(e: *const wasm_extern_t) -> *mut wasm_externtype_t { pub unsafe extern "C" fn wasm_extern_type(e: *const wasm_extern_t) -> *mut wasm_externtype_t {
let et = Box::new(wasm_externtype_t { let et = Box::new(wasm_externtype_t {
ty: (*e).ext.r#type(), ty: match &(*e).which {
ExternHost::Func(f) => ExternType::Func(f.borrow().ty().clone()),
ExternHost::Global(f) => ExternType::Global(f.borrow().ty().clone()),
ExternHost::Table(f) => ExternType::Table(f.borrow().ty().clone()),
ExternHost::Memory(f) => ExternType::Memory(f.borrow().ty().clone()),
},
cache: wasm_externtype_t_type_cache::Empty, cache: wasm_externtype_t_type_cache::Empty,
}); });
Box::into_raw(et) Box::into_raw(et)
@@ -1120,17 +1179,22 @@ pub unsafe extern "C" fn wasm_externtype_delete(et: *mut wasm_externtype_t) {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_externtype_kind(et: *const wasm_externtype_t) -> wasm_externkind_t { pub unsafe extern "C" fn wasm_externtype_kind(et: *const wasm_externtype_t) -> wasm_externkind_t {
from_externtype(&(*et).ty) match &(*et).ty {
ExternType::Func(_) => WASM_EXTERN_FUNC,
ExternType::Table(_) => WASM_EXTERN_TABLE,
ExternType::Global(_) => WASM_EXTERN_GLOBAL,
ExternType::Memory(_) => WASM_EXTERN_MEMORY,
}
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_func_param_arity(f: *const wasm_func_t) -> usize { pub unsafe extern "C" fn wasm_func_param_arity(f: *const wasm_func_t) -> usize {
(*f).func.borrow().param_arity() (*f).func().borrow().param_arity()
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_func_result_arity(f: *const wasm_func_t) -> usize { pub unsafe extern "C" fn wasm_func_result_arity(f: *const wasm_func_t) -> usize {
(*f).func.borrow().result_arity() (*f).func().borrow().result_arity()
} }
#[no_mangle] #[no_mangle]
@@ -1279,32 +1343,15 @@ pub unsafe extern "C" fn wasm_valtype_kind(vt: *const wasm_valtype_t) -> wasm_va
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_as_global(e: *mut wasm_extern_t) -> *mut wasm_global_t { pub unsafe extern "C" fn wasm_extern_as_global(e: *mut wasm_extern_t) -> *mut wasm_global_t {
if let wasm_extern_t_type_cache::Empty = (*e).cache { match &(*e).which {
(*e).cache = wasm_extern_t_type_cache::Global(wasm_global_t { ExternHost::Global(_) => e.cast(),
global: (*e).ext.global().unwrap().clone(), _ => ptr::null_mut(),
ext: None,
});
}
match &mut (*e).cache {
wasm_extern_t_type_cache::Global(g) => g,
_ => panic!("wasm_extern_as_global"),
} }
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_global_as_extern(g: *mut wasm_global_t) -> *mut wasm_extern_t { pub unsafe extern "C" fn wasm_global_as_extern(g: *mut wasm_global_t) -> *mut wasm_extern_t {
if (*g).ext.is_none() { &mut (*g).ext
(*g).ext = Some(Box::new(wasm_extern_t {
ext: Extern::Global((*g).global.clone()),
cache: wasm_extern_t_type_cache::Empty,
}));
}
match &mut (*g).ext {
Some(e) => e.as_mut(),
_ => panic!("wasm_global_as_extern"),
}
} }
#[no_mangle] #[no_mangle]
@@ -1322,7 +1369,7 @@ pub unsafe extern "C" fn wasm_global_same(
g1: *const wasm_global_t, g1: *const wasm_global_t,
g2: *const wasm_global_t, g2: *const wasm_global_t,
) -> bool { ) -> bool {
(*g1).global.ptr_eq(&(*g2).global) (*g1).global().ptr_eq(&(*g2).global())
} }
#[no_mangle] #[no_mangle]
@@ -1336,18 +1383,22 @@ pub unsafe extern "C" fn wasm_global_new(
(*gt).globaltype.clone(), (*gt).globaltype.clone(),
(*val).val(), (*val).val(),
)); ));
let g = Box::new(wasm_global_t { global, ext: None }); let g = Box::new(wasm_global_t {
ext: wasm_extern_t {
which: ExternHost::Global(global),
},
});
Box::into_raw(g) Box::into_raw(g)
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_global_get(g: *const wasm_global_t, out: *mut wasm_val_t) { pub unsafe extern "C" fn wasm_global_get(g: *const wasm_global_t, out: *mut wasm_val_t) {
(*out).set((*g).global.borrow_mut().get()); (*out).set((*g).global().borrow().get());
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_global_set(g: *mut wasm_global_t, val: *const wasm_val_t) { pub unsafe extern "C" fn wasm_global_set(g: *mut wasm_global_t, val: *const wasm_val_t) {
(*g).global.borrow_mut().set((*val).val()) (*g).global().borrow().set((*val).val())
} }
#[no_mangle] #[no_mangle]
@@ -1377,32 +1428,15 @@ pub unsafe extern "C" fn wasm_globaltype_new(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_as_memory(e: *mut wasm_extern_t) -> *mut wasm_memory_t { pub unsafe extern "C" fn wasm_extern_as_memory(e: *mut wasm_extern_t) -> *mut wasm_memory_t {
if let wasm_extern_t_type_cache::Empty = (*e).cache { match &(*e).which {
(*e).cache = wasm_extern_t_type_cache::Memory(wasm_memory_t { ExternHost::Memory(_) => e.cast(),
memory: (*e).ext.memory().unwrap().clone(), _ => ptr::null_mut(),
ext: None,
});
}
match &mut (*e).cache {
wasm_extern_t_type_cache::Memory(m) => m,
_ => panic!("wasm_extern_as_memory"),
} }
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memory_as_extern(m: *mut wasm_memory_t) -> *mut wasm_extern_t { pub unsafe extern "C" fn wasm_memory_as_extern(m: *mut wasm_memory_t) -> *mut wasm_extern_t {
if (*m).ext.is_none() { &mut (*m).ext
(*m).ext = Some(Box::new(wasm_extern_t {
ext: Extern::Memory((*m).memory.clone()),
cache: wasm_extern_t_type_cache::Empty,
}));
}
match &mut (*m).ext {
Some(e) => e.as_mut(),
_ => panic!("wasm_global_as_extern"),
}
} }
#[no_mangle] #[no_mangle]
@@ -1420,22 +1454,22 @@ pub unsafe extern "C" fn wasm_memory_same(
m1: *const wasm_memory_t, m1: *const wasm_memory_t,
m2: *const wasm_memory_t, m2: *const wasm_memory_t,
) -> bool { ) -> bool {
(*m1).memory.ptr_eq(&(*m2).memory) (*m1).memory().ptr_eq(&(*m2).memory())
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memory_data(m: *mut wasm_memory_t) -> *mut u8 { pub unsafe extern "C" fn wasm_memory_data(m: *mut wasm_memory_t) -> *mut u8 {
(*m).memory.borrow().data_ptr() (*m).memory().borrow().data_ptr()
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memory_data_size(m: *const wasm_memory_t) -> usize { pub unsafe extern "C" fn wasm_memory_data_size(m: *const wasm_memory_t) -> usize {
(*m).memory.borrow().data_size() (*m).memory().borrow().data_size()
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memory_size(m: *const wasm_memory_t) -> wasm_memory_pages_t { pub unsafe extern "C" fn wasm_memory_size(m: *const wasm_memory_t) -> wasm_memory_pages_t {
(*m).memory.borrow().size() (*m).memory().borrow().size()
} }
#[no_mangle] #[no_mangle]
@@ -1443,7 +1477,7 @@ pub unsafe extern "C" fn wasm_memory_grow(
m: *mut wasm_memory_t, m: *mut wasm_memory_t,
delta: wasm_memory_pages_t, delta: wasm_memory_pages_t,
) -> bool { ) -> bool {
(*m).memory.borrow_mut().grow(delta) (*m).memory().borrow().grow(delta)
} }
#[no_mangle] #[no_mangle]
@@ -1455,7 +1489,11 @@ pub unsafe extern "C" fn wasm_memory_new(
&(*store).store.borrow(), &(*store).store.borrow(),
(*mt).memorytype.clone(), (*mt).memorytype.clone(),
)); ));
let m = Box::new(wasm_memory_t { memory, ext: None }); let m = Box::new(wasm_memory_t {
ext: wasm_extern_t {
which: ExternHost::Memory(memory),
},
});
Box::into_raw(m) Box::into_raw(m)
} }
@@ -1483,37 +1521,20 @@ pub unsafe extern "C" fn wasm_memorytype_new(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_as_table(e: *mut wasm_extern_t) -> *mut wasm_table_t { pub unsafe extern "C" fn wasm_extern_as_table(e: *mut wasm_extern_t) -> *mut wasm_table_t {
if let wasm_extern_t_type_cache::Empty = (*e).cache { match &(*e).which {
(*e).cache = wasm_extern_t_type_cache::Table(wasm_table_t { ExternHost::Table(_) => e.cast(),
table: (*e).ext.table().unwrap().clone(), _ => ptr::null_mut(),
ext: None,
});
}
match &mut (*e).cache {
wasm_extern_t_type_cache::Table(t) => t,
_ => panic!("wasm_extern_as_table"),
} }
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_table_as_extern(t: *mut wasm_table_t) -> *mut wasm_extern_t { pub unsafe extern "C" fn wasm_table_as_extern(t: *mut wasm_table_t) -> *mut wasm_extern_t {
if (*t).ext.is_none() { &mut (*t).ext
(*t).ext = Some(Box::new(wasm_extern_t {
ext: Extern::Table((*t).table.clone()),
cache: wasm_extern_t_type_cache::Empty,
}));
}
match &mut (*t).ext {
Some(e) => e.as_mut(),
_ => panic!("wasm_table_as_extern"),
}
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_func_as_ref(f: *mut wasm_func_t) -> *mut wasm_ref_t { pub unsafe extern "C" fn wasm_func_as_ref(f: *mut wasm_func_t) -> *mut wasm_ref_t {
let r = (*f).func.anyref(); let r = (*f).func().anyref();
let f = Box::new(wasm_ref_t { r }); let f = Box::new(wasm_ref_t { r });
Box::into_raw(f) Box::into_raw(f)
} }
@@ -1547,12 +1568,13 @@ pub unsafe extern "C" fn wasm_table_new(
Val::AnyRef(AnyRef::Null) Val::AnyRef(AnyRef::Null)
}; };
let t = Box::new(wasm_table_t { let t = Box::new(wasm_table_t {
table: HostRef::new(Table::new( ext: wasm_extern_t {
which: ExternHost::Table(HostRef::new(Table::new(
&(*store).store.borrow(), &(*store).store.borrow(),
(*tt).tabletype.clone(), (*tt).tabletype.clone(),
init, init,
)), ))),
ext: None, },
}); });
Box::into_raw(t) Box::into_raw(t)
} }
@@ -1582,7 +1604,7 @@ pub unsafe extern "C" fn wasm_table_get(
t: *const wasm_table_t, t: *const wasm_table_t,
index: wasm_table_size_t, index: wasm_table_size_t,
) -> *mut wasm_ref_t { ) -> *mut wasm_ref_t {
let val = (*t).table.borrow().get(index); let val = (*t).table().borrow().get(index);
into_funcref(val) into_funcref(val)
} }
@@ -1593,12 +1615,12 @@ pub unsafe extern "C" fn wasm_table_set(
r: *mut wasm_ref_t, r: *mut wasm_ref_t,
) -> bool { ) -> bool {
let val = from_funcref(r); let val = from_funcref(r);
(*t).table.borrow().set(index, val) (*t).table().borrow().set(index, val)
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_table_size(t: *const wasm_table_t) -> wasm_table_size_t { pub unsafe extern "C" fn wasm_table_size(t: *const wasm_table_t) -> wasm_table_size_t {
(*t).table.borrow().size() (*t).table().borrow().size()
} }
#[no_mangle] #[no_mangle]
@@ -1608,12 +1630,12 @@ pub unsafe extern "C" fn wasm_table_grow(
init: *mut wasm_ref_t, init: *mut wasm_ref_t,
) -> bool { ) -> bool {
let init = from_funcref(init); let init = from_funcref(init);
(*t).table.borrow_mut().grow(delta, init) (*t).table().borrow().grow(delta, init)
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_table_same(t1: *const wasm_table_t, t2: *const wasm_table_t) -> bool { pub unsafe extern "C" fn wasm_table_same(t1: *const wasm_table_t, t2: *const wasm_table_t) -> bool {
(*t1).table.ptr_eq(&(*t2).table) (*t1).table().ptr_eq((*t2).table())
} }
#[no_mangle] #[no_mangle]

View File

@@ -0,0 +1,68 @@
use std::rc::Rc;
use wasmtime::*;
#[test]
fn same_import_names_still_distinct() -> anyhow::Result<()> {
const WAT: &str = r#"
(module
(import "" "" (func $a (result i32)))
(import "" "" (func $b (result f32)))
(func (export "foo") (result i32)
call $a
call $b
i32.trunc_f32_u
i32.add)
)
"#;
struct Ret1;
impl Callable for Ret1 {
fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Trap> {
assert!(params.is_empty());
assert_eq!(results.len(), 1);
results[0] = 1i32.into();
Ok(())
}
}
struct Ret2;
impl Callable for Ret2 {
fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Trap> {
assert!(params.is_empty());
assert_eq!(results.len(), 1);
results[0] = 2.0f32.into();
Ok(())
}
}
let store = Store::default();
let wasm = wat::parse_str(WAT)?;
let module = Module::new(&store, &wasm)?;
let imports = [
Func::new(
&store,
FuncType::new(Box::new([]), Box::new([ValType::I32])),
Rc::new(Ret1),
)
.into(),
Func::new(
&store,
FuncType::new(Box::new([]), Box::new([ValType::F32])),
Rc::new(Ret2),
)
.into(),
];
let instance = Instance::new(&module, &imports)?;
let func = instance.find_export_by_name("foo").unwrap().func().unwrap();
let results = func.call(&[])?;
assert_eq!(results.len(), 1);
match results[0] {
Val::I32(n) => assert_eq!(n, 3),
_ => panic!("unexpected type of return"),
}
Ok(())
}

View File

@@ -1,4 +1,4 @@
use std::cell::{Ref, RefCell}; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use wasmtime::*; use wasmtime::*;
@@ -16,7 +16,7 @@ fn test_import_calling_export() {
"#; "#;
struct Callback { struct Callback {
pub other: RefCell<Option<HostRef<Func>>>, pub other: RefCell<Option<Func>>,
} }
impl Callable for Callback { impl Callable for Callback {
@@ -25,7 +25,6 @@ fn test_import_calling_export() {
.borrow() .borrow()
.as_ref() .as_ref()
.expect("expected a function ref") .expect("expected a function ref")
.borrow()
.call(&[]) .call(&[])
.expect("expected function not to trap"); .expect("expected function not to trap");
Ok(()) Ok(())
@@ -40,18 +39,17 @@ fn test_import_calling_export() {
other: RefCell::new(None), other: RefCell::new(None),
}); });
let callback_func = HostRef::new(Func::new( let callback_func = Func::new(
&store, &store,
FuncType::new(Box::new([]), Box::new([])), FuncType::new(Box::new([]), Box::new([])),
callback.clone(), callback.clone(),
));
let imports = vec![callback_func.into()];
let instance = HostRef::new(
Instance::new(&store, &module, imports.as_slice()).expect("failed to instantiate module"),
); );
let exports = Ref::map(instance.borrow(), |instance| instance.exports()); let imports = vec![callback_func.into()];
let instance =
Instance::new(&module, imports.as_slice()).expect("failed to instantiate module");
let exports = instance.exports();
assert!(!exports.is_empty()); assert!(!exports.is_empty());
let run_func = exports[0] let run_func = exports[0]
@@ -65,8 +63,5 @@ fn test_import_calling_export() {
.clone(), .clone(),
); );
run_func run_func.call(&[]).expect("expected function not to trap");
.borrow()
.call(&[])
.expect("expected function not to trap");
} }

View File

@@ -0,0 +1,33 @@
use anyhow::{Context as _, Result};
use wasmtime::*;
#[test]
fn test_invoke_func_via_table() -> Result<()> {
let store = Store::default();
let binary = wat::parse_str(
r#"
(module
(func $f (result i64) (i64.const 42))
(table (export "table") 1 1 anyfunc)
(elem (i32.const 0) $f)
)
"#,
)?;
let module = Module::new(&store, &binary).context("> Error compiling module!")?;
let instance = Instance::new(&store, &module, &[]).context("> Error instantiating module!")?;
let f = instance
.find_export_by_name("table")
.unwrap()
.table()
.unwrap()
.get(0)
.funcref()
.unwrap()
.clone();
let result = f.call(&[]).unwrap();
assert_eq!(result[0].unwrap_i64(), 42);
Ok(())
}

View File

@@ -1,54 +1,38 @@
use wasmtime::*; use wasmtime::*;
use wat::parse_str;
#[test] #[test]
fn test_module_no_name() -> Result<(), String> { fn test_module_no_name() -> anyhow::Result<()> {
let store = Store::default(); let store = Store::default();
let binary = parse_str( let binary = wat::parse_str(
r#" r#"
(module (module
(func (export "run") (nop)) (func (export "run") (nop))
) )
"#, "#,
) )?;
.map_err(|e| format!("failed to parse WebAssembly text source: {}", e))?;
let module = HostRef::new( let module = Module::new(&store, &binary)?;
Module::new(&store, &binary).map_err(|e| format!("failed to compile module: {}", e))?, assert_eq!(module.name(), None);
);
assert_eq!(module.borrow().name().cloned(), None);
Ok(()) Ok(())
} }
#[test] #[test]
fn test_module_name() -> Result<(), String> { fn test_module_name() -> anyhow::Result<()> {
let store = Store::default(); let store = Store::default();
let binary = parse_str( let binary = wat::parse_str(
r#" r#"
(module $from_name_section (module $from_name_section
(func (export "run") (nop)) (func (export "run") (nop))
) )
"#, "#,
) )?;
.map_err(|e| format!("failed to parse WebAssembly text source: {}", e))?;
let module = HostRef::new( let module = Module::new(&store, &binary)?;
Module::new(&store, &binary).map_err(|e| format!("failed to compile module: {}", e))?, assert_eq!(module.name(), Some("from_name_section"));
);
assert_eq!(
module.borrow().name().cloned(),
Some("from_name_section".to_string())
);
let module = HostRef::new( let module = Module::new_with_name(&store, &binary, "override")?;
Module::new_with_name(&store, &binary, "override".to_string()) assert_eq!(module.name(), Some("override"));
.map_err(|e| format!("failed to compile module: {}", e))?,
);
assert_eq!(
module.borrow().name().cloned(),
Some("override".to_string())
);
Ok(()) Ok(())
} }

View File

@@ -26,20 +26,16 @@ fn test_trap_return() -> Result<(), String> {
let module = let module =
Module::new(&store, &binary).map_err(|e| format!("failed to compile module: {}", e))?; Module::new(&store, &binary).map_err(|e| format!("failed to compile module: {}", e))?;
let hello_type = FuncType::new(Box::new([]), Box::new([])); let hello_type = FuncType::new(Box::new([]), Box::new([]));
let hello_func = HostRef::new(Func::new(&store, hello_type, Rc::new(HelloCallback))); let hello_func = Func::new(&store, hello_type, Rc::new(HelloCallback));
let imports = vec![hello_func.into()]; let imports = vec![hello_func.into()];
let instance = Instance::new(&store, &module, imports.as_slice()) let instance = Instance::new(&module, &imports)
.map_err(|e| format!("failed to instantiate module: {:?}", e))?; .map_err(|e| format!("failed to instantiate module: {:?}", e))?;
let run_func = instance.exports()[0] let run_func = instance.exports()[0]
.func() .func()
.expect("expected function export"); .expect("expected function export");
let e = run_func let e = run_func.call(&[]).err().expect("error calling function");
.borrow()
.call(&[])
.err()
.expect("error calling function");
assert_eq!(e.message(), "test 123"); assert_eq!(e.message(), "test 123");

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime-debug" name = "wasmtime-debug"
version = "0.7.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
description = "Debug utils for WebAsssembly code in Cranelift" description = "Debug utils for WebAsssembly code in Cranelift"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -13,10 +13,10 @@ edition = "2018"
[dependencies] [dependencies]
gimli = "0.19.0" gimli = "0.19.0"
wasmparser = "0.45.1" wasmparser = "0.47.0"
faerie = "0.13.0" faerie = "0.14.0"
wasmtime-environ = { path = "../environ" } wasmtime-environ = { path = "../environ", version = "0.9.0" }
target-lexicon = { version = "0.9.0", default-features = false } target-lexicon = { version = "0.10.0", default-features = false }
anyhow = "1.0" anyhow = "1.0"
thiserror = "1.0.4" thiserror = "1.0.4"
more-asserts = "0.2.1" more-asserts = "0.2.1"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime-environ" name = "wasmtime-environ"
version = "0.7.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
description = "Standalone environment support for WebAsssembly code in Cranelift" description = "Standalone environment support for WebAsssembly code in Cranelift"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -13,11 +13,11 @@ edition = "2018"
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
cranelift-codegen = { version = "0.52.0", features = ["enable-serde"] } cranelift-codegen = { version = "0.54", features = ["enable-serde"] }
cranelift-entity = { version = "0.52.0", features = ["enable-serde"] } cranelift-entity = { version = "0.54", features = ["enable-serde"] }
cranelift-wasm = { version = "0.52.0", features = ["enable-serde"] } cranelift-wasm = { version = "0.54", features = ["enable-serde"] }
wasmparser = "0.45.1" wasmparser = "0.47.0"
lightbeam = { path = "../lightbeam", optional = true } lightbeam = { path = "../lightbeam", optional = true, version = "0.9.0" }
indexmap = "1.0.2" indexmap = "1.0.2"
rayon = "1.2.1" rayon = "1.2.1"
thiserror = "1.0.4" thiserror = "1.0.4"
@@ -43,10 +43,10 @@ errno = "0.2.4"
[dev-dependencies] [dev-dependencies]
tempfile = "3" tempfile = "3"
target-lexicon = { version = "0.9.0", default-features = false } target-lexicon = { version = "0.10.0", default-features = false }
pretty_env_logger = "0.3.0" pretty_env_logger = "0.3.0"
rand = { version = "0.7.0", default-features = false, features = ["small_rng"] } rand = { version = "0.7.0", default-features = false, features = ["small_rng"] }
cranelift-codegen = { version = "0.52.0", features = ["enable-serde", "all-arch"] } cranelift-codegen = { version = "0.54", features = ["enable-serde", "all-arch"] }
filetime = "0.2.7" filetime = "0.2.7"
[badges] [badges]

View File

@@ -362,6 +362,10 @@ impl<'module_environment> TargetEnvironment for FuncEnvironment<'module_environm
} }
impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'module_environment> { impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'module_environment> {
fn is_wasm_parameter(&self, func: &ir::Function, index: usize) -> bool {
func.signature.params[index].purpose == ir::ArgumentPurpose::Normal
}
fn make_table(&mut self, func: &mut ir::Function, index: TableIndex) -> WasmResult<ir::Table> { fn make_table(&mut self, func: &mut ir::Function, index: TableIndex) -> WasmResult<ir::Table> {
let pointer_type = self.pointer_type(); let pointer_type = self.pointer_type();

View File

@@ -136,17 +136,18 @@ pub struct Module {
/// Unprocessed signatures exactly as provided by `declare_signature()`. /// Unprocessed signatures exactly as provided by `declare_signature()`.
pub signatures: PrimaryMap<SignatureIndex, ir::Signature>, pub signatures: PrimaryMap<SignatureIndex, ir::Signature>,
/// Names of imported functions. /// Names of imported functions, as well as the index of the import that
pub imported_funcs: PrimaryMap<FuncIndex, (String, String)>, /// performed this import.
pub imported_funcs: PrimaryMap<FuncIndex, (String, String, u32)>,
/// Names of imported tables. /// Names of imported tables.
pub imported_tables: PrimaryMap<TableIndex, (String, String)>, pub imported_tables: PrimaryMap<TableIndex, (String, String, u32)>,
/// Names of imported memories. /// Names of imported memories.
pub imported_memories: PrimaryMap<MemoryIndex, (String, String)>, pub imported_memories: PrimaryMap<MemoryIndex, (String, String, u32)>,
/// Names of imported globals. /// Names of imported globals.
pub imported_globals: PrimaryMap<GlobalIndex, (String, String)>, pub imported_globals: PrimaryMap<GlobalIndex, (String, String, u32)>,
/// Types of functions, imported and local. /// Types of functions, imported and local.
pub functions: PrimaryMap<FuncIndex, SignatureIndex>, pub functions: PrimaryMap<FuncIndex, SignatureIndex>,

View File

@@ -55,6 +55,7 @@ impl<'data> ModuleTranslation<'data> {
pub struct ModuleEnvironment<'data> { pub struct ModuleEnvironment<'data> {
/// The result to be filled in. /// The result to be filled in.
result: ModuleTranslation<'data>, result: ModuleTranslation<'data>,
imports: u32,
} }
impl<'data> ModuleEnvironment<'data> { impl<'data> ModuleEnvironment<'data> {
@@ -69,6 +70,7 @@ impl<'data> ModuleEnvironment<'data> {
tunables, tunables,
module_translation: None, module_translation: None,
}, },
imports: 0,
} }
} }
@@ -123,10 +125,12 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
); );
self.result.module.functions.push(sig_index); self.result.module.functions.push(sig_index);
self.result self.result.module.imported_funcs.push((
.module String::from(module),
.imported_funcs String::from(field),
.push((String::from(module), String::from(field))); self.imports,
));
self.imports += 1;
Ok(()) Ok(())
} }
@@ -139,10 +143,12 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
let plan = TablePlan::for_table(table, &self.result.tunables); let plan = TablePlan::for_table(table, &self.result.tunables);
self.result.module.table_plans.push(plan); self.result.module.table_plans.push(plan);
self.result self.result.module.imported_tables.push((
.module String::from(module),
.imported_tables String::from(field),
.push((String::from(module), String::from(field))); self.imports,
));
self.imports += 1;
Ok(()) Ok(())
} }
@@ -160,10 +166,12 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
let plan = MemoryPlan::for_memory(memory, &self.result.tunables); let plan = MemoryPlan::for_memory(memory, &self.result.tunables);
self.result.module.memory_plans.push(plan); self.result.module.memory_plans.push(plan);
self.result self.result.module.imported_memories.push((
.module String::from(module),
.imported_memories String::from(field),
.push((String::from(module), String::from(field))); self.imports,
));
self.imports += 1;
Ok(()) Ok(())
} }
@@ -180,10 +188,12 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
); );
self.result.module.globals.push(global); self.result.module.globals.push(global);
self.result self.result.module.imported_globals.push((
.module String::from(module),
.imported_globals String::from(field),
.push((String::from(module), String::from(field))); self.imports,
));
self.imports += 1;
Ok(()) Ok(())
} }

View File

@@ -4,7 +4,7 @@ description = "Fuzzing infrastructure for Wasmtime"
edition = "2018" edition = "2018"
name = "wasmtime-fuzzing" name = "wasmtime-fuzzing"
publish = false publish = false
version = "0.1.0" version = "0.9.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -14,11 +14,11 @@ arbitrary = "0.2.0"
binaryen = "0.8.2" binaryen = "0.8.2"
env_logger = { version = "0.7.1", optional = true } env_logger = { version = "0.7.1", optional = true }
log = "0.4.8" log = "0.4.8"
wasmparser = "0.45.1" wasmparser = "0.47.0"
wasmprinter = "0.2.0" wasmprinter = "0.2.0"
wasmtime = { path = "../api" } wasmtime = { path = "../api", version = "0.9.0" }
wasmtime-environ = { path = "../environ" } wasmtime-environ = { path = "../environ", version = "0.9.0" }
wasmtime-jit = { path = "../jit" } wasmtime-jit = { path = "../jit", version = "0.9.0" }
[dev-dependencies] [dev-dependencies]
wat = "1.0" wat = "1.0"

View File

@@ -60,7 +60,7 @@ pub fn instantiate(wasm: &[u8], strategy: Strategy) {
// aren't caught during validation or compilation. For example, an imported // aren't caught during validation or compilation. For example, an imported
// table might not have room for an element segment that we want to // table might not have room for an element segment that we want to
// initialize into it. // initialize into it.
let _result = Instance::new(&store, &module, &imports); let _result = Instance::new(&module, &imports);
} }
/// Compile the Wasm buffer, and implicitly fail if we have an unexpected /// Compile the Wasm buffer, and implicitly fail if we have an unexpected
@@ -96,7 +96,7 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
let mut engine: Option<Engine> = None; let mut engine: Option<Engine> = None;
let mut store: Option<Store> = None; let mut store: Option<Store> = None;
let mut modules: HashMap<usize, Module> = Default::default(); let mut modules: HashMap<usize, Module> = Default::default();
let mut instances: HashMap<usize, HostRef<Instance>> = Default::default(); let mut instances: HashMap<usize, Instance> = Default::default();
for call in api.calls { for call in api.calls {
match call { match call {
@@ -152,8 +152,8 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
// aren't caught during validation or compilation. For example, an imported // aren't caught during validation or compilation. For example, an imported
// table might not have room for an element segment that we want to // table might not have room for an element segment that we want to
// initialize into it. // initialize into it.
if let Ok(instance) = Instance::new(store.as_ref().unwrap(), &module, &imports) { if let Ok(instance) = Instance::new(&module, &imports) {
instances.insert(id, HostRef::new(instance)); instances.insert(id, instance);
} }
} }
@@ -175,25 +175,22 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
} }
}; };
let funcs = { let funcs = instance
let instance = instance.borrow();
instance
.exports() .exports()
.iter() .iter()
.filter_map(|e| match e { .filter_map(|e| match e {
Extern::Func(f) => Some(f.clone()), Extern::Func(f) => Some(f.clone()),
_ => None, _ => None,
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>();
};
if funcs.is_empty() { if funcs.is_empty() {
continue; continue;
} }
let nth = nth % funcs.len(); let nth = nth % funcs.len();
let f = funcs[nth].borrow(); let f = &funcs[nth];
let ty = f.r#type(); let ty = f.ty();
let params = match ty let params = match ty
.params() .params()
.iter() .iter()

View File

@@ -2,7 +2,7 @@
use std::rc::Rc; use std::rc::Rc;
use wasmtime::{ use wasmtime::{
Callable, Extern, ExternType, Func, FuncType, Global, GlobalType, HostRef, ImportType, Memory, Callable, Extern, ExternType, Func, FuncType, Global, GlobalType, ImportType, Memory,
MemoryType, Store, Table, TableType, Trap, Val, ValType, MemoryType, Store, Table, TableType, Trap, Val, ValType,
}; };
@@ -11,18 +11,12 @@ pub fn dummy_imports(store: &Store, import_tys: &[ImportType]) -> Result<Vec<Ext
let mut imports = Vec::with_capacity(import_tys.len()); let mut imports = Vec::with_capacity(import_tys.len());
for imp in import_tys { for imp in import_tys {
imports.push(match imp.ty() { imports.push(match imp.ty() {
ExternType::Func(func_ty) => { ExternType::Func(func_ty) => Extern::Func(DummyFunc::new(&store, func_ty.clone())),
Extern::Func(HostRef::new(DummyFunc::new(&store, func_ty.clone())))
}
ExternType::Global(global_ty) => { ExternType::Global(global_ty) => {
Extern::Global(HostRef::new(dummy_global(&store, global_ty.clone())?)) Extern::Global(dummy_global(&store, global_ty.clone())?)
}
ExternType::Table(table_ty) => {
Extern::Table(HostRef::new(dummy_table(&store, table_ty.clone())?))
}
ExternType::Memory(mem_ty) => {
Extern::Memory(HostRef::new(dummy_memory(&store, mem_ty.clone())))
} }
ExternType::Table(table_ty) => Extern::Table(dummy_table(&store, table_ty.clone())?),
ExternType::Memory(mem_ty) => Extern::Memory(dummy_memory(&store, mem_ty.clone())),
}); });
} }
Ok(imports) Ok(imports)

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime-interface-types" name = "wasmtime-interface-types"
version = "0.7.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
description = "Support for wasm interface types with wasmtime" description = "Support for wasm interface types with wasmtime"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -13,13 +13,13 @@ edition = "2018"
[dependencies] [dependencies]
anyhow = "1.0.19" anyhow = "1.0.19"
walrus = "0.13" walrus = "0.13"
wasmparser = { version = "0.45.1", default-features = false } wasmparser = { version = "0.47.0", default-features = false }
wasm-webidl-bindings = "0.6" wasm-webidl-bindings = "0.6"
wasmtime = { path = '../api' } wasmtime = { path = "../api", version = "0.9.0" }
wasmtime-jit = { path = '../jit' } wasmtime-jit = { path = "../jit", version = "0.9.0" }
wasmtime-environ = { path = '../environ' } wasmtime-environ = { path = "../environ", version = "0.9.0" }
wasmtime-runtime = { path = '../runtime' } wasmtime-runtime = { path = "../runtime", version = "0.9.0" }
wasmtime-wasi = { path = '../wasi' } wasmtime-wasi = { path = "../wasi", version = "0.9.0" }
[badges] [badges]
maintenance = { status = "actively-developed" } maintenance = { status = "actively-developed" }

View File

@@ -125,18 +125,17 @@ impl ModuleData {
/// wasm interface types. /// wasm interface types.
pub fn invoke_export( pub fn invoke_export(
&self, &self,
instance: &wasmtime::HostRef<wasmtime::Instance>, instance: &wasmtime::Instance,
export: &str, export: &str,
args: &[Value], args: &[Value],
) -> Result<Vec<Value>> { ) -> Result<Vec<Value>> {
let mut handle = instance.borrow().handle().clone(); let mut handle = instance.handle().clone();
let binding = self.binding_for_export(&mut handle, export)?; let binding = self.binding_for_export(&mut handle, export)?;
let incoming = binding.param_bindings()?; let incoming = binding.param_bindings()?;
let outgoing = binding.result_bindings()?; let outgoing = binding.result_bindings()?;
let f = instance let f = instance
.borrow()
.find_export_by_name(export) .find_export_by_name(export)
.ok_or_else(|| format_err!("failed to find export `{}`", export))? .ok_or_else(|| format_err!("failed to find export `{}`", export))?
.func() .func()
@@ -148,7 +147,7 @@ impl ModuleData {
.into_iter() .into_iter()
.map(|rv| rv.into()) .map(|rv| rv.into())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let wasm_results = match f.borrow().call(&wasm_args) { let wasm_results = match f.call(&wasm_args) {
Ok(values) => values Ok(values) => values
.to_vec() .to_vec()
.into_iter() .into_iter()
@@ -322,20 +321,19 @@ trait TranslateContext {
unsafe fn get_memory(&mut self) -> Result<&mut [u8]>; unsafe fn get_memory(&mut self) -> Result<&mut [u8]>;
} }
struct InstanceTranslateContext(pub wasmtime::HostRef<wasmtime::Instance>); struct InstanceTranslateContext(pub wasmtime::Instance);
impl TranslateContext for InstanceTranslateContext { impl TranslateContext for InstanceTranslateContext {
fn invoke_alloc(&mut self, alloc_func_name: &str, len: i32) -> Result<i32> { fn invoke_alloc(&mut self, alloc_func_name: &str, len: i32) -> Result<i32> {
let alloc = self let alloc = self
.0 .0
.borrow()
.find_export_by_name(alloc_func_name) .find_export_by_name(alloc_func_name)
.ok_or_else(|| format_err!("failed to find alloc function `{}`", alloc_func_name))? .ok_or_else(|| format_err!("failed to find alloc function `{}`", alloc_func_name))?
.func() .func()
.ok_or_else(|| format_err!("`{}` is not a (alloc) function", alloc_func_name))? .ok_or_else(|| format_err!("`{}` is not a (alloc) function", alloc_func_name))?
.clone(); .clone();
let alloc_args = vec![wasmtime::Val::I32(len)]; let alloc_args = vec![wasmtime::Val::I32(len)];
let results = match alloc.borrow().call(&alloc_args) { let results = match alloc.call(&alloc_args) {
Ok(values) => values, Ok(values) => values,
Err(trap) => bail!("trapped: {:?}", trap), Err(trap) => bail!("trapped: {:?}", trap),
}; };
@@ -350,14 +348,13 @@ impl TranslateContext for InstanceTranslateContext {
unsafe fn get_memory(&mut self) -> Result<&mut [u8]> { unsafe fn get_memory(&mut self) -> Result<&mut [u8]> {
let memory = self let memory = self
.0 .0
.borrow()
.find_export_by_name("memory") .find_export_by_name("memory")
.ok_or_else(|| format_err!("failed to find `memory` export"))? .ok_or_else(|| format_err!("failed to find `memory` export"))?
.memory() .memory()
.ok_or_else(|| format_err!("`memory` is not a memory"))? .ok_or_else(|| format_err!("`memory` is not a memory"))?
.clone(); .clone();
let ptr = memory.borrow().data_ptr(); let ptr = memory.data_ptr();
let len = memory.borrow().data_size(); let len = memory.data_size();
Ok(std::slice::from_raw_parts_mut(ptr, len)) Ok(std::slice::from_raw_parts_mut(ptr, len))
} }
} }

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime-jit" name = "wasmtime-jit"
version = "0.7.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
description = "JIT-style execution for WebAsssembly code in Cranelift" description = "JIT-style execution for WebAsssembly code in Cranelift"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -11,18 +11,18 @@ readme = "README.md"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
cranelift-codegen = { version = "0.52.0", features = ["enable-serde"] } cranelift-codegen = { version = "0.54", features = ["enable-serde"] }
cranelift-entity = { version = "0.52.0", features = ["enable-serde"] } cranelift-entity = { version = "0.54", features = ["enable-serde"] }
cranelift-wasm = { version = "0.52.0", features = ["enable-serde"] } cranelift-wasm = { version = "0.54", features = ["enable-serde"] }
cranelift-native = "0.52.0" cranelift-native = "0.54"
cranelift-frontend = "0.52.0" cranelift-frontend = "0.54"
wasmtime-environ = { path = "../environ" } wasmtime-environ = { path = "../environ", version = "0.9.0" }
wasmtime-runtime = { path = "../runtime" } wasmtime-runtime = { path = "../runtime", version = "0.9.0" }
wasmtime-debug = { path = "../debug" } wasmtime-debug = { path = "../debug", version = "0.9.0" }
region = "2.0.0" region = "2.0.0"
thiserror = "1.0.4" thiserror = "1.0.4"
target-lexicon = { version = "0.9.0", default-features = false } target-lexicon = { version = "0.10.0", default-features = false }
wasmparser = { version = "0.45.1", default-features = false } wasmparser = { version = "0.47.0", default-features = false }
more-asserts = "0.2.1" more-asserts = "0.2.1"
anyhow = "1.0" anyhow = "1.0"

View File

@@ -14,6 +14,11 @@ pub struct CodeMemory {
published: usize, published: usize,
} }
fn _assert() {
fn _assert_send_sync<T: Send + Sync>() {}
_assert_send_sync::<CodeMemory>();
}
impl CodeMemory { impl CodeMemory {
/// Create a new `CodeMemory` instance. /// Create a new `CodeMemory` instance.
pub fn new() -> Self { pub fn new() -> Self {

View File

@@ -60,7 +60,7 @@ impl<'data> RawCompiledModule<'data> {
fn new( fn new(
compiler: &mut Compiler, compiler: &mut Compiler,
data: &'data [u8], data: &'data [u8],
module_name: Option<String>, module_name: Option<&str>,
resolver: &mut dyn Resolver, resolver: &mut dyn Resolver,
debug_info: bool, debug_info: bool,
) -> Result<Self, SetupError> { ) -> Result<Self, SetupError> {
@@ -76,7 +76,7 @@ impl<'data> RawCompiledModule<'data> {
None None
}; };
translation.module.name = module_name; translation.module.name = module_name.map(|s| s.to_string());
let (allocated_functions, jt_offsets, relocations, dbg_image) = compiler.compile( let (allocated_functions, jt_offsets, relocations, dbg_image) = compiler.compile(
&translation.module, &translation.module,
@@ -155,7 +155,7 @@ impl CompiledModule {
pub fn new<'data>( pub fn new<'data>(
compiler: &mut Compiler, compiler: &mut Compiler,
data: &'data [u8], data: &'data [u8],
module_name: Option<String>, module_name: Option<&str>,
resolver: &mut dyn Resolver, resolver: &mut dyn Resolver,
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>, global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
debug_info: bool, debug_info: bool,
@@ -263,7 +263,7 @@ impl OwnedDataInitializer {
pub fn instantiate( pub fn instantiate(
compiler: &mut Compiler, compiler: &mut Compiler,
data: &[u8], data: &[u8],
module_name: Option<String>, module_name: Option<&str>,
resolver: &mut dyn Resolver, resolver: &mut dyn Resolver,
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>, global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
debug_info: bool, debug_info: bool,

View File

@@ -30,8 +30,8 @@ pub fn link_module(
let mut dependencies = HashSet::new(); let mut dependencies = HashSet::new();
let mut function_imports = PrimaryMap::with_capacity(module.imported_funcs.len()); let mut function_imports = PrimaryMap::with_capacity(module.imported_funcs.len());
for (index, (ref module_name, ref field)) in module.imported_funcs.iter() { for (index, (module_name, field, import_idx)) in module.imported_funcs.iter() {
match resolver.resolve(module_name, field) { match resolver.resolve(*import_idx, module_name, field) {
Some(export_value) => match export_value { Some(export_value) => match export_value {
Export::Function { Export::Function {
address, address,
@@ -71,8 +71,8 @@ pub fn link_module(
} }
let mut table_imports = PrimaryMap::with_capacity(module.imported_tables.len()); let mut table_imports = PrimaryMap::with_capacity(module.imported_tables.len());
for (index, (ref module_name, ref field)) in module.imported_tables.iter() { for (index, (module_name, field, import_idx)) in module.imported_tables.iter() {
match resolver.resolve(module_name, field) { match resolver.resolve(*import_idx, module_name, field) {
Some(export_value) => match export_value { Some(export_value) => match export_value {
Export::Table { Export::Table {
definition, definition,
@@ -110,8 +110,8 @@ pub fn link_module(
} }
let mut memory_imports = PrimaryMap::with_capacity(module.imported_memories.len()); let mut memory_imports = PrimaryMap::with_capacity(module.imported_memories.len());
for (index, (ref module_name, ref field)) in module.imported_memories.iter() { for (index, (module_name, field, import_idx)) in module.imported_memories.iter() {
match resolver.resolve(module_name, field) { match resolver.resolve(*import_idx, module_name, field) {
Some(export_value) => match export_value { Some(export_value) => match export_value {
Export::Memory { Export::Memory {
definition, definition,
@@ -163,8 +163,8 @@ pub fn link_module(
} }
let mut global_imports = PrimaryMap::with_capacity(module.imported_globals.len()); let mut global_imports = PrimaryMap::with_capacity(module.imported_globals.len());
for (index, (ref module_name, ref field)) in module.imported_globals.iter() { for (index, (module_name, field, import_idx)) in module.imported_globals.iter() {
match resolver.resolve(module_name, field) { match resolver.resolve(*import_idx, module_name, field) {
Some(export_value) => match export_value { Some(export_value) => match export_value {
Export::Table { .. } | Export::Memory { .. } | Export::Function { .. } => { Export::Table { .. } | Export::Memory { .. } | Export::Function { .. } => {
return Err(LinkError(format!( return Err(LinkError(format!(

View File

@@ -36,7 +36,7 @@ impl Namespace {
} }
impl Resolver for Namespace { impl Resolver for Namespace {
fn resolve(&mut self, name: &str, field: &str) -> Option<Export> { fn resolve(&mut self, _idx: u32, name: &str, field: &str) -> Option<Export> {
if let Some(instance) = self.names.get_mut(name) { if let Some(instance) = self.names.get_mut(name) {
instance.lookup(field) instance.lookup(field)
} else { } else {

View File

@@ -5,15 +5,22 @@ use wasmtime_runtime::Export;
/// Import resolver connects imports with available exported values. /// Import resolver connects imports with available exported values.
pub trait Resolver { pub trait Resolver {
/// Resolve the given module/field combo. /// Resolves an import a WebAssembly module to an export it's hooked up to.
fn resolve(&mut self, module: &str, field: &str) -> Option<Export>; ///
/// The `index` provided is the index of the import in the wasm module
/// that's being resolved. For example 1 means that it's the second import
/// listed in the wasm module.
///
/// The `module` and `field` arguments provided are the module/field names
/// listed on the import itself.
fn resolve(&mut self, index: u32, module: &str, field: &str) -> Option<Export>;
} }
/// `Resolver` implementation that always resolves to `None`. /// `Resolver` implementation that always resolves to `None`.
pub struct NullResolver {} pub struct NullResolver {}
impl Resolver for NullResolver { impl Resolver for NullResolver {
fn resolve(&mut self, _module: &str, _field: &str) -> Option<Export> { fn resolve(&mut self, _idx: u32, _module: &str, _field: &str) -> Option<Export> {
None None
} }
} }

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "lightbeam" name = "lightbeam"
version = "0.7.0" version = "0.9.0"
authors = ["The Lightbeam Project Developers"] authors = ["The Lightbeam Project Developers"]
description = "An optimising one-pass streaming compiler for WebAssembly" description = "An optimising one-pass streaming compiler for WebAssembly"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -14,12 +14,12 @@ edition = "2018"
smallvec = "1.0.0" smallvec = "1.0.0"
dynasm = "0.5.2" dynasm = "0.5.2"
dynasmrt = "0.5.2" dynasmrt = "0.5.2"
wasmparser = "0.45.1" wasmparser = "0.47.0"
memoffset = "0.5.3" memoffset = "0.5.3"
itertools = "0.8.2" itertools = "0.8.2"
capstone = "0.6.0" capstone = "0.6.0"
thiserror = "1.0.9" thiserror = "1.0.9"
cranelift-codegen = "0.52.0" cranelift-codegen = "0.54"
multi_mut = "0.1" multi_mut = "0.1"
either = "1.5" either = "1.5"
typemap = "0.3" typemap = "0.3"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime-py" name = "wasmtime-py"
version = "0.7.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
description = "Python extension for Wasmtime" description = "Python extension for Wasmtime"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -17,15 +17,15 @@ test = false
doc = false doc = false
[dependencies] [dependencies]
wasmtime = { path = "../../api" } wasmtime = { path = "../../api", version = "0.9.0" }
wasmtime-environ = { path = "../../environ" } wasmtime-environ = { path = "../../environ", version = "0.9.0" }
wasmtime-interface-types = { path = "../../interface-types" } wasmtime-interface-types = { path = "../../interface-types", version = "0.9.0" }
wasmtime-runtime = { path = "../../runtime" } wasmtime-runtime = { path = "../../runtime", version = "0.9.0" }
wasmtime-wasi = { path = "../../wasi" } wasmtime-wasi = { path = "../../wasi", version = "0.9.0" }
target-lexicon = { version = "0.9.0", default-features = false } target-lexicon = { version = "0.10.0", default-features = false }
anyhow = "1.0.19" anyhow = "1.0.19"
region = "2.0.0" region = "2.0.0"
wasmparser = "0.45.1" wasmparser = "0.47.0"
pyo3 = { version = "0.8.0", features = ["extension-module"] } pyo3 = { version = "0.8.0", features = ["extension-module"] }
[badges] [badges]

View File

@@ -10,17 +10,16 @@ use wasmtime_interface_types::ModuleData;
// TODO support non-export functions // TODO support non-export functions
#[pyclass] #[pyclass]
pub struct Function { pub struct Function {
pub instance: wasmtime::HostRef<wasmtime::Instance>, pub instance: wasmtime::Instance,
pub export_name: String, pub export_name: String,
pub args_types: Vec<wasmtime::ValType>, pub args_types: Vec<wasmtime::ValType>,
pub data: Rc<ModuleData>, pub data: Rc<ModuleData>,
} }
impl Function { impl Function {
pub fn func(&self) -> wasmtime::HostRef<wasmtime::Func> { pub fn func(&self) -> wasmtime::Func {
let e = self let e = self
.instance .instance
.borrow()
.find_export_by_name(&self.export_name) .find_export_by_name(&self.export_name)
.expect("named export") .expect("named export")
.clone(); .clone();
@@ -125,10 +124,7 @@ impl wasmtime::Callable for WrappedFn {
} }
} }
pub fn wrap_into_pyfunction( pub fn wrap_into_pyfunction(store: &wasmtime::Store, callable: &PyAny) -> PyResult<wasmtime::Func> {
store: &wasmtime::Store,
callable: &PyAny,
) -> PyResult<wasmtime::HostRef<wasmtime::Func>> {
if !callable.hasattr("__annotations__")? { if !callable.hasattr("__annotations__")? {
// TODO support calls without annotations? // TODO support calls without annotations?
return Err(PyErr::new::<Exception, _>( return Err(PyErr::new::<Exception, _>(
@@ -154,6 +150,5 @@ pub fn wrap_into_pyfunction(
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let wrapped = WrappedFn::new(callable.to_object(gil.python()), returns); let wrapped = WrappedFn::new(callable.to_object(gil.python()), returns);
let f = wasmtime::Func::new(store, ft, Rc::new(wrapped)); Ok(wasmtime::Func::new(store, ft, Rc::new(wrapped)))
Ok(wasmtime::HostRef::new(f))
} }

View File

@@ -9,7 +9,7 @@ use wasmtime_interface_types::ModuleData;
#[pyclass] #[pyclass]
pub struct Instance { pub struct Instance {
pub instance: wasmtime::HostRef<wasmtime::Instance>, pub instance: wasmtime::Instance,
pub data: Rc<ModuleData>, pub data: Rc<ModuleData>,
} }
@@ -20,7 +20,7 @@ impl Instance {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let exports = PyDict::new(py); let exports = PyDict::new(py);
let module = self.instance.borrow().module().clone(); let module = self.instance.module().clone();
for (i, e) in module.exports().iter().enumerate() { for (i, e) in module.exports().iter().enumerate() {
match e.ty() { match e.ty() {
wasmtime::ExternType::Func(ft) => { wasmtime::ExternType::Func(ft) => {
@@ -43,10 +43,7 @@ impl Instance {
let f = Py::new( let f = Py::new(
py, py,
Memory { Memory {
memory: self.instance.borrow().exports()[i] memory: self.instance.exports()[i].memory().unwrap().clone(),
.memory()
.unwrap()
.clone(),
}, },
)?; )?;
exports.set_item(e.name().to_string(), f)?; exports.set_item(e.name().to_string(), f)?;

View File

@@ -1,5 +1,3 @@
#![allow(improper_ctypes)]
use crate::function::{wrap_into_pyfunction, Function}; use crate::function::{wrap_into_pyfunction, Function};
use crate::instance::Instance; use crate::instance::Instance;
use crate::memory::Memory; use crate::memory::Memory;
@@ -122,10 +120,8 @@ pub fn instantiate(
} }
} }
let instance = wasmtime::HostRef::new( let instance = wasmtime::Instance::new(&module, &imports)
wasmtime::Instance::new(&store, &module, &imports) .map_err(|t| PyErr::new::<Exception, _>(format!("instantiated with trap {:?}", t)))?;
.map_err(|t| PyErr::new::<Exception, _>(format!("instantiated with trap {:?}", t)))?,
);
let module = Py::new(py, Module { module })?; let module = Py::new(py, Module { module })?;

View File

@@ -10,14 +10,14 @@ use std::ptr;
#[pyclass] #[pyclass]
pub struct Memory { pub struct Memory {
pub memory: wasmtime::HostRef<wasmtime::Memory>, pub memory: wasmtime::Memory,
} }
#[pymethods] #[pymethods]
impl Memory { impl Memory {
#[getter(current)] #[getter(current)]
pub fn current(&self) -> u32 { pub fn current(&self) -> u32 {
self.memory.borrow().size() self.memory.size()
} }
pub fn grow(&self, _number: u32) -> u32 { pub fn grow(&self, _number: u32) -> u32 {
@@ -48,8 +48,8 @@ impl PyBufferProtocol for Memory {
}; };
unsafe { unsafe {
let base = self.memory.borrow().data_ptr(); let base = self.memory.data_ptr();
let current_length = self.memory.borrow().data_size(); let current_length = self.memory.data_size();
(*view).buf = base as *mut c_void; (*view).buf = base as *mut c_void;
(*view).len = current_length as isize; (*view).len = current_length as isize;

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime-rust" name = "wasmtime-rust"
version = "0.7.0" version = "0.9.0"
authors = ["Alex Crichton <alex@alexcrichton.com>"] authors = ["Alex Crichton <alex@alexcrichton.com>"]
description = "Rust extension for Wasmtime" description = "Rust extension for Wasmtime"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -15,10 +15,10 @@ test = false
doctest = false doctest = false
[dependencies] [dependencies]
wasmtime-interface-types = { path = "../../interface-types" } wasmtime-interface-types = { path = "../../interface-types", version = "0.9.0" }
wasmtime-rust-macro = { path = "./macro" } wasmtime-rust-macro = { path = "./macro", version = "0.9.0" }
wasmtime-wasi = { path = "../../wasi" } wasmtime-wasi = { path = "../../wasi", version = "0.9.0" }
wasmtime = { path = "../../api" } wasmtime = { path = "../../api", version = "0.9.0" }
anyhow = "1.0.19" anyhow = "1.0.19"
[badges] [badges]

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime-rust-macro" name = "wasmtime-rust-macro"
version = "0.7.0" version = "0.9.0"
authors = ["Alex Crichton <alex@alexcrichton.com>"] authors = ["Alex Crichton <alex@alexcrichton.com>"]
description = "Macro support crate for wasmtime-rust" description = "Macro support crate for wasmtime-rust"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"

View File

@@ -34,7 +34,7 @@ fn generate_struct(item: &syn::ItemTrait) -> syn::Result<TokenStream> {
let root = root(); let root = root();
Ok(quote! { Ok(quote! {
#vis struct #name { #vis struct #name {
instance: #root::wasmtime::HostRef<#root::wasmtime::Instance>, instance: #root::wasmtime::Instance,
data: #root::wasmtime_interface_types::ModuleData, data: #root::wasmtime_interface_types::ModuleData,
} }
}) })
@@ -48,7 +48,7 @@ fn generate_load(item: &syn::ItemTrait) -> syn::Result<TokenStream> {
#vis fn load_file(path: impl AsRef<std::path::Path>) -> #root::anyhow::Result<#name> { #vis fn load_file(path: impl AsRef<std::path::Path>) -> #root::anyhow::Result<#name> {
let bytes = std::fs::read(path)?; let bytes = std::fs::read(path)?;
use #root::wasmtime::{HostRef, Config, Extern, Engine, Store, Instance, Module}; use #root::wasmtime::{Config, Extern, Engine, Store, Instance, Module};
use #root::anyhow::{bail, format_err}; use #root::anyhow::{bail, format_err};
let engine = Engine::new(Config::new().wasm_multi_value(true)); let engine = Engine::new(Config::new().wasm_multi_value(true));
@@ -74,9 +74,8 @@ fn generate_load(item: &syn::ItemTrait) -> syn::Result<TokenStream> {
} }
} }
} }
let instance = HostRef::new( let instance =
Instance::new(&store, &module, &imports).map_err(|t| format_err!("instantiation trap: {:?}", t))? Instance::new(&module, &imports).map_err(|t| format_err!("instantiation trap: {:?}", t))?;
);
Ok(#name { instance, data }) Ok(#name { instance, data })
} }

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime-obj" name = "wasmtime-obj"
version = "0.7.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
description = "Native object file output for WebAsssembly code in Wasmtime" description = "Native object file output for WebAsssembly code in Wasmtime"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -12,8 +12,8 @@ edition = "2018"
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
wasmtime-environ = { path = "../environ" } wasmtime-environ = { path = "../environ", version = "0.9.0" }
faerie = "0.13.0" faerie = "0.14.0"
more-asserts = "0.2.1" more-asserts = "0.2.1"
[badges] [badges]

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime-runtime" name = "wasmtime-runtime"
version = "0.7.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
description = "Runtime library support for Wasmtime" description = "Runtime library support for Wasmtime"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -11,7 +11,7 @@ readme = "README.md"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
wasmtime-environ = { path = "../environ" } wasmtime-environ = { path = "../environ", version = "0.9.0" }
region = "2.0.0" region = "2.0.0"
lazy_static = "1.2.0" lazy_static = "1.2.0"
libc = { version = "0.2.60", default-features = false } libc = { version = "0.2.60", default-features = false }

View File

@@ -1,6 +1,5 @@
//! Runtime library support for Wasmtime. //! Runtime library support for Wasmtime.
#![allow(improper_ctypes)]
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] #![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)] #![warn(unused_import_braces)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))] #![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]

View File

@@ -1,11 +1,8 @@
//! Low-level abstraction for allocating and managing zero-filled pages //! Low-level abstraction for allocating and managing zero-filled pages
//! of memory. //! of memory.
#[cfg(not(target_os = "windows"))]
use libc;
use more_asserts::assert_le; use more_asserts::assert_le;
use more_asserts::assert_lt; use more_asserts::assert_lt;
use region;
use std::io; use std::io;
use std::ptr; use std::ptr;
use std::slice; use std::slice;
@@ -19,7 +16,11 @@ fn round_up_to_page_size(size: usize, page_size: usize) -> usize {
/// and initially-zeroed memory and a length. /// and initially-zeroed memory and a length.
#[derive(Debug)] #[derive(Debug)]
pub struct Mmap { pub struct Mmap {
ptr: *mut u8, // Note that this is stored as a `usize` instead of a `*const` or `*mut`
// pointer to allow this structure to be natively `Send` and `Sync` without
// `unsafe impl`. This type is sendable across threads and shareable since
// the coordination all happens at the OS layer.
ptr: usize,
len: usize, len: usize,
} }
@@ -29,8 +30,9 @@ impl Mmap {
// Rust's slices require non-null pointers, even when empty. `Vec` // Rust's slices require non-null pointers, even when empty. `Vec`
// contains code to create a non-null dangling pointer value when // contains code to create a non-null dangling pointer value when
// constructed empty, so we reuse that here. // constructed empty, so we reuse that here.
let empty = Vec::<u8>::new();
Self { Self {
ptr: Vec::new().as_mut_ptr(), ptr: empty.as_ptr() as usize,
len: 0, len: 0,
} }
} }
@@ -78,7 +80,7 @@ impl Mmap {
} }
Self { Self {
ptr: ptr as *mut u8, ptr: ptr as usize,
len: mapping_size, len: mapping_size,
} }
} else { } else {
@@ -98,7 +100,7 @@ impl Mmap {
} }
let mut result = Self { let mut result = Self {
ptr: ptr as *mut u8, ptr: ptr as usize,
len: mapping_size, len: mapping_size,
}; };
@@ -142,7 +144,7 @@ impl Mmap {
} }
Self { Self {
ptr: ptr as *mut u8, ptr: ptr as usize,
len: mapping_size, len: mapping_size,
} }
} else { } else {
@@ -154,7 +156,7 @@ impl Mmap {
} }
let mut result = Self { let mut result = Self {
ptr: ptr as *mut u8, ptr: ptr as usize,
len: mapping_size, len: mapping_size,
}; };
@@ -179,7 +181,8 @@ impl Mmap {
assert_lt!(start, self.len - len); assert_lt!(start, self.len - len);
// Commit the accessible size. // Commit the accessible size.
unsafe { region::protect(self.ptr.add(start), len, region::Protection::ReadWrite) } let ptr = self.ptr as *const u8;
unsafe { region::protect(ptr.add(start), len, region::Protection::ReadWrite) }
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
} }
@@ -198,9 +201,10 @@ impl Mmap {
assert_lt!(start, self.len - len); assert_lt!(start, self.len - len);
// Commit the accessible size. // Commit the accessible size.
let ptr = self.ptr as *const u8;
if unsafe { if unsafe {
VirtualAlloc( VirtualAlloc(
self.ptr.add(start) as *mut c_void, ptr.add(start) as *mut c_void,
len, len,
MEM_COMMIT, MEM_COMMIT,
PAGE_READWRITE, PAGE_READWRITE,
@@ -216,22 +220,22 @@ impl Mmap {
/// Return the allocated memory as a slice of u8. /// Return the allocated memory as a slice of u8.
pub fn as_slice(&self) -> &[u8] { pub fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.ptr, self.len) } unsafe { slice::from_raw_parts(self.ptr as *const u8, self.len) }
} }
/// Return the allocated memory as a mutable slice of u8. /// Return the allocated memory as a mutable slice of u8.
pub fn as_mut_slice(&mut self) -> &mut [u8] { pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.ptr, self.len) } unsafe { slice::from_raw_parts_mut(self.ptr as *mut u8, self.len) }
} }
/// Return the allocated memory as a pointer to u8. /// Return the allocated memory as a pointer to u8.
pub fn as_ptr(&self) -> *const u8 { pub fn as_ptr(&self) -> *const u8 {
self.ptr self.ptr as *const u8
} }
/// Return the allocated memory as a mutable pointer to u8. /// Return the allocated memory as a mutable pointer to u8.
pub fn as_mut_ptr(&mut self) -> *mut u8 { pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.ptr self.ptr as *mut u8
} }
/// Return the length of the allocated memory. /// Return the length of the allocated memory.
@@ -266,6 +270,11 @@ impl Drop for Mmap {
} }
} }
fn _assert() {
fn _assert_send_sync<T: Send + Sync>() {}
_assert_send_sync::<Mmap>();
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "test-programs" name = "test-programs"
version = "0.7.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
readme = "README.md" readme = "README.md"
edition = "2018" edition = "2018"
@@ -10,13 +10,13 @@ publish = false
cfg-if = "0.1.9" cfg-if = "0.1.9"
[dev-dependencies] [dev-dependencies]
wasi-common = { path = "../wasi-common" } wasi-common = { path = "../wasi-common", version = "0.9.0" }
wasmtime-runtime = { path = "../runtime" } wasmtime-runtime = { path = "../runtime", version = "0.9.0" }
wasmtime-environ = { path = "../environ" } wasmtime-environ = { path = "../environ", version = "0.9.0" }
wasmtime-jit = { path = "../jit" } wasmtime-jit = { path = "../jit", version = "0.9.0" }
wasmtime-wasi = { path = "../wasi" } wasmtime-wasi = { path = "../wasi", version = "0.9.0" }
wasmtime = { path = "../api" } wasmtime = { path = "../api", version = "0.9.0" }
target-lexicon = "0.9.0" target-lexicon = "0.10.0"
pretty_env_logger = "0.3.0" pretty_env_logger = "0.3.0"
tempfile = "3.1.0" tempfile = "3.1.0"
os_pipe = "0.9" os_pipe = "0.9"

View File

@@ -1,7 +1,7 @@
use anyhow::{bail, Context}; use anyhow::{bail, Context};
use std::fs::File; use std::fs::File;
use std::path::Path; use std::path::Path;
use wasmtime::{HostRef, Instance, Module, Store}; use wasmtime::{Instance, Module, Store};
pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> anyhow::Result<()> { pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> anyhow::Result<()> {
let store = Store::default(); let store = Store::default();
@@ -61,13 +61,12 @@ pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> any
}) })
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let instance = HostRef::new(Instance::new(&store, &module, &imports).context(format!( let instance = Instance::new(&module, &imports).context(format!(
"error while instantiating Wasm module '{}'", "error while instantiating Wasm module '{}'",
bin_name, bin_name,
))?); ))?;
let export = instance let export = instance
.borrow()
.find_export_by_name("_start") .find_export_by_name("_start")
.context("expected a _start export")? .context("expected a _start export")?
.clone(); .clone();
@@ -75,7 +74,6 @@ pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> any
if let Err(trap) = export if let Err(trap) = export
.func() .func()
.context("expected export to be a func")? .context("expected export to be a func")?
.borrow()
.call(&[]) .call(&[])
{ {
bail!("trapped: {:?}", trap); bail!("trapped: {:?}", trap);

View File

@@ -0,0 +1,30 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "libc"
version = "0.2.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "more-asserts"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wasi-tests"
version = "0.9.0"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"more-asserts 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
"checksum more-asserts 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238"
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasi-tests" name = "wasi-tests"
version = "0.7.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
readme = "README.md" readme = "README.md"
edition = "2018" edition = "2018"

View File

@@ -9,7 +9,11 @@ unsafe fn test_fd_advise(dir_fd: wasi::Fd) {
0, 0,
"file", "file",
wasi::OFLAGS_CREAT, wasi::OFLAGS_CREAT,
wasi::RIGHTS_FD_READ | wasi::RIGHTS_FD_WRITE, wasi::RIGHTS_FD_READ
| wasi::RIGHTS_FD_WRITE
| wasi::RIGHTS_FD_ADVISE
| wasi::RIGHTS_FD_FILESTAT_GET
| wasi::RIGHTS_FD_ALLOCATE,
0, 0,
0, 0,
) )

View File

@@ -9,7 +9,11 @@ unsafe fn test_fd_filestat_set(dir_fd: wasi::Fd) {
0, 0,
"file", "file",
wasi::OFLAGS_CREAT, wasi::OFLAGS_CREAT,
wasi::RIGHTS_FD_READ | wasi::RIGHTS_FD_WRITE, wasi::RIGHTS_FD_READ
| wasi::RIGHTS_FD_WRITE
| wasi::RIGHTS_FD_FILESTAT_GET
| wasi::RIGHTS_FD_FILESTAT_SET_SIZE
| wasi::RIGHTS_FD_FILESTAT_SET_TIMES,
0, 0,
0, 0,
) )

View File

@@ -0,0 +1,165 @@
use std::{env, process};
use wasi;
use wasi_tests::open_scratch_directory;
unsafe fn test_fd_fdstat_set_flags(dir_fd: wasi::Fd) {
const FILE_NAME: &str = "file";
let data = &[0u8; 100];
let file_fd = wasi::path_open(
dir_fd,
0,
FILE_NAME,
wasi::OFLAGS_CREAT,
wasi::RIGHTS_FD_READ
| wasi::RIGHTS_FD_WRITE
| wasi::RIGHTS_FD_SEEK
| wasi::RIGHTS_FD_TELL
| wasi::RIGHTS_FD_FDSTAT_SET_FLAGS,
0,
wasi::FDFLAGS_APPEND,
)
.expect("opening a file");
// Write some data and then verify the written data
assert_eq!(
wasi::fd_write(
file_fd,
&[wasi::Ciovec {
buf: data.as_ptr(),
buf_len: data.len(),
}],
)
.expect("writing to a file"),
data.len(),
"should write {} bytes",
data.len(),
);
wasi::fd_seek(file_fd, 0, wasi::WHENCE_SET).expect("seeking file");
let buffer = &mut [0u8; 100];
assert_eq!(
wasi::fd_read(
file_fd,
&[wasi::Iovec {
buf: buffer.as_mut_ptr(),
buf_len: buffer.len(),
}]
)
.expect("reading file"),
buffer.len(),
"shoudl read {} bytes",
buffer.len()
);
assert_eq!(&data[..], &buffer[..]);
let data = &[1u8; 100];
// Seek back to the start to ensure we're in append-only mode
wasi::fd_seek(file_fd, 0, wasi::WHENCE_SET).expect("seeking file");
assert_eq!(
wasi::fd_write(
file_fd,
&[wasi::Ciovec {
buf: data.as_ptr(),
buf_len: data.len(),
}],
)
.expect("writing to a file"),
data.len(),
"should write {} bytes",
data.len(),
);
wasi::fd_seek(file_fd, 100, wasi::WHENCE_SET).expect("seeking file");
assert_eq!(
wasi::fd_read(
file_fd,
&[wasi::Iovec {
buf: buffer.as_mut_ptr(),
buf_len: buffer.len(),
}]
)
.expect("reading file"),
buffer.len(),
"shoudl read {} bytes",
buffer.len()
);
assert_eq!(&data[..], &buffer[..]);
wasi::fd_fdstat_set_flags(file_fd, 0).expect("disabling flags");
// Overwrite some existing data to ensure the append mode is now off
wasi::fd_seek(file_fd, 0, wasi::WHENCE_SET).expect("seeking file");
let data = &[2u8; 100];
assert_eq!(
wasi::fd_write(
file_fd,
&[wasi::Ciovec {
buf: data.as_ptr(),
buf_len: data.len(),
}],
)
.expect("writing to a file"),
data.len(),
"should write {} bytes",
data.len(),
);
wasi::fd_seek(file_fd, 0, wasi::WHENCE_SET).expect("seeking file");
assert_eq!(
wasi::fd_read(
file_fd,
&[wasi::Iovec {
buf: buffer.as_mut_ptr(),
buf_len: buffer.len(),
}]
)
.expect("reading file"),
buffer.len(),
"shoudl read {} bytes",
buffer.len()
);
assert_eq!(&data[..], &buffer[..]);
wasi::fd_close(file_fd).expect("close file");
let stat = wasi::path_filestat_get(dir_fd, 0, FILE_NAME).expect("stat path");
assert_eq!(stat.size, 200, "expected a file size of 200");
wasi::path_unlink_file(dir_fd, FILE_NAME).expect("unlinking file");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", prog);
process::exit(1);
};
let dir_fd = match open_scratch_directory(&arg) {
Ok(dir_fd) => dir_fd,
Err(err) => {
eprintln!("{}", err);
process::exit(1)
}
};
unsafe {
test_fd_fdstat_set_flags(dir_fd);
}
}

View File

@@ -90,7 +90,10 @@ unsafe fn test_fd_readdir(dir_fd: wasi::Fd) {
0, 0,
"file", "file",
wasi::OFLAGS_CREAT, wasi::OFLAGS_CREAT,
wasi::RIGHTS_FD_READ | wasi::RIGHTS_FD_WRITE, wasi::RIGHTS_FD_READ
| wasi::RIGHTS_FD_WRITE
| wasi::RIGHTS_FD_READDIR
| wasi::RIGHTS_FD_FILESTAT_GET,
0, 0,
0, 0,
) )

View File

@@ -9,7 +9,10 @@ unsafe fn test_file_allocate(dir_fd: wasi::Fd) {
0, 0,
"file", "file",
wasi::OFLAGS_CREAT, wasi::OFLAGS_CREAT,
wasi::RIGHTS_FD_READ | wasi::RIGHTS_FD_WRITE, wasi::RIGHTS_FD_READ
| wasi::RIGHTS_FD_WRITE
| wasi::RIGHTS_FD_ALLOCATE
| wasi::RIGHTS_FD_FILESTAT_GET,
0, 0,
0, 0,
) )

View File

@@ -9,7 +9,7 @@ unsafe fn test_file_seek_tell(dir_fd: wasi::Fd) {
0, 0,
"file", "file",
wasi::OFLAGS_CREAT, wasi::OFLAGS_CREAT,
wasi::RIGHTS_FD_READ | wasi::RIGHTS_FD_WRITE, wasi::RIGHTS_FD_READ | wasi::RIGHTS_FD_WRITE | wasi::RIGHTS_FD_SEEK | wasi::RIGHTS_FD_TELL,
0, 0,
0, 0,
) )

View File

@@ -2,8 +2,15 @@ use more_asserts::assert_gt;
use std::{env, process}; use std::{env, process};
use wasi_tests::{create_file, open_scratch_directory}; use wasi_tests::{create_file, open_scratch_directory};
const TEST_RIGHTS: wasi::Rights = wasi::RIGHTS_FD_READ
| wasi::RIGHTS_PATH_LINK_SOURCE
| wasi::RIGHTS_PATH_LINK_TARGET
| wasi::RIGHTS_FD_FILESTAT_GET
| wasi::RIGHTS_PATH_OPEN
| wasi::RIGHTS_PATH_UNLINK_FILE;
unsafe fn create_or_open(dir_fd: wasi::Fd, name: &str, flags: wasi::Oflags) -> wasi::Fd { unsafe fn create_or_open(dir_fd: wasi::Fd, name: &str, flags: wasi::Oflags) -> wasi::Fd {
let file_fd = wasi::path_open(dir_fd, 0, name, flags, 0, 0, 0) let file_fd = wasi::path_open(dir_fd, 0, name, flags, TEST_RIGHTS, TEST_RIGHTS, 0)
.unwrap_or_else(|_| panic!("opening '{}'", name)); .unwrap_or_else(|_| panic!("opening '{}'", name));
assert_gt!( assert_gt!(
file_fd, file_fd,
@@ -14,7 +21,7 @@ unsafe fn create_or_open(dir_fd: wasi::Fd, name: &str, flags: wasi::Oflags) -> w
} }
unsafe fn open_link(dir_fd: wasi::Fd, name: &str) -> wasi::Fd { unsafe fn open_link(dir_fd: wasi::Fd, name: &str) -> wasi::Fd {
let file_fd = wasi::path_open(dir_fd, 0, name, 0, 0, 0, 0) let file_fd = wasi::path_open(dir_fd, 0, name, 0, TEST_RIGHTS, TEST_RIGHTS, 0)
.unwrap_or_else(|_| panic!("opening a link '{}'", name)); .unwrap_or_else(|_| panic!("opening a link '{}'", name));
assert_gt!( assert_gt!(
file_fd, file_fd,

View File

@@ -0,0 +1,79 @@
use std::{env, process};
use wasi_tests::open_scratch_directory;
use wasi_tests::{create_file, drop_rights, fd_get_rights};
const TEST_FILENAME: &'static str = "file";
unsafe fn try_read_file(dir_fd: wasi::Fd) {
let fd = wasi::path_open(dir_fd, 0, TEST_FILENAME, 0, 0, 0, 0).expect("opening the file");
// Check that we don't have the right to exeucute fd_read
let (rbase, rinher) = fd_get_rights(fd);
assert_eq!(
rbase & wasi::RIGHTS_FD_READ,
0,
"should not have base RIGHTS_FD_READ"
);
assert_eq!(
rinher & wasi::RIGHTS_FD_READ,
0,
"should not have inheriting RIGHTS_FD_READ"
);
let contents = &mut [0u8; 1];
let iovec = wasi::Iovec {
buf: contents.as_mut_ptr() as *mut _,
buf_len: contents.len(),
};
// Since we no longer have the right to fd_read, trying to read a file
// should be an error.
assert_eq!(
wasi::fd_read(fd, &[iovec])
.expect_err("reading bytes from file should fail")
.raw_error(),
wasi::ERRNO_NOTCAPABLE,
"the errno should be ENOTCAPABLE"
);
}
unsafe fn test_read_rights(dir_fd: wasi::Fd) {
create_file(dir_fd, TEST_FILENAME);
drop_rights(dir_fd, wasi::RIGHTS_FD_READ, wasi::RIGHTS_FD_READ);
let (rbase, rinher) = fd_get_rights(dir_fd);
assert_eq!(
rbase & wasi::RIGHTS_FD_READ,
0,
"dir should not have base RIGHTS_FD_READ"
);
assert_eq!(
rinher & wasi::RIGHTS_FD_READ,
0,
"dir should not have inheriting RIGHTS_FD_READ"
);
try_read_file(dir_fd);
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", prog);
process::exit(1);
};
// Open scratch directory
let dir_fd = match open_scratch_directory(&arg) {
Ok(dir_fd) => dir_fd,
Err(err) => {
eprintln!("{}", err);
process::exit(1)
}
};
// Run the tests.
unsafe { test_read_rights(dir_fd) }
}

View File

@@ -198,7 +198,7 @@ unsafe fn test_fd_readwrite_valid_fd(dir_fd: wasi::Fd) {
0, 0,
"file", "file",
wasi::OFLAGS_CREAT, wasi::OFLAGS_CREAT,
wasi::RIGHTS_FD_READ | wasi::RIGHTS_FD_WRITE, wasi::RIGHTS_FD_READ | wasi::RIGHTS_FD_WRITE | wasi::RIGHTS_POLL_FD_READWRITE,
0, 0,
0, 0,
) )

View File

@@ -24,8 +24,11 @@ pub fn open_scratch_directory(path: &str) -> Result<wasi::Fd, String> {
} }
dst.set_len(stat.u.dir.pr_name_len); dst.set_len(stat.u.dir.pr_name_len);
if dst == path.as_bytes() { if dst == path.as_bytes() {
return Ok(wasi::path_open(i, 0, ".", wasi::OFLAGS_DIRECTORY, 0, 0, 0) let (base, inherit) = fd_get_rights(i);
.expect("failed to open dir")); return Ok(
wasi::path_open(i, 0, ".", wasi::OFLAGS_DIRECTORY, base, inherit, 0)
.expect("failed to open dir"),
);
} }
} }
@@ -43,3 +46,18 @@ pub unsafe fn create_file(dir_fd: wasi::Fd, filename: &str) {
); );
wasi::fd_close(file_fd).expect("closing a file"); wasi::fd_close(file_fd).expect("closing a file");
} }
// Returns: (rights_base, rights_inheriting)
pub unsafe fn fd_get_rights(fd: wasi::Fd) -> (wasi::Rights, wasi::Rights) {
let fdstat = wasi::fd_fdstat_get(fd).expect("fd_fdstat_get failed");
(fdstat.fs_rights_base, fdstat.fs_rights_inheriting)
}
pub unsafe fn drop_rights(fd: wasi::Fd, drop_base: wasi::Rights, drop_inheriting: wasi::Rights) {
let (current_base, current_inheriting) = fd_get_rights(fd);
let new_base = current_base & !drop_base;
let new_inheriting = current_inheriting & !drop_inheriting;
wasi::fd_fdstat_set_rights(fd, new_base, new_inheriting).expect("dropping fd rights");
}

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime-wasi-c" name = "wasmtime-wasi-c"
version = "0.7.0" version = "0.9.0"
authors = ["The Cranelift Project Developers"] authors = ["The Cranelift Project Developers"]
description = "WASI API support for Wasmtime" description = "WASI API support for Wasmtime"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -11,20 +11,20 @@ readme = "README.md"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
wasmtime-runtime = { path = "../runtime" } wasmtime-runtime = { path = "../runtime", version = "0.9.0" }
wasmtime-environ = { path = "../environ" } wasmtime-environ = { path = "../environ", version = "0.9.0" }
wasmtime-jit = { path = "../jit" } wasmtime-jit = { path = "../jit", version = "0.9.0" }
cranelift-codegen = { version = "0.52.0", features = ["enable-serde"] } cranelift-codegen = { version = "0.54", features = ["enable-serde"] }
cranelift-entity = { version = "0.52.0", features = ["enable-serde"] } cranelift-entity = { version = "0.54", features = ["enable-serde"] }
cranelift-wasm = { version = "0.52.0", features = ["enable-serde"] } cranelift-wasm = { version = "0.54", features = ["enable-serde"] }
target-lexicon = "0.9.0" target-lexicon = "0.10.0"
log = { version = "0.4.8", default-features = false } log = { version = "0.4.8", default-features = false }
libc = "0.2.60" libc = "0.2.60"
more-asserts = "0.2.1" more-asserts = "0.2.1"
[build-dependencies] [build-dependencies]
cmake = "0.1.35" cmake = "0.1.35"
bindgen = "0.51.0" bindgen = "0.52.0"
[badges] [badges]
maintenance = { status = "actively-developed" } maintenance = { status = "actively-developed" }

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasi-common" name = "wasi-common"
version = "0.7.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
description = "WASI implementation in Rust" description = "WASI implementation in Rust"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -11,7 +11,7 @@ readme = "README.md"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
wasi-common-cbindgen = { path = "wasi-common-cbindgen" } wasi-common-cbindgen = { path = "wasi-common-cbindgen", version = "0.9.0" }
anyhow = "1.0" anyhow = "1.0"
thiserror = "1.0" thiserror = "1.0"
libc = "0.2" libc = "0.2"
@@ -21,14 +21,14 @@ log = "0.4"
filetime = "0.2.7" filetime = "0.2.7"
lazy_static = "1.4.0" lazy_static = "1.4.0"
num = { version = "0.2.0", default-features = false } num = { version = "0.2.0", default-features = false }
wig = { path = "wig" }
crossbeam = "0.7.3" crossbeam = "0.7.3"
wig = { path = "wig", version = "0.9.2" }
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
yanix = { path = "yanix" } yanix = { path = "yanix", version = "0.9.0" }
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winx = { path = "winx" } winx = { path = "winx", version = "0.9.0" }
winapi = "0.3" winapi = "0.3"
cpu-time = "1.0" cpu-time = "1.0"

View File

@@ -155,8 +155,21 @@ impl FdEntry {
rights_base: wasi::__wasi_rights_t, rights_base: wasi::__wasi_rights_t,
rights_inheriting: wasi::__wasi_rights_t, rights_inheriting: wasi::__wasi_rights_t,
) -> Result<()> { ) -> Result<()> {
if !self.rights_base & rights_base != 0 || !self.rights_inheriting & rights_inheriting != 0 let missing_base = !self.rights_base & rights_base;
{ let missing_inheriting = !self.rights_inheriting & rights_inheriting;
if missing_base != 0 || missing_inheriting != 0 {
log::trace!(
" | validate_rights failed: required: \
rights_base = {:#x}, rights_inheriting = {:#x}; \
actual: rights_base = {:#x}, rights_inheriting = {:#x}; \
missing_base = {:#x}, missing_inheriting = {:#x}",
rights_base,
rights_inheriting,
self.rights_base,
self.rights_inheriting,
missing_base,
missing_inheriting
);
Err(Error::ENOTCAPABLE) Err(Error::ENOTCAPABLE)
} else { } else {
Ok(()) Ok(())

View File

@@ -67,7 +67,7 @@ hostcalls! {
) -> wasi::__wasi_errno_t; ) -> wasi::__wasi_errno_t;
pub unsafe fn fd_fdstat_set_flags( pub unsafe fn fd_fdstat_set_flags(
wasi_ctx: &WasiCtx, wasi_ctx: &mut WasiCtx,
memory: &mut [u8], memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
fdflags: wasi::__wasi_fdflags_t, fdflags: wasi::__wasi_fdflags_t,

View File

@@ -5,7 +5,6 @@ use crate::fdentry::{Descriptor, FdEntry};
use crate::helpers::*; use crate::helpers::*;
use crate::memory::*; use crate::memory::*;
use crate::sandboxed_tty_writer::SandboxedTTYWriter; use crate::sandboxed_tty_writer::SandboxedTTYWriter;
use crate::sys::fdentry_impl::determine_type_rights;
use crate::sys::hostcalls_impl::fs_helpers::path_open_rights; use crate::sys::hostcalls_impl::fs_helpers::path_open_rights;
use crate::sys::{host_impl, hostcalls_impl}; use crate::sys::{host_impl, hostcalls_impl};
use crate::{helpers, host, wasi, wasi32, Error, Result}; use crate::{helpers, host, wasi, wasi32, Error, Result};
@@ -299,19 +298,24 @@ pub(crate) unsafe fn fd_fdstat_get(
} }
pub(crate) unsafe fn fd_fdstat_set_flags( pub(crate) unsafe fn fd_fdstat_set_flags(
wasi_ctx: &WasiCtx, wasi_ctx: &mut WasiCtx,
_memory: &mut [u8], _memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
fdflags: wasi::__wasi_fdflags_t, fdflags: wasi::__wasi_fdflags_t,
) -> Result<()> { ) -> Result<()> {
trace!("fd_fdstat_set_flags(fd={:?}, fdflags={:#x?})", fd, fdflags); trace!("fd_fdstat_set_flags(fd={:?}, fdflags={:#x?})", fd, fdflags);
let fd = wasi_ctx let descriptor = wasi_ctx
.get_fd_entry(fd)? .get_fd_entry_mut(fd)?
.as_descriptor(0, 0)? .as_descriptor_mut(wasi::__WASI_RIGHTS_FD_FDSTAT_SET_FLAGS, 0)?;
.as_os_handle();
hostcalls_impl::fd_fdstat_set_flags(&fd, fdflags) if let Some(new_handle) =
hostcalls_impl::fd_fdstat_set_flags(&descriptor.as_os_handle(), fdflags)?
{
*descriptor = Descriptor::OsHandle(new_handle);
}
Ok(())
} }
pub(crate) unsafe fn fd_fdstat_set_rights( pub(crate) unsafe fn fd_fdstat_set_rights(
@@ -574,6 +578,11 @@ pub(crate) unsafe fn path_open(
let (needed_base, needed_inheriting) = let (needed_base, needed_inheriting) =
path_open_rights(fs_rights_base, fs_rights_inheriting, oflags, fs_flags); path_open_rights(fs_rights_base, fs_rights_inheriting, oflags, fs_flags);
trace!(
" | needed_base = {}, needed_inheriting = {}",
needed_base,
needed_inheriting
);
let fe = wasi_ctx.get_fd_entry(dirfd)?; let fe = wasi_ctx.get_fd_entry(dirfd)?;
let resolved = path_get( let resolved = path_get(
fe, fe,
@@ -593,13 +602,20 @@ pub(crate) unsafe fn path_open(
| wasi::__WASI_RIGHTS_FD_FILESTAT_SET_SIZE) | wasi::__WASI_RIGHTS_FD_FILESTAT_SET_SIZE)
!= 0; != 0;
trace!(
" | calling path_open impl: read={}, write={}",
read,
write
);
let fd = hostcalls_impl::path_open(resolved, read, write, oflags, fs_flags)?; let fd = hostcalls_impl::path_open(resolved, read, write, oflags, fs_flags)?;
// Determine the type of the new file descriptor and which rights contradict with this type
let (_ty, max_base, max_inheriting) = determine_type_rights(&fd)?;
let mut fe = FdEntry::from(fd)?; let mut fe = FdEntry::from(fd)?;
fe.rights_base &= max_base; // We need to manually deny the rights which are not explicitly requested.
fe.rights_inheriting &= max_inheriting; // This should not be needed, but currently determine_type_and_access_rights,
// which is used by FdEntry::from, may grant extra rights while inferring it
// from the open mode.
fe.rights_base &= fs_rights_base;
fe.rights_inheriting &= fs_rights_inheriting;
let guest_fd = wasi_ctx.insert_fd_entry(fe)?; let guest_fd = wasi_ctx.insert_fd_entry(fe)?;
trace!(" | *fd={:?}", guest_fd); trace!(" | *fd={:?}", guest_fd);
@@ -709,7 +725,10 @@ pub(crate) unsafe fn fd_filestat_get(
filestat_ptr filestat_ptr
); );
let fd = wasi_ctx.get_fd_entry(fd)?.as_descriptor(0, 0)?.as_file()?; let fd = wasi_ctx
.get_fd_entry(fd)?
.as_descriptor(wasi::__WASI_RIGHTS_FD_FILESTAT_GET, 0)?
.as_file()?;
let host_filestat = hostcalls_impl::fd_filestat_get(fd)?; let host_filestat = hostcalls_impl::fd_filestat_get(fd)?;
trace!(" | *filestat_ptr={:?}", host_filestat); trace!(" | *filestat_ptr={:?}", host_filestat);

View File

@@ -242,9 +242,9 @@ pub(crate) fn poll_oneoff(
{ {
let wasi_fd = unsafe { subscription.u.fd_readwrite.file_descriptor }; let wasi_fd = unsafe { subscription.u.fd_readwrite.file_descriptor };
let rights = if r#type == wasi::__WASI_EVENTTYPE_FD_READ { let rights = if r#type == wasi::__WASI_EVENTTYPE_FD_READ {
wasi::__WASI_RIGHTS_FD_READ wasi::__WASI_RIGHTS_FD_READ | wasi::__WASI_RIGHTS_POLL_FD_READWRITE
} else { } else {
wasi::__WASI_RIGHTS_FD_WRITE wasi::__WASI_RIGHTS_FD_WRITE | wasi::__WASI_RIGHTS_POLL_FD_READWRITE
}; };
match unsafe { match unsafe {

View File

@@ -29,9 +29,14 @@ pub(crate) fn fd_fdstat_get(fd: &File) -> Result<wasi::__wasi_fdflags_t> {
.map_err(Into::into) .map_err(Into::into)
} }
pub(crate) fn fd_fdstat_set_flags(fd: &File, fdflags: wasi::__wasi_fdflags_t) -> Result<()> { pub(crate) fn fd_fdstat_set_flags(
fd: &File,
fdflags: wasi::__wasi_fdflags_t,
) -> Result<Option<OsHandle>> {
let nix_flags = host_impl::nix_from_fdflags(fdflags); let nix_flags = host_impl::nix_from_fdflags(fdflags);
unsafe { yanix::fcntl::set_status_flags(fd.as_raw_fd(), nix_flags) }.map_err(Into::into) unsafe { yanix::fcntl::set_status_flags(fd.as_raw_fd(), nix_flags) }
.map(|_| None)
.map_err(Into::into)
} }
pub(crate) fn fd_advise( pub(crate) fn fd_advise(

View File

@@ -5,7 +5,7 @@ use crate::ctx::WasiCtx;
use crate::fdentry::FdEntry; use crate::fdentry::FdEntry;
use crate::host::{Dirent, FileType}; use crate::host::{Dirent, FileType};
use crate::hostcalls_impl::{fd_filestat_set_times_impl, PathGet}; use crate::hostcalls_impl::{fd_filestat_set_times_impl, PathGet};
use crate::sys::fdentry_impl::determine_type_rights; use crate::sys::fdentry_impl::{determine_type_rights, OsHandle};
use crate::sys::host_impl::{self, path_from_host}; use crate::sys::host_impl::{self, path_from_host};
use crate::sys::hostcalls_impl::fs_helpers::PathGetExt; use crate::sys::hostcalls_impl::fs_helpers::PathGetExt;
use crate::{wasi, Error, Result}; use crate::{wasi, Error, Result};
@@ -78,8 +78,26 @@ pub(crate) fn fd_fdstat_get(fd: &File) -> Result<wasi::__wasi_fdflags_t> {
Ok(fdflags) Ok(fdflags)
} }
pub(crate) fn fd_fdstat_set_flags(fd: &File, fdflags: wasi::__wasi_fdflags_t) -> Result<()> { pub(crate) fn fd_fdstat_set_flags(
unimplemented!("fd_fdstat_set_flags") fd: &File,
fdflags: wasi::__wasi_fdflags_t,
) -> Result<Option<OsHandle>> {
let handle = unsafe { fd.as_raw_handle() };
let access_mode = winx::file::query_access_information(handle)?;
let new_access_mode = file_access_mode_from_fdflags(
fdflags,
access_mode.contains(AccessMode::FILE_READ_DATA),
access_mode.contains(AccessMode::FILE_WRITE_DATA)
| access_mode.contains(AccessMode::FILE_APPEND_DATA),
);
unsafe {
Ok(Some(OsHandle::from(File::from_raw_handle(
winx::file::reopen_file(handle, new_access_mode, file_flags_from_fdflags(fdflags))?,
))))
}
} }
pub(crate) fn fd_advise( pub(crate) fn fd_advise(
@@ -119,9 +137,20 @@ pub(crate) fn path_open(
) -> Result<File> { ) -> Result<File> {
use winx::file::{AccessMode, CreationDisposition, Flags}; use winx::file::{AccessMode, CreationDisposition, Flags};
let is_trunc = oflags & wasi::__WASI_OFLAGS_TRUNC != 0;
if is_trunc {
// Windows does not support append mode when opening for truncation
// This is because truncation requires `GENERIC_WRITE` access, which will override the removal
// of the `FILE_WRITE_DATA` permission.
if fdflags & wasi::__WASI_FDFLAGS_APPEND != 0 {
return Err(Error::ENOTSUP);
}
}
// convert open flags // convert open flags
// note: the calls to `write(true)` are to bypass an internal OpenOption check // note: the calls to `write(true)` are to bypass an internal OpenOption check
// the write flag will ultimately be ignored when `access_mode` is called below. // the write flag will ultimately be ignored when `access_mode` is calculated below.
let mut opts = OpenOptions::new(); let mut opts = OpenOptions::new();
match creation_disposition_from_oflags(oflags) { match creation_disposition_from_oflags(oflags) {
CreationDisposition::CREATE_ALWAYS => { CreationDisposition::CREATE_ALWAYS => {
@@ -168,7 +197,14 @@ pub(crate) fn path_open(
}, },
} }
opts.access_mode(file_access_mode_from_fdflags(fdflags, read, write).bits()) let mut access_mode = file_access_mode_from_fdflags(fdflags, read, write);
// Truncation requires the special `GENERIC_WRITE` bit set (this is why it doesn't work with append-only mode)
if is_trunc {
access_mode |= AccessMode::GENERIC_WRITE;
}
opts.access_mode(access_mode.bits())
.custom_flags(file_flags_from_fdflags(fdflags).bits()) .custom_flags(file_flags_from_fdflags(fdflags).bits())
.open(&path) .open(&path)
.map_err(Into::into) .map_err(Into::into)
@@ -195,12 +231,15 @@ fn file_access_mode_from_fdflags(
) -> AccessMode { ) -> AccessMode {
let mut access_mode = AccessMode::READ_CONTROL; let mut access_mode = AccessMode::READ_CONTROL;
// Note that `GENERIC_READ` and `GENERIC_WRITE` cannot be used to properly support append-only mode
// The file-specific flags `FILE_GENERIC_READ` and `FILE_GENERIC_WRITE` are used here instead
// These flags have the same semantic meaning for file objects, but allow removal of specific permissions (see below)
if read { if read {
access_mode.insert(AccessMode::GENERIC_READ); access_mode.insert(AccessMode::FILE_GENERIC_READ);
} }
if write { if write {
access_mode.insert(AccessMode::GENERIC_WRITE); access_mode.insert(AccessMode::FILE_GENERIC_WRITE);
} }
// For append, grant the handle FILE_APPEND_DATA access but *not* FILE_WRITE_DATA. // For append, grant the handle FILE_APPEND_DATA access but *not* FILE_WRITE_DATA.

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasi-common-cbindgen" name = "wasi-common-cbindgen"
version = "0.7.0" version = "0.9.0"
authors = ["Jakub Konka <kubkon@jakubkonka.com>"] authors = ["Jakub Konka <kubkon@jakubkonka.com>"]
description = "Interface generator utilities used by wasi-common" description = "Interface generator utilities used by wasi-common"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wig" name = "wig"
version = "0.7.0" version = "0.9.2"
authors = ["Dan Gohman <sunfish@mozilla.com>"] authors = ["Dan Gohman <sunfish@mozilla.com>"]
description = "WebAssembly Interface Generator" description = "WebAssembly Interface Generator"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -8,6 +8,7 @@ categories = ["wasm"]
keywords = ["webassembly", "wasm"] keywords = ["webassembly", "wasm"]
repository = "https://github.com/bytecodealliance/wasmtime" repository = "https://github.com/bytecodealliance/wasmtime"
edition = "2018" edition = "2018"
include = ["src/**/*", "LICENSE", "WASI"]
[lib] [lib]
proc-macro = true proc-macro = true
@@ -19,7 +20,7 @@ heck = "0.3.1"
# We include the WASI repo primarily for the witx files, but it's also useful # We include the WASI repo primarily for the witx files, but it's also useful
# to use the witx parser it contains, rather than the witx crate from # to use the witx parser it contains, rather than the witx crate from
# crates.io, so that it always matches the version of the witx files. # crates.io, so that it always matches the version of the witx files.
witx = { path = "../WASI/tools/witx" } witx = "0.6.0"
[badges] [badges]
maintenance = { status = "actively-developed" } maintenance = { status = "actively-developed" }

View File

@@ -28,7 +28,7 @@ pub(crate) fn witx_path_from_args(args: TokenStream) -> (String, String) {
fn witx_path(phase: &str, id: &str) -> String { fn witx_path(phase: &str, id: &str) -> String {
let root = env!("CARGO_MANIFEST_DIR"); let root = env!("CARGO_MANIFEST_DIR");
format!("{}/../WASI/phases/{}/witx/{}.witx", root, phase, id) format!("{}/WASI/phases/{}/witx/{}.witx", root, phase, id)
} }
// Convert a `Literal` holding a string literal into the `String`. // Convert a `Literal` holding a string literal into the `String`.

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "winx" name = "winx"
version = "0.7.0" version = "0.9.0"
authors = ["Jakub Konka <kubkon@jakubkonka.com>"] authors = ["Jakub Konka <kubkon@jakubkonka.com>"]
description = "Windows API helper library" description = "Windows API helper library"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"

View File

@@ -434,3 +434,22 @@ pub fn query_mode_information(handle: RawHandle) -> Result<FileModeInformation>
Ok(FileModeInformation::from_bits_truncate(info.Mode)) Ok(FileModeInformation::from_bits_truncate(info.Mode))
} }
pub fn reopen_file(handle: RawHandle, access_mode: AccessMode, flags: Flags) -> Result<RawHandle> {
// Files on Windows are opened with DELETE, READ, and WRITE share mode by default (see OpenOptions in stdlib)
// This keeps the same share mode when reopening the file handle
let new_handle = unsafe {
winbase::ReOpenFile(
handle,
access_mode.bits(),
winnt::FILE_SHARE_DELETE | winnt::FILE_SHARE_READ | winnt::FILE_SHARE_WRITE,
flags.bits(),
)
};
if new_handle == winapi::um::handleapi::INVALID_HANDLE_VALUE {
return Err(winerror::WinError::last());
}
Ok(new_handle)
}

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "yanix" name = "yanix"
version = "0.1.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
description = "Yet Another Nix crate: a Unix API helper library" description = "Yet Another Nix crate: a Unix API helper library"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime-wasi" name = "wasmtime-wasi"
version = "0.7.0" version = "0.9.0"
authors = ["The Cranelift Project Developers"] authors = ["The Cranelift Project Developers"]
description = "WASI API support for Wasmtime" description = "WASI API support for Wasmtime"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -11,17 +11,17 @@ readme = "README.md"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
wasmtime = { path = "../api" } wasmtime = { path = "../api", version = "0.9.0" }
wasmtime-runtime = { path = "../runtime" } wasmtime-runtime = { path = "../runtime", version = "0.9.0" }
wasmtime-environ = { path = "../environ" } wasmtime-environ = { path = "../environ", version = "0.9.0" }
wasmtime-jit = { path = "../jit" } wasmtime-jit = { path = "../jit", version = "0.9.0" }
wasi-common = { path = "../wasi-common" } wasi-common = { path = "../wasi-common", version = "0.9.0" }
cranelift-codegen = { version = "0.52.0", features = ["enable-serde"] } cranelift-codegen = { version = "0.54", features = ["enable-serde"] }
cranelift-entity = { version = "0.52.0", features = ["enable-serde"] } cranelift-entity = { version = "0.54", features = ["enable-serde"] }
cranelift-wasm = { version = "0.52.0", features = ["enable-serde"] } cranelift-wasm = { version = "0.54", features = ["enable-serde"] }
target-lexicon = "0.9.0" target-lexicon = "0.10.0"
log = { version = "0.4.8", default-features = false } log = { version = "0.4.8", default-features = false }
wig = { path = "../wasi-common/wig" } wig = { path = "../wasi-common/wig", version = "0.9.2" }
[badges] [badges]
maintenance = { status = "actively-developed" } maintenance = { status = "actively-developed" }

View File

@@ -1,5 +1,3 @@
#![allow(improper_ctypes)]
mod instantiate; mod instantiate;
pub mod old; pub mod old;

View File

@@ -1,5 +1,3 @@
#![allow(improper_ctypes)]
extern crate alloc; extern crate alloc;
mod instantiate; mod instantiate;

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime-wast" name = "wasmtime-wast"
version = "0.7.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
description = "wast testing support for wasmtime" description = "wast testing support for wasmtime"
license = "Apache-2.0 WITH LLVM-exception" license = "Apache-2.0 WITH LLVM-exception"
@@ -12,8 +12,8 @@ edition = "2018"
[dependencies] [dependencies]
anyhow = "1.0.19" anyhow = "1.0.19"
wasmtime = { path = "../api" } wasmtime = { path = "../api", version = "0.9.0" }
wast = "5.0.1" wast = "6.0.0"
[badges] [badges]
maintenance = { status = "actively-developed" } maintenance = { status = "actively-developed" }

View File

@@ -1,5 +1,3 @@
#![allow(improper_ctypes)]
use anyhow::Result; use anyhow::Result;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
@@ -31,35 +29,35 @@ pub fn instantiate_spectest(store: &Store) -> HashMap<&'static str, Extern> {
let ty = FuncType::new(Box::new([]), Box::new([])); let ty = FuncType::new(Box::new([]), Box::new([]));
let func = wrap(store, ty, |_params, _results| Ok(())); let func = wrap(store, ty, |_params, _results| Ok(()));
ret.insert("print", Extern::Func(HostRef::new(func))); ret.insert("print", Extern::Func(func));
let ty = FuncType::new(Box::new([ValType::I32]), Box::new([])); let ty = FuncType::new(Box::new([ValType::I32]), Box::new([]));
let func = wrap(store, ty, |params, _results| { let func = wrap(store, ty, |params, _results| {
println!("{}: i32", params[0].unwrap_i32()); println!("{}: i32", params[0].unwrap_i32());
Ok(()) Ok(())
}); });
ret.insert("print_i32", Extern::Func(HostRef::new(func))); ret.insert("print_i32", Extern::Func(func));
let ty = FuncType::new(Box::new([ValType::I64]), Box::new([])); let ty = FuncType::new(Box::new([ValType::I64]), Box::new([]));
let func = wrap(store, ty, |params, _results| { let func = wrap(store, ty, |params, _results| {
println!("{}: i64", params[0].unwrap_i64()); println!("{}: i64", params[0].unwrap_i64());
Ok(()) Ok(())
}); });
ret.insert("print_i64", Extern::Func(HostRef::new(func))); ret.insert("print_i64", Extern::Func(func));
let ty = FuncType::new(Box::new([ValType::F32]), Box::new([])); let ty = FuncType::new(Box::new([ValType::F32]), Box::new([]));
let func = wrap(store, ty, |params, _results| { let func = wrap(store, ty, |params, _results| {
println!("{}: f32", params[0].unwrap_f32()); println!("{}: f32", params[0].unwrap_f32());
Ok(()) Ok(())
}); });
ret.insert("print_f32", Extern::Func(HostRef::new(func))); ret.insert("print_f32", Extern::Func(func));
let ty = FuncType::new(Box::new([ValType::F64]), Box::new([])); let ty = FuncType::new(Box::new([ValType::F64]), Box::new([]));
let func = wrap(store, ty, |params, _results| { let func = wrap(store, ty, |params, _results| {
println!("{}: f64", params[0].unwrap_f64()); println!("{}: f64", params[0].unwrap_f64());
Ok(()) Ok(())
}); });
ret.insert("print_f64", Extern::Func(HostRef::new(func))); ret.insert("print_f64", Extern::Func(func));
let ty = FuncType::new(Box::new([ValType::I32, ValType::F32]), Box::new([])); let ty = FuncType::new(Box::new([ValType::I32, ValType::F32]), Box::new([]));
let func = wrap(store, ty, |params, _results| { let func = wrap(store, ty, |params, _results| {
@@ -67,7 +65,7 @@ pub fn instantiate_spectest(store: &Store) -> HashMap<&'static str, Extern> {
println!("{}: f32", params[1].unwrap_f32()); println!("{}: f32", params[1].unwrap_f32());
Ok(()) Ok(())
}); });
ret.insert("print_i32_f32", Extern::Func(HostRef::new(func))); ret.insert("print_i32_f32", Extern::Func(func));
let ty = FuncType::new(Box::new([ValType::F64, ValType::F64]), Box::new([])); let ty = FuncType::new(Box::new([ValType::F64, ValType::F64]), Box::new([]));
let func = wrap(store, ty, |params, _results| { let func = wrap(store, ty, |params, _results| {
@@ -75,31 +73,31 @@ pub fn instantiate_spectest(store: &Store) -> HashMap<&'static str, Extern> {
println!("{}: f64", params[1].unwrap_f64()); println!("{}: f64", params[1].unwrap_f64());
Ok(()) Ok(())
}); });
ret.insert("print_f64_f64", Extern::Func(HostRef::new(func))); ret.insert("print_f64_f64", Extern::Func(func));
let ty = GlobalType::new(ValType::I32, Mutability::Const); let ty = GlobalType::new(ValType::I32, Mutability::Const);
let g = Global::new(store, ty, Val::I32(666)); let g = Global::new(store, ty, Val::I32(666));
ret.insert("global_i32", Extern::Global(HostRef::new(g))); ret.insert("global_i32", Extern::Global(g));
let ty = GlobalType::new(ValType::I64, Mutability::Const); let ty = GlobalType::new(ValType::I64, Mutability::Const);
let g = Global::new(store, ty, Val::I64(666)); let g = Global::new(store, ty, Val::I64(666));
ret.insert("global_i64", Extern::Global(HostRef::new(g))); ret.insert("global_i64", Extern::Global(g));
let ty = GlobalType::new(ValType::F32, Mutability::Const); let ty = GlobalType::new(ValType::F32, Mutability::Const);
let g = Global::new(store, ty, Val::F32(0x4426_8000)); let g = Global::new(store, ty, Val::F32(0x4426_8000));
ret.insert("global_f32", Extern::Global(HostRef::new(g))); ret.insert("global_f32", Extern::Global(g));
let ty = GlobalType::new(ValType::F64, Mutability::Const); let ty = GlobalType::new(ValType::F64, Mutability::Const);
let g = Global::new(store, ty, Val::F64(0x4084_d000_0000_0000)); let g = Global::new(store, ty, Val::F64(0x4084_d000_0000_0000));
ret.insert("global_f64", Extern::Global(HostRef::new(g))); ret.insert("global_f64", Extern::Global(g));
let ty = TableType::new(ValType::FuncRef, Limits::new(10, Some(20))); let ty = TableType::new(ValType::FuncRef, Limits::new(10, Some(20)));
let table = Table::new(store, ty, Val::AnyRef(AnyRef::Null)); let table = Table::new(store, ty, Val::AnyRef(AnyRef::Null));
ret.insert("table", Extern::Table(HostRef::new(table))); ret.insert("table", Extern::Table(table));
let ty = MemoryType::new(Limits::new(1, Some(2))); let ty = MemoryType::new(Limits::new(1, Some(2)));
let memory = Memory::new(store, ty); let memory = Memory::new(store, ty);
ret.insert("memory", Extern::Memory(HostRef::new(memory))); ret.insert("memory", Extern::Memory(memory));
return ret; return ret;
} }

View File

@@ -27,9 +27,9 @@ fn runtime_value(v: &wast::Expression<'_>) -> Result<Val> {
pub struct WastContext { pub struct WastContext {
/// Wast files have a concept of a "current" module, which is the most /// Wast files have a concept of a "current" module, which is the most
/// recently defined. /// recently defined.
current: Option<HostRef<Instance>>, current: Option<Instance>,
instances: HashMap<String, HostRef<Instance>>, instances: HashMap<String, Instance>,
store: Store, store: Store,
spectest: Option<HashMap<&'static str, Extern>>, spectest: Option<HashMap<&'static str, Extern>>,
} }
@@ -39,6 +39,15 @@ enum Outcome<T = Vec<Val>> {
Trap(Trap), Trap(Trap),
} }
impl<T> Outcome<T> {
fn into_result(self) -> Result<T, Trap> {
match self {
Outcome::Ok(t) => Ok(t),
Outcome::Trap(t) => Err(t),
}
}
}
impl WastContext { impl WastContext {
/// Construct a new instance of `WastContext`. /// Construct a new instance of `WastContext`.
pub fn new(store: Store) -> Self { pub fn new(store: Store) -> Self {
@@ -50,7 +59,7 @@ impl WastContext {
} }
} }
fn get_instance(&self, instance_name: Option<&str>) -> Result<HostRef<Instance>> { fn get_instance(&self, instance_name: Option<&str>) -> Result<Instance> {
match instance_name { match instance_name {
Some(name) => self Some(name) => self
.instances .instances
@@ -64,7 +73,7 @@ impl WastContext {
} }
} }
fn instantiate(&self, module: &[u8]) -> Result<Outcome<HostRef<Instance>>> { fn instantiate(&self, module: &[u8]) -> Result<Outcome<Instance>> {
let module = Module::new(&self.store, module)?; let module = Module::new(&self.store, module)?;
let mut imports = Vec::new(); let mut imports = Vec::new();
for import in module.imports() { for import in module.imports() {
@@ -85,23 +94,16 @@ impl WastContext {
.get(import.module()) .get(import.module())
.ok_or_else(|| anyhow!("no module named `{}`", import.module()))?; .ok_or_else(|| anyhow!("no module named `{}`", import.module()))?;
let export = instance let export = instance
.borrow()
.find_export_by_name(import.name()) .find_export_by_name(import.name())
.ok_or_else(|| anyhow!("unknown import `{}::{}`", import.name(), import.module()))? .ok_or_else(|| anyhow!("unknown import `{}::{}`", import.name(), import.module()))?
.clone(); .clone();
imports.push(export); imports.push(export);
} }
let instance = match Instance::new(&self.store, &module, &imports) { let instance = match Instance::new(&module, &imports) {
Ok(i) => i, Ok(i) => i,
Err(e) => { Err(e) => return e.downcast::<Trap>().map(Outcome::Trap),
let err = e.chain().filter_map(|e| e.downcast_ref::<Trap>()).next();
if let Some(trap) = err {
return Ok(Outcome::Trap(trap.clone()));
}
return Err(e);
}
}; };
Ok(Outcome::Ok(HostRef::new(instance))) Ok(Outcome::Ok(instance))
} }
/// Register "spectest" which is used by the spec testsuite. /// Register "spectest" which is used by the spec testsuite.
@@ -127,7 +129,12 @@ impl WastContext {
} }
fn perform_invoke(&mut self, exec: wast::WastInvoke<'_>) -> Result<Outcome> { fn perform_invoke(&mut self, exec: wast::WastInvoke<'_>) -> Result<Outcome> {
self.invoke(exec.module.map(|i| i.name()), exec.name, &exec.args) let values = exec
.args
.iter()
.map(runtime_value)
.collect::<Result<Vec<_>>>()?;
self.invoke(exec.module.map(|i| i.name()), exec.name, &values)
} }
/// Define a module and register it. /// Define a module and register it.
@@ -155,19 +162,17 @@ impl WastContext {
&mut self, &mut self,
instance_name: Option<&str>, instance_name: Option<&str>,
field: &str, field: &str,
args: &[wast::Expression], args: &[Val],
) -> Result<Outcome> { ) -> Result<Outcome> {
let values = args.iter().map(runtime_value).collect::<Result<Vec<_>>>()?;
let instance = self.get_instance(instance_name.as_ref().map(|x| &**x))?; let instance = self.get_instance(instance_name.as_ref().map(|x| &**x))?;
let instance = instance.borrow();
let export = instance let export = instance
.find_export_by_name(field) .find_export_by_name(field)
.ok_or_else(|| anyhow!("no global named `{}`", field))?; .ok_or_else(|| anyhow!("no global named `{}`", field))?;
let func = match export { let func = match export {
Extern::Func(f) => f.borrow(), Extern::Func(f) => f,
_ => bail!("export of `{}` wasn't a global", field), _ => bail!("export of `{}` wasn't a global", field),
}; };
Ok(match func.call(&values) { Ok(match func.call(args) {
Ok(result) => Outcome::Ok(result.into()), Ok(result) => Outcome::Ok(result.into()),
Err(e) => Outcome::Trap(e), Err(e) => Outcome::Trap(e),
}) })
@@ -176,21 +181,44 @@ impl WastContext {
/// Get the value of an exported global from an instance. /// Get the value of an exported global from an instance.
fn get(&mut self, instance_name: Option<&str>, field: &str) -> Result<Outcome> { fn get(&mut self, instance_name: Option<&str>, field: &str) -> Result<Outcome> {
let instance = self.get_instance(instance_name.as_ref().map(|x| &**x))?; let instance = self.get_instance(instance_name.as_ref().map(|x| &**x))?;
let instance = instance.borrow();
let export = instance let export = instance
.find_export_by_name(field) .find_export_by_name(field)
.ok_or_else(|| anyhow!("no global named `{}`", field))?; .ok_or_else(|| anyhow!("no global named `{}`", field))?;
let global = match export { let global = match export {
Extern::Global(g) => g.borrow(), Extern::Global(g) => g,
_ => bail!("export of `{}` wasn't a global", field), _ => bail!("export of `{}` wasn't a global", field),
}; };
Ok(Outcome::Ok(vec![global.get()])) Ok(Outcome::Ok(vec![global.get()]))
} }
fn assert_return(&self, result: Outcome, results: &[wast::AssertExpression]) -> Result<()> {
let values = result.into_result()?;
for (v, e) in values.iter().zip(results) {
if val_matches(v, e)? {
continue;
}
bail!("expected {:?}, got {:?}", e, v)
}
Ok(())
}
fn assert_trap(&self, result: Outcome, message: &str) -> Result<()> {
let trap = match result {
Outcome::Ok(values) => bail!("expected trap, got {:?}", values),
Outcome::Trap(t) => t,
};
if trap.message().contains(message) {
return Ok(());
}
if cfg!(feature = "lightbeam") {
println!("TODO: Check the assert_trap message: {}", message);
return Ok(());
}
bail!("expected {}, got {}", message, trap.message())
}
/// Run a wast script from a byte buffer. /// Run a wast script from a byte buffer.
pub fn run_buffer(&mut self, filename: &str, wast: &[u8]) -> Result<()> { pub fn run_buffer(&mut self, filename: &str, wast: &[u8]) -> Result<()> {
use wast::WastDirective::*;
let wast = str::from_utf8(wast)?; let wast = str::from_utf8(wast)?;
let adjust_wast = |mut err: wast::Error| { let adjust_wast = |mut err: wast::Error| {
@@ -198,262 +226,83 @@ impl WastContext {
err.set_text(wast); err.set_text(wast);
err err
}; };
let context = |sp: wast::Span| {
let (line, col) = sp.linecol_in(wast);
format!("for directive on {}:{}:{}", filename, line + 1, col)
};
let buf = wast::parser::ParseBuffer::new(wast).map_err(adjust_wast)?; let buf = wast::parser::ParseBuffer::new(wast).map_err(adjust_wast)?;
let wast = wast::parser::parse::<wast::Wast>(&buf).map_err(adjust_wast)?; let ast = wast::parser::parse::<wast::Wast>(&buf).map_err(adjust_wast)?;
for directive in ast.directives {
let sp = directive.span();
self.run_directive(directive).with_context(|| {
let (line, col) = sp.linecol_in(wast);
format!("failed directive on {}:{}:{}", filename, line + 1, col)
})?;
}
Ok(())
}
fn run_directive(&mut self, directive: wast::WastDirective) -> Result<()> {
use wast::WastDirective::*;
for directive in wast.directives {
match directive { match directive {
Module(mut module) => { Module(mut module) => {
let binary = module.encode().map_err(adjust_wast)?; let binary = module.encode()?;
self.module(module.name.map(|s| s.name()), &binary) self.module(module.name.map(|s| s.name()), &binary)?;
.with_context(|| context(module.span))?;
} }
Register { span, name, module } => { Register {
self.register(module.map(|s| s.name()), name) span: _,
.with_context(|| context(span))?; name,
module,
} => {
self.register(module.map(|s| s.name()), name)?;
} }
Invoke(i) => { Invoke(i) => {
let span = i.span; self.perform_invoke(i)?;
self.perform_invoke(i).with_context(|| context(span))?;
} }
AssertReturn { AssertReturn {
span, span: _,
exec, exec,
results, results,
} => match self.perform_execute(exec).with_context(|| context(span))? { } => {
Outcome::Ok(values) => { let result = self.perform_execute(exec)?;
for (v, e) in values.iter().zip(results.iter().map(runtime_value)) { self.assert_return(result, &results)?;
let e = e?;
if values_equal(v, &e)? {
continue;
} }
bail!("{}\nexpected {:?}, got {:?}", context(span), e, v)
}
}
Outcome::Trap(t) => {
bail!("{}\nunexpected trap: {}", context(span), t.message())
}
},
AssertTrap { AssertTrap {
span, span: _,
exec, exec,
message, message,
} => match self.perform_execute(exec).with_context(|| context(span))? { } => {
Outcome::Ok(values) => { let result = self.perform_execute(exec)?;
bail!("{}\nexpected trap, got {:?}", context(span), values) self.assert_trap(result, message)?;
} }
Outcome::Trap(t) => {
if t.message().contains(message) {
continue;
}
if cfg!(feature = "lightbeam") {
println!(
"{}\nTODO: Check the assert_trap message: {}",
context(span),
message
);
continue;
}
bail!(
"{}\nexpected {}, got {}",
context(span),
message,
t.message(),
)
}
},
AssertExhaustion { AssertExhaustion {
span, span: _,
call, call,
message, message,
} => match self.perform_invoke(call).with_context(|| context(span))? { } => {
Outcome::Ok(values) => { let result = self.perform_invoke(call)?;
bail!("{}\nexpected trap, got {:?}", context(span), values) self.assert_trap(result, message)?;
}
Outcome::Trap(t) => {
if t.message().contains(message) {
continue;
}
bail!(
"{}\nexpected exhaustion with {}, got {}",
context(span),
message,
t.message(),
)
}
},
AssertReturnCanonicalNan { span, invoke } => {
match self.perform_invoke(invoke).with_context(|| context(span))? {
Outcome::Ok(values) => {
for v in values.iter() {
match v {
Val::F32(x) => {
if !is_canonical_f32_nan(*x) {
bail!("{}\nexpected canonical NaN", context(span))
}
}
Val::F64(x) => {
if !is_canonical_f64_nan(*x) {
bail!("{}\nexpected canonical NaN", context(span))
}
}
other => bail!("expected float, got {:?}", other),
};
}
}
Outcome::Trap(t) => {
bail!("{}\nunexpected trap: {}", context(span), t.message())
}
}
}
AssertReturnCanonicalNanF32x4 { span, invoke } => {
match self.perform_invoke(invoke).with_context(|| context(span))? {
Outcome::Ok(values) => {
for v in values.iter() {
let val = match v {
Val::V128(x) => x,
other => bail!("expected v128, got {:?}", other),
};
for l in 0..4 {
if !is_canonical_f32_nan(extract_lane_as_u32(val, l)?) {
bail!(
"{}\nexpected f32x4 canonical NaN in lane {}",
context(span),
l
)
}
}
}
}
Outcome::Trap(t) => {
bail!("{}\nunexpected trap: {}", context(span), t.message())
}
}
}
AssertReturnCanonicalNanF64x2 { span, invoke } => {
match self.perform_invoke(invoke).with_context(|| context(span))? {
Outcome::Ok(values) => {
for v in values.iter() {
let val = match v {
Val::V128(x) => x,
other => bail!("expected v128, got {:?}", other),
};
for l in 0..2 {
if !is_canonical_f64_nan(extract_lane_as_u64(val, l)?) {
bail!(
"{}\nexpected f64x2 canonical NaN in lane {}",
context(span),
l
)
}
}
}
}
Outcome::Trap(t) => {
bail!("{}\nunexpected trap: {}", context(span), t.message())
}
}
}
AssertReturnArithmeticNan { span, invoke } => {
match self.perform_invoke(invoke).with_context(|| context(span))? {
Outcome::Ok(values) => {
for v in values.iter() {
match v {
Val::F32(x) => {
if !is_arithmetic_f32_nan(*x) {
bail!("{}\nexpected arithmetic NaN", context(span))
}
}
Val::F64(x) => {
if !is_arithmetic_f64_nan(*x) {
bail!("{}\nexpected arithmetic NaN", context(span))
}
}
other => bail!("expected float, got {:?}", other),
};
}
}
Outcome::Trap(t) => {
bail!("{}\nunexpected trap: {}", context(span), t.message())
}
}
}
AssertReturnArithmeticNanF32x4 { span, invoke } => {
match self.perform_invoke(invoke).with_context(|| context(span))? {
Outcome::Ok(values) => {
for v in values.iter() {
let val = match v {
Val::V128(x) => x,
other => bail!("expected v128, got {:?}", other),
};
for l in 0..4 {
if !is_arithmetic_f32_nan(extract_lane_as_u32(val, l)?) {
bail!(
"{}\nexpected f32x4 arithmetic NaN in lane {}",
context(span),
l
)
}
}
}
}
Outcome::Trap(t) => {
bail!("{}\nunexpected trap: {}", context(span), t.message())
}
}
}
AssertReturnArithmeticNanF64x2 { span, invoke } => {
match self.perform_invoke(invoke).with_context(|| context(span))? {
Outcome::Ok(values) => {
for v in values.iter() {
let val = match v {
Val::V128(x) => x,
other => bail!("expected v128, got {:?}", other),
};
for l in 0..2 {
if !is_arithmetic_f64_nan(extract_lane_as_u64(val, l)?) {
bail!(
"{}\nexpected f64x2 arithmetic NaN in lane {}",
context(span),
l
)
}
}
}
}
Outcome::Trap(t) => {
bail!("{}\nunexpected trap: {}", context(span), t.message())
}
}
} }
AssertInvalid { AssertInvalid {
span, span: _,
mut module, mut module,
message, message,
} => { } => {
let bytes = module.encode().map_err(adjust_wast)?; let bytes = module.encode()?;
let err = match self.module(None, &bytes) { let err = match self.module(None, &bytes) {
Ok(()) => bail!("{}\nexpected module to fail to build", context(span)), Ok(()) => bail!("expected module to fail to build"),
Err(e) => e, Err(e) => e,
}; };
let error_message = format!("{:?}", err); let error_message = format!("{:?}", err);
if !error_message.contains(&message) { if !error_message.contains(&message) {
// TODO: change to bail! // TODO: change to bail!
println!( println!(
"{}\nassert_invalid: expected {}, got {}", "assert_invalid: expected {}, got {}",
context(span), message, error_message
message,
error_message
) )
} }
} }
AssertMalformed { AssertMalformed {
span, span: _,
module, module,
message, message,
} => { } => {
@@ -463,39 +312,34 @@ impl WastContext {
// interested in // interested in
wast::QuoteModule::Quote(_) => return Ok(()), wast::QuoteModule::Quote(_) => return Ok(()),
}; };
let bytes = module.encode().map_err(adjust_wast)?; let bytes = module.encode()?;
let err = match self.module(None, &bytes) { let err = match self.module(None, &bytes) {
Ok(()) => { Ok(()) => bail!("expected module to fail to instantiate"),
bail!("{}\nexpected module to fail to instantiate", context(span))
}
Err(e) => e, Err(e) => e,
}; };
let error_message = format!("{:?}", err); let error_message = format!("{:?}", err);
if !error_message.contains(&message) { if !error_message.contains(&message) {
// TODO: change to bail! // TODO: change to bail!
println!( println!(
"{}\nassert_malformed: expected {}, got {}", "assert_malformed: expected {}, got {}",
context(span), message, error_message
message,
error_message
) )
} }
} }
AssertUnlinkable { AssertUnlinkable {
span, span: _,
mut module, mut module,
message, message,
} => { } => {
let bytes = module.encode().map_err(adjust_wast)?; let bytes = module.encode()?;
let err = match self.module(None, &bytes) { let err = match self.module(None, &bytes) {
Ok(()) => bail!("{}\nexpected module to fail to link", context(span)), Ok(()) => bail!("expected module to fail to link"),
Err(e) => e, Err(e) => e,
}; };
let error_message = format!("{:?}", err); let error_message = format!("{:?}", err);
if !error_message.contains(&message) { if !error_message.contains(&message) {
bail!( bail!(
"{}\nassert_unlinkable: expected {}, got {}", "assert_unlinkable: expected {}, got {}",
context(span),
message, message,
error_message error_message
) )
@@ -503,7 +347,6 @@ impl WastContext {
} }
AssertReturnFunc { .. } => bail!("need to implement assert_return_func"), AssertReturnFunc { .. } => bail!("need to implement assert_return_func"),
} }
}
Ok(()) Ok(())
} }
@@ -516,12 +359,20 @@ impl WastContext {
} }
} }
fn extract_lane_as_u32(bytes: &u128, lane: usize) -> Result<u32> { fn extract_lane_as_i8(bytes: u128, lane: usize) -> i8 {
Ok((*bytes >> (lane * 32)) as u32) (bytes >> (lane * 8)) as i8
} }
fn extract_lane_as_u64(bytes: &u128, lane: usize) -> Result<u64> { fn extract_lane_as_i16(bytes: u128, lane: usize) -> i16 {
Ok((*bytes >> (lane * 64)) as u64) (bytes >> (lane * 16)) as i16
}
fn extract_lane_as_i32(bytes: u128, lane: usize) -> i32 {
(bytes >> (lane * 32)) as i32
}
fn extract_lane_as_i64(bytes: u128, lane: usize) -> i64 {
(bytes >> (lane * 64)) as i64
} }
fn is_canonical_f32_nan(bits: u32) -> bool { fn is_canonical_f32_nan(bits: u32) -> bool {
@@ -542,15 +393,64 @@ fn is_arithmetic_f64_nan(bits: u64) -> bool {
(bits & AF64_NAN) == AF64_NAN (bits & AF64_NAN) == AF64_NAN
} }
fn values_equal(v1: &Val, v2: &Val) -> Result<bool> { fn val_matches(actual: &Val, expected: &wast::AssertExpression) -> Result<bool> {
Ok(match (v1, v2) { Ok(match (actual, expected) {
(Val::I32(a), Val::I32(b)) => a == b, (Val::I32(a), wast::AssertExpression::I32(b)) => a == b,
(Val::I64(a), Val::I64(b)) => a == b, (Val::I64(a), wast::AssertExpression::I64(b)) => a == b,
// Note that these float comparisons are comparing bits, not float // Note that these float comparisons are comparing bits, not float
// values, so we're testing for bit-for-bit equivalence // values, so we're testing for bit-for-bit equivalence
(Val::F32(a), Val::F32(b)) => a == b, (Val::F32(a), wast::AssertExpression::F32(b)) => f32_matches(*a, b),
(Val::F64(a), Val::F64(b)) => a == b, (Val::F64(a), wast::AssertExpression::F64(b)) => f64_matches(*a, b),
(Val::V128(a), Val::V128(b)) => a == b, (Val::V128(a), wast::AssertExpression::V128(b)) => v128_matches(*a, b),
_ => bail!("don't know how to compare {:?} and {:?} yet", v1, v2), _ => bail!(
"don't know how to compare {:?} and {:?} yet",
actual,
expected
),
}) })
} }
fn f32_matches(actual: u32, expected: &wast::NanPattern<wast::Float32>) -> bool {
match expected {
wast::NanPattern::CanonicalNan => is_canonical_f32_nan(actual),
wast::NanPattern::ArithmeticNan => is_arithmetic_f32_nan(actual),
wast::NanPattern::Value(expected_value) => actual == expected_value.bits,
}
}
fn f64_matches(actual: u64, expected: &wast::NanPattern<wast::Float64>) -> bool {
match expected {
wast::NanPattern::CanonicalNan => is_canonical_f64_nan(actual),
wast::NanPattern::ArithmeticNan => is_arithmetic_f64_nan(actual),
wast::NanPattern::Value(expected_value) => actual == expected_value.bits,
}
}
fn v128_matches(actual: u128, expected: &wast::V128Pattern) -> bool {
match expected {
wast::V128Pattern::I8x16(b) => b
.iter()
.enumerate()
.all(|(i, b)| *b == extract_lane_as_i8(actual, i)),
wast::V128Pattern::I16x8(b) => b
.iter()
.enumerate()
.all(|(i, b)| *b == extract_lane_as_i16(actual, i)),
wast::V128Pattern::I32x4(b) => b
.iter()
.enumerate()
.all(|(i, b)| *b == extract_lane_as_i32(actual, i)),
wast::V128Pattern::I64x2(b) => b
.iter()
.enumerate()
.all(|(i, b)| *b == extract_lane_as_i64(actual, i)),
wast::V128Pattern::F32x4(b) => b.iter().enumerate().all(|(i, b)| {
let a = extract_lane_as_i32(actual, i) as u32;
f32_matches(a, b)
}),
wast::V128Pattern::F64x2(b) => b.iter().enumerate().all(|(i, b)| {
let a = extract_lane_as_i64(actual, i) as u64;
f64_matches(a, b)
}),
}
}

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "wasmtime-fuzz" name = "wasmtime-fuzz"
version = "0.7.0" version = "0.9.0"
authors = ["The Wasmtime Project Developers"] authors = ["The Wasmtime Project Developers"]
edition = "2018" edition = "2018"
publish = false publish = false

View File

@@ -9,16 +9,16 @@ topdir=$(dirname "$0")/..
cd "$topdir" cd "$topdir"
# All the cranelift-* crates have the same version number # All the cranelift-* crates have the same version number
version="0.49" version="0.53"
# Update all of the Cargo.toml files. # Update all of the Cargo.toml files.
echo "Updating crate versions to $version" echo "Updating crate versions to $version"
for crate in . crates/* crates/misc/* fuzz; do for toml in Cargo.toml crates/*/Cargo.toml crates/misc/*/Cargo.toml fuzz/Cargo.toml; do
# Update the version number of this crate to $version. # Update the version number of this crate to $version.
sed -i.bk -e "/^cranelift-/s/\"[^\"]*\"/\"$version\"/" \ sed -i.bk -e "/^cranelift-/s/\"[^\"]*\"/\"$version\"/" \
"$crate/Cargo.toml" "$toml"
# Update the required version number of any cranelift* dependencies. # Update the required version number of any cranelift* dependencies.
sed -i.bk -e "/^cranelift-/s/version = \"[^\"]*\"/version = \"$version\"/" \ sed -i.bk -e "/^cranelift-/s/version = \"[^\"]*\"/version = \"$version\"/" \
"$crate/Cargo.toml" "$toml"
done done

View File

@@ -9,7 +9,7 @@ topdir=$(dirname "$0")/..
cd "$topdir" cd "$topdir"
# All the wasmtime-* crates have the same version number # All the wasmtime-* crates have the same version number
version="0.7.0" version="0.9.0"
# Update the version numbers of the crates to $version. # Update the version numbers of the crates to $version.
echo "Updating crate versions to $version" echo "Updating crate versions to $version"
@@ -17,6 +17,13 @@ find -name Cargo.toml \
-not -path ./crates/wasi-common/WASI/tools/witx/Cargo.toml \ -not -path ./crates/wasi-common/WASI/tools/witx/Cargo.toml \
-exec sed -i.bk -e "s/^version = \"[[:digit:]].*/version = \"$version\"/" {} \; -exec sed -i.bk -e "s/^version = \"[[:digit:]].*/version = \"$version\"/" {} \;
# Update the required version numbers of path dependencies.
find -name Cargo.toml \
-not -path ./crates/wasi-common/wig/WASI/tools/witx/Cargo.toml \
-exec sed -i.bk \
-e "/\> *= *{.*\<path *= *\"/s/version = \"[^\"]*\"/version = \"$version\"/" \
{} \;
# Update our local Cargo.lock (not checked in). # Update our local Cargo.lock (not checked in).
cargo update cargo update
scripts/test-all.sh scripts/test-all.sh
@@ -42,10 +49,10 @@ for cargo_toml in \
crates/runtime/Cargo.toml \ crates/runtime/Cargo.toml \
crates/debug/Cargo.toml \ crates/debug/Cargo.toml \
crates/jit/Cargo.toml \ crates/jit/Cargo.toml \
crates/wast/Cargo.toml \
crates/wasi-c/Cargo.toml \ crates/wasi-c/Cargo.toml \
crates/wasi/Cargo.toml \
crates/api/Cargo.toml \ crates/api/Cargo.toml \
crates/wasi/Cargo.toml \
crates/wast/Cargo.toml \
crates/interface-types/Cargo.toml \ crates/interface-types/Cargo.toml \
crates/misc/py/Cargo.toml \ crates/misc/py/Cargo.toml \
crates/misc/rust/macro/Cargo.toml \ crates/misc/rust/macro/Cargo.toml \

View File

@@ -11,7 +11,7 @@ use std::{
}; };
use structopt::{clap::AppSettings, StructOpt}; use structopt::{clap::AppSettings, StructOpt};
use wasi_common::preopen_dir; use wasi_common::preopen_dir;
use wasmtime::{Config, Engine, HostRef, Instance, Module, Store}; use wasmtime::{Config, Engine, Instance, Module, Store};
use wasmtime_environ::cache_init; use wasmtime_environ::cache_init;
use wasmtime_interface_types::ModuleData; use wasmtime_interface_types::ModuleData;
use wasmtime_wasi::{ use wasmtime_wasi::{
@@ -148,7 +148,7 @@ impl RunCommand {
let preopen_dirs = self.compute_preopen_dirs()?; let preopen_dirs = self.compute_preopen_dirs()?;
let argv = self.compute_argv(); let argv = self.compute_argv();
let wasi_unstable = HostRef::new(if self.enable_wasi_c { let wasi_unstable = if self.enable_wasi_c {
#[cfg(feature = "wasi-c")] #[cfg(feature = "wasi-c")]
{ {
let global_exports = store.global_exports().clone(); let global_exports = store.global_exports().clone();
@@ -161,14 +161,10 @@ impl RunCommand {
} }
} else { } else {
create_wasi_instance_snapshot_0(&store, &preopen_dirs, &argv, &self.vars)? create_wasi_instance_snapshot_0(&store, &preopen_dirs, &argv, &self.vars)?
}); };
let wasi_snapshot_preview1 = HostRef::new(create_wasi_instance( let wasi_snapshot_preview1 =
&store, create_wasi_instance(&store, &preopen_dirs, &argv, &self.vars)?;
&preopen_dirs,
&argv,
&self.vars,
)?);
module_registry.insert("wasi_unstable".to_owned(), wasi_unstable); module_registry.insert("wasi_unstable".to_owned(), wasi_unstable);
module_registry.insert("wasi_snapshot_preview1".to_owned(), wasi_snapshot_preview1); module_registry.insert("wasi_snapshot_preview1".to_owned(), wasi_snapshot_preview1);
@@ -232,9 +228,9 @@ impl RunCommand {
fn instantiate_module( fn instantiate_module(
store: &Store, store: &Store,
module_registry: &HashMap<String, HostRef<Instance>>, module_registry: &HashMap<String, Instance>,
path: &Path, path: &Path,
) -> Result<(HostRef<Instance>, Module, Vec<u8>)> { ) -> Result<(Instance, Module, Vec<u8>)> {
// Read the wasm module binary either as `*.wat` or a raw binary // Read the wasm module binary either as `*.wat` or a raw binary
let data = wat::parse_file(path)?; let data = wat::parse_file(path)?;
@@ -248,7 +244,7 @@ impl RunCommand {
let module_name = i.module(); let module_name = i.module();
if let Some(instance) = module_registry.get(module_name) { if let Some(instance) = module_registry.get(module_name) {
let field_name = i.name(); let field_name = i.name();
if let Some(export) = instance.borrow().find_export_by_name(field_name) { if let Some(export) = instance.find_export_by_name(field_name) {
Ok(export.clone()) Ok(export.clone())
} else { } else {
bail!( bail!(
@@ -263,10 +259,8 @@ impl RunCommand {
}) })
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let instance = HostRef::new( let instance = Instance::new(&module, &imports)
Instance::new(store, &module, &imports) .context(format!("failed to instantiate {:?}", path))?;
.context(format!("failed to instantiate {:?}", path))?,
);
Ok((instance, module, data)) Ok((instance, module, data))
} }
@@ -274,7 +268,7 @@ impl RunCommand {
fn handle_module( fn handle_module(
&self, &self,
store: &Store, store: &Store,
module_registry: &HashMap<String, HostRef<Instance>>, module_registry: &HashMap<String, Instance>,
) -> Result<()> { ) -> Result<()> {
let (instance, module, data) = let (instance, module, data) =
Self::instantiate_module(store, module_registry, &self.module)?; Self::instantiate_module(store, module_registry, &self.module)?;
@@ -301,16 +295,11 @@ impl RunCommand {
Ok(()) Ok(())
} }
fn invoke_export( fn invoke_export(&self, instance: Instance, data: &ModuleData, name: &str) -> Result<()> {
&self,
instance: HostRef<Instance>,
data: &ModuleData,
name: &str,
) -> Result<()> {
use wasm_webidl_bindings::ast; use wasm_webidl_bindings::ast;
use wasmtime_interface_types::Value; use wasmtime_interface_types::Value;
let mut handle = instance.borrow().handle().clone(); let mut handle = instance.handle().clone();
// Use the binding information in `ModuleData` to figure out what arguments // Use the binding information in `ModuleData` to figure out what arguments
// need to be passed to the function that we're invoking. Currently we take // need to be passed to the function that we're invoking. Currently we take

View File

@@ -154,7 +154,7 @@ impl WasmToObjCommand {
&module_translation, &module_translation,
lazy_function_body_inputs, lazy_function_body_inputs,
&*isa, &*isa,
generate_debug_info, self.common.debug_info,
), ),
#[cfg(not(feature = "lightbeam"))] #[cfg(not(feature = "lightbeam"))]
Strategy::Lightbeam => bail!("lightbeam support not enabled"), Strategy::Lightbeam => bail!("lightbeam support not enabled"),

View File

@@ -1,24 +1,54 @@
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
mod tests { mod tests {
use core::cell::Ref; use anyhow::Result;
use std::rc::Rc; use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use wasmtime::*; use wasmtime::*;
use wasmtime_interface_types::{ModuleData, Value};
fn invoke_export( const WAT1: &str = r#"
instance: &HostRef<Instance>, (module
data: &[u8], (func $read (export "read") (result i32)
func_name: &str, (i32.load (i32.const 0))
) -> Result<Vec<Value>, anyhow::Error> { )
ModuleData::new(&data) (func $read_out_of_bounds (export "read_out_of_bounds") (result i32)
.expect("module data") (i32.load
.invoke_export(instance, func_name, &[]) (i32.mul
;; memory size in Wasm pages
(memory.size)
;; Wasm page size
(i32.const 65536)
)
)
)
(func $start
(i32.store (i32.const 0) (i32.const 123))
)
(start $start)
(memory (export "memory") 1 4)
)
"#;
const WAT2: &str = r#"
(module
(import "other_module" "read" (func $other_module.read (result i32)))
(func $run (export "run") (result i32)
call $other_module.read)
)
"#;
fn invoke_export(instance: &Instance, func_name: &str) -> Result<Box<[Val]>, Trap> {
let ret = instance
.find_export_by_name(func_name)
.unwrap()
.func()
.unwrap()
.call(&[])?;
Ok(ret)
} }
// Locate "memory" export, get base address and size and set memory protection to PROT_NONE // Locate "memory" export, get base address and size and set memory protection to PROT_NONE
fn set_up_memory(instance: &HostRef<Instance>) -> (*mut u8, usize) { fn set_up_memory(instance: &Instance) -> (*mut u8, usize) {
let mem_export = instance.borrow().get_wasmtime_memory().expect("memory"); let mem_export = instance.get_wasmtime_memory().expect("memory");
let (base, length) = if let wasmtime_runtime::Export::Memory { let (base, length) = if let wasmtime_runtime::Export::Memory {
definition, definition,
@@ -73,39 +103,34 @@ mod tests {
} }
#[test] #[test]
fn test_custom_signal_handler_single_instance() { fn test_custom_signal_handler_single_instance() -> Result<()> {
let engine = HostRef::new(Engine::new(&Config::default())); let engine = Engine::new(&Config::default());
let store = HostRef::new(Store::new(&engine)); let store = Store::new(&engine);
let data = let data = wat::parse_str(WAT1)?;
std::fs::read("tests/custom_signal_handler.wasm").expect("failed to read wasm file"); let module = Module::new(&store, &data)?;
let module = HostRef::new(Module::new(&store, &data).expect("failed to create module")); let instance = Instance::new(&module, &[])?;
let instance = HostRef::new(
Instance::new(&store, &module, &[]).expect("failed to instantiate module"),
);
let (base, length) = set_up_memory(&instance); let (base, length) = set_up_memory(&instance);
instance instance.set_signal_handler(move |signum, siginfo, _| {
.borrow_mut()
.set_signal_handler(move |signum, siginfo, _| {
handle_sigsegv(base, length, signum, siginfo) handle_sigsegv(base, length, signum, siginfo)
}); });
let exports = Ref::map(instance.borrow(), |instance| instance.exports()); let exports = instance.exports();
assert!(!exports.is_empty()); assert!(!exports.is_empty());
// these invoke wasmtime_call_trampoline from action.rs // these invoke wasmtime_call_trampoline from action.rs
{ {
println!("calling read..."); println!("calling read...");
let result = invoke_export(&instance, &data, "read").expect("read succeeded"); let result = invoke_export(&instance, "read").expect("read succeeded");
assert_eq!("123", result[0].clone().to_string()); assert_eq!(123, result[0].unwrap_i32());
} }
{ {
println!("calling read_out_of_bounds..."); println!("calling read_out_of_bounds...");
let trap = invoke_export(&instance, &data, "read_out_of_bounds").unwrap_err(); let trap = invoke_export(&instance, "read_out_of_bounds").unwrap_err();
assert!(trap.root_cause().to_string().starts_with( assert!(trap
"trapped: Ref(Trap { message: \"wasm trap: out of bounds memory access" .message()
)); .starts_with("call error: wasm trap: out of bounds memory access"));
} }
// these invoke wasmtime_call_trampoline from callable.rs // these invoke wasmtime_call_trampoline from callable.rs
@@ -114,10 +139,7 @@ mod tests {
.func() .func()
.expect("expected a 'read' func in the module"); .expect("expected a 'read' func in the module");
println!("calling read..."); println!("calling read...");
let result = read_func let result = read_func.call(&[]).expect("expected function not to trap");
.borrow()
.call(&[])
.expect("expected function not to trap");
assert_eq!(123i32, result[0].clone().unwrap_i32()); assert_eq!(123i32, result[0].clone().unwrap_i32());
} }
@@ -126,33 +148,30 @@ mod tests {
.func() .func()
.expect("expected a 'read_out_of_bounds' func in the module"); .expect("expected a 'read_out_of_bounds' func in the module");
println!("calling read_out_of_bounds..."); println!("calling read_out_of_bounds...");
let trap = read_out_of_bounds_func.borrow().call(&[]).unwrap_err(); let trap = read_out_of_bounds_func.call(&[]).unwrap_err();
assert!(trap assert!(trap
.borrow()
.message() .message()
.starts_with("wasm trap: out of bounds memory access")); .starts_with("call error: wasm trap: out of bounds memory access"));
} }
Ok(())
} }
#[test] #[test]
fn test_custom_signal_handler_multiple_instances() { fn test_custom_signal_handler_multiple_instances() -> Result<()> {
let engine = HostRef::new(Engine::new(&Config::default())); let engine = Engine::new(&Config::default());
let store = HostRef::new(Store::new(&engine)); let store = Store::new(&engine);
let data = let data = wat::parse_str(WAT1)?;
std::fs::read("tests/custom_signal_handler.wasm").expect("failed to read wasm file"); let module = Module::new(&store, &data)?;
let module = HostRef::new(Module::new(&store, &data).expect("failed to create module"));
// Set up multiple instances // Set up multiple instances
let instance1 = HostRef::new( let instance1 = Instance::new(&module, &[])?;
Instance::new(&store, &module, &[]).expect("failed to instantiate module"),
);
let instance1_handler_triggered = Rc::new(AtomicBool::new(false)); let instance1_handler_triggered = Rc::new(AtomicBool::new(false));
{ {
let (base1, length1) = set_up_memory(&instance1); let (base1, length1) = set_up_memory(&instance1);
instance1.borrow_mut().set_signal_handler({ instance1.set_signal_handler({
let instance1_handler_triggered = instance1_handler_triggered.clone(); let instance1_handler_triggered = instance1_handler_triggered.clone();
move |_signum, _siginfo, _context| { move |_signum, _siginfo, _context| {
// Remove protections so the execution may resume // Remove protections so the execution may resume
@@ -173,15 +192,13 @@ mod tests {
}); });
} }
let instance2 = HostRef::new( let instance2 = Instance::new(&module, &[]).expect("failed to instantiate module");
Instance::new(&store, &module, &[]).expect("failed to instantiate module"),
);
let instance2_handler_triggered = Rc::new(AtomicBool::new(false)); let instance2_handler_triggered = Rc::new(AtomicBool::new(false));
{ {
let (base2, length2) = set_up_memory(&instance2); let (base2, length2) = set_up_memory(&instance2);
instance2.borrow_mut().set_signal_handler({ instance2.set_signal_handler({
let instance2_handler_triggered = instance2_handler_triggered.clone(); let instance2_handler_triggered = instance2_handler_triggered.clone();
move |_signum, _siginfo, _context| { move |_signum, _siginfo, _context| {
// Remove protections so the execution may resume // Remove protections so the execution may resume
@@ -206,12 +223,12 @@ mod tests {
// First instance1 // First instance1
{ {
let exports1 = Ref::map(instance1.borrow(), |i| i.exports()); let exports1 = instance1.exports();
assert!(!exports1.is_empty()); assert!(!exports1.is_empty());
println!("calling instance1.read..."); println!("calling instance1.read...");
let result = invoke_export(&instance1, &data, "read").expect("read succeeded"); let result = invoke_export(&instance1, "read").expect("read succeeded");
assert_eq!("123", result[0].clone().to_string()); assert_eq!(123, result[0].unwrap_i32());
assert_eq!( assert_eq!(
instance1_handler_triggered.load(Ordering::SeqCst), instance1_handler_triggered.load(Ordering::SeqCst),
true, true,
@@ -221,62 +238,53 @@ mod tests {
// And then instance2 // And then instance2
{ {
let exports2 = Ref::map(instance2.borrow(), |i| i.exports()); let exports2 = instance2.exports();
assert!(!exports2.is_empty()); assert!(!exports2.is_empty());
println!("calling instance2.read..."); println!("calling instance2.read...");
let result = invoke_export(&instance2, &data, "read").expect("read succeeded"); let result = invoke_export(&instance2, "read").expect("read succeeded");
assert_eq!("123", result[0].clone().to_string()); assert_eq!(123, result[0].unwrap_i32());
assert_eq!( assert_eq!(
instance2_handler_triggered.load(Ordering::SeqCst), instance2_handler_triggered.load(Ordering::SeqCst),
true, true,
"instance1 signal handler has been triggered" "instance1 signal handler has been triggered"
); );
} }
Ok(())
} }
#[test] #[test]
fn test_custom_signal_handler_instance_calling_another_instance() { fn test_custom_signal_handler_instance_calling_another_instance() -> Result<()> {
let engine = HostRef::new(Engine::new(&Config::default())); let engine = Engine::new(&Config::default());
let store = HostRef::new(Store::new(&engine)); let store = Store::new(&engine);
// instance1 which defines 'read' // instance1 which defines 'read'
let data1 = let data1 = wat::parse_str(WAT1)?;
std::fs::read("tests/custom_signal_handler.wasm").expect("failed to read wasm file"); let module1 = Module::new(&store, &data1)?;
let module1 = HostRef::new(Module::new(&store, &data1).expect("failed to create module")); let instance1 = Instance::new(&module1, &[])?;
let instance1: HostRef<Instance> = HostRef::new(
Instance::new(&store, &module1, &[]).expect("failed to instantiate module"),
);
let (base1, length1) = set_up_memory(&instance1); let (base1, length1) = set_up_memory(&instance1);
instance1 instance1.set_signal_handler(move |signum, siginfo, _| {
.borrow_mut()
.set_signal_handler(move |signum, siginfo, _| {
println!("instance1"); println!("instance1");
handle_sigsegv(base1, length1, signum, siginfo) handle_sigsegv(base1, length1, signum, siginfo)
}); });
let instance1_exports = Ref::map(instance1.borrow(), |i| i.exports()); let instance1_exports = instance1.exports();
assert!(!instance1_exports.is_empty()); assert!(!instance1_exports.is_empty());
let instance1_read = instance1_exports[0].clone(); let instance1_read = instance1_exports[0].clone();
// instance2 wich calls 'instance1.read' // instance2 wich calls 'instance1.read'
let data2 = let data2 = wat::parse_str(WAT2)?;
std::fs::read("tests/custom_signal_handler_2.wasm").expect("failed to read wasm file"); let module2 = Module::new(&store, &data2)?;
let module2 = HostRef::new(Module::new(&store, &data2).expect("failed to create module")); let instance2 = Instance::new(&module2, &[instance1_read])?;
let instance2 = HostRef::new(
Instance::new(&store, &module2, &[instance1_read])
.expect("failed to instantiate module"),
);
// since 'instance2.run' calls 'instance1.read' we need to set up the signal handler to handle // since 'instance2.run' calls 'instance1.read' we need to set up the signal handler to handle
// SIGSEGV originating from within the memory of instance1 // SIGSEGV originating from within the memory of instance1
instance2 instance2.set_signal_handler(move |signum, siginfo, _| {
.borrow_mut()
.set_signal_handler(move |signum, siginfo, _| {
handle_sigsegv(base1, length1, signum, siginfo) handle_sigsegv(base1, length1, signum, siginfo)
}); });
println!("calling instance2.run"); println!("calling instance2.run");
let result = invoke_export(&instance2, &data2, "run").expect("instance2.run succeeded"); let result = invoke_export(&instance2, "run")?;
assert_eq!("123", result[0].clone().to_string()); assert_eq!(123, result[0].unwrap_i32());
Ok(())
} }
} }

Binary file not shown.

View File

@@ -1,20 +0,0 @@
(module
(func $read (export "read") (result i32)
(i32.load (i32.const 0))
)
(func $read_out_of_bounds (export "read_out_of_bounds") (result i32)
(i32.load
(i32.mul
;; memory size in Wasm pages
(memory.size)
;; Wasm page size
(i32.const 65536)
)
)
)
(func $start
(i32.store (i32.const 0) (i32.const 123))
)
(start $start)
(memory (export "memory") 1 4)
)

Some files were not shown because too many files have changed in this diff Show More