diff --git a/.gitmodules b/.gitmodules index 6447c5a6c9..2bb139cd81 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,5 +5,5 @@ path = crates/api/c-examples/wasm-c-api url = https://github.com/WebAssembly/wasm-c-api [submodule "crates/wasi-common/WASI"] - path = crates/wasi-common/WASI + path = crates/wasi-common/wig/WASI url = https://github.com/WebAssembly/WASI diff --git a/Cargo.lock b/Cargo.lock index d91401e018..d8b036cd0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,9 +20,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14" +checksum = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c" [[package]] name = "arbitrary" @@ -53,10 +53,11 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" [[package]] name = "atty" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ + "hermit-abi", "libc", "winapi", ] @@ -67,6 +68,12 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + [[package]] name = "backtrace" version = "0.3.40" @@ -119,7 +126,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "440d600bca1c3b3982dd2533518e15ba73d051b532768804aa3c06ae52f4ce44" dependencies = [ - "bindgen 0.52.0", + "bindgen", "cc", "cmake", "heck", @@ -136,29 +143,6 @@ dependencies = [ "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]] name = "bindgen" version = "0.52.0" @@ -191,9 +175,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "blake2b_simd" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b83b7baab1e671718d78204225800d6b170e648188ac7dc992e9d6bddf87d0c0" +checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" dependencies = [ "arrayref", "arrayvec 0.5.1", @@ -262,12 +246,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.48" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76" +checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" dependencies = [ "jobserver", - "num_cpus", ] [[package]] @@ -358,18 +341,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.52.0" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56aa72ef104c5d634f2f9e84ef2c47e116c1d185fae13f196b97ca84b0a514f1" +checksum = "bd3225fff1be118941c5fb66f1fb1f7f3e86468fac0e7364713c4fb99b72632b" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.52.0" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460b9d20793543599308d22f5a1172c196e63a780c4e9aacb0b3f4f63d63ffe1" +checksum = "f3e3e6679892029f76a99b9059d2b74e77ac03637d573bb014bc21579ec1b7da" dependencies = [ "byteorder", "cranelift-bforest", @@ -385,9 +368,9 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.52.0" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc70e4e8ccebd53a4f925147def857c9e9f7fe0fdbef4bb645a420473e012f50" +checksum = "3cabe691548e28ca82ebd218f2fe76eec4c5629b64ef3db8b58443b7d9047275" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -395,24 +378,24 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.52.0" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3992000be4d18df0fe332b7c42c120de896e8ec54cd7b6cfa050910a8c9f6e2f" +checksum = "d173252ffade4aa6e929090977b9a4cd5ac28e15a42626f878be3844b3000ad9" [[package]] name = "cranelift-entity" -version = "0.52.0" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "722957e05064d97a3157bf0976deed0f3e8ee4f8a4ce167a7c724ca63a4e8bd9" +checksum = "3498ad9ba021715716a1c52e2b31d7829a149913fb0d88493e4b07d3b772b656" dependencies = [ "serde", ] [[package]] name = "cranelift-frontend" -version = "0.52.0" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13051964302dc7948e8869735de42591559ea55e319b9b92da5b38f8e6a75cb7" +checksum = "521a30773b8de74345c807a38853f055aca8fecaa39a0fc7698bfebc5a3da515" dependencies = [ "cranelift-codegen", "log", @@ -422,9 +405,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.52.0" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21398a0bc6ba389ea86964ac4a495426dd61080f2ddd306184777a8560fe9976" +checksum = "624e755cbe984e437308968239736e7f9aa3193e99928fb76eec7a1946627b34" dependencies = [ "cranelift-codegen", "raw-cpuid", @@ -433,9 +416,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.52.0" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b72b7b10c09f70a604122fab76e6c4411255cf35403b68c3285566cc9d21c486" +checksum = "0320733e518ab9e0e2d1a22034d40e2851fb403ed14db5220cf9b86576b9cfd4" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -443,7 +426,7 @@ dependencies = [ "log", "serde", "thiserror", - "wasmparser 0.45.1", + "wasmparser 0.45.2", ] [[package]] @@ -462,7 +445,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" dependencies = [ - "autocfg", + "autocfg 0.1.7", "cfg-if", "crossbeam-utils 0.7.0", "lazy_static", @@ -472,10 +455,11 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfd6515864a82d2f877b42813d4553292c6659498c9a2aa31bab5a15243c2700" +checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" dependencies = [ + "cfg-if", "crossbeam-utils 0.7.0", ] @@ -495,7 +479,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" dependencies = [ - "autocfg", + "autocfg 0.1.7", "cfg-if", "lazy_static", ] @@ -630,9 +614,9 @@ dependencies = [ [[package]] name = "faerie" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f902f2af041f6c7177a2a04f805687cdc71e69c7cbef059a2755d8923f4cd7a8" +checksum = "74b9ed6159e4a6212c61d9c6a86bee01876b192a64accecf58d5b5ae3b667b52" dependencies = [ "anyhow", "goblin", @@ -723,9 +707,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ "cfg-if", "libc", @@ -764,9 +748,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "goblin" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a79ef1f0dad46fd78075b6f80f92d97710eddf87b3e18a15a66761e8942672" +checksum = "3081214398d39e4bd7f2c1975f0488ed04614ffdd976c6fc7a0708278552c0da" dependencies = [ "log", "plain", @@ -784,9 +768,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" +checksum = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" dependencies = [ "libc", ] @@ -812,7 +796,7 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2" dependencies = [ - "autocfg", + "autocfg 0.1.7", ] [[package]] @@ -840,9 +824,9 @@ dependencies = [ [[package]] name = "inventory" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4cece20baea71d9f3435e7bbe9adf4765f091c5fe404975f844006964a71299" +checksum = "2bf98296081bd2cb540acc09ef9c97f22b7e487841520350293605db1b2c7a27" dependencies = [ "ctor", "ghost", @@ -851,9 +835,9 @@ dependencies = [ [[package]] name = "inventory-impl" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2869bf972e998977b1cb87e60df70341d48e48dca0823f534feb91ea44adaf9" +checksum = "0a8e30575afe28eea36a9a39136b70b2fb6b0dd0a212a5bd1f30a498395c0274" dependencies = [ "proc-macro2", "quote", @@ -877,13 +861,11 @@ checksum = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" [[package]] name = "jobserver" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b1d42ef453b30b7387e113da1c83ab1605d90c5b4e0eb8e96d016ed3b8c160" +checksum = "230ae9adf468173aecd4176c7233bddc84a15871a586c5971ace9a55f881c075" dependencies = [ - "getrandom", "libc", - "log", ] [[package]] @@ -931,7 +913,7 @@ dependencies = [ [[package]] name = "lightbeam" -version = "0.7.0" +version = "0.9.0" dependencies = [ "anyhow", "capstone", @@ -948,7 +930,7 @@ dependencies = [ "smallvec", "thiserror", "typemap", - "wasmparser 0.45.1", + "wasmparser 0.47.0", "wat", ] @@ -1025,9 +1007,9 @@ dependencies = [ [[package]] name = "num" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" dependencies = [ "num-complex", "num-integer", @@ -1038,53 +1020,53 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb0cf31fb3ff77e6d2a6ebd6800df7fdcd106f2ad89113c9130bcd07f93dffc" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" dependencies = [ - "autocfg", + "autocfg 1.0.0", "num-traits", ] [[package]] name = "num-integer" -version = "0.1.41" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" +checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" dependencies = [ - "autocfg", + "autocfg 1.0.0", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" +checksum = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00" dependencies = [ - "autocfg", + "autocfg 1.0.0", "num-integer", "num-traits", ] [[package]] name = "num-rational" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454" +checksum = "da4dc79f9e6c81bef96148c8f6b8e72ad4541caa4a24373e900a36da07de03a3" dependencies = [ - "autocfg", + "autocfg 1.0.0", "num-integer", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" +checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" dependencies = [ - "autocfg", + "autocfg 1.0.0", ] [[package]] @@ -1175,13 +1157,28 @@ dependencies = [ [[package]] name = "proc-macro-error" -version = "0.2.6" +version = "0.4.4" 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 = [ "proc-macro2", "quote", + "rustversion", "syn", + "syn-mid", ] [[package]] @@ -1197,18 +1194,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" +checksum = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc" dependencies = [ "unicode-xid", ] [[package]] name = "pyo3" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b338139584e698b341996e4f453c71fa937daa408aaf301e042383724e0caca" +checksum = "e1bfe257586436fbe1296d917f14a167d4253d0873bf43e2c9b9bdd58a3f9f35" dependencies = [ "indoc", "inventory", @@ -1227,9 +1224,9 @@ dependencies = [ [[package]] name = "pyo3-derive-backend" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b8c805249a82c04a00d96f562e66537e8ddfe5d895bc2a414a8e6b6ae3d53be" +checksum = "4882d8237fd8c7373cc25cb802fe0dab9ff70830fd56f47ef6c7f3f287fcc057" dependencies = [ "proc-macro2", "quote", @@ -1238,9 +1235,9 @@ dependencies = [ [[package]] name = "pyo3cls" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3575ad614aa547044119f3ff78aff7bdcba6bcde53fcd67065611546d2b8a122" +checksum = "fdf321cfab555f7411298733c86d21e5136f5ded13f5872fabf9de3337beecda" dependencies = [ "proc-macro2", "pyo3-derive-backend", @@ -1250,9 +1247,9 @@ dependencies = [ [[package]] name = "quick-error" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quickcheck" @@ -1368,9 +1365,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43739f8831493b276363637423d3622d4bd6394ab6f0a9c4a552e208aeb7fddd" +checksum = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098" dependencies = [ "crossbeam-deque", "either", @@ -1379,9 +1376,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bf17de6f23b05473c437eb958b9c850bfc8af0961fe17b4cc92d5a627b4791" +checksum = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9" dependencies = [ "crossbeam-deque", "crossbeam-queue", @@ -1419,9 +1416,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.3.1" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" +checksum = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87" dependencies = [ "aho-corasick", "memchr", @@ -1431,9 +1428,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.12" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" +checksum = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90" [[package]] name = "region" @@ -1491,6 +1488,17 @@ dependencies = [ "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]] name = "ryu" version = "1.0.2" @@ -1540,18 +1548,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" +checksum = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c6faef9a2e64b0064f48570289b4bf8823b7581f1d6157c1b52152306651d0" +checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" dependencies = [ "proc-macro2", "quote", @@ -1571,9 +1579,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" +checksum = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0" dependencies = [ "block-buffer", "digest", @@ -1589,9 +1597,9 @@ checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" [[package]] name = "smallvec" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86" +checksum = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4" [[package]] name = "spin" @@ -1622,9 +1630,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b3a3e93f5ad553c38b3301c8a0a0cec829a36783f6a0c467fc4bf553a5f5bf" +checksum = "884ae79d6aad1e738f4a70dff314203fd498490a63ebc4d03ea83323c40b7b72" dependencies = [ "clap", "structopt-derive", @@ -1632,9 +1640,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.3.5" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea692d40005b3ceba90a9fe7a78fa8d4b82b0ce627eebbffc329aab850f3410e" +checksum = "0a97f829a34a0a9d5b353a881025a23b8c9fd09d46be6045df6b22920dbd7a93" dependencies = [ "heck", "proc-macro-error", @@ -1645,15 +1653,26 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238" +checksum = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8" dependencies = [ "proc-macro2", "quote", "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]] name = "synstructure" version = "0.12.3" @@ -1668,9 +1687,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f4c118a7a38378f305a9e111fcb2f7f838c0be324bfb31a77ea04f7f6e684b4" +checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d" [[package]] name = "tempfile" @@ -1697,7 +1716,7 @@ dependencies = [ [[package]] name = "test-programs" -version = "0.7.0" +version = "0.9.0" dependencies = [ "anyhow", "cfg-if", @@ -1745,9 +1764,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +checksum = "88ddf1ad580c7e3d1efff877d972bcc93f995556b9087a5a259630985c88ceab" dependencies = [ "lazy_static", ] @@ -1780,9 +1799,9 @@ checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" [[package]] name = "trybuild" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75e31d624df08744532e935f1d4bfedd319a277d5a162c5b15f6ced59307575" +checksum = "987d6fdc45ddd7f3be5aa7386c8c8a844d1655c95b9ed948a9cd9cded8f2b79f" dependencies = [ "glob", "lazy_static", @@ -1886,13 +1905,13 @@ dependencies = [ [[package]] name = "wasi" -version = "0.7.0" +version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi-common" -version = "0.7.0" +version = "0.9.0" dependencies = [ "anyhow", "cfg-if", @@ -1913,7 +1932,7 @@ dependencies = [ [[package]] name = "wasi-common-cbindgen" -version = "0.7.0" +version = "0.9.0" dependencies = [ "proc-macro2", "quote", @@ -1947,9 +1966,15 @@ checksum = "1527c84a5bd585215f29c06b0e2a5274e478ad4dfc970d26ffad66fdc6cb311d" [[package]] name = "wasmparser" -version = "0.45.1" +version = "0.45.2" 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]] name = "wasmprinter" @@ -1963,27 +1988,28 @@ dependencies = [ [[package]] name = "wasmtime" -version = "0.7.0" +version = "0.9.0" dependencies = [ "anyhow", + "cfg-if", "file-per-thread-logger", + "libc", "pretty_env_logger", "rayon", "region", "target-lexicon", "wasi-common", - "wasmparser 0.45.1", + "wasmparser 0.47.0", "wasmtime-environ", "wasmtime-jit", "wasmtime-runtime", - "wasmtime-wasi", - "wasmtime-wast", "wat", + "winapi", ] [[package]] name = "wasmtime-cli" -version = "0.7.0" +version = "0.9.0" dependencies = [ "anyhow", "faerie", @@ -2003,6 +2029,7 @@ dependencies = [ "wasmtime-interface-types", "wasmtime-jit", "wasmtime-obj", + "wasmtime-runtime", "wasmtime-wasi", "wasmtime-wasi-c", "wasmtime-wast", @@ -2011,7 +2038,7 @@ dependencies = [ [[package]] name = "wasmtime-debug" -version = "0.7.0" +version = "0.9.0" dependencies = [ "anyhow", "faerie", @@ -2019,13 +2046,13 @@ dependencies = [ "more-asserts", "target-lexicon", "thiserror", - "wasmparser 0.45.1", + "wasmparser 0.47.0", "wasmtime-environ", ] [[package]] name = "wasmtime-environ" -version = "0.7.0" +version = "0.9.0" dependencies = [ "anyhow", "base64 0.11.0", @@ -2053,14 +2080,14 @@ dependencies = [ "tempfile", "thiserror", "toml", - "wasmparser 0.45.1", + "wasmparser 0.47.0", "winapi", "zstd", ] [[package]] name = "wasmtime-fuzz" -version = "0.7.0" +version = "0.9.0" dependencies = [ "arbitrary", "env_logger 0.7.1", @@ -2073,14 +2100,14 @@ dependencies = [ [[package]] name = "wasmtime-fuzzing" -version = "0.1.0" +version = "0.9.0" dependencies = [ "anyhow", "arbitrary", "binaryen", "env_logger 0.7.1", "log", - "wasmparser 0.45.1", + "wasmparser 0.47.0", "wasmprinter", "wasmtime", "wasmtime-environ", @@ -2090,12 +2117,12 @@ dependencies = [ [[package]] name = "wasmtime-interface-types" -version = "0.7.0" +version = "0.9.0" dependencies = [ "anyhow", "walrus", "wasm-webidl-bindings", - "wasmparser 0.45.1", + "wasmparser 0.47.0", "wasmtime", "wasmtime-environ", "wasmtime-jit", @@ -2105,7 +2132,7 @@ dependencies = [ [[package]] name = "wasmtime-jit" -version = "0.7.0" +version = "0.9.0" dependencies = [ "anyhow", "cranelift-codegen", @@ -2117,7 +2144,7 @@ dependencies = [ "region", "target-lexicon", "thiserror", - "wasmparser 0.45.1", + "wasmparser 0.47.0", "wasmtime-debug", "wasmtime-environ", "wasmtime-runtime", @@ -2126,7 +2153,7 @@ dependencies = [ [[package]] name = "wasmtime-obj" -version = "0.7.0" +version = "0.9.0" dependencies = [ "anyhow", "faerie", @@ -2136,13 +2163,13 @@ dependencies = [ [[package]] name = "wasmtime-py" -version = "0.7.0" +version = "0.9.0" dependencies = [ "anyhow", "pyo3", "region", "target-lexicon", - "wasmparser 0.45.1", + "wasmparser 0.47.0", "wasmtime", "wasmtime-environ", "wasmtime-interface-types", @@ -2152,9 +2179,10 @@ dependencies = [ [[package]] name = "wasmtime-runtime" -version = "0.7.0" +version = "0.9.0" dependencies = [ "cc", + "cfg-if", "indexmap", "lazy_static", "libc", @@ -2168,7 +2196,7 @@ dependencies = [ [[package]] name = "wasmtime-rust" -version = "0.7.0" +version = "0.9.0" dependencies = [ "anyhow", "wasmtime", @@ -2179,7 +2207,7 @@ dependencies = [ [[package]] name = "wasmtime-rust-macro" -version = "0.7.0" +version = "0.9.0" dependencies = [ "proc-macro2", "quote", @@ -2188,7 +2216,7 @@ dependencies = [ [[package]] name = "wasmtime-wasi" -version = "0.7.0" +version = "0.9.0" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -2205,9 +2233,9 @@ dependencies = [ [[package]] name = "wasmtime-wasi-c" -version = "0.7.0" +version = "0.9.0" dependencies = [ - "bindgen 0.51.1", + "bindgen", "cmake", "cranelift-codegen", "cranelift-entity", @@ -2223,11 +2251,11 @@ dependencies = [ [[package]] name = "wasmtime-wast" -version = "0.7.0" +version = "0.9.0" dependencies = [ "anyhow", "wasmtime", - "wast 5.0.1", + "wast 6.0.0", ] [[package]] @@ -2241,29 +2269,20 @@ dependencies = [ [[package]] name = "wast" -version = "4.0.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd03645007fe5c76cdacbcf51c145db79ab82756e977f7ed051b7cf896dc7df" -dependencies = [ - "leb128", -] - -[[package]] -name = "wast" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d1de68310854a9840d39487701a8c1acccb5c9f9f2650d5fce3cdfe6650c372" +checksum = "3ed3db7029d1d31a15c10126e78b58e51781faefafbc8afb20fb01291b779984" dependencies = [ "leb128", ] [[package]] name = "wat" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ba86afa8d9f69291394de512e10e5ca6788998f4c426a56113770048826dc9" +checksum = "9d59ba5b224f5507d55e4f89d0b18cc6452d84640ab11b4c9086d61a3ee62d03" dependencies = [ - "wast 4.0.0", + "wast 6.0.0", ] [[package]] @@ -2277,7 +2296,7 @@ dependencies = [ [[package]] name = "wig" -version = "0.7.0" +version = "0.9.2" dependencies = [ "heck", "proc-macro2", @@ -2328,7 +2347,7 @@ dependencies = [ [[package]] name = "winx" -version = "0.7.0" +version = "0.9.0" dependencies = [ "bitflags", "cvt", @@ -2338,6 +2357,8 @@ dependencies = [ [[package]] name = "witx" version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abc432537dbc9940e06816ebc3e1c4694fc835b90720615c32038769d7b2967d" dependencies = [ "clap", "thiserror", @@ -2346,7 +2367,7 @@ dependencies = [ [[package]] name = "yanix" -version = "0.1.0" +version = "0.9.0" dependencies = [ "bitflags", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index 3e72c70c8b..378189e3c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime-cli" -version = "0.7.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] description = "Command-line interface for Wasmtime" 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 } wasi-common = { path = "crates/wasi-common" } structopt = { version = "0.3.5", features = ["color", "suggestions"] } -faerie = "0.13.0" +faerie = "0.14.0" 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" file-per-thread-logger = "0.1.1" wat = "1.0.2" @@ -40,6 +40,7 @@ rayon = "1.2.1" wasm-webidl-bindings = "0.6" [dev-dependencies] +wasmtime-runtime = { path = "crates/runtime" } more-asserts = "0.2.1" # This feature requires the wasm32-wasi target be installed. It enables # wasm32-wasi integration tests. To enable, run diff --git a/build.rs b/build.rs index 4eed5d4154..ea89c70031 100644 --- a/build.rs +++ b/build.rs @@ -30,26 +30,8 @@ fn main() -> anyhow::Result<()> { // Skip running spec_testsuite tests if the submodule isn't checked // out. if spec_tests > 0 { - start_test_module(&mut out, "simd")?; - write_testsuite_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(&mut out, "tests/spec_testsuite/proposals/simd", strategy) + .expect("generating tests"); test_directory( &mut out, @@ -139,7 +121,6 @@ fn write_testsuite_tests( strategy: &str, ) -> anyhow::Result<()> { let path = path.as_ref(); - println!("cargo:rerun-if-changed={}", path.display()); let testname = extract_name(path); writeln!(out, "#[test]")?; @@ -165,9 +146,23 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool { "Lightbeam" => match (testsuite, testname) { (_, _) if testname.starts_with("simd") => 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) { + ("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"), diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml index 75850b0503..67961e0299 100644 --- a/crates/api/Cargo.toml +++ b/crates/api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime" -version = "0.7.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] description = "High-level API to expose the Wasmtime runtime" license = "Apache-2.0 WITH LLVM-exception" @@ -13,11 +13,11 @@ name = "wasmtime" crate-type = ["lib", "staticlib", "cdylib"] [dependencies] -wasmtime-runtime = { path = "../runtime" } -wasmtime-environ = { path = "../environ" } -wasmtime-jit = { path = "../jit" } -wasmparser = { version = "0.45.1", default-features = false } -target-lexicon = { version = "0.9.0", default-features = false } +wasmtime-runtime = { path = "../runtime", version = "0.9.0" } +wasmtime-environ = { path = "../environ", version = "0.9.0" } +wasmtime-jit = { path = "../jit", version = "0.9.0" } +wasmparser = { version = "0.47.0", default-features = false } +target-lexicon = { version = "0.10.0", default-features = false } anyhow = "1.0.19" region = "2.0.0" libc = "0.2" @@ -28,10 +28,8 @@ winapi = "0.3.7" [dev-dependencies] # for wasmtime.rs -wasi-common = { path = "../wasi-common" } +wasi-common = { path = "../wasi-common", version = "0.9.0" } pretty_env_logger = "0.3.0" -wasmtime-wast = { path = "../wast" } -wasmtime-wasi = { path = "../wasi" } rayon = "1.2.1" file-per-thread-logger = "0.1.1" wat = "1.0" diff --git a/crates/api/c-examples/wasm-c-api b/crates/api/c-examples/wasm-c-api index 8782d5b456..d9a80099d4 160000 --- a/crates/api/c-examples/wasm-c-api +++ b/crates/api/c-examples/wasm-c-api @@ -1 +1 @@ -Subproject commit 8782d5b456f39e5ebf86bbbfa88d0ac13743edfa +Subproject commit d9a80099d496b5cdba6f3fe8fc77586e0e505ddc diff --git a/crates/api/examples/gcd.rs b/crates/api/examples/gcd.rs index 93313cb708..43a29fcf01 100644 --- a/crates/api/examples/gcd.rs +++ b/crates/api/examples/gcd.rs @@ -50,11 +50,11 @@ fn main() -> anyhow::Result<()> { .0; // Instantiate the module. - let instance = Instance::new(&store, &module, &[])?; + let instance = Instance::new(&module, &[])?; // Invoke `gcd` export 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); Ok(()) diff --git a/crates/api/examples/hello.rs b/crates/api/examples/hello.rs index 5caaa75af6..c33b2c4495 100644 --- a/crates/api/examples/hello.rs +++ b/crates/api/examples/hello.rs @@ -41,15 +41,14 @@ fn main() -> Result<()> { // `HelloCallback` type and its associated implementation of `Callback. println!("Creating callback..."); 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 // 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. println!("Instantiating module..."); let imports = vec![hello_func.into()]; - let instance = Instance::new(&store, &module, imports.as_slice()) - .context("> Error instantiating module!")?; + let instance = Instance::new(&module, &imports).context("> Error instantiating module!")?; // Next we poke around a bit to extract the `run` function from the module. println!("Extracting export..."); @@ -59,7 +58,7 @@ fn main() -> Result<()> { // And last but not least we can call it! println!("Calling export..."); - run_func.borrow().call(&[])?; + run_func.call(&[])?; println!("Done."); Ok(()) diff --git a/crates/api/examples/memory.rs b/crates/api/examples/memory.rs index bd7d0be21a..a167e6f1ac 100644 --- a/crates/api/examples/memory.rs +++ b/crates/api/examples/memory.rs @@ -3,7 +3,7 @@ use anyhow::{bail, ensure, Context as _, Error}; use wasmtime::*; -fn get_export_memory(exports: &[Extern], i: usize) -> Result, Error> { +fn get_export_memory(exports: &[Extern], i: usize) -> Result { if exports.len() <= i { bail!("> Error accessing memory export {}!", i); } @@ -13,7 +13,7 @@ fn get_export_memory(exports: &[Extern], i: usize) -> Result, Er .clone()) } -fn get_export_func(exports: &[Extern], i: usize) -> Result, Error> { +fn get_export_func(exports: &[Extern], i: usize) -> Result { if exports.len() <= i { bail!("> Error accessing function export {}!", i); } @@ -33,7 +33,7 @@ macro_rules! check { macro_rules! check_ok { ($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"); } } @@ -41,7 +41,7 @@ macro_rules! check_ok { macro_rules! check_trap { ($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"); } } @@ -49,7 +49,7 @@ macro_rules! check_trap { macro_rules! call { ($func:expr, $($p:expr),*) => { - match $func.borrow().call(&[$($p.into()),*]) { + match $func.call(&[$($p.into()),*]) { Ok(result) => { let result: i32 = result[0].unwrap_i32(); result @@ -90,7 +90,7 @@ fn main() -> Result<(), Error> { // Instantiate. println!("Instantiating module..."); - let instance = Instance::new(&store, &module, &[]).context("> Error instantiating module!")?; + let instance = Instance::new(&module, &[]).context("> Error instantiating module!")?; // Extract export. println!("Extracting export..."); @@ -101,16 +101,13 @@ fn main() -> Result<(), Error> { let load_func = get_export_func(&exports, 2)?; let store_func = get_export_func(&exports, 3)?; - // Try cloning. - check!(memory.clone().ptr_eq(&memory), true); - // Check initial memory. println!("Checking memory..."); - check!(memory.borrow().size(), 2u32); - check!(memory.borrow().data_size(), 0x20000usize); - check!(unsafe { memory.borrow().data()[0] }, 0); - check!(unsafe { memory.borrow().data()[0x1000] }, 1); - check!(unsafe { memory.borrow().data()[0x1003] }, 4); + check!(memory.size(), 2u32); + check!(memory.data_size(), 0x20000usize); + check!(unsafe { memory.data()[0] }, 0); + check!(unsafe { memory.data()[0x1000] }, 1); + check!(unsafe { memory.data()[0x1003] }, 4); check!(call!(size_func,), 2); check!(call!(load_func, 0), 0); @@ -122,36 +119,36 @@ fn main() -> Result<(), Error> { // Mutate memory. println!("Mutating memory..."); unsafe { - memory.borrow_mut().data()[0x1003] = 5; + memory.data()[0x1003] = 5; } check_ok!(store_func, 0x1002, 6); check_trap!(store_func, 0x20000, 0); - check!(unsafe { memory.borrow().data()[0x1002] }, 6); - check!(unsafe { memory.borrow().data()[0x1003] }, 5); + check!(unsafe { memory.data()[0x1002] }, 6); + check!(unsafe { memory.data()[0x1003] }, 5); check!(call!(load_func, 0x1002), 6); check!(call!(load_func, 0x1003), 5); // Grow memory. println!("Growing memory..."); - check!(memory.borrow_mut().grow(1), true); - check!(memory.borrow().size(), 3u32); - check!(memory.borrow().data_size(), 0x30000usize); + check!(memory.grow(1), true); + check!(memory.size(), 3u32); + check!(memory.data_size(), 0x30000usize); check!(call!(load_func, 0x20000), 0); check_ok!(store_func, 0x20000, 0); check_trap!(load_func, 0x30000); check_trap!(store_func, 0x30000, 0); - check!(memory.borrow_mut().grow(1), false); - check!(memory.borrow_mut().grow(0), true); + check!(memory.grow(1), false); + check!(memory.grow(0), true); // Create stand-alone memory. // TODO(wasm+): Once Wasm allows multiple memories, turn this into import. println!("Creating stand-alone memory..."); 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.grow(1), false); check!(memory2.grow(0), true); diff --git a/crates/api/examples/multi.rs b/crates/api/examples/multi.rs index 8898accf11..830d899138 100644 --- a/crates/api/examples/multi.rs +++ b/crates/api/examples/multi.rs @@ -62,13 +62,13 @@ fn main() -> Result<()> { Box::new([ValType::I32, ValType::I64]), 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. println!("Instantiating module..."); let imports = vec![callback_func.into()]; - let instance = Instance::new(&store, &module, imports.as_slice()) - .context("Error instantiating module!")?; + let instance = + Instance::new(&module, imports.as_slice()).context("Error instantiating module!")?; // Extract exports. println!("Extracting export..."); @@ -83,7 +83,6 @@ fn main() -> Result<()> { println!("Calling export \"g\"..."); let args = vec![Val::I32(1), Val::I64(3)]; let results = g - .borrow() .call(&args) .map_err(|e| format_err!("> Error calling g! {:?}", e))?; @@ -108,7 +107,6 @@ fn main() -> Result<()> { Val::I64(9), ]; let results = round_trip_many - .borrow() .call(&args) .map_err(|e| format_err!("> Error calling round_trip_many! {:?}", e))?; diff --git a/crates/api/src/callable.rs b/crates/api/src/callable.rs index 317875a7fd..139959f359 100644 --- a/crates/api/src/callable.rs +++ b/crates/api/src/callable.rs @@ -12,7 +12,7 @@ use wasmtime_runtime::Export; /// WebAssembly. /// # Example /// ``` -/// use wasmtime::{HostRef, Val}; +/// use wasmtime::Val; /// /// struct TimesTwo; /// @@ -54,13 +54,11 @@ use wasmtime_runtime::Export; /// ); /// /// // Build a reference to the "times_two" function that can be used. -/// let times_two_function = HostRef::new( -/// wasmtime::Func::new(&store, times_two_type, std::rc::Rc::new(TimesTwo)) -/// ); +/// let times_two_function = +/// wasmtime::Func::new(&store, times_two_type, std::rc::Rc::new(TimesTwo)); /// /// // Create module instance that imports our function /// let instance = wasmtime::Instance::new( -/// &store, /// &module, /// &[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. /// let original = 5i32; /// let results = run_function -/// .borrow() /// .call(&[original.into()]) /// .map_err(|trap| trap.to_string())?; /// diff --git a/crates/api/src/externals.rs b/crates/api/src/externals.rs index c5be5b27a0..0062b60b1d 100644 --- a/crates/api/src/externals.rs +++ b/crates/api/src/externals.rs @@ -1,5 +1,5 @@ use crate::callable::{Callable, NativeCallable, WasmtimeFn, WrappedCallable}; -use crate::r#ref::{AnyRef, HostRef}; +use crate::r#ref::AnyRef; use crate::runtime::Store; use crate::trampoline::{generate_global_export, generate_memory_export, generate_table_export}; use crate::trap::Trap; @@ -15,53 +15,53 @@ use wasmtime_runtime::InstanceHandle; #[derive(Clone)] pub enum Extern { - Func(HostRef), - Global(HostRef), - Table(HostRef), - Memory(HostRef), + Func(Func), + Global(Global), + Table(Table), + Memory(Memory), } impl Extern { - pub fn func(&self) -> Option<&HostRef> { + pub fn func(&self) -> Option<&Func> { match self { Extern::Func(func) => Some(func), _ => None, } } - pub fn global(&self) -> Option<&HostRef> { + pub fn global(&self) -> Option<&Global> { match self { Extern::Global(global) => Some(global), _ => None, } } - pub fn table(&self) -> Option<&HostRef
> { + pub fn table(&self) -> Option<&Table> { match self { Extern::Table(table) => Some(table), _ => None, } } - pub fn memory(&self) -> Option<&HostRef> { + pub fn memory(&self) -> Option<&Memory> { match self { Extern::Memory(memory) => Some(memory), _ => None, } } - pub fn r#type(&self) -> ExternType { + pub fn ty(&self) -> ExternType { match self { - Extern::Func(ft) => ExternType::Func(ft.borrow().r#type().clone()), - Extern::Memory(ft) => ExternType::Memory(ft.borrow().r#type().clone()), - Extern::Table(tt) => ExternType::Table(tt.borrow().r#type().clone()), - Extern::Global(gt) => ExternType::Global(gt.borrow().r#type().clone()), + Extern::Func(ft) => ExternType::Func(ft.ty().clone()), + Extern::Memory(ft) => ExternType::Memory(ft.ty().clone()), + Extern::Table(tt) => ExternType::Table(tt.ty().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 { - Extern::Func(f) => f.borrow().wasmtime_export().clone(), - Extern::Global(g) => g.borrow().wasmtime_export().clone(), - Extern::Memory(m) => m.borrow().wasmtime_export().clone(), - Extern::Table(t) => t.borrow().wasmtime_export().clone(), + Extern::Func(f) => f.wasmtime_export().clone(), + Extern::Global(g) => g.wasmtime_export().clone(), + Extern::Memory(m) => m.wasmtime_export().clone(), + Extern::Table(t) => t.wasmtime_export().clone(), } } @@ -71,50 +71,51 @@ impl Extern { export: wasmtime_runtime::Export, ) -> Extern { match export { - wasmtime_runtime::Export::Function { .. } => Extern::Func(HostRef::new( - Func::from_wasmtime_function(export, store, instance_handle), - )), - wasmtime_runtime::Export::Memory { .. } => Extern::Memory(HostRef::new( - Memory::from_wasmtime_memory(export, store, instance_handle), - )), - wasmtime_runtime::Export::Global { .. } => { - Extern::Global(HostRef::new(Global::from_wasmtime_global(export, store))) + wasmtime_runtime::Export::Function { .. } => { + Extern::Func(Func::from_wasmtime_function(export, store, instance_handle)) + } + wasmtime_runtime::Export::Memory { .. } => { + Extern::Memory(Memory::from_wasmtime_memory(export, store, instance_handle)) + } + wasmtime_runtime::Export::Global { .. } => { + 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> for Extern { - fn from(r: HostRef) -> Self { +impl From for Extern { + fn from(r: Func) -> Self { Extern::Func(r) } } -impl From> for Extern { - fn from(r: HostRef) -> Self { +impl From for Extern { + fn from(r: Global) -> Self { Extern::Global(r) } } -impl From> for Extern { - fn from(r: HostRef) -> Self { +impl From for Extern { + fn from(r: Memory) -> Self { Extern::Memory(r) } } -impl From> for Extern { - fn from(r: HostRef
) -> Self { +impl From
for Extern { + fn from(r: Table) -> Self { Extern::Table(r) } } +#[derive(Clone)] pub struct Func { _store: Store, callable: Rc, - r#type: FuncType, + ty: FuncType, } impl Func { @@ -125,26 +126,26 @@ impl Func { fn from_wrapped( store: &Store, - r#type: FuncType, + ty: FuncType, callable: Rc, ) -> Func { Func { _store: store.clone(), callable, - r#type, + ty, } } - pub fn r#type(&self) -> &FuncType { - &self.r#type + pub fn ty(&self) -> &FuncType { + &self.ty } pub fn param_arity(&self) -> usize { - self.r#type.params().len() + self.ty.params().len() } pub fn result_arity(&self) -> usize { - self.r#type.results().len() + self.ty.results().len() } pub fn call(&self, params: &[Val]) -> Result, Trap> { @@ -162,8 +163,12 @@ impl Func { store: &Store, instance_handle: InstanceHandle, ) -> 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 { FuncType::from_wasmtime_signature(signature.clone()) + .expect("core wasm signature should be supported") } else { panic!("expected function export") }; @@ -178,32 +183,39 @@ impl fmt::Debug for Func { } } +#[derive(Clone)] pub struct Global { + inner: Rc, +} + +struct GlobalInner { _store: Store, - r#type: GlobalType, + ty: GlobalType, wasmtime_export: wasmtime_runtime::Export, #[allow(dead_code)] wasmtime_state: Option, } 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) = - generate_global_export(&r#type, val).expect("generated global"); + generate_global_export(&ty, val).expect("generated global"); Global { - _store: store.clone(), - r#type, - wasmtime_export, - wasmtime_state: Some(wasmtime_state), + inner: Rc::new(GlobalInner { + _store: store.clone(), + ty, + wasmtime_export, + wasmtime_state: Some(wasmtime_state), + }), } } - pub fn r#type(&self) -> &GlobalType { - &self.r#type + pub fn ty(&self) -> &GlobalType { + &self.inner.ty } fn wasmtime_global_definition(&self) -> *mut wasmtime_runtime::VMGlobalDefinition { - match self.wasmtime_export { + match self.inner.wasmtime_export { wasmtime_runtime::Export::Global { definition, .. } => definition, _ => panic!("global definition not found"), } @@ -212,22 +224,22 @@ impl Global { pub fn get(&self) -> Val { let definition = unsafe { &mut *self.wasmtime_global_definition() }; unsafe { - match self.r#type().content() { + match self.ty().content() { ValType::I32 => Val::from(*definition.as_i32()), ValType::I64 => Val::from(*definition.as_i64()), ValType::F32 => Val::F32(*definition.as_u32()), 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) { - if val.r#type() != *self.r#type().content() { + pub fn set(&self, val: Val) { + if val.ty() != *self.ty().content() { panic!( "global of type {:?} cannot be set to {:?}", - self.r#type().content(), - val.r#type() + self.ty().content(), + val.ty() ); } let definition = unsafe { &mut *self.wasmtime_global_definition() }; @@ -237,34 +249,40 @@ impl Global { Val::I64(i) => *definition.as_i64_mut() = i, Val::F32(f) => *definition.as_u32_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 { - &self.wasmtime_export + &self.inner.wasmtime_export } pub(crate) fn from_wasmtime_global(export: wasmtime_runtime::Export, store: &Store) -> Global { let global = if let wasmtime_runtime::Export::Global { ref global, .. } = export { global } 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 { - _store: store.clone(), - r#type: ty, - wasmtime_export: export, - wasmtime_state: None, + inner: Rc::new(GlobalInner { + _store: store.clone(), + ty: ty, + wasmtime_export: export, + wasmtime_state: None, + }), } } } +#[derive(Clone)] pub struct Table { store: Store, - r#type: TableType, + ty: TableType, wasmtime_handle: InstanceHandle, wasmtime_export: wasmtime_runtime::Export, } @@ -299,13 +317,13 @@ fn set_table_item( } impl Table { - pub fn new(store: &Store, r#type: TableType, init: Val) -> Table { - match r#type.element() { + pub fn new(store: &Store, ty: TableType, init: Val) -> Table { + match ty.element() { ValType::FuncRef => (), _ => panic!("table is not for funcref"), } 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. match wasmtime_export { @@ -323,14 +341,14 @@ impl Table { Table { store: store.clone(), - r#type, + ty, wasmtime_handle, wasmtime_export, } } - pub fn r#type(&self) -> &TableType { - &self.r#type + pub fn ty(&self) -> &TableType { + &self.ty } 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(); - 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(); for i in 0..delta { let i = len - (delta - i); @@ -395,34 +413,35 @@ impl Table { let ty = TableType::from_wasmtime_table(&table.table); Table { store: store.clone(), - r#type: ty, + ty: ty, wasmtime_handle: instance_handle, wasmtime_export: export, } } } +#[derive(Clone)] pub struct Memory { _store: Store, - r#type: MemoryType, + ty: MemoryType, wasmtime_handle: InstanceHandle, wasmtime_export: wasmtime_runtime::Export, } impl Memory { - pub fn new(store: &Store, r#type: MemoryType) -> Memory { + pub fn new(store: &Store, ty: MemoryType) -> Memory { let (wasmtime_handle, wasmtime_export) = - generate_memory_export(&r#type).expect("generated memory"); + generate_memory_export(&ty).expect("generated memory"); Memory { _store: store.clone(), - r#type, + ty, wasmtime_handle, wasmtime_export, } } - pub fn r#type(&self) -> &MemoryType { - &self.r#type + pub fn ty(&self) -> &MemoryType { + &self.ty } 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 } - pub fn grow(&mut self, delta: u32) -> bool { + pub fn grow(&self, delta: u32) -> bool { match self.wasmtime_export { wasmtime_runtime::Export::Memory { definition, .. } => { let definition = unsafe { &(*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"), } @@ -481,7 +503,7 @@ impl Memory { let ty = MemoryType::from_wasmtime_memory(&memory.memory); Memory { _store: store.clone(), - r#type: ty, + ty: ty, wasmtime_handle: instance_handle, wasmtime_export: export, } diff --git a/crates/api/src/instance.rs b/crates/api/src/instance.rs index 81b2a4ccee..48b080528b 100644 --- a/crates/api/src/instance.rs +++ b/crates/api/src/instance.rs @@ -9,45 +9,50 @@ use anyhow::{Error, Result}; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::rc::Rc; -use wasmtime_jit::{instantiate, Resolver, SetupError}; +use wasmtime_jit::{CompiledModule, Resolver}; use wasmtime_runtime::{Export, InstanceHandle, InstantiationError}; -struct SimpleResolver { - imports: Vec<(String, String, Extern)>, +struct SimpleResolver<'a> { + imports: &'a [Extern], } -impl Resolver for SimpleResolver { - fn resolve(&mut self, name: &str, field: &str) -> Option { - // TODO speedup lookup +impl Resolver for SimpleResolver<'_> { + fn resolve(&mut self, idx: u32, _name: &str, _field: &str) -> Option { self.imports - .iter_mut() - .find(|(n, f, _)| name == n && field == f) - .map(|(_, _, e)| e.get_wasmtime_export()) + .get(idx as usize) + .map(|i| i.get_wasmtime_export()) } } -pub fn instantiate_in_context( +fn instantiate_in_context( + store: &Store, data: &[u8], - imports: Vec<(String, String, Extern)>, - module_name: Option, + imports: &[Extern], + module_name: Option<&str>, context: Context, exports: Rc>>>, ) -> Result<(InstanceHandle, HashSet), Error> { let mut contexts = HashSet::new(); let debug_info = context.debug_info(); let mut resolver = SimpleResolver { imports }; - let instance = instantiate( + let mut compiled_module = CompiledModule::new( &mut context.compiler(), data, module_name, &mut resolver, exports, 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() { trap.into() - } else if let SetupError::Instantiate(InstantiationError::StartTrap(msg)) = e { + } else if let InstantiationError::StartTrap(msg) = e { Trap::new(msg).into() } else { e.into() @@ -70,19 +75,15 @@ pub struct Instance { } impl Instance { - pub fn new(store: &Store, module: &Module, externs: &[Extern]) -> Result { + pub fn new(module: &Module, externs: &[Extern]) -> Result { + let store = module.store(); let context = store.context().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::>(); let (mut instance_handle, contexts) = instantiate_in_context( + module.store(), module.binary().expect("binary"), - imports, - module.name().cloned(), + externs, + module.name(), context, exports, )?; @@ -108,14 +109,27 @@ impl Instance { }) } - pub fn exports(&self) -> &[Extern] { - &self.exports + /// Returns the associated [`Store`] that this `Instance` is compiled into. + /// + /// 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 { &self.module } + pub fn exports(&self) -> &[Extern] { + &self.exports + } + pub fn find_export_by_name(&self, name: &str) -> Option<&Extern> { let (i, _) = self .module @@ -140,7 +154,14 @@ impl Instance { // imported into this store using the from_handle() method. 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.push(Extern::from_wasmtime_export( store, @@ -175,29 +196,29 @@ cfg_if::cfg_if! { impl Instance { /// The signal handler must be /// [async-signal-safe](http://man7.org/linux/man-pages/man7/signal-safety.7.html). - pub fn set_signal_handler(&mut self, handler: H) + pub fn set_signal_handler(&self, handler: H) where 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")] { impl Instance { - pub fn set_signal_handler(&mut self, handler: H) + pub fn set_signal_handler(&self, handler: H) where 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")] { impl Instance { - pub fn set_signal_handler(&mut self, handler: H) + pub fn set_signal_handler(&self, handler: H) where 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); } } } diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index 49622c94fe..7ccf342ca5 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -6,8 +6,6 @@ //! and there to implement Rust idioms. This crate also defines the actual C API //! itself for consumption from other languages. -#![allow(improper_ctypes)] - mod callable; mod context; mod externals; @@ -26,7 +24,7 @@ pub use crate::callable::Callable; pub use crate::externals::*; pub use crate::instance::Instance; 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::trap::{FrameInfo, Trap}; pub use crate::types::*; diff --git a/crates/api/src/module.rs b/crates/api/src/module.rs index f7bed9928e..3704f11e14 100644 --- a/crates/api/src/module.rs +++ b/crates/api/src/module.rs @@ -56,138 +56,6 @@ fn into_table_type(tt: wasmparser::TableType) -> TableType { TableType::new(ty, limits) } -fn read_imports_and_exports( - binary: &[u8], -) -> Result<(Box<[ImportType]>, Box<[ExportType]>, Option)> { - let mut reader = ModuleReader::new(binary)?; - let mut imports = Vec::new(); - let mut exports = Vec::new(); - let mut memories = Vec::new(); - let mut tables = Vec::new(); - let mut func_sig = Vec::new(); - let mut sigs = Vec::new(); - let mut globals = Vec::new(); - let mut module_name = None; - while !reader.eof() { - let section = reader.read()?; - match section.code { - SectionCode::Memory => { - let section = section.get_memory_section_reader()?; - memories.reserve_exact(section.get_count() as usize); - for entry in section { - memories.push(into_memory_type(entry?)); - } - } - SectionCode::Type => { - let section = section.get_type_section_reader()?; - sigs.reserve_exact(section.get_count() as usize); - for entry in section { - sigs.push(into_func_type(entry?)); - } - } - SectionCode::Function => { - let section = section.get_function_section_reader()?; - func_sig.reserve_exact(section.get_count() as usize); - for entry in section { - func_sig.push(entry?); - } - } - SectionCode::Global => { - let section = section.get_global_section_reader()?; - globals.reserve_exact(section.get_count() as usize); - for entry in section { - globals.push(into_global_type(entry?.ty)); - } - } - SectionCode::Table => { - let section = section.get_table_section_reader()?; - tables.reserve_exact(section.get_count() as usize); - for entry in section { - tables.push(into_table_type(entry?)) - } - } - SectionCode::Import => { - let section = section.get_import_section_reader()?; - imports.reserve_exact(section.get_count() as usize); - for entry in section { - let entry = entry?; - let r#type = match entry.ty { - ImportSectionEntryType::Function(index) => { - func_sig.push(index); - let sig = &sigs[index as usize]; - ExternType::Func(sig.clone()) - } - ImportSectionEntryType::Table(tt) => { - let table = into_table_type(tt); - tables.push(table.clone()); - ExternType::Table(table) - } - ImportSectionEntryType::Memory(mt) => { - let memory = into_memory_type(mt); - memories.push(memory.clone()); - ExternType::Memory(memory) - } - ImportSectionEntryType::Global(gt) => { - let global = into_global_type(gt); - globals.push(global.clone()); - ExternType::Global(global) - } - }; - imports.push(ImportType::new(entry.module, entry.field, r#type)); - } - } - SectionCode::Export => { - let section = section.get_export_section_reader()?; - exports.reserve_exact(section.get_count() as usize); - for entry in section { - let entry = entry?; - let r#type = match entry.kind { - ExternalKind::Function => { - let sig_index = func_sig[entry.index as usize] as usize; - let sig = &sigs[sig_index]; - ExternType::Func(sig.clone()) - } - ExternalKind::Table => { - ExternType::Table(tables[entry.index as usize].clone()) - } - ExternalKind::Memory => { - ExternType::Memory(memories[entry.index as usize].clone()) - } - ExternalKind::Global => { - ExternType::Global(globals[entry.index as usize].clone()) - } - }; - exports.push(ExportType::new(entry.field, r#type)); - } - } - SectionCode::Custom { - kind: CustomSectionKind::Name, - .. - } => { - // Read name section. Per spec, ignore invalid custom section. - if let Ok(mut reader) = section.get_name_section_reader() { - while let Ok(entry) = reader.read() { - if let Name::Module(name) = entry { - if let Ok(name) = name.get_name() { - module_name = Some(name.to_string()); - } - break; - } - } - } - } - _ => { - // skip other sections - } - } - } - Ok(( - imports.into_boxed_slice(), - exports.into_boxed_slice(), - module_name, - )) -} - #[derive(Clone)] pub(crate) enum ModuleCodeSource { Binary(Box<[u8]>), @@ -259,20 +127,21 @@ impl Module { /// /// [binary]: https://webassembly.github.io/spec/core/binary/index.html pub fn new(store: &Store, binary: &[u8]) -> Result { - Self::validate(store, binary)?; + 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 { Self::create(store, binary, None) } + 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: String) -> Result { - Self::validate(store, binary)?; - unsafe { Self::create(store, binary, Some(name)) } + pub fn new_with_name(store: &Store, binary: &[u8], name: &str) -> Result { + 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` @@ -302,24 +171,9 @@ impl Module { /// be somewhat valid for decoding purposes, and the basics of decoding can /// still fail. pub unsafe fn new_unchecked(store: &Store, binary: &[u8]) -> Result { - Self::create(store, binary, None) - } - - unsafe fn create( - store: &Store, - binary: &[u8], - name_override: Option, - ) -> Result { - 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), - }), - }) + let mut ret = Module::empty(store); + ret.read_imports_and_exports(binary)?; + Ok(ret) } /// Validates `binary` input data as a WebAssembly binary given the @@ -356,12 +210,18 @@ impl Module { } 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, + exports: Box::new([]), name: None, }), } @@ -376,8 +236,8 @@ impl Module { /// 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() + pub fn name(&self) -> Option<&str> { + self.inner.name.as_deref() } /// Returns the list of imports that this [`Module`] has and must be @@ -396,4 +256,134 @@ impl Module { 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 imports = Vec::new(); + let mut exports = Vec::new(); + let mut memories = Vec::new(); + let mut tables = Vec::new(); + let mut func_sig = Vec::new(); + let mut sigs = Vec::new(); + let mut globals = Vec::new(); + while !reader.eof() { + let section = reader.read()?; + match section.code { + SectionCode::Memory => { + let section = section.get_memory_section_reader()?; + memories.reserve_exact(section.get_count() as usize); + for entry in section { + memories.push(into_memory_type(entry?)); + } + } + SectionCode::Type => { + let section = section.get_type_section_reader()?; + sigs.reserve_exact(section.get_count() as usize); + for entry in section { + sigs.push(into_func_type(entry?)); + } + } + SectionCode::Function => { + let section = section.get_function_section_reader()?; + func_sig.reserve_exact(section.get_count() as usize); + for entry in section { + func_sig.push(entry?); + } + } + SectionCode::Global => { + let section = section.get_global_section_reader()?; + globals.reserve_exact(section.get_count() as usize); + for entry in section { + globals.push(into_global_type(entry?.ty)); + } + } + SectionCode::Table => { + let section = section.get_table_section_reader()?; + tables.reserve_exact(section.get_count() as usize); + for entry in section { + tables.push(into_table_type(entry?)) + } + } + SectionCode::Import => { + let section = section.get_import_section_reader()?; + imports.reserve_exact(section.get_count() as usize); + for entry in section { + let entry = entry?; + let r#type = match entry.ty { + ImportSectionEntryType::Function(index) => { + func_sig.push(index); + let sig = &sigs[index as usize]; + ExternType::Func(sig.clone()) + } + ImportSectionEntryType::Table(tt) => { + let table = into_table_type(tt); + tables.push(table.clone()); + ExternType::Table(table) + } + ImportSectionEntryType::Memory(mt) => { + let memory = into_memory_type(mt); + memories.push(memory.clone()); + ExternType::Memory(memory) + } + ImportSectionEntryType::Global(gt) => { + let global = into_global_type(gt); + globals.push(global.clone()); + ExternType::Global(global) + } + }; + imports.push(ImportType::new(entry.module, entry.field, r#type)); + } + } + SectionCode::Export => { + let section = section.get_export_section_reader()?; + exports.reserve_exact(section.get_count() as usize); + for entry in section { + let entry = entry?; + let r#type = match entry.kind { + ExternalKind::Function => { + let sig_index = func_sig[entry.index as usize] as usize; + let sig = &sigs[sig_index]; + ExternType::Func(sig.clone()) + } + ExternalKind::Table => { + ExternType::Table(tables[entry.index as usize].clone()) + } + ExternalKind::Memory => { + ExternType::Memory(memories[entry.index as usize].clone()) + } + ExternalKind::Global => { + ExternType::Global(globals[entry.index as usize].clone()) + } + }; + exports.push(ExportType::new(entry.field, r#type)); + } + } + SectionCode::Custom { + kind: CustomSectionKind::Name, + .. + } => { + // Read name section. Per spec, ignore invalid custom section. + if let Ok(mut reader) = section.get_name_section_reader() { + while let Ok(entry) = reader.read() { + if let Name::Module(name) = entry { + if let Ok(name) = name.get_name() { + inner.name = Some(name.to_string()); + } + break; + } + } + } + } + _ => { + // skip other sections + } + } + } + + inner.imports = imports.into(); + inner.exports = exports.into(); + Ok(()) + } } diff --git a/crates/api/src/runtime.rs b/crates/api/src/runtime.rs index d2a4117950..7476bc44c9 100644 --- a/crates/api/src/runtime.rs +++ b/crates/api/src/runtime.rs @@ -397,6 +397,10 @@ impl Store { .get(&type_index) .cloned() } + + pub(crate) fn ptr_eq(a: &Store, b: &Store) -> bool { + Rc::ptr_eq(&a.inner, &b.inner) + } } impl Default for Store { diff --git a/crates/api/src/trampoline/func.rs b/crates/api/src/trampoline/func.rs index 8ace580382..328a325490 100644 --- a/crates/api/src/trampoline/func.rs +++ b/crates/api/src/trampoline/func.rs @@ -3,7 +3,7 @@ use super::create_handle::create_handle; use super::trap::{record_api_trap, TrapSink, API_TRAP_CODE}; use crate::{Callable, FuncType, Store, Val}; -use anyhow::Result; +use anyhow::{bail, Result}; use std::cmp; use std::convert::TryFrom; use std::rc::Rc; @@ -234,7 +234,10 @@ pub fn create_handle_with_function( func: &Rc, store: &Store, ) -> Result { - 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_builder = native::builder(); diff --git a/crates/api/src/trampoline/global.rs b/crates/api/src/trampoline/global.rs index f1b610559d..f53701f167 100644 --- a/crates/api/src/trampoline/global.rs +++ b/crates/api/src/trampoline/global.rs @@ -1,6 +1,6 @@ use super::create_handle::create_handle; use crate::{GlobalType, Mutability, Val}; -use anyhow::Result; +use anyhow::{bail, Result}; use wasmtime_environ::entity::PrimaryMap; use wasmtime_environ::{wasm, Module}; 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 { - 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::Const => false, Mutability::Var => true, diff --git a/crates/api/src/trampoline/table.rs b/crates/api/src/trampoline/table.rs index 5d2441bf92..713de1b43a 100644 --- a/crates/api/src/trampoline/table.rs +++ b/crates/api/src/trampoline/table.rs @@ -1,6 +1,6 @@ use super::create_handle::create_handle; use crate::{TableType, ValType}; -use anyhow::Result; +use anyhow::{bail, Result}; use wasmtime_environ::entity::PrimaryMap; use wasmtime_environ::{wasm, Module}; use wasmtime_runtime::InstanceHandle; @@ -13,7 +13,10 @@ pub fn create_handle_with_table(table: &TableType) -> Result { maximum: table.limits().max(), ty: match table.element() { 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(); diff --git a/crates/api/src/types.rs b/crates/api/src/types.rs index 36fde8ff20..5162c49c54 100644 --- a/crates/api/src/types.rs +++ b/crates/api/src/types.rs @@ -84,25 +84,25 @@ impl ValType { } } - pub(crate) fn get_wasmtime_type(&self) -> ir::Type { + pub(crate) fn get_wasmtime_type(&self) -> Option { match self { - ValType::I32 => ir::types::I32, - ValType::I64 => ir::types::I64, - ValType::F32 => ir::types::F32, - ValType::F64 => ir::types::F64, - ValType::V128 => ir::types::I8X16, - _ => unimplemented!("get_wasmtime_type other"), + ValType::I32 => Some(ir::types::I32), + ValType::I64 => Some(ir::types::I64), + ValType::F32 => Some(ir::types::F32), + ValType::F64 => Some(ir::types::F64), + ValType::V128 => Some(ir::types::I8X16), + _ => None, } } - pub(crate) fn from_wasmtime_type(ty: ir::Type) -> ValType { + pub(crate) fn from_wasmtime_type(ty: ir::Type) -> Option { match ty { - ir::types::I32 => ValType::I32, - ir::types::I64 => ValType::I64, - ir::types::F32 => ValType::F32, - ir::types::F64 => ValType::F64, - ir::types::I8X16 => ValType::V128, - _ => unimplemented!("from_wasmtime_type other"), + ir::types::I32 => Some(ValType::I32), + ir::types::I64 => Some(ValType::I64), + ir::types::F32 => Some(ValType::F32), + ir::types::F64 => Some(ValType::F64), + ir::types::I8X16 => Some(ValType::V128), + _ => None, } } } @@ -153,26 +153,29 @@ impl ExternType { (Table(TableType) table unwrap_table) (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 { + Some(match export { 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, .. } => { ExternType::Memory(MemoryType::from_wasmtime_memory(&memory.memory)) } wasmtime_runtime::Export::Global { global, .. } => { - ExternType::Global(GlobalType::from_wasmtime_global(&global)) + ExternType::Global(GlobalType::from_wasmtime_global(&global)?) } wasmtime_runtime::Export::Table { table, .. } => { ExternType::Table(TableType::from_wasmtime_table(&table.table)) } - } + }) } } // Function Types -fn from_wasmtime_abiparam(param: &ir::AbiParam) -> ValType { +fn from_wasmtime_abiparam(param: &ir::AbiParam) -> Option { assert_eq!(param.purpose, ir::ArgumentPurpose::Normal); ValType::from_wasmtime_type(param.value_type) } @@ -184,7 +187,12 @@ fn from_wasmtime_abiparam(param: &ir::AbiParam) -> ValType { pub struct FuncType { params: 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, } impl FuncType { @@ -196,23 +204,26 @@ impl FuncType { use wasmtime_environ::ir::{types, AbiParam, ArgumentPurpose, Signature}; use wasmtime_jit::native; let call_conv = native::call_conv(); - let signature: Signature = { - let mut params = params - .iter() - .map(|p| AbiParam::new(p.get_wasmtime_type())) - .collect::>(); - let returns = results - .iter() - .map(|p| AbiParam::new(p.get_wasmtime_type())) - .collect::>(); - params.insert(0, AbiParam::special(types::I64, ArgumentPurpose::VMContext)); + let signature = params + .iter() + .map(|p| p.get_wasmtime_type().map(AbiParam::new)) + .collect::>>() + .and_then(|params| { + results + .iter() + .map(|p| p.get_wasmtime_type().map(AbiParam::new)) + .collect::>>() + .map(|results| (params, results)) + }) + .map(|(mut params, returns)| { + params.insert(0, AbiParam::special(types::I64, ArgumentPurpose::VMContext)); - Signature { - params, - returns, - call_conv, - } - }; + Signature { + params, + returns, + call_conv, + } + }); FuncType { params, results, @@ -230,27 +241,33 @@ impl FuncType { &self.results } - pub(crate) fn get_wasmtime_signature(&self) -> &ir::Signature { - &self.signature + /// Returns `Some` if this function signature was compatible with cranelift, + /// 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 { let params = signature .params .iter() .filter(|p| p.purpose == ir::ArgumentPurpose::Normal) .map(|p| from_wasmtime_abiparam(p)) - .collect::>(); + .collect::>>()?; let results = signature .returns .iter() .map(|p| from_wasmtime_abiparam(p)) - .collect::>(); - FuncType { + .collect::>>()?; + Some(FuncType { params: params.into_boxed_slice(), results: results.into_boxed_slice(), - signature, - } + signature: Some(signature), + }) } } @@ -287,14 +304,16 @@ impl GlobalType { self.mutability } - pub(crate) fn from_wasmtime_global(global: &wasm::Global) -> GlobalType { - let ty = ValType::from_wasmtime_type(global.ty); + /// Returns `None` if the wasmtime global has a type that we can't + /// represent, but that should only very rarely happen and indicate a bug. + pub(crate) fn from_wasmtime_global(global: &wasm::Global) -> Option { + let ty = ValType::from_wasmtime_type(global.ty)?; let mutability = if global.mutability { Mutability::Var } else { Mutability::Const }; - GlobalType::new(ty, mutability) + Some(GlobalType::new(ty, mutability)) } } diff --git a/crates/api/src/values.rs b/crates/api/src/values.rs index 419f4534f9..4d470a2e23 100644 --- a/crates/api/src/values.rs +++ b/crates/api/src/values.rs @@ -1,5 +1,5 @@ use crate::externals::Func; -use crate::r#ref::{AnyRef, HostRef}; +use crate::r#ref::AnyRef; use crate::runtime::Store; use crate::types::ValType; use std::ptr; @@ -34,7 +34,7 @@ pub enum Val { AnyRef(AnyRef), /// A first-class reference to a WebAssembly function. - FuncRef(HostRef), + FuncRef(Func), /// A 128-bit number V128(u128), @@ -71,7 +71,7 @@ impl Val { } /// Returns the corresponding [`ValType`] for this `Val`. - pub fn r#type(&self) -> ValType { + pub fn ty(&self) -> ValType { match self { Val::I32(_) => ValType::I32, Val::I64(_) => ValType::I64, @@ -111,7 +111,7 @@ impl Val { (I64(i64) i64 unwrap_i64 *e) (F32(f32) f32 unwrap_f32 f32::from_bits(*e)) (F64(f64) f64 unwrap_f64 f64::from_bits(*e)) - (FuncRef(&HostRef) funcref unwrap_funcref e) + (FuncRef(&Func) funcref unwrap_funcref e) (V128(u128) v128 unwrap_v128 *e) } @@ -122,7 +122,6 @@ impl Val { pub fn anyref(&self) -> Option { match self { Val::AnyRef(e) => Some(e.clone()), - Val::FuncRef(e) => Some(e.anyref()), _ => None, } } @@ -164,21 +163,12 @@ impl From for Val { impl From for Val { fn from(val: AnyRef) -> Val { - match &val { - AnyRef::Ref(r) => { - if r.is_ref::() { - Val::FuncRef(r.get_ref()) - } else { - Val::AnyRef(val) - } - } - _ => unimplemented!("AnyRef::Other"), - } + Val::AnyRef(val) } } -impl From> for Val { - fn from(val: HostRef) -> Val { +impl From for Val { + fn from(val: Func) -> Val { Val::FuncRef(val) } } @@ -206,7 +196,6 @@ pub(crate) fn into_checked_anyfunc( vmctx: ptr::null_mut(), }, Val::FuncRef(f) => { - let f = f.borrow(); let (vmctx, func_ptr, signature) = match f.wasmtime_export() { wasmtime_runtime::Export::Function { vmctx, @@ -243,5 +232,5 @@ pub(crate) fn from_checked_anyfunc( vmctx: item.vmctx, }; let f = Func::from_wasmtime_function(export, store, instance_handle); - Val::FuncRef(HostRef::new(f)) + Val::FuncRef(f) } diff --git a/crates/api/src/wasm.rs b/crates/api/src/wasm.rs index 1776eb06ec..083671406f 100644 --- a/crates/api/src/wasm.rs +++ b/crates/api/src/wasm.rs @@ -7,9 +7,11 @@ use super::{ AnyRef, Callable, Engine, ExportType, Extern, ExternType, Func, FuncType, Global, GlobalType, - HostInfo, HostRef, ImportType, Instance, Limits, Memory, MemoryType, Module, Store, Table, - TableType, Trap, Val, ValType, + ImportType, Instance, Limits, Memory, MemoryType, Module, Store, Table, TableType, Trap, Val, + ValType, }; +use crate::r#ref::{HostInfo, HostRef}; +use std::cell::RefCell; use std::rc::Rc; 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); 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)] #[derive(Clone)] pub struct wasm_importtype_t { @@ -312,6 +320,7 @@ declare_vec!(wasm_frame_vec_t, *mut wasm_frame_t); #[derive(Clone)] pub struct wasm_instance_t { instance: HostRef, + exports_cache: RefCell>>, } pub type wasm_message_t = wasm_name_t; #[repr(C)] @@ -336,12 +345,22 @@ pub struct wasm_module_t { pub struct wasm_shared_module_t { _unused: [u8; 0], } -#[repr(C)] + #[derive(Clone)] +#[repr(transparent)] pub struct wasm_func_t { - func: HostRef, - ext: Option>, + ext: wasm_extern_t, } + +impl wasm_func_t { + fn func(&self) -> &HostRef { + match &self.ext.which { + ExternHost::Func(f) => f, + _ => unsafe { std::hint::unreachable_unchecked() }, + } + } +} + 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, >; @@ -352,40 +371,67 @@ pub type wasm_func_callback_with_env_t = std::option::Option< results: *mut wasm_val_t, ) -> *mut wasm_trap_t, >; -#[repr(C)] + #[derive(Clone)] +#[repr(transparent)] pub struct wasm_global_t { - global: HostRef, - ext: Option>, + ext: wasm_extern_t, } -#[repr(C)] -#[derive(Clone)] -pub struct wasm_table_t { - table: HostRef
, - ext: Option>, -} -pub type wasm_table_size_t = u32; -#[repr(C)] -#[derive(Clone)] -pub struct wasm_memory_t { - memory: HostRef, - ext: Option>, -} -pub type wasm_memory_pages_t = u32; -#[repr(C)] -#[derive(Clone)] -pub struct wasm_extern_t { - ext: Extern, - cache: wasm_extern_t_type_cache, + +impl wasm_global_t { + fn global(&self) -> &HostRef { + match &self.ext.which { + ExternHost::Global(g) => g, + _ => unsafe { std::hint::unreachable_unchecked() }, + } + } } #[derive(Clone)] -enum wasm_extern_t_type_cache { - Empty, - Func(wasm_func_t), - Global(wasm_global_t), - Memory(wasm_memory_t), - Table(wasm_table_t), +#[repr(transparent)] +pub struct wasm_table_t { + ext: wasm_extern_t, +} + +impl wasm_table_t { + fn table(&self) -> &HostRef
{ + 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 { + 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), + Global(HostRef), + Memory(HostRef), + Table(HostRef
), } 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] 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 { - (*e).cache = wasm_extern_t_type_cache::Func(wasm_func_t { - func: (*e).ext.func().unwrap().clone(), - ext: None, - }); - } - - match &mut (*e).cache { - wasm_extern_t_type_cache::Func(f) => f, - _ => panic!("wasm_extern_as_func"), + match &(*e).which { + ExternHost::Func(_) => e.cast(), + _ => ptr::null_mut(), } } @@ -435,17 +474,7 @@ pub unsafe extern "C" fn wasm_extern_vec_delete(v: *mut wasm_extern_vec_t) { #[no_mangle] pub unsafe extern "C" fn wasm_func_as_extern(f: *mut wasm_func_t) -> *mut wasm_extern_t { - if (*f).ext.is_none() { - (*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"), - } + &mut (*f).ext } #[no_mangle] @@ -454,7 +483,7 @@ pub unsafe extern "C" fn wasm_func_call( args: *const wasm_val_t, results: *mut wasm_val_t, ) -> *mut wasm_trap_t { - let func = (*func).func.borrow(); + let func = (*func).func().borrow(); let mut params = Vec::with_capacity(func.param_arity()); for i in 0..func.param_arity() { let val = &(*args.add(i)); @@ -606,8 +635,9 @@ pub unsafe extern "C" fn wasm_func_new( let ty = (*ty).functype.clone(); let callback = Rc::new(callback); let func = Box::new(wasm_func_t { - func: HostRef::new(Func::new(store, ty, callback)), - ext: None, + ext: wasm_extern_t { + which: ExternHost::Func(HostRef::new(Func::new(store, ty, callback))), + }, }); Box::into_raw(func) } @@ -656,17 +686,35 @@ pub unsafe extern "C" fn wasm_instance_new( imports: *const *const wasm_extern_t, result: *mut *mut wasm_trap_t, ) -> *mut wasm_instance_t { - let store = &(*store).store.borrow(); let mut externs: Vec = Vec::with_capacity((*module).imports.len()); for i in 0..(*module).imports.len() { 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(); - 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) => { let instance = Box::new(wasm_instance_t { instance: HostRef::new(instance), + exports_cache: RefCell::new(None), }); if !result.is_null() { (*result) = ptr::null_mut(); @@ -694,14 +742,23 @@ pub unsafe extern "C" fn wasm_instance_exports( instance: *const wasm_instance_t, out: *mut wasm_extern_vec_t, ) { - let instance = &(*instance).instance.borrow(); - let exports = instance.exports(); + let mut cache = (*instance).exports_cache.borrow_mut(); + let exports = cache.get_or_insert_with(|| { + let instance = &(*instance).instance.borrow(); + instance + .exports() + .iter() + .map(|e| match e { + Extern::Func(f) => ExternHost::Func(HostRef::new(f.clone())), + 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.iter() { - let ext = Box::new(wasm_extern_t { - ext: e.clone(), - cache: wasm_extern_t_type_cache::Empty, - }); + for e in exports { + let ext = Box::new(wasm_extern_t { which: e.clone() }); buffer.push(Box::into_raw(ext)); } (*out).set_buffer(buffer); @@ -817,8 +874,9 @@ pub unsafe extern "C" fn wasm_func_new_with_env( finalizer, }); let func = Box::new(wasm_func_t { - func: HostRef::new(Func::new(store, ty, callback)), - ext: None, + ext: wasm_extern_t { + which: ExternHost::Func(HostRef::new(Func::new(store, ty, callback))), + }, }); Box::into_raw(func) } @@ -1012,24 +1070,25 @@ pub unsafe extern "C" fn wasm_exporttype_vec_delete(et: *mut wasm_exporttype_vec (*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] 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] pub unsafe extern "C" fn wasm_extern_type(e: *const wasm_extern_t) -> *mut 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, }); Box::into_raw(et) @@ -1120,17 +1179,22 @@ pub unsafe extern "C" fn wasm_externtype_delete(et: *mut wasm_externtype_t) { #[no_mangle] 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] 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] 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] @@ -1279,32 +1343,15 @@ pub unsafe extern "C" fn wasm_valtype_kind(vt: *const wasm_valtype_t) -> wasm_va #[no_mangle] 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 { - (*e).cache = wasm_extern_t_type_cache::Global(wasm_global_t { - global: (*e).ext.global().unwrap().clone(), - ext: None, - }); - } - - match &mut (*e).cache { - wasm_extern_t_type_cache::Global(g) => g, - _ => panic!("wasm_extern_as_global"), + match &(*e).which { + ExternHost::Global(_) => e.cast(), + _ => ptr::null_mut(), } } #[no_mangle] pub unsafe extern "C" fn wasm_global_as_extern(g: *mut wasm_global_t) -> *mut wasm_extern_t { - if (*g).ext.is_none() { - (*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"), - } + &mut (*g).ext } #[no_mangle] @@ -1322,7 +1369,7 @@ pub unsafe extern "C" fn wasm_global_same( g1: *const wasm_global_t, g2: *const wasm_global_t, ) -> bool { - (*g1).global.ptr_eq(&(*g2).global) + (*g1).global().ptr_eq(&(*g2).global()) } #[no_mangle] @@ -1336,18 +1383,22 @@ pub unsafe extern "C" fn wasm_global_new( (*gt).globaltype.clone(), (*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) } #[no_mangle] 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] 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] @@ -1377,32 +1428,15 @@ pub unsafe extern "C" fn wasm_globaltype_new( #[no_mangle] 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 { - (*e).cache = wasm_extern_t_type_cache::Memory(wasm_memory_t { - memory: (*e).ext.memory().unwrap().clone(), - ext: None, - }); - } - - match &mut (*e).cache { - wasm_extern_t_type_cache::Memory(m) => m, - _ => panic!("wasm_extern_as_memory"), + match &(*e).which { + ExternHost::Memory(_) => e.cast(), + _ => ptr::null_mut(), } } #[no_mangle] pub unsafe extern "C" fn wasm_memory_as_extern(m: *mut wasm_memory_t) -> *mut wasm_extern_t { - if (*m).ext.is_none() { - (*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"), - } + &mut (*m).ext } #[no_mangle] @@ -1420,22 +1454,22 @@ pub unsafe extern "C" fn wasm_memory_same( m1: *const wasm_memory_t, m2: *const wasm_memory_t, ) -> bool { - (*m1).memory.ptr_eq(&(*m2).memory) + (*m1).memory().ptr_eq(&(*m2).memory()) } #[no_mangle] 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] 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] 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] @@ -1443,7 +1477,7 @@ pub unsafe extern "C" fn wasm_memory_grow( m: *mut wasm_memory_t, delta: wasm_memory_pages_t, ) -> bool { - (*m).memory.borrow_mut().grow(delta) + (*m).memory().borrow().grow(delta) } #[no_mangle] @@ -1455,7 +1489,11 @@ pub unsafe extern "C" fn wasm_memory_new( &(*store).store.borrow(), (*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) } @@ -1483,37 +1521,20 @@ pub unsafe extern "C" fn wasm_memorytype_new( #[no_mangle] 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 { - (*e).cache = wasm_extern_t_type_cache::Table(wasm_table_t { - table: (*e).ext.table().unwrap().clone(), - ext: None, - }); - } - - match &mut (*e).cache { - wasm_extern_t_type_cache::Table(t) => t, - _ => panic!("wasm_extern_as_table"), + match &(*e).which { + ExternHost::Table(_) => e.cast(), + _ => ptr::null_mut(), } } #[no_mangle] pub unsafe extern "C" fn wasm_table_as_extern(t: *mut wasm_table_t) -> *mut wasm_extern_t { - if (*t).ext.is_none() { - (*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"), - } + &mut (*t).ext } #[no_mangle] 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 }); Box::into_raw(f) } @@ -1547,12 +1568,13 @@ pub unsafe extern "C" fn wasm_table_new( Val::AnyRef(AnyRef::Null) }; let t = Box::new(wasm_table_t { - table: HostRef::new(Table::new( - &(*store).store.borrow(), - (*tt).tabletype.clone(), - init, - )), - ext: None, + ext: wasm_extern_t { + which: ExternHost::Table(HostRef::new(Table::new( + &(*store).store.borrow(), + (*tt).tabletype.clone(), + init, + ))), + }, }); Box::into_raw(t) } @@ -1582,7 +1604,7 @@ pub unsafe extern "C" fn wasm_table_get( t: *const wasm_table_t, index: wasm_table_size_t, ) -> *mut wasm_ref_t { - let val = (*t).table.borrow().get(index); + let val = (*t).table().borrow().get(index); into_funcref(val) } @@ -1593,12 +1615,12 @@ pub unsafe extern "C" fn wasm_table_set( r: *mut wasm_ref_t, ) -> bool { let val = from_funcref(r); - (*t).table.borrow().set(index, val) + (*t).table().borrow().set(index, val) } #[no_mangle] 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] @@ -1608,12 +1630,12 @@ pub unsafe extern "C" fn wasm_table_grow( init: *mut wasm_ref_t, ) -> bool { let init = from_funcref(init); - (*t).table.borrow_mut().grow(delta, init) + (*t).table().borrow().grow(delta, init) } #[no_mangle] 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] diff --git a/crates/api/tests/import-indexes.rs b/crates/api/tests/import-indexes.rs new file mode 100644 index 0000000000..8406a8b63a --- /dev/null +++ b/crates/api/tests/import-indexes.rs @@ -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(()) +} diff --git a/crates/api/tests/import_calling_export.rs b/crates/api/tests/import_calling_export.rs index e8d94e6e25..aad031d173 100644 --- a/crates/api/tests/import_calling_export.rs +++ b/crates/api/tests/import_calling_export.rs @@ -1,4 +1,4 @@ -use std::cell::{Ref, RefCell}; +use std::cell::RefCell; use std::rc::Rc; use wasmtime::*; @@ -16,7 +16,7 @@ fn test_import_calling_export() { "#; struct Callback { - pub other: RefCell>>, + pub other: RefCell>, } impl Callable for Callback { @@ -25,7 +25,6 @@ fn test_import_calling_export() { .borrow() .as_ref() .expect("expected a function ref") - .borrow() .call(&[]) .expect("expected function not to trap"); Ok(()) @@ -40,18 +39,17 @@ fn test_import_calling_export() { other: RefCell::new(None), }); - let callback_func = HostRef::new(Func::new( + let callback_func = Func::new( &store, FuncType::new(Box::new([]), Box::new([])), 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()); let run_func = exports[0] @@ -65,8 +63,5 @@ fn test_import_calling_export() { .clone(), ); - run_func - .borrow() - .call(&[]) - .expect("expected function not to trap"); + run_func.call(&[]).expect("expected function not to trap"); } diff --git a/crates/api/tests/invoke_func_via_table.rs b/crates/api/tests/invoke_func_via_table.rs new file mode 100644 index 0000000000..c10d696ef2 --- /dev/null +++ b/crates/api/tests/invoke_func_via_table.rs @@ -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(()) +} diff --git a/crates/api/tests/name.rs b/crates/api/tests/name.rs index 0d83708639..24c86caeea 100644 --- a/crates/api/tests/name.rs +++ b/crates/api/tests/name.rs @@ -1,54 +1,38 @@ use wasmtime::*; -use wat::parse_str; #[test] -fn test_module_no_name() -> Result<(), String> { +fn test_module_no_name() -> anyhow::Result<()> { let store = Store::default(); - let binary = parse_str( + let binary = wat::parse_str( r#" - (module - (func (export "run") (nop)) - ) - "#, - ) - .map_err(|e| format!("failed to parse WebAssembly text source: {}", e))?; + (module + (func (export "run") (nop)) + ) + "#, + )?; - let module = HostRef::new( - Module::new(&store, &binary).map_err(|e| format!("failed to compile module: {}", e))?, - ); - assert_eq!(module.borrow().name().cloned(), None); + let module = Module::new(&store, &binary)?; + assert_eq!(module.name(), None); Ok(()) } #[test] -fn test_module_name() -> Result<(), String> { +fn test_module_name() -> anyhow::Result<()> { let store = Store::default(); - let binary = parse_str( + let binary = wat::parse_str( r#" - (module $from_name_section - (func (export "run") (nop)) - ) - "#, - ) - .map_err(|e| format!("failed to parse WebAssembly text source: {}", e))?; + (module $from_name_section + (func (export "run") (nop)) + ) + "#, + )?; - let module = HostRef::new( - Module::new(&store, &binary).map_err(|e| format!("failed to compile module: {}", e))?, - ); - assert_eq!( - module.borrow().name().cloned(), - Some("from_name_section".to_string()) - ); + let module = Module::new(&store, &binary)?; + assert_eq!(module.name(), Some("from_name_section")); - let module = HostRef::new( - Module::new_with_name(&store, &binary, "override".to_string()) - .map_err(|e| format!("failed to compile module: {}", e))?, - ); - assert_eq!( - module.borrow().name().cloned(), - Some("override".to_string()) - ); + let module = Module::new_with_name(&store, &binary, "override")?; + assert_eq!(module.name(), Some("override")); Ok(()) } diff --git a/crates/api/tests/traps.rs b/crates/api/tests/traps.rs index a5b8cc9caf..aea6404a9b 100644 --- a/crates/api/tests/traps.rs +++ b/crates/api/tests/traps.rs @@ -26,20 +26,16 @@ fn test_trap_return() -> Result<(), String> { let module = Module::new(&store, &binary).map_err(|e| format!("failed to compile module: {}", e))?; 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 instance = Instance::new(&store, &module, imports.as_slice()) + let instance = Instance::new(&module, &imports) .map_err(|e| format!("failed to instantiate module: {:?}", e))?; let run_func = instance.exports()[0] .func() .expect("expected function export"); - let e = run_func - .borrow() - .call(&[]) - .err() - .expect("error calling function"); + let e = run_func.call(&[]).err().expect("error calling function"); assert_eq!(e.message(), "test 123"); diff --git a/crates/debug/Cargo.toml b/crates/debug/Cargo.toml index 02fca694f2..f7ac2cc8c0 100644 --- a/crates/debug/Cargo.toml +++ b/crates/debug/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime-debug" -version = "0.7.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] description = "Debug utils for WebAsssembly code in Cranelift" license = "Apache-2.0 WITH LLVM-exception" @@ -13,10 +13,10 @@ edition = "2018" [dependencies] gimli = "0.19.0" -wasmparser = "0.45.1" -faerie = "0.13.0" -wasmtime-environ = { path = "../environ" } -target-lexicon = { version = "0.9.0", default-features = false } +wasmparser = "0.47.0" +faerie = "0.14.0" +wasmtime-environ = { path = "../environ", version = "0.9.0" } +target-lexicon = { version = "0.10.0", default-features = false } anyhow = "1.0" thiserror = "1.0.4" more-asserts = "0.2.1" diff --git a/crates/environ/Cargo.toml b/crates/environ/Cargo.toml index e4e3a5465d..0f3d3e52ac 100644 --- a/crates/environ/Cargo.toml +++ b/crates/environ/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime-environ" -version = "0.7.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] description = "Standalone environment support for WebAsssembly code in Cranelift" license = "Apache-2.0 WITH LLVM-exception" @@ -13,11 +13,11 @@ edition = "2018" [dependencies] anyhow = "1.0" -cranelift-codegen = { version = "0.52.0", features = ["enable-serde"] } -cranelift-entity = { version = "0.52.0", features = ["enable-serde"] } -cranelift-wasm = { version = "0.52.0", features = ["enable-serde"] } -wasmparser = "0.45.1" -lightbeam = { path = "../lightbeam", optional = true } +cranelift-codegen = { version = "0.54", features = ["enable-serde"] } +cranelift-entity = { version = "0.54", features = ["enable-serde"] } +cranelift-wasm = { version = "0.54", features = ["enable-serde"] } +wasmparser = "0.47.0" +lightbeam = { path = "../lightbeam", optional = true, version = "0.9.0" } indexmap = "1.0.2" rayon = "1.2.1" thiserror = "1.0.4" @@ -43,10 +43,10 @@ errno = "0.2.4" [dev-dependencies] 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" 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" [badges] diff --git a/crates/environ/src/func_environ.rs b/crates/environ/src/func_environ.rs index 6daa016b69..b218641877 100644 --- a/crates/environ/src/func_environ.rs +++ b/crates/environ/src/func_environ.rs @@ -362,6 +362,10 @@ impl<'module_environment> TargetEnvironment for FuncEnvironment<'module_environm } 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 { let pointer_type = self.pointer_type(); diff --git a/crates/environ/src/module.rs b/crates/environ/src/module.rs index 0ff8c79d04..766eacf11c 100644 --- a/crates/environ/src/module.rs +++ b/crates/environ/src/module.rs @@ -136,17 +136,18 @@ pub struct Module { /// Unprocessed signatures exactly as provided by `declare_signature()`. pub signatures: PrimaryMap, - /// Names of imported functions. - pub imported_funcs: PrimaryMap, + /// Names of imported functions, as well as the index of the import that + /// performed this import. + pub imported_funcs: PrimaryMap, /// Names of imported tables. - pub imported_tables: PrimaryMap, + pub imported_tables: PrimaryMap, /// Names of imported memories. - pub imported_memories: PrimaryMap, + pub imported_memories: PrimaryMap, /// Names of imported globals. - pub imported_globals: PrimaryMap, + pub imported_globals: PrimaryMap, /// Types of functions, imported and local. pub functions: PrimaryMap, diff --git a/crates/environ/src/module_environ.rs b/crates/environ/src/module_environ.rs index 1acc61e63b..ee0ad17202 100644 --- a/crates/environ/src/module_environ.rs +++ b/crates/environ/src/module_environ.rs @@ -55,6 +55,7 @@ impl<'data> ModuleTranslation<'data> { pub struct ModuleEnvironment<'data> { /// The result to be filled in. result: ModuleTranslation<'data>, + imports: u32, } impl<'data> ModuleEnvironment<'data> { @@ -69,6 +70,7 @@ impl<'data> ModuleEnvironment<'data> { tunables, 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 - .imported_funcs - .push((String::from(module), String::from(field))); + self.result.module.imported_funcs.push(( + String::from(module), + String::from(field), + self.imports, + )); + self.imports += 1; Ok(()) } @@ -139,10 +143,12 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data let plan = TablePlan::for_table(table, &self.result.tunables); self.result.module.table_plans.push(plan); - self.result - .module - .imported_tables - .push((String::from(module), String::from(field))); + self.result.module.imported_tables.push(( + String::from(module), + String::from(field), + self.imports, + )); + self.imports += 1; Ok(()) } @@ -160,10 +166,12 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data let plan = MemoryPlan::for_memory(memory, &self.result.tunables); self.result.module.memory_plans.push(plan); - self.result - .module - .imported_memories - .push((String::from(module), String::from(field))); + self.result.module.imported_memories.push(( + String::from(module), + String::from(field), + self.imports, + )); + self.imports += 1; Ok(()) } @@ -180,10 +188,12 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data ); self.result.module.globals.push(global); - self.result - .module - .imported_globals - .push((String::from(module), String::from(field))); + self.result.module.imported_globals.push(( + String::from(module), + String::from(field), + self.imports, + )); + self.imports += 1; Ok(()) } diff --git a/crates/fuzzing/Cargo.toml b/crates/fuzzing/Cargo.toml index a99134b03a..e6eefeafe7 100644 --- a/crates/fuzzing/Cargo.toml +++ b/crates/fuzzing/Cargo.toml @@ -4,7 +4,7 @@ description = "Fuzzing infrastructure for Wasmtime" edition = "2018" name = "wasmtime-fuzzing" 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 @@ -14,11 +14,11 @@ arbitrary = "0.2.0" binaryen = "0.8.2" env_logger = { version = "0.7.1", optional = true } log = "0.4.8" -wasmparser = "0.45.1" +wasmparser = "0.47.0" wasmprinter = "0.2.0" -wasmtime = { path = "../api" } -wasmtime-environ = { path = "../environ" } -wasmtime-jit = { path = "../jit" } +wasmtime = { path = "../api", version = "0.9.0" } +wasmtime-environ = { path = "../environ", version = "0.9.0" } +wasmtime-jit = { path = "../jit", version = "0.9.0" } [dev-dependencies] wat = "1.0" diff --git a/crates/fuzzing/src/oracles.rs b/crates/fuzzing/src/oracles.rs index 1afd7467aa..bb5860c9a1 100644 --- a/crates/fuzzing/src/oracles.rs +++ b/crates/fuzzing/src/oracles.rs @@ -60,7 +60,7 @@ pub fn instantiate(wasm: &[u8], strategy: Strategy) { // aren't caught during validation or compilation. For example, an imported // table might not have room for an element segment that we want to // 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 @@ -96,7 +96,7 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) { let mut engine: Option = None; let mut store: Option = None; let mut modules: HashMap = Default::default(); - let mut instances: HashMap> = Default::default(); + let mut instances: HashMap = Default::default(); for call in api.calls { 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 // table might not have room for an element segment that we want to // initialize into it. - if let Ok(instance) = Instance::new(store.as_ref().unwrap(), &module, &imports) { - instances.insert(id, HostRef::new(instance)); + if let Ok(instance) = Instance::new(&module, &imports) { + instances.insert(id, instance); } } @@ -175,25 +175,22 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) { } }; - let funcs = { - let instance = instance.borrow(); - instance - .exports() - .iter() - .filter_map(|e| match e { - Extern::Func(f) => Some(f.clone()), - _ => None, - }) - .collect::>() - }; + let funcs = instance + .exports() + .iter() + .filter_map(|e| match e { + Extern::Func(f) => Some(f.clone()), + _ => None, + }) + .collect::>(); if funcs.is_empty() { continue; } let nth = nth % funcs.len(); - let f = funcs[nth].borrow(); - let ty = f.r#type(); + let f = &funcs[nth]; + let ty = f.ty(); let params = match ty .params() .iter() diff --git a/crates/fuzzing/src/oracles/dummy.rs b/crates/fuzzing/src/oracles/dummy.rs index f72cd4858f..0a0b06b69b 100644 --- a/crates/fuzzing/src/oracles/dummy.rs +++ b/crates/fuzzing/src/oracles/dummy.rs @@ -2,7 +2,7 @@ use std::rc::Rc; 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, }; @@ -11,18 +11,12 @@ pub fn dummy_imports(store: &Store, import_tys: &[ImportType]) -> Result { - Extern::Func(HostRef::new(DummyFunc::new(&store, func_ty.clone()))) - } + ExternType::Func(func_ty) => Extern::Func(DummyFunc::new(&store, func_ty.clone())), ExternType::Global(global_ty) => { - Extern::Global(HostRef::new(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()))) + Extern::Global(dummy_global(&store, global_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) diff --git a/crates/interface-types/Cargo.toml b/crates/interface-types/Cargo.toml index 2b5892cbd5..380d466766 100644 --- a/crates/interface-types/Cargo.toml +++ b/crates/interface-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime-interface-types" -version = "0.7.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] description = "Support for wasm interface types with wasmtime" license = "Apache-2.0 WITH LLVM-exception" @@ -13,13 +13,13 @@ edition = "2018" [dependencies] anyhow = "1.0.19" walrus = "0.13" -wasmparser = { version = "0.45.1", default-features = false } +wasmparser = { version = "0.47.0", default-features = false } wasm-webidl-bindings = "0.6" -wasmtime = { path = '../api' } -wasmtime-jit = { path = '../jit' } -wasmtime-environ = { path = '../environ' } -wasmtime-runtime = { path = '../runtime' } -wasmtime-wasi = { path = '../wasi' } +wasmtime = { path = "../api", version = "0.9.0" } +wasmtime-jit = { path = "../jit", version = "0.9.0" } +wasmtime-environ = { path = "../environ", version = "0.9.0" } +wasmtime-runtime = { path = "../runtime", version = "0.9.0" } +wasmtime-wasi = { path = "../wasi", version = "0.9.0" } [badges] maintenance = { status = "actively-developed" } diff --git a/crates/interface-types/src/lib.rs b/crates/interface-types/src/lib.rs index 62122b62ac..4934e7370c 100644 --- a/crates/interface-types/src/lib.rs +++ b/crates/interface-types/src/lib.rs @@ -125,18 +125,17 @@ impl ModuleData { /// wasm interface types. pub fn invoke_export( &self, - instance: &wasmtime::HostRef, + instance: &wasmtime::Instance, export: &str, args: &[Value], ) -> Result> { - let mut handle = instance.borrow().handle().clone(); + let mut handle = instance.handle().clone(); let binding = self.binding_for_export(&mut handle, export)?; let incoming = binding.param_bindings()?; let outgoing = binding.result_bindings()?; let f = instance - .borrow() .find_export_by_name(export) .ok_or_else(|| format_err!("failed to find export `{}`", export))? .func() @@ -148,7 +147,7 @@ impl ModuleData { .into_iter() .map(|rv| rv.into()) .collect::>(); - let wasm_results = match f.borrow().call(&wasm_args) { + let wasm_results = match f.call(&wasm_args) { Ok(values) => values .to_vec() .into_iter() @@ -322,20 +321,19 @@ trait TranslateContext { unsafe fn get_memory(&mut self) -> Result<&mut [u8]>; } -struct InstanceTranslateContext(pub wasmtime::HostRef); +struct InstanceTranslateContext(pub wasmtime::Instance); impl TranslateContext for InstanceTranslateContext { fn invoke_alloc(&mut self, alloc_func_name: &str, len: i32) -> Result { let alloc = self .0 - .borrow() .find_export_by_name(alloc_func_name) .ok_or_else(|| format_err!("failed to find alloc function `{}`", alloc_func_name))? .func() .ok_or_else(|| format_err!("`{}` is not a (alloc) function", alloc_func_name))? .clone(); 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, Err(trap) => bail!("trapped: {:?}", trap), }; @@ -350,14 +348,13 @@ impl TranslateContext for InstanceTranslateContext { unsafe fn get_memory(&mut self) -> Result<&mut [u8]> { let memory = self .0 - .borrow() .find_export_by_name("memory") .ok_or_else(|| format_err!("failed to find `memory` export"))? .memory() .ok_or_else(|| format_err!("`memory` is not a memory"))? .clone(); - let ptr = memory.borrow().data_ptr(); - let len = memory.borrow().data_size(); + let ptr = memory.data_ptr(); + let len = memory.data_size(); Ok(std::slice::from_raw_parts_mut(ptr, len)) } } diff --git a/crates/jit/Cargo.toml b/crates/jit/Cargo.toml index 9ef028bee4..368b9eb4ad 100644 --- a/crates/jit/Cargo.toml +++ b/crates/jit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime-jit" -version = "0.7.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] description = "JIT-style execution for WebAsssembly code in Cranelift" license = "Apache-2.0 WITH LLVM-exception" @@ -11,18 +11,18 @@ readme = "README.md" edition = "2018" [dependencies] -cranelift-codegen = { version = "0.52.0", features = ["enable-serde"] } -cranelift-entity = { version = "0.52.0", features = ["enable-serde"] } -cranelift-wasm = { version = "0.52.0", features = ["enable-serde"] } -cranelift-native = "0.52.0" -cranelift-frontend = "0.52.0" -wasmtime-environ = { path = "../environ" } -wasmtime-runtime = { path = "../runtime" } -wasmtime-debug = { path = "../debug" } +cranelift-codegen = { version = "0.54", features = ["enable-serde"] } +cranelift-entity = { version = "0.54", features = ["enable-serde"] } +cranelift-wasm = { version = "0.54", features = ["enable-serde"] } +cranelift-native = "0.54" +cranelift-frontend = "0.54" +wasmtime-environ = { path = "../environ", version = "0.9.0" } +wasmtime-runtime = { path = "../runtime", version = "0.9.0" } +wasmtime-debug = { path = "../debug", version = "0.9.0" } region = "2.0.0" thiserror = "1.0.4" -target-lexicon = { version = "0.9.0", default-features = false } -wasmparser = { version = "0.45.1", default-features = false } +target-lexicon = { version = "0.10.0", default-features = false } +wasmparser = { version = "0.47.0", default-features = false } more-asserts = "0.2.1" anyhow = "1.0" diff --git a/crates/jit/src/code_memory.rs b/crates/jit/src/code_memory.rs index 49dc86a9e1..49e6d5ee2d 100644 --- a/crates/jit/src/code_memory.rs +++ b/crates/jit/src/code_memory.rs @@ -14,6 +14,11 @@ pub struct CodeMemory { published: usize, } +fn _assert() { + fn _assert_send_sync() {} + _assert_send_sync::(); +} + impl CodeMemory { /// Create a new `CodeMemory` instance. pub fn new() -> Self { diff --git a/crates/jit/src/instantiate.rs b/crates/jit/src/instantiate.rs index 1a22399125..68e6fac6df 100644 --- a/crates/jit/src/instantiate.rs +++ b/crates/jit/src/instantiate.rs @@ -60,7 +60,7 @@ impl<'data> RawCompiledModule<'data> { fn new( compiler: &mut Compiler, data: &'data [u8], - module_name: Option, + module_name: Option<&str>, resolver: &mut dyn Resolver, debug_info: bool, ) -> Result { @@ -76,7 +76,7 @@ impl<'data> RawCompiledModule<'data> { 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( &translation.module, @@ -155,7 +155,7 @@ impl CompiledModule { pub fn new<'data>( compiler: &mut Compiler, data: &'data [u8], - module_name: Option, + module_name: Option<&str>, resolver: &mut dyn Resolver, global_exports: Rc>>>, debug_info: bool, @@ -263,7 +263,7 @@ impl OwnedDataInitializer { pub fn instantiate( compiler: &mut Compiler, data: &[u8], - module_name: Option, + module_name: Option<&str>, resolver: &mut dyn Resolver, global_exports: Rc>>>, debug_info: bool, diff --git a/crates/jit/src/link.rs b/crates/jit/src/link.rs index 867ddea681..f8c9c62589 100644 --- a/crates/jit/src/link.rs +++ b/crates/jit/src/link.rs @@ -30,8 +30,8 @@ pub fn link_module( let mut dependencies = HashSet::new(); let mut function_imports = PrimaryMap::with_capacity(module.imported_funcs.len()); - for (index, (ref module_name, ref field)) in module.imported_funcs.iter() { - match resolver.resolve(module_name, field) { + for (index, (module_name, field, import_idx)) in module.imported_funcs.iter() { + match resolver.resolve(*import_idx, module_name, field) { Some(export_value) => match export_value { Export::Function { address, @@ -71,8 +71,8 @@ pub fn link_module( } let mut table_imports = PrimaryMap::with_capacity(module.imported_tables.len()); - for (index, (ref module_name, ref field)) in module.imported_tables.iter() { - match resolver.resolve(module_name, field) { + for (index, (module_name, field, import_idx)) in module.imported_tables.iter() { + match resolver.resolve(*import_idx, module_name, field) { Some(export_value) => match export_value { Export::Table { definition, @@ -110,8 +110,8 @@ pub fn link_module( } let mut memory_imports = PrimaryMap::with_capacity(module.imported_memories.len()); - for (index, (ref module_name, ref field)) in module.imported_memories.iter() { - match resolver.resolve(module_name, field) { + for (index, (module_name, field, import_idx)) in module.imported_memories.iter() { + match resolver.resolve(*import_idx, module_name, field) { Some(export_value) => match export_value { Export::Memory { definition, @@ -163,8 +163,8 @@ pub fn link_module( } let mut global_imports = PrimaryMap::with_capacity(module.imported_globals.len()); - for (index, (ref module_name, ref field)) in module.imported_globals.iter() { - match resolver.resolve(module_name, field) { + for (index, (module_name, field, import_idx)) in module.imported_globals.iter() { + match resolver.resolve(*import_idx, module_name, field) { Some(export_value) => match export_value { Export::Table { .. } | Export::Memory { .. } | Export::Function { .. } => { return Err(LinkError(format!( diff --git a/crates/jit/src/namespace.rs b/crates/jit/src/namespace.rs index dc2c0a9e1f..a8f5449c6f 100644 --- a/crates/jit/src/namespace.rs +++ b/crates/jit/src/namespace.rs @@ -36,7 +36,7 @@ impl Namespace { } impl Resolver for Namespace { - fn resolve(&mut self, name: &str, field: &str) -> Option { + fn resolve(&mut self, _idx: u32, name: &str, field: &str) -> Option { if let Some(instance) = self.names.get_mut(name) { instance.lookup(field) } else { diff --git a/crates/jit/src/resolver.rs b/crates/jit/src/resolver.rs index 9b8ba197cb..34f052c45a 100644 --- a/crates/jit/src/resolver.rs +++ b/crates/jit/src/resolver.rs @@ -5,15 +5,22 @@ use wasmtime_runtime::Export; /// Import resolver connects imports with available exported values. pub trait Resolver { - /// Resolve the given module/field combo. - fn resolve(&mut self, module: &str, field: &str) -> Option; + /// Resolves an import a WebAssembly module to an export it's hooked up to. + /// + /// 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; } /// `Resolver` implementation that always resolves to `None`. pub struct NullResolver {} impl Resolver for NullResolver { - fn resolve(&mut self, _module: &str, _field: &str) -> Option { + fn resolve(&mut self, _idx: u32, _module: &str, _field: &str) -> Option { None } } diff --git a/crates/lightbeam/Cargo.toml b/crates/lightbeam/Cargo.toml index 3e19cd3d04..225a73c311 100644 --- a/crates/lightbeam/Cargo.toml +++ b/crates/lightbeam/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lightbeam" -version = "0.7.0" +version = "0.9.0" authors = ["The Lightbeam Project Developers"] description = "An optimising one-pass streaming compiler for WebAssembly" license = "Apache-2.0 WITH LLVM-exception" @@ -14,12 +14,12 @@ edition = "2018" smallvec = "1.0.0" dynasm = "0.5.2" dynasmrt = "0.5.2" -wasmparser = "0.45.1" +wasmparser = "0.47.0" memoffset = "0.5.3" itertools = "0.8.2" capstone = "0.6.0" thiserror = "1.0.9" -cranelift-codegen = "0.52.0" +cranelift-codegen = "0.54" multi_mut = "0.1" either = "1.5" typemap = "0.3" diff --git a/crates/misc/py/Cargo.toml b/crates/misc/py/Cargo.toml index be738b34de..633cab3adb 100644 --- a/crates/misc/py/Cargo.toml +++ b/crates/misc/py/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime-py" -version = "0.7.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] description = "Python extension for Wasmtime" license = "Apache-2.0 WITH LLVM-exception" @@ -17,15 +17,15 @@ test = false doc = false [dependencies] -wasmtime = { path = "../../api" } -wasmtime-environ = { path = "../../environ" } -wasmtime-interface-types = { path = "../../interface-types" } -wasmtime-runtime = { path = "../../runtime" } -wasmtime-wasi = { path = "../../wasi" } -target-lexicon = { version = "0.9.0", default-features = false } +wasmtime = { path = "../../api", version = "0.9.0" } +wasmtime-environ = { path = "../../environ", version = "0.9.0" } +wasmtime-interface-types = { path = "../../interface-types", version = "0.9.0" } +wasmtime-runtime = { path = "../../runtime", version = "0.9.0" } +wasmtime-wasi = { path = "../../wasi", version = "0.9.0" } +target-lexicon = { version = "0.10.0", default-features = false } anyhow = "1.0.19" region = "2.0.0" -wasmparser = "0.45.1" +wasmparser = "0.47.0" pyo3 = { version = "0.8.0", features = ["extension-module"] } [badges] diff --git a/crates/misc/py/src/function.rs b/crates/misc/py/src/function.rs index 3b88dcccf0..8227394c7a 100644 --- a/crates/misc/py/src/function.rs +++ b/crates/misc/py/src/function.rs @@ -10,17 +10,16 @@ use wasmtime_interface_types::ModuleData; // TODO support non-export functions #[pyclass] pub struct Function { - pub instance: wasmtime::HostRef, + pub instance: wasmtime::Instance, pub export_name: String, pub args_types: Vec, pub data: Rc, } impl Function { - pub fn func(&self) -> wasmtime::HostRef { + pub fn func(&self) -> wasmtime::Func { let e = self .instance - .borrow() .find_export_by_name(&self.export_name) .expect("named export") .clone(); @@ -125,10 +124,7 @@ impl wasmtime::Callable for WrappedFn { } } -pub fn wrap_into_pyfunction( - store: &wasmtime::Store, - callable: &PyAny, -) -> PyResult> { +pub fn wrap_into_pyfunction(store: &wasmtime::Store, callable: &PyAny) -> PyResult { if !callable.hasattr("__annotations__")? { // TODO support calls without annotations? return Err(PyErr::new::( @@ -154,6 +150,5 @@ pub fn wrap_into_pyfunction( let gil = Python::acquire_gil(); let wrapped = WrappedFn::new(callable.to_object(gil.python()), returns); - let f = wasmtime::Func::new(store, ft, Rc::new(wrapped)); - Ok(wasmtime::HostRef::new(f)) + Ok(wasmtime::Func::new(store, ft, Rc::new(wrapped))) } diff --git a/crates/misc/py/src/instance.rs b/crates/misc/py/src/instance.rs index f5c0480885..717d24aa2a 100644 --- a/crates/misc/py/src/instance.rs +++ b/crates/misc/py/src/instance.rs @@ -9,7 +9,7 @@ use wasmtime_interface_types::ModuleData; #[pyclass] pub struct Instance { - pub instance: wasmtime::HostRef, + pub instance: wasmtime::Instance, pub data: Rc, } @@ -20,7 +20,7 @@ impl Instance { let gil = Python::acquire_gil(); let py = gil.python(); 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() { match e.ty() { wasmtime::ExternType::Func(ft) => { @@ -43,10 +43,7 @@ impl Instance { let f = Py::new( py, Memory { - memory: self.instance.borrow().exports()[i] - .memory() - .unwrap() - .clone(), + memory: self.instance.exports()[i].memory().unwrap().clone(), }, )?; exports.set_item(e.name().to_string(), f)?; diff --git a/crates/misc/py/src/lib.rs b/crates/misc/py/src/lib.rs index 7247b1e867..61a6132c53 100644 --- a/crates/misc/py/src/lib.rs +++ b/crates/misc/py/src/lib.rs @@ -1,5 +1,3 @@ -#![allow(improper_ctypes)] - use crate::function::{wrap_into_pyfunction, Function}; use crate::instance::Instance; use crate::memory::Memory; @@ -122,10 +120,8 @@ pub fn instantiate( } } - let instance = wasmtime::HostRef::new( - wasmtime::Instance::new(&store, &module, &imports) - .map_err(|t| PyErr::new::(format!("instantiated with trap {:?}", t)))?, - ); + let instance = wasmtime::Instance::new(&module, &imports) + .map_err(|t| PyErr::new::(format!("instantiated with trap {:?}", t)))?; let module = Py::new(py, Module { module })?; diff --git a/crates/misc/py/src/memory.rs b/crates/misc/py/src/memory.rs index c6e8430ebe..1a43c82d84 100644 --- a/crates/misc/py/src/memory.rs +++ b/crates/misc/py/src/memory.rs @@ -10,14 +10,14 @@ use std::ptr; #[pyclass] pub struct Memory { - pub memory: wasmtime::HostRef, + pub memory: wasmtime::Memory, } #[pymethods] impl Memory { #[getter(current)] pub fn current(&self) -> u32 { - self.memory.borrow().size() + self.memory.size() } pub fn grow(&self, _number: u32) -> u32 { @@ -48,8 +48,8 @@ impl PyBufferProtocol for Memory { }; unsafe { - let base = self.memory.borrow().data_ptr(); - let current_length = self.memory.borrow().data_size(); + let base = self.memory.data_ptr(); + let current_length = self.memory.data_size(); (*view).buf = base as *mut c_void; (*view).len = current_length as isize; diff --git a/crates/misc/rust/Cargo.toml b/crates/misc/rust/Cargo.toml index c6e778090c..be1584f6da 100644 --- a/crates/misc/rust/Cargo.toml +++ b/crates/misc/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime-rust" -version = "0.7.0" +version = "0.9.0" authors = ["Alex Crichton "] description = "Rust extension for Wasmtime" license = "Apache-2.0 WITH LLVM-exception" @@ -15,10 +15,10 @@ test = false doctest = false [dependencies] -wasmtime-interface-types = { path = "../../interface-types" } -wasmtime-rust-macro = { path = "./macro" } -wasmtime-wasi = { path = "../../wasi" } -wasmtime = { path = "../../api" } +wasmtime-interface-types = { path = "../../interface-types", version = "0.9.0" } +wasmtime-rust-macro = { path = "./macro", version = "0.9.0" } +wasmtime-wasi = { path = "../../wasi", version = "0.9.0" } +wasmtime = { path = "../../api", version = "0.9.0" } anyhow = "1.0.19" [badges] diff --git a/crates/misc/rust/macro/Cargo.toml b/crates/misc/rust/macro/Cargo.toml index 2093ba7892..7c0b022686 100644 --- a/crates/misc/rust/macro/Cargo.toml +++ b/crates/misc/rust/macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime-rust-macro" -version = "0.7.0" +version = "0.9.0" authors = ["Alex Crichton "] description = "Macro support crate for wasmtime-rust" license = "Apache-2.0 WITH LLVM-exception" diff --git a/crates/misc/rust/macro/src/lib.rs b/crates/misc/rust/macro/src/lib.rs index b70cccfa61..0cbc1e027c 100644 --- a/crates/misc/rust/macro/src/lib.rs +++ b/crates/misc/rust/macro/src/lib.rs @@ -34,7 +34,7 @@ fn generate_struct(item: &syn::ItemTrait) -> syn::Result { let root = root(); Ok(quote! { #vis struct #name { - instance: #root::wasmtime::HostRef<#root::wasmtime::Instance>, + instance: #root::wasmtime::Instance, data: #root::wasmtime_interface_types::ModuleData, } }) @@ -48,7 +48,7 @@ fn generate_load(item: &syn::ItemTrait) -> syn::Result { #vis fn load_file(path: impl AsRef) -> #root::anyhow::Result<#name> { 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}; let engine = Engine::new(Config::new().wasm_multi_value(true)); @@ -74,9 +74,8 @@ fn generate_load(item: &syn::ItemTrait) -> syn::Result { } } } - let instance = HostRef::new( - Instance::new(&store, &module, &imports).map_err(|t| format_err!("instantiation trap: {:?}", t))? - ); + let instance = + Instance::new(&module, &imports).map_err(|t| format_err!("instantiation trap: {:?}", t))?; Ok(#name { instance, data }) } diff --git a/crates/obj/Cargo.toml b/crates/obj/Cargo.toml index fabe65a65f..66843b6cbc 100644 --- a/crates/obj/Cargo.toml +++ b/crates/obj/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime-obj" -version = "0.7.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] description = "Native object file output for WebAsssembly code in Wasmtime" license = "Apache-2.0 WITH LLVM-exception" @@ -12,8 +12,8 @@ edition = "2018" [dependencies] anyhow = "1.0" -wasmtime-environ = { path = "../environ" } -faerie = "0.13.0" +wasmtime-environ = { path = "../environ", version = "0.9.0" } +faerie = "0.14.0" more-asserts = "0.2.1" [badges] diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index f613d42e27..21c62fcf42 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime-runtime" -version = "0.7.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] description = "Runtime library support for Wasmtime" license = "Apache-2.0 WITH LLVM-exception" @@ -11,7 +11,7 @@ readme = "README.md" edition = "2018" [dependencies] -wasmtime-environ = { path = "../environ" } +wasmtime-environ = { path = "../environ", version = "0.9.0" } region = "2.0.0" lazy_static = "1.2.0" libc = { version = "0.2.60", default-features = false } diff --git a/crates/runtime/src/lib.rs b/crates/runtime/src/lib.rs index 4a1f06d66c..5a48273e12 100644 --- a/crates/runtime/src/lib.rs +++ b/crates/runtime/src/lib.rs @@ -1,6 +1,5 @@ //! Runtime library support for Wasmtime. -#![allow(improper_ctypes)] #![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] #![warn(unused_import_braces)] #![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))] diff --git a/crates/runtime/src/mmap.rs b/crates/runtime/src/mmap.rs index 570cfb1a32..8cba107404 100644 --- a/crates/runtime/src/mmap.rs +++ b/crates/runtime/src/mmap.rs @@ -1,11 +1,8 @@ //! Low-level abstraction for allocating and managing zero-filled pages //! of memory. -#[cfg(not(target_os = "windows"))] -use libc; use more_asserts::assert_le; use more_asserts::assert_lt; -use region; use std::io; use std::ptr; 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. #[derive(Debug)] 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, } @@ -29,8 +30,9 @@ impl Mmap { // Rust's slices require non-null pointers, even when empty. `Vec` // contains code to create a non-null dangling pointer value when // constructed empty, so we reuse that here. + let empty = Vec::::new(); Self { - ptr: Vec::new().as_mut_ptr(), + ptr: empty.as_ptr() as usize, len: 0, } } @@ -78,7 +80,7 @@ impl Mmap { } Self { - ptr: ptr as *mut u8, + ptr: ptr as usize, len: mapping_size, } } else { @@ -98,7 +100,7 @@ impl Mmap { } let mut result = Self { - ptr: ptr as *mut u8, + ptr: ptr as usize, len: mapping_size, }; @@ -142,7 +144,7 @@ impl Mmap { } Self { - ptr: ptr as *mut u8, + ptr: ptr as usize, len: mapping_size, } } else { @@ -154,7 +156,7 @@ impl Mmap { } let mut result = Self { - ptr: ptr as *mut u8, + ptr: ptr as usize, len: mapping_size, }; @@ -179,7 +181,8 @@ impl Mmap { assert_lt!(start, self.len - len); // 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()) } @@ -198,9 +201,10 @@ impl Mmap { assert_lt!(start, self.len - len); // Commit the accessible size. + let ptr = self.ptr as *const u8; if unsafe { VirtualAlloc( - self.ptr.add(start) as *mut c_void, + ptr.add(start) as *mut c_void, len, MEM_COMMIT, PAGE_READWRITE, @@ -216,22 +220,22 @@ impl Mmap { /// Return the allocated memory as a slice of 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. 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. pub fn as_ptr(&self) -> *const u8 { - self.ptr + self.ptr as *const u8 } /// Return the allocated memory as a mutable pointer to u8. pub fn as_mut_ptr(&mut self) -> *mut u8 { - self.ptr + self.ptr as *mut u8 } /// Return the length of the allocated memory. @@ -266,6 +270,11 @@ impl Drop for Mmap { } } +fn _assert() { + fn _assert_send_sync() {} + _assert_send_sync::(); +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/test-programs/Cargo.toml b/crates/test-programs/Cargo.toml index 4f24e2f9c1..28833c37ab 100644 --- a/crates/test-programs/Cargo.toml +++ b/crates/test-programs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test-programs" -version = "0.7.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] readme = "README.md" edition = "2018" @@ -10,13 +10,13 @@ publish = false cfg-if = "0.1.9" [dev-dependencies] -wasi-common = { path = "../wasi-common" } -wasmtime-runtime = { path = "../runtime" } -wasmtime-environ = { path = "../environ" } -wasmtime-jit = { path = "../jit" } -wasmtime-wasi = { path = "../wasi" } -wasmtime = { path = "../api" } -target-lexicon = "0.9.0" +wasi-common = { path = "../wasi-common", version = "0.9.0" } +wasmtime-runtime = { path = "../runtime", version = "0.9.0" } +wasmtime-environ = { path = "../environ", version = "0.9.0" } +wasmtime-jit = { path = "../jit", version = "0.9.0" } +wasmtime-wasi = { path = "../wasi", version = "0.9.0" } +wasmtime = { path = "../api", version = "0.9.0" } +target-lexicon = "0.10.0" pretty_env_logger = "0.3.0" tempfile = "3.1.0" os_pipe = "0.9" diff --git a/crates/test-programs/tests/wasm_tests/runtime.rs b/crates/test-programs/tests/wasm_tests/runtime.rs index 0970d31f26..28eef2878d 100644 --- a/crates/test-programs/tests/wasm_tests/runtime.rs +++ b/crates/test-programs/tests/wasm_tests/runtime.rs @@ -1,7 +1,7 @@ use anyhow::{bail, Context}; use std::fs::File; 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<()> { let store = Store::default(); @@ -61,13 +61,12 @@ pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> any }) .collect::, _>>()?; - let instance = HostRef::new(Instance::new(&store, &module, &imports).context(format!( + let instance = Instance::new(&module, &imports).context(format!( "error while instantiating Wasm module '{}'", bin_name, - ))?); + ))?; let export = instance - .borrow() .find_export_by_name("_start") .context("expected a _start export")? .clone(); @@ -75,7 +74,6 @@ pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> any if let Err(trap) = export .func() .context("expected export to be a func")? - .borrow() .call(&[]) { bail!("trapped: {:?}", trap); diff --git a/crates/test-programs/wasi-tests/Cargo.lock b/crates/test-programs/wasi-tests/Cargo.lock new file mode 100644 index 0000000000..b1962b4c0e --- /dev/null +++ b/crates/test-programs/wasi-tests/Cargo.lock @@ -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" diff --git a/crates/test-programs/wasi-tests/Cargo.toml b/crates/test-programs/wasi-tests/Cargo.toml index 3a874d56f4..68a9a7add1 100644 --- a/crates/test-programs/wasi-tests/Cargo.toml +++ b/crates/test-programs/wasi-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasi-tests" -version = "0.7.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] readme = "README.md" edition = "2018" diff --git a/crates/test-programs/wasi-tests/src/bin/fd_advise.rs b/crates/test-programs/wasi-tests/src/bin/fd_advise.rs index 359f47fbb6..408edf3490 100644 --- a/crates/test-programs/wasi-tests/src/bin/fd_advise.rs +++ b/crates/test-programs/wasi-tests/src/bin/fd_advise.rs @@ -9,7 +9,11 @@ unsafe fn test_fd_advise(dir_fd: wasi::Fd) { 0, "file", 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, ) diff --git a/crates/test-programs/wasi-tests/src/bin/fd_filestat_set.rs b/crates/test-programs/wasi-tests/src/bin/fd_filestat_set.rs index ea1be8fe1a..0f7cefcfe5 100644 --- a/crates/test-programs/wasi-tests/src/bin/fd_filestat_set.rs +++ b/crates/test-programs/wasi-tests/src/bin/fd_filestat_set.rs @@ -9,7 +9,11 @@ unsafe fn test_fd_filestat_set(dir_fd: wasi::Fd) { 0, "file", 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, ) diff --git a/crates/test-programs/wasi-tests/src/bin/fd_flags_set.rs b/crates/test-programs/wasi-tests/src/bin/fd_flags_set.rs new file mode 100644 index 0000000000..e642ca19a5 --- /dev/null +++ b/crates/test-programs/wasi-tests/src/bin/fd_flags_set.rs @@ -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: {} ", 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); + } +} diff --git a/crates/test-programs/wasi-tests/src/bin/fd_readdir.rs b/crates/test-programs/wasi-tests/src/bin/fd_readdir.rs index 8a3931cde8..8790ea0218 100644 --- a/crates/test-programs/wasi-tests/src/bin/fd_readdir.rs +++ b/crates/test-programs/wasi-tests/src/bin/fd_readdir.rs @@ -90,7 +90,10 @@ unsafe fn test_fd_readdir(dir_fd: wasi::Fd) { 0, "file", 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, ) diff --git a/crates/test-programs/wasi-tests/src/bin/file_allocate.rs b/crates/test-programs/wasi-tests/src/bin/file_allocate.rs index f1df5e8060..cadee68ab5 100644 --- a/crates/test-programs/wasi-tests/src/bin/file_allocate.rs +++ b/crates/test-programs/wasi-tests/src/bin/file_allocate.rs @@ -9,7 +9,10 @@ unsafe fn test_file_allocate(dir_fd: wasi::Fd) { 0, "file", 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, ) diff --git a/crates/test-programs/wasi-tests/src/bin/file_seek_tell.rs b/crates/test-programs/wasi-tests/src/bin/file_seek_tell.rs index 9c179580e6..59357d3ad8 100644 --- a/crates/test-programs/wasi-tests/src/bin/file_seek_tell.rs +++ b/crates/test-programs/wasi-tests/src/bin/file_seek_tell.rs @@ -9,7 +9,7 @@ unsafe fn test_file_seek_tell(dir_fd: wasi::Fd) { 0, "file", 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, ) diff --git a/crates/test-programs/wasi-tests/src/bin/path_link.rs b/crates/test-programs/wasi-tests/src/bin/path_link.rs index 3e39e5f2cb..3e005012fd 100644 --- a/crates/test-programs/wasi-tests/src/bin/path_link.rs +++ b/crates/test-programs/wasi-tests/src/bin/path_link.rs @@ -2,8 +2,15 @@ use more_asserts::assert_gt; use std::{env, process}; 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 { - 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)); assert_gt!( 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 { - 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)); assert_gt!( file_fd, diff --git a/crates/test-programs/wasi-tests/src/bin/path_open_read_without_rights.rs b/crates/test-programs/wasi-tests/src/bin/path_open_read_without_rights.rs new file mode 100644 index 0000000000..26113c08c8 --- /dev/null +++ b/crates/test-programs/wasi-tests/src/bin/path_open_read_without_rights.rs @@ -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: {} ", 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) } +} diff --git a/crates/test-programs/wasi-tests/src/bin/poll_oneoff.rs b/crates/test-programs/wasi-tests/src/bin/poll_oneoff.rs index 362ff95c94..416f0217c5 100644 --- a/crates/test-programs/wasi-tests/src/bin/poll_oneoff.rs +++ b/crates/test-programs/wasi-tests/src/bin/poll_oneoff.rs @@ -198,7 +198,7 @@ unsafe fn test_fd_readwrite_valid_fd(dir_fd: wasi::Fd) { 0, "file", 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, ) diff --git a/crates/test-programs/wasi-tests/src/lib.rs b/crates/test-programs/wasi-tests/src/lib.rs index a1080c00be..0a9bee6f9d 100644 --- a/crates/test-programs/wasi-tests/src/lib.rs +++ b/crates/test-programs/wasi-tests/src/lib.rs @@ -24,8 +24,11 @@ pub fn open_scratch_directory(path: &str) -> Result { } dst.set_len(stat.u.dir.pr_name_len); if dst == path.as_bytes() { - return Ok(wasi::path_open(i, 0, ".", wasi::OFLAGS_DIRECTORY, 0, 0, 0) - .expect("failed to open dir")); + let (base, inherit) = fd_get_rights(i); + 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"); } + +// 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"); +} diff --git a/crates/wasi-c/Cargo.toml b/crates/wasi-c/Cargo.toml index 6104753440..d169491a89 100644 --- a/crates/wasi-c/Cargo.toml +++ b/crates/wasi-c/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime-wasi-c" -version = "0.7.0" +version = "0.9.0" authors = ["The Cranelift Project Developers"] description = "WASI API support for Wasmtime" license = "Apache-2.0 WITH LLVM-exception" @@ -11,20 +11,20 @@ readme = "README.md" edition = "2018" [dependencies] -wasmtime-runtime = { path = "../runtime" } -wasmtime-environ = { path = "../environ" } -wasmtime-jit = { path = "../jit" } -cranelift-codegen = { version = "0.52.0", features = ["enable-serde"] } -cranelift-entity = { version = "0.52.0", features = ["enable-serde"] } -cranelift-wasm = { version = "0.52.0", features = ["enable-serde"] } -target-lexicon = "0.9.0" +wasmtime-runtime = { path = "../runtime", version = "0.9.0" } +wasmtime-environ = { path = "../environ", version = "0.9.0" } +wasmtime-jit = { path = "../jit", version = "0.9.0" } +cranelift-codegen = { version = "0.54", features = ["enable-serde"] } +cranelift-entity = { version = "0.54", features = ["enable-serde"] } +cranelift-wasm = { version = "0.54", features = ["enable-serde"] } +target-lexicon = "0.10.0" log = { version = "0.4.8", default-features = false } libc = "0.2.60" more-asserts = "0.2.1" [build-dependencies] cmake = "0.1.35" -bindgen = "0.51.0" +bindgen = "0.52.0" [badges] maintenance = { status = "actively-developed" } diff --git a/crates/wasi-common/Cargo.toml b/crates/wasi-common/Cargo.toml index 370e615397..3905ae0860 100644 --- a/crates/wasi-common/Cargo.toml +++ b/crates/wasi-common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasi-common" -version = "0.7.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] description = "WASI implementation in Rust" license = "Apache-2.0 WITH LLVM-exception" @@ -11,7 +11,7 @@ readme = "README.md" edition = "2018" [dependencies] -wasi-common-cbindgen = { path = "wasi-common-cbindgen" } +wasi-common-cbindgen = { path = "wasi-common-cbindgen", version = "0.9.0" } anyhow = "1.0" thiserror = "1.0" libc = "0.2" @@ -21,14 +21,14 @@ log = "0.4" filetime = "0.2.7" lazy_static = "1.4.0" num = { version = "0.2.0", default-features = false } -wig = { path = "wig" } crossbeam = "0.7.3" +wig = { path = "wig", version = "0.9.2" } [target.'cfg(unix)'.dependencies] -yanix = { path = "yanix" } +yanix = { path = "yanix", version = "0.9.0" } [target.'cfg(windows)'.dependencies] -winx = { path = "winx" } +winx = { path = "winx", version = "0.9.0" } winapi = "0.3" cpu-time = "1.0" diff --git a/crates/wasi-common/WASI b/crates/wasi-common/WASI deleted file mode 160000 index 9150e66a34..0000000000 --- a/crates/wasi-common/WASI +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9150e66a349dff6215b0290ee8f66794fbfa5ea8 diff --git a/crates/wasi-common/src/fdentry.rs b/crates/wasi-common/src/fdentry.rs index 73027cda1d..a86e6ce8b4 100644 --- a/crates/wasi-common/src/fdentry.rs +++ b/crates/wasi-common/src/fdentry.rs @@ -155,8 +155,21 @@ impl FdEntry { rights_base: wasi::__wasi_rights_t, rights_inheriting: wasi::__wasi_rights_t, ) -> 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) } else { Ok(()) diff --git a/crates/wasi-common/src/hostcalls/fs.rs b/crates/wasi-common/src/hostcalls/fs.rs index f9a140869c..6746ba79d4 100644 --- a/crates/wasi-common/src/hostcalls/fs.rs +++ b/crates/wasi-common/src/hostcalls/fs.rs @@ -67,7 +67,7 @@ hostcalls! { ) -> wasi::__wasi_errno_t; pub unsafe fn fd_fdstat_set_flags( - wasi_ctx: &WasiCtx, + wasi_ctx: &mut WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t, fdflags: wasi::__wasi_fdflags_t, diff --git a/crates/wasi-common/src/hostcalls_impl/fs.rs b/crates/wasi-common/src/hostcalls_impl/fs.rs index 7f93fbc27d..3d2e732433 100644 --- a/crates/wasi-common/src/hostcalls_impl/fs.rs +++ b/crates/wasi-common/src/hostcalls_impl/fs.rs @@ -5,7 +5,6 @@ use crate::fdentry::{Descriptor, FdEntry}; use crate::helpers::*; use crate::memory::*; 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::{host_impl, hostcalls_impl}; 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( - wasi_ctx: &WasiCtx, + wasi_ctx: &mut WasiCtx, _memory: &mut [u8], fd: wasi::__wasi_fd_t, fdflags: wasi::__wasi_fdflags_t, ) -> Result<()> { trace!("fd_fdstat_set_flags(fd={:?}, fdflags={:#x?})", fd, fdflags); - let fd = wasi_ctx - .get_fd_entry(fd)? - .as_descriptor(0, 0)? - .as_os_handle(); + let descriptor = wasi_ctx + .get_fd_entry_mut(fd)? + .as_descriptor_mut(wasi::__WASI_RIGHTS_FD_FDSTAT_SET_FLAGS, 0)?; - 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( @@ -574,6 +578,11 @@ pub(crate) unsafe fn path_open( let (needed_base, needed_inheriting) = 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 resolved = path_get( fe, @@ -593,13 +602,20 @@ pub(crate) unsafe fn path_open( | wasi::__WASI_RIGHTS_FD_FILESTAT_SET_SIZE) != 0; + trace!( + " | calling path_open impl: read={}, write={}", + read, + write + ); 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)?; - fe.rights_base &= max_base; - fe.rights_inheriting &= max_inheriting; + // We need to manually deny the rights which are not explicitly requested. + // 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)?; trace!(" | *fd={:?}", guest_fd); @@ -709,7 +725,10 @@ pub(crate) unsafe fn fd_filestat_get( 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)?; trace!(" | *filestat_ptr={:?}", host_filestat); diff --git a/crates/wasi-common/src/hostcalls_impl/misc.rs b/crates/wasi-common/src/hostcalls_impl/misc.rs index 696eb1b7ba..7e266033f8 100644 --- a/crates/wasi-common/src/hostcalls_impl/misc.rs +++ b/crates/wasi-common/src/hostcalls_impl/misc.rs @@ -242,9 +242,9 @@ pub(crate) fn poll_oneoff( { let wasi_fd = unsafe { subscription.u.fd_readwrite.file_descriptor }; 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 { - wasi::__WASI_RIGHTS_FD_WRITE + wasi::__WASI_RIGHTS_FD_WRITE | wasi::__WASI_RIGHTS_POLL_FD_READWRITE }; match unsafe { diff --git a/crates/wasi-common/src/sys/unix/hostcalls_impl/fs.rs b/crates/wasi-common/src/sys/unix/hostcalls_impl/fs.rs index e96d7252cc..cf7c143a41 100644 --- a/crates/wasi-common/src/sys/unix/hostcalls_impl/fs.rs +++ b/crates/wasi-common/src/sys/unix/hostcalls_impl/fs.rs @@ -29,9 +29,14 @@ pub(crate) fn fd_fdstat_get(fd: &File) -> Result { .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> { 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( diff --git a/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs b/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs index 654a475b2d..1baacb5e05 100644 --- a/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs +++ b/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs @@ -5,7 +5,7 @@ use crate::ctx::WasiCtx; use crate::fdentry::FdEntry; use crate::host::{Dirent, FileType}; 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::hostcalls_impl::fs_helpers::PathGetExt; use crate::{wasi, Error, Result}; @@ -78,8 +78,26 @@ pub(crate) fn fd_fdstat_get(fd: &File) -> Result { Ok(fdflags) } -pub(crate) fn fd_fdstat_set_flags(fd: &File, fdflags: wasi::__wasi_fdflags_t) -> Result<()> { - unimplemented!("fd_fdstat_set_flags") +pub(crate) fn fd_fdstat_set_flags( + fd: &File, + fdflags: wasi::__wasi_fdflags_t, +) -> Result> { + 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( @@ -119,9 +137,20 @@ pub(crate) fn path_open( ) -> Result { 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 // 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(); match creation_disposition_from_oflags(oflags) { 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()) .open(&path) .map_err(Into::into) @@ -195,12 +231,15 @@ fn file_access_mode_from_fdflags( ) -> AccessMode { 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 { - access_mode.insert(AccessMode::GENERIC_READ); + access_mode.insert(AccessMode::FILE_GENERIC_READ); } 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. diff --git a/crates/wasi-common/wasi-common-cbindgen/Cargo.toml b/crates/wasi-common/wasi-common-cbindgen/Cargo.toml index dadae6a915..c30668c212 100644 --- a/crates/wasi-common/wasi-common-cbindgen/Cargo.toml +++ b/crates/wasi-common/wasi-common-cbindgen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasi-common-cbindgen" -version = "0.7.0" +version = "0.9.0" authors = ["Jakub Konka "] description = "Interface generator utilities used by wasi-common" license = "Apache-2.0 WITH LLVM-exception" diff --git a/crates/wasi-common/wig/Cargo.toml b/crates/wasi-common/wig/Cargo.toml index c5a537d815..fb2720923e 100644 --- a/crates/wasi-common/wig/Cargo.toml +++ b/crates/wasi-common/wig/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wig" -version = "0.7.0" +version = "0.9.2" authors = ["Dan Gohman "] description = "WebAssembly Interface Generator" license = "Apache-2.0 WITH LLVM-exception" @@ -8,6 +8,7 @@ categories = ["wasm"] keywords = ["webassembly", "wasm"] repository = "https://github.com/bytecodealliance/wasmtime" edition = "2018" +include = ["src/**/*", "LICENSE", "WASI"] [lib] 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 # 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. -witx = { path = "../WASI/tools/witx" } +witx = "0.6.0" [badges] maintenance = { status = "actively-developed" } diff --git a/crates/wasi-common/wig/WASI b/crates/wasi-common/wig/WASI new file mode 160000 index 0000000000..04d4eba571 --- /dev/null +++ b/crates/wasi-common/wig/WASI @@ -0,0 +1 @@ +Subproject commit 04d4eba571dc1d6fe9ab129ea9343911bcc256dc diff --git a/crates/wasi-common/wig/src/utils.rs b/crates/wasi-common/wig/src/utils.rs index 74d71e5eb4..a3a29963c3 100644 --- a/crates/wasi-common/wig/src/utils.rs +++ b/crates/wasi-common/wig/src/utils.rs @@ -28,7 +28,7 @@ pub(crate) fn witx_path_from_args(args: TokenStream) -> (String, String) { fn witx_path(phase: &str, id: &str) -> String { 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`. diff --git a/crates/wasi-common/winx/Cargo.toml b/crates/wasi-common/winx/Cargo.toml index e3ee6519fa..fc04ffa22b 100644 --- a/crates/wasi-common/winx/Cargo.toml +++ b/crates/wasi-common/winx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "winx" -version = "0.7.0" +version = "0.9.0" authors = ["Jakub Konka "] description = "Windows API helper library" license = "Apache-2.0 WITH LLVM-exception" diff --git a/crates/wasi-common/winx/src/file.rs b/crates/wasi-common/winx/src/file.rs index a5fd7537b3..2a1bee7cfd 100644 --- a/crates/wasi-common/winx/src/file.rs +++ b/crates/wasi-common/winx/src/file.rs @@ -434,3 +434,22 @@ pub fn query_mode_information(handle: RawHandle) -> Result Ok(FileModeInformation::from_bits_truncate(info.Mode)) } + +pub fn reopen_file(handle: RawHandle, access_mode: AccessMode, flags: Flags) -> Result { + // 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) +} diff --git a/crates/wasi-common/yanix/Cargo.toml b/crates/wasi-common/yanix/Cargo.toml index 61c52488cb..417ff89c4d 100644 --- a/crates/wasi-common/yanix/Cargo.toml +++ b/crates/wasi-common/yanix/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "yanix" -version = "0.1.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] description = "Yet Another Nix crate: a Unix API helper library" license = "Apache-2.0 WITH LLVM-exception" diff --git a/crates/wasi/Cargo.toml b/crates/wasi/Cargo.toml index 71a2f09928..4aaca18c0b 100644 --- a/crates/wasi/Cargo.toml +++ b/crates/wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime-wasi" -version = "0.7.0" +version = "0.9.0" authors = ["The Cranelift Project Developers"] description = "WASI API support for Wasmtime" license = "Apache-2.0 WITH LLVM-exception" @@ -11,17 +11,17 @@ readme = "README.md" edition = "2018" [dependencies] -wasmtime = { path = "../api" } -wasmtime-runtime = { path = "../runtime" } -wasmtime-environ = { path = "../environ" } -wasmtime-jit = { path = "../jit" } -wasi-common = { path = "../wasi-common" } -cranelift-codegen = { version = "0.52.0", features = ["enable-serde"] } -cranelift-entity = { version = "0.52.0", features = ["enable-serde"] } -cranelift-wasm = { version = "0.52.0", features = ["enable-serde"] } -target-lexicon = "0.9.0" +wasmtime = { path = "../api", version = "0.9.0" } +wasmtime-runtime = { path = "../runtime", version = "0.9.0" } +wasmtime-environ = { path = "../environ", version = "0.9.0" } +wasmtime-jit = { path = "../jit", version = "0.9.0" } +wasi-common = { path = "../wasi-common", version = "0.9.0" } +cranelift-codegen = { version = "0.54", features = ["enable-serde"] } +cranelift-entity = { version = "0.54", features = ["enable-serde"] } +cranelift-wasm = { version = "0.54", features = ["enable-serde"] } +target-lexicon = "0.10.0" log = { version = "0.4.8", default-features = false } -wig = { path = "../wasi-common/wig" } +wig = { path = "../wasi-common/wig", version = "0.9.2" } [badges] maintenance = { status = "actively-developed" } diff --git a/crates/wasi/src/lib.rs b/crates/wasi/src/lib.rs index c152b34132..565958f9e8 100644 --- a/crates/wasi/src/lib.rs +++ b/crates/wasi/src/lib.rs @@ -1,5 +1,3 @@ -#![allow(improper_ctypes)] - mod instantiate; pub mod old; diff --git a/crates/wasi/src/old/snapshot_0/mod.rs b/crates/wasi/src/old/snapshot_0/mod.rs index ef699ce0b6..b4ffd25440 100644 --- a/crates/wasi/src/old/snapshot_0/mod.rs +++ b/crates/wasi/src/old/snapshot_0/mod.rs @@ -1,5 +1,3 @@ -#![allow(improper_ctypes)] - extern crate alloc; mod instantiate; diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml index 29270d75f5..3213febf42 100644 --- a/crates/wast/Cargo.toml +++ b/crates/wast/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime-wast" -version = "0.7.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] description = "wast testing support for wasmtime" license = "Apache-2.0 WITH LLVM-exception" @@ -12,8 +12,8 @@ edition = "2018" [dependencies] anyhow = "1.0.19" -wasmtime = { path = "../api" } -wast = "5.0.1" +wasmtime = { path = "../api", version = "0.9.0" } +wast = "6.0.0" [badges] maintenance = { status = "actively-developed" } diff --git a/crates/wast/src/spectest.rs b/crates/wast/src/spectest.rs index 8d906f56c6..c180a7689c 100644 --- a/crates/wast/src/spectest.rs +++ b/crates/wast/src/spectest.rs @@ -1,5 +1,3 @@ -#![allow(improper_ctypes)] - use anyhow::Result; use std::collections::HashMap; 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 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 func = wrap(store, ty, |params, _results| { println!("{}: i32", params[0].unwrap_i32()); 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 func = wrap(store, ty, |params, _results| { println!("{}: i64", params[0].unwrap_i64()); 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 func = wrap(store, ty, |params, _results| { println!("{}: f32", params[0].unwrap_f32()); 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 func = wrap(store, ty, |params, _results| { println!("{}: f64", params[0].unwrap_f64()); 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 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()); 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 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()); 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 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 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 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 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 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 memory = Memory::new(store, ty); - ret.insert("memory", Extern::Memory(HostRef::new(memory))); + ret.insert("memory", Extern::Memory(memory)); return ret; } diff --git a/crates/wast/src/wast.rs b/crates/wast/src/wast.rs index 4f8f2ba0c6..fc71896ac9 100644 --- a/crates/wast/src/wast.rs +++ b/crates/wast/src/wast.rs @@ -27,9 +27,9 @@ fn runtime_value(v: &wast::Expression<'_>) -> Result { pub struct WastContext { /// Wast files have a concept of a "current" module, which is the most /// recently defined. - current: Option>, + current: Option, - instances: HashMap>, + instances: HashMap, store: Store, spectest: Option>, } @@ -39,6 +39,15 @@ enum Outcome> { Trap(Trap), } +impl Outcome { + fn into_result(self) -> Result { + match self { + Outcome::Ok(t) => Ok(t), + Outcome::Trap(t) => Err(t), + } + } +} + impl WastContext { /// Construct a new instance of `WastContext`. pub fn new(store: Store) -> Self { @@ -50,7 +59,7 @@ impl WastContext { } } - fn get_instance(&self, instance_name: Option<&str>) -> Result> { + fn get_instance(&self, instance_name: Option<&str>) -> Result { match instance_name { Some(name) => self .instances @@ -64,7 +73,7 @@ impl WastContext { } } - fn instantiate(&self, module: &[u8]) -> Result>> { + fn instantiate(&self, module: &[u8]) -> Result> { let module = Module::new(&self.store, module)?; let mut imports = Vec::new(); for import in module.imports() { @@ -85,23 +94,16 @@ impl WastContext { .get(import.module()) .ok_or_else(|| anyhow!("no module named `{}`", import.module()))?; let export = instance - .borrow() .find_export_by_name(import.name()) .ok_or_else(|| anyhow!("unknown import `{}::{}`", import.name(), import.module()))? .clone(); imports.push(export); } - let instance = match Instance::new(&self.store, &module, &imports) { + let instance = match Instance::new(&module, &imports) { Ok(i) => i, - Err(e) => { - let err = e.chain().filter_map(|e| e.downcast_ref::()).next(); - if let Some(trap) = err { - return Ok(Outcome::Trap(trap.clone())); - } - return Err(e); - } + Err(e) => return e.downcast::().map(Outcome::Trap), }; - Ok(Outcome::Ok(HostRef::new(instance))) + Ok(Outcome::Ok(instance)) } /// Register "spectest" which is used by the spec testsuite. @@ -127,7 +129,12 @@ impl WastContext { } fn perform_invoke(&mut self, exec: wast::WastInvoke<'_>) -> Result { - self.invoke(exec.module.map(|i| i.name()), exec.name, &exec.args) + let values = exec + .args + .iter() + .map(runtime_value) + .collect::>>()?; + self.invoke(exec.module.map(|i| i.name()), exec.name, &values) } /// Define a module and register it. @@ -155,19 +162,17 @@ impl WastContext { &mut self, instance_name: Option<&str>, field: &str, - args: &[wast::Expression], + args: &[Val], ) -> Result { - let values = args.iter().map(runtime_value).collect::>>()?; let instance = self.get_instance(instance_name.as_ref().map(|x| &**x))?; - let instance = instance.borrow(); let export = instance .find_export_by_name(field) .ok_or_else(|| anyhow!("no global named `{}`", field))?; let func = match export { - Extern::Func(f) => f.borrow(), + Extern::Func(f) => f, _ => bail!("export of `{}` wasn't a global", field), }; - Ok(match func.call(&values) { + Ok(match func.call(args) { Ok(result) => Outcome::Ok(result.into()), Err(e) => Outcome::Trap(e), }) @@ -176,21 +181,44 @@ impl WastContext { /// Get the value of an exported global from an instance. fn get(&mut self, instance_name: Option<&str>, field: &str) -> Result { let instance = self.get_instance(instance_name.as_ref().map(|x| &**x))?; - let instance = instance.borrow(); let export = instance .find_export_by_name(field) .ok_or_else(|| anyhow!("no global named `{}`", field))?; let global = match export { - Extern::Global(g) => g.borrow(), + Extern::Global(g) => g, _ => bail!("export of `{}` wasn't a global", field), }; 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. pub fn run_buffer(&mut self, filename: &str, wast: &[u8]) -> Result<()> { - use wast::WastDirective::*; - let wast = str::from_utf8(wast)?; let adjust_wast = |mut err: wast::Error| { @@ -198,311 +226,126 @@ impl WastContext { err.set_text(wast); 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 wast = wast::parser::parse::(&buf).map_err(adjust_wast)?; + let ast = wast::parser::parse::(&buf).map_err(adjust_wast)?; - for directive in wast.directives { - match directive { - Module(mut module) => { - let binary = module.encode().map_err(adjust_wast)?; - self.module(module.name.map(|s| s.name()), &binary) - .with_context(|| context(module.span))?; - } - Register { span, name, module } => { - self.register(module.map(|s| s.name()), name) - .with_context(|| context(span))?; - } - Invoke(i) => { - let span = i.span; - self.perform_invoke(i).with_context(|| context(span))?; - } - AssertReturn { - span, - exec, - results, - } => match self.perform_execute(exec).with_context(|| context(span))? { - Outcome::Ok(values) => { - for (v, e) in values.iter().zip(results.iter().map(runtime_value)) { - 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 { - span, - exec, - message, - } => match self.perform_execute(exec).with_context(|| context(span))? { - Outcome::Ok(values) => { - bail!("{}\nexpected trap, got {:?}", context(span), values) - } - 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 { - span, - call, - message, - } => match self.perform_invoke(call).with_context(|| context(span))? { - Outcome::Ok(values) => { - bail!("{}\nexpected trap, got {:?}", context(span), values) - } - 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 { - span, - mut module, - message, - } => { - let bytes = module.encode().map_err(adjust_wast)?; - let err = match self.module(None, &bytes) { - Ok(()) => bail!("{}\nexpected module to fail to build", context(span)), - Err(e) => e, - }; - let error_message = format!("{:?}", err); - if !error_message.contains(&message) { - // TODO: change to bail! - println!( - "{}\nassert_invalid: expected {}, got {}", - context(span), - message, - error_message - ) - } - } - AssertMalformed { - span, - module, - message, - } => { - let mut module = match module { - wast::QuoteModule::Module(m) => m, - // this is a `*.wat` parser test which we're not - // interested in - wast::QuoteModule::Quote(_) => return Ok(()), - }; - let bytes = module.encode().map_err(adjust_wast)?; - let err = match self.module(None, &bytes) { - Ok(()) => { - bail!("{}\nexpected module to fail to instantiate", context(span)) - } - Err(e) => e, - }; - let error_message = format!("{:?}", err); - if !error_message.contains(&message) { - // TODO: change to bail! - println!( - "{}\nassert_malformed: expected {}, got {}", - context(span), - message, - error_message - ) - } - } - AssertUnlinkable { - span, - mut module, - message, - } => { - let bytes = module.encode().map_err(adjust_wast)?; - let err = match self.module(None, &bytes) { - Ok(()) => bail!("{}\nexpected module to fail to link", context(span)), - Err(e) => e, - }; - let error_message = format!("{:?}", err); - if !error_message.contains(&message) { - bail!( - "{}\nassert_unlinkable: expected {}, got {}", - context(span), - message, - error_message - ) - } - } - AssertReturnFunc { .. } => bail!("need to implement assert_return_func"), + 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::*; + + match directive { + Module(mut module) => { + let binary = module.encode()?; + self.module(module.name.map(|s| s.name()), &binary)?; } + Register { + span: _, + name, + module, + } => { + self.register(module.map(|s| s.name()), name)?; + } + Invoke(i) => { + self.perform_invoke(i)?; + } + AssertReturn { + span: _, + exec, + results, + } => { + let result = self.perform_execute(exec)?; + self.assert_return(result, &results)?; + } + AssertTrap { + span: _, + exec, + message, + } => { + let result = self.perform_execute(exec)?; + self.assert_trap(result, message)?; + } + AssertExhaustion { + span: _, + call, + message, + } => { + let result = self.perform_invoke(call)?; + self.assert_trap(result, message)?; + } + AssertInvalid { + span: _, + mut module, + message, + } => { + let bytes = module.encode()?; + let err = match self.module(None, &bytes) { + Ok(()) => bail!("expected module to fail to build"), + Err(e) => e, + }; + let error_message = format!("{:?}", err); + if !error_message.contains(&message) { + // TODO: change to bail! + println!( + "assert_invalid: expected {}, got {}", + message, error_message + ) + } + } + AssertMalformed { + span: _, + module, + message, + } => { + let mut module = match module { + wast::QuoteModule::Module(m) => m, + // this is a `*.wat` parser test which we're not + // interested in + wast::QuoteModule::Quote(_) => return Ok(()), + }; + let bytes = module.encode()?; + let err = match self.module(None, &bytes) { + Ok(()) => bail!("expected module to fail to instantiate"), + Err(e) => e, + }; + let error_message = format!("{:?}", err); + if !error_message.contains(&message) { + // TODO: change to bail! + println!( + "assert_malformed: expected {}, got {}", + message, error_message + ) + } + } + AssertUnlinkable { + span: _, + mut module, + message, + } => { + let bytes = module.encode()?; + let err = match self.module(None, &bytes) { + Ok(()) => bail!("expected module to fail to link"), + Err(e) => e, + }; + let error_message = format!("{:?}", err); + if !error_message.contains(&message) { + bail!( + "assert_unlinkable: expected {}, got {}", + message, + error_message + ) + } + } + AssertReturnFunc { .. } => bail!("need to implement assert_return_func"), } Ok(()) @@ -516,12 +359,20 @@ impl WastContext { } } -fn extract_lane_as_u32(bytes: &u128, lane: usize) -> Result { - Ok((*bytes >> (lane * 32)) as u32) +fn extract_lane_as_i8(bytes: u128, lane: usize) -> i8 { + (bytes >> (lane * 8)) as i8 } -fn extract_lane_as_u64(bytes: &u128, lane: usize) -> Result { - Ok((*bytes >> (lane * 64)) as u64) +fn extract_lane_as_i16(bytes: u128, lane: usize) -> i16 { + (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 { @@ -542,15 +393,64 @@ fn is_arithmetic_f64_nan(bits: u64) -> bool { (bits & AF64_NAN) == AF64_NAN } -fn values_equal(v1: &Val, v2: &Val) -> Result { - Ok(match (v1, v2) { - (Val::I32(a), Val::I32(b)) => a == b, - (Val::I64(a), Val::I64(b)) => a == b, +fn val_matches(actual: &Val, expected: &wast::AssertExpression) -> Result { + Ok(match (actual, expected) { + (Val::I32(a), wast::AssertExpression::I32(b)) => a == b, + (Val::I64(a), wast::AssertExpression::I64(b)) => a == b, // Note that these float comparisons are comparing bits, not float // values, so we're testing for bit-for-bit equivalence - (Val::F32(a), Val::F32(b)) => a == b, - (Val::F64(a), Val::F64(b)) => a == b, - (Val::V128(a), Val::V128(b)) => a == b, - _ => bail!("don't know how to compare {:?} and {:?} yet", v1, v2), + (Val::F32(a), wast::AssertExpression::F32(b)) => f32_matches(*a, b), + (Val::F64(a), wast::AssertExpression::F64(b)) => f64_matches(*a, b), + (Val::V128(a), wast::AssertExpression::V128(b)) => v128_matches(*a, b), + _ => bail!( + "don't know how to compare {:?} and {:?} yet", + actual, + expected + ), }) } + +fn f32_matches(actual: u32, expected: &wast::NanPattern) -> 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) -> 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) + }), + } +} diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index a1d2e97545..996c53b2f3 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmtime-fuzz" -version = "0.7.0" +version = "0.9.0" authors = ["The Wasmtime Project Developers"] edition = "2018" publish = false diff --git a/scripts/cranelift-version.sh b/scripts/cranelift-version.sh index db34f24b8b..7af91d26cd 100755 --- a/scripts/cranelift-version.sh +++ b/scripts/cranelift-version.sh @@ -9,16 +9,16 @@ topdir=$(dirname "$0")/.. cd "$topdir" # All the cranelift-* crates have the same version number -version="0.49" +version="0.53" # Update all of the Cargo.toml files. 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. sed -i.bk -e "/^cranelift-/s/\"[^\"]*\"/\"$version\"/" \ - "$crate/Cargo.toml" + "$toml" # Update the required version number of any cranelift* dependencies. sed -i.bk -e "/^cranelift-/s/version = \"[^\"]*\"/version = \"$version\"/" \ - "$crate/Cargo.toml" + "$toml" done diff --git a/scripts/publish-all.sh b/scripts/publish-all.sh index ae00756dcc..b5ef28c216 100755 --- a/scripts/publish-all.sh +++ b/scripts/publish-all.sh @@ -9,7 +9,7 @@ topdir=$(dirname "$0")/.. cd "$topdir" # 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. echo "Updating crate versions to $version" @@ -17,6 +17,13 @@ find -name Cargo.toml \ -not -path ./crates/wasi-common/WASI/tools/witx/Cargo.toml \ -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 "/\> *= *{.*\>, + module_registry: &HashMap, path: &Path, - ) -> Result<(HostRef, Module, Vec)> { + ) -> Result<(Instance, Module, Vec)> { // Read the wasm module binary either as `*.wat` or a raw binary let data = wat::parse_file(path)?; @@ -248,7 +244,7 @@ impl RunCommand { let module_name = i.module(); if let Some(instance) = module_registry.get(module_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()) } else { bail!( @@ -263,10 +259,8 @@ impl RunCommand { }) .collect::, _>>()?; - let instance = HostRef::new( - Instance::new(store, &module, &imports) - .context(format!("failed to instantiate {:?}", path))?, - ); + let instance = Instance::new(&module, &imports) + .context(format!("failed to instantiate {:?}", path))?; Ok((instance, module, data)) } @@ -274,7 +268,7 @@ impl RunCommand { fn handle_module( &self, store: &Store, - module_registry: &HashMap>, + module_registry: &HashMap, ) -> Result<()> { let (instance, module, data) = Self::instantiate_module(store, module_registry, &self.module)?; @@ -301,16 +295,11 @@ impl RunCommand { Ok(()) } - fn invoke_export( - &self, - instance: HostRef, - data: &ModuleData, - name: &str, - ) -> Result<()> { + fn invoke_export(&self, instance: Instance, data: &ModuleData, name: &str) -> Result<()> { use wasm_webidl_bindings::ast; 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 // need to be passed to the function that we're invoking. Currently we take diff --git a/src/commands/wasm2obj.rs b/src/commands/wasm2obj.rs index 0c5f04b972..b33d8c08b7 100644 --- a/src/commands/wasm2obj.rs +++ b/src/commands/wasm2obj.rs @@ -154,7 +154,7 @@ impl WasmToObjCommand { &module_translation, lazy_function_body_inputs, &*isa, - generate_debug_info, + self.common.debug_info, ), #[cfg(not(feature = "lightbeam"))] Strategy::Lightbeam => bail!("lightbeam support not enabled"), diff --git a/tests/custom_signal_handler.rs b/tests/custom_signal_handler.rs index 253d62d49d..40f9080998 100644 --- a/tests/custom_signal_handler.rs +++ b/tests/custom_signal_handler.rs @@ -1,24 +1,54 @@ #[cfg(not(target_os = "windows"))] mod tests { - use core::cell::Ref; + use anyhow::Result; use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; use wasmtime::*; - use wasmtime_interface_types::{ModuleData, Value}; - fn invoke_export( - instance: &HostRef, - data: &[u8], - func_name: &str, - ) -> Result, anyhow::Error> { - ModuleData::new(&data) - .expect("module data") - .invoke_export(instance, func_name, &[]) + const WAT1: &str = r#" +(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) +) +"#; + + 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, 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 - fn set_up_memory(instance: &HostRef) -> (*mut u8, usize) { - let mem_export = instance.borrow().get_wasmtime_memory().expect("memory"); + fn set_up_memory(instance: &Instance) -> (*mut u8, usize) { + let mem_export = instance.get_wasmtime_memory().expect("memory"); let (base, length) = if let wasmtime_runtime::Export::Memory { definition, @@ -73,39 +103,34 @@ mod tests { } #[test] - fn test_custom_signal_handler_single_instance() { - let engine = HostRef::new(Engine::new(&Config::default())); - let store = HostRef::new(Store::new(&engine)); - let data = - std::fs::read("tests/custom_signal_handler.wasm").expect("failed to read wasm file"); - let module = HostRef::new(Module::new(&store, &data).expect("failed to create module")); - let instance = HostRef::new( - Instance::new(&store, &module, &[]).expect("failed to instantiate module"), - ); + fn test_custom_signal_handler_single_instance() -> Result<()> { + let engine = Engine::new(&Config::default()); + let store = Store::new(&engine); + let data = wat::parse_str(WAT1)?; + let module = Module::new(&store, &data)?; + let instance = Instance::new(&module, &[])?; let (base, length) = set_up_memory(&instance); - instance - .borrow_mut() - .set_signal_handler(move |signum, siginfo, _| { - handle_sigsegv(base, length, signum, siginfo) - }); + instance.set_signal_handler(move |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()); // these invoke wasmtime_call_trampoline from action.rs { println!("calling read..."); - let result = invoke_export(&instance, &data, "read").expect("read succeeded"); - assert_eq!("123", result[0].clone().to_string()); + let result = invoke_export(&instance, "read").expect("read succeeded"); + assert_eq!(123, result[0].unwrap_i32()); } { println!("calling read_out_of_bounds..."); - let trap = invoke_export(&instance, &data, "read_out_of_bounds").unwrap_err(); - assert!(trap.root_cause().to_string().starts_with( - "trapped: Ref(Trap { message: \"wasm trap: out of bounds memory access" - )); + let trap = invoke_export(&instance, "read_out_of_bounds").unwrap_err(); + assert!(trap + .message() + .starts_with("call error: wasm trap: out of bounds memory access")); } // these invoke wasmtime_call_trampoline from callable.rs @@ -114,10 +139,7 @@ mod tests { .func() .expect("expected a 'read' func in the module"); println!("calling read..."); - let result = read_func - .borrow() - .call(&[]) - .expect("expected function not to trap"); + let result = read_func.call(&[]).expect("expected function not to trap"); assert_eq!(123i32, result[0].clone().unwrap_i32()); } @@ -126,33 +148,30 @@ mod tests { .func() .expect("expected a 'read_out_of_bounds' func in the module"); 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 - .borrow() .message() - .starts_with("wasm trap: out of bounds memory access")); + .starts_with("call error: wasm trap: out of bounds memory access")); } + Ok(()) } #[test] - fn test_custom_signal_handler_multiple_instances() { - let engine = HostRef::new(Engine::new(&Config::default())); - let store = HostRef::new(Store::new(&engine)); - let data = - std::fs::read("tests/custom_signal_handler.wasm").expect("failed to read wasm file"); - let module = HostRef::new(Module::new(&store, &data).expect("failed to create module")); + fn test_custom_signal_handler_multiple_instances() -> Result<()> { + let engine = Engine::new(&Config::default()); + let store = Store::new(&engine); + let data = wat::parse_str(WAT1)?; + let module = Module::new(&store, &data)?; // Set up multiple instances - let instance1 = HostRef::new( - Instance::new(&store, &module, &[]).expect("failed to instantiate module"), - ); + let instance1 = Instance::new(&module, &[])?; let instance1_handler_triggered = Rc::new(AtomicBool::new(false)); { 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(); move |_signum, _siginfo, _context| { // Remove protections so the execution may resume @@ -173,15 +192,13 @@ mod tests { }); } - let instance2 = HostRef::new( - Instance::new(&store, &module, &[]).expect("failed to instantiate module"), - ); + let instance2 = Instance::new(&module, &[]).expect("failed to instantiate module"); let instance2_handler_triggered = Rc::new(AtomicBool::new(false)); { 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(); move |_signum, _siginfo, _context| { // Remove protections so the execution may resume @@ -206,12 +223,12 @@ mod tests { // First instance1 { - let exports1 = Ref::map(instance1.borrow(), |i| i.exports()); + let exports1 = instance1.exports(); assert!(!exports1.is_empty()); println!("calling instance1.read..."); - let result = invoke_export(&instance1, &data, "read").expect("read succeeded"); - assert_eq!("123", result[0].clone().to_string()); + let result = invoke_export(&instance1, "read").expect("read succeeded"); + assert_eq!(123, result[0].unwrap_i32()); assert_eq!( instance1_handler_triggered.load(Ordering::SeqCst), true, @@ -221,62 +238,53 @@ mod tests { // And then instance2 { - let exports2 = Ref::map(instance2.borrow(), |i| i.exports()); + let exports2 = instance2.exports(); assert!(!exports2.is_empty()); println!("calling instance2.read..."); - let result = invoke_export(&instance2, &data, "read").expect("read succeeded"); - assert_eq!("123", result[0].clone().to_string()); + let result = invoke_export(&instance2, "read").expect("read succeeded"); + assert_eq!(123, result[0].unwrap_i32()); assert_eq!( instance2_handler_triggered.load(Ordering::SeqCst), true, "instance1 signal handler has been triggered" ); } + Ok(()) } #[test] - fn test_custom_signal_handler_instance_calling_another_instance() { - let engine = HostRef::new(Engine::new(&Config::default())); - let store = HostRef::new(Store::new(&engine)); + fn test_custom_signal_handler_instance_calling_another_instance() -> Result<()> { + let engine = Engine::new(&Config::default()); + let store = Store::new(&engine); // instance1 which defines 'read' - let data1 = - std::fs::read("tests/custom_signal_handler.wasm").expect("failed to read wasm file"); - let module1 = HostRef::new(Module::new(&store, &data1).expect("failed to create module")); - let instance1: HostRef = HostRef::new( - Instance::new(&store, &module1, &[]).expect("failed to instantiate module"), - ); + let data1 = wat::parse_str(WAT1)?; + let module1 = Module::new(&store, &data1)?; + let instance1 = Instance::new(&module1, &[])?; let (base1, length1) = set_up_memory(&instance1); - instance1 - .borrow_mut() - .set_signal_handler(move |signum, siginfo, _| { - println!("instance1"); - handle_sigsegv(base1, length1, signum, siginfo) - }); + instance1.set_signal_handler(move |signum, siginfo, _| { + println!("instance1"); + 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()); let instance1_read = instance1_exports[0].clone(); // instance2 wich calls 'instance1.read' - let data2 = - std::fs::read("tests/custom_signal_handler_2.wasm").expect("failed to read wasm file"); - let module2 = HostRef::new(Module::new(&store, &data2).expect("failed to create module")); - let instance2 = HostRef::new( - Instance::new(&store, &module2, &[instance1_read]) - .expect("failed to instantiate module"), - ); + let data2 = wat::parse_str(WAT2)?; + let module2 = Module::new(&store, &data2)?; + let instance2 = Instance::new(&module2, &[instance1_read])?; // since 'instance2.run' calls 'instance1.read' we need to set up the signal handler to handle // SIGSEGV originating from within the memory of instance1 - instance2 - .borrow_mut() - .set_signal_handler(move |signum, siginfo, _| { - handle_sigsegv(base1, length1, signum, siginfo) - }); + instance2.set_signal_handler(move |signum, siginfo, _| { + handle_sigsegv(base1, length1, signum, siginfo) + }); println!("calling instance2.run"); - let result = invoke_export(&instance2, &data2, "run").expect("instance2.run succeeded"); - assert_eq!("123", result[0].clone().to_string()); + let result = invoke_export(&instance2, "run")?; + assert_eq!(123, result[0].unwrap_i32()); + Ok(()) } } diff --git a/tests/custom_signal_handler.wasm b/tests/custom_signal_handler.wasm deleted file mode 100644 index 9348e1a61e..0000000000 Binary files a/tests/custom_signal_handler.wasm and /dev/null differ diff --git a/tests/custom_signal_handler.wat b/tests/custom_signal_handler.wat deleted file mode 100644 index e80533f7e4..0000000000 --- a/tests/custom_signal_handler.wat +++ /dev/null @@ -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) -) diff --git a/tests/custom_signal_handler_2.wasm b/tests/custom_signal_handler_2.wasm deleted file mode 100644 index f0c4da5ae9..0000000000 Binary files a/tests/custom_signal_handler_2.wasm and /dev/null differ diff --git a/tests/custom_signal_handler_2.wat b/tests/custom_signal_handler_2.wat deleted file mode 100644 index a93c5db8d0..0000000000 --- a/tests/custom_signal_handler_2.wat +++ /dev/null @@ -1,5 +0,0 @@ -(module - (import "other_module" "read" (func $other_module.read (result i32))) - (func $run (export "run") (result i32) - call $other_module.read) -) diff --git a/tests/spec_testsuite b/tests/spec_testsuite index ab59e3a7cb..c70c3c8b13 160000 --- a/tests/spec_testsuite +++ b/tests/spec_testsuite @@ -1 +1 @@ -Subproject commit ab59e3a7cb039f9a50d4e24da7634dd4dd472ce3 +Subproject commit c70c3c8b136e5e7193135d40ec3960f4ef1cb20a diff --git a/tests/wast_testsuites.rs b/tests/wast_testsuites.rs index 877c59ccfc..02734add70 100644 --- a/tests/wast_testsuites.rs +++ b/tests/wast_testsuites.rs @@ -10,8 +10,11 @@ include!(concat!(env!("OUT_DIR"), "/wast_testsuite_tests.rs")); fn run_wast(wast: &str, strategy: Strategy) -> anyhow::Result<()> { let wast = Path::new(wast); + let simd = wast.iter().any(|s| s == "simd"); + let mut cfg = Config::new(); - cfg.wasm_simd(wast.iter().any(|s| s == "simd")) + cfg.wasm_simd(simd) + .wasm_reference_types(simd) // some simd tests assume multiple tables ok .wasm_multi_value(wast.iter().any(|s| s == "multi-value")) .strategy(strategy)? .cranelift_debug_verifier(true);