diff --git a/Cargo.lock b/Cargo.lock index 9328944bd83..9003a06b829 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,6 +37,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "android_system_properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e" +dependencies = [ + "libc", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -48,9 +57,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.60" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142" +checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305" [[package]] name = "arbitrary" @@ -81,7 +90,7 @@ checksum = "c98233c6673d8601ab23e77eb38f999c51100d46c5703b17288c57fddf3a1ffe" dependencies = [ "bstr", "doc-comment", - "predicates 2.1.1", + "predicates", "predicates-core", "predicates-tree", "wait-timeout", @@ -215,9 +224,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.10.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" [[package]] name = "bytecheck" @@ -270,7 +279,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6358dedf60f4d9b8db43ad187391afe959746101346fe51bb978126bec61dfb" dependencies = [ - "clap 3.2.16", + "clap 3.2.17", "heck", "indexmap", "log", @@ -312,10 +321,11 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6127248204b9aba09a362f6c930ef6a78f2c1b2215f8a7b398c06e1083f17af0" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" dependencies = [ + "iana-time-zone", "js-sys", "num-integer", "num-traits", @@ -351,9 +361,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.16" +version = "3.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3dbbb6653e7c55cc8595ad3e1f7be8f32aba4eb7ff7f0fd1163d4f3d137c0a9" +checksum = "29e724a68d9319343bb3328c9cc2dfde263f4b3142ee1059a9980580171c954b" dependencies = [ "atty", "bitflags", @@ -368,9 +378,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.2.15" +version = "3.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba52acd3b0a5c33aeada5cdaa3267cdc7c594a98731d4268cdc1532f4264cb4" +checksum = "13547f7012c01ab4a0e8f8967730ada8f9fdf419e8b6c792788f39cf4e46eefa" dependencies = [ "heck", "proc-macro-error", @@ -474,6 +484,18 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "cooked-waker" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f" + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + [[package]] name = "corosensei" version = "0.1.3" @@ -487,6 +509,15 @@ dependencies = [ "windows-sys 0.33.0", ] +[[package]] +name = "cpufeatures" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc948ebb96241bb40ab73effeb80d9f93afaad49359d159a5e61be51619fe813" +dependencies = [ + "libc", +] + [[package]] name = "cranelift-bforest" version = "0.86.1" @@ -755,12 +786,6 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" -[[package]] -name = "difference" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" - [[package]] name = "difflib" version = "0.4.0" @@ -871,9 +896,9 @@ dependencies = [ [[package]] name = "either" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "enum-iterator" @@ -987,9 +1012,9 @@ dependencies = [ [[package]] name = "float-cmp" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" dependencies = [ "num-traits", ] @@ -1162,6 +1187,19 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "iana-time-zone" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad2bfd338099682614d3ee3fe0cd72e0b6a41ca6a87f6a74a3bd593c91650501" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "js-sys", + "wasm-bindgen", + "winapi", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1207,15 +1245,15 @@ dependencies = [ [[package]] name = "inline-c" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b370741c5913d9b3765d280493b9b97658818410fd64cbf6e8d333b42a1049e" +checksum = "340dd3d6102fa919bd20987024a6d84954c36ec691ac1efea37742ee983c8dd5" dependencies = [ "assert_cmd", "cc", "inline-c-macro", "lazy_static", - "predicates 1.0.8", + "predicates", "regex", "rustc_version 0.3.3", "target-lexicon 0.11.2", @@ -1302,9 +1340,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.127" +version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" [[package]] name = "libfuzzer-sys" @@ -1368,6 +1406,15 @@ dependencies = [ "libc", ] +[[package]] +name = "matchers" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" +dependencies = [ + "regex-automata", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1385,9 +1432,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap2" -version = "0.5.5" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a79b39c93a7a5a27eeaf9a23b5ff43f1b9e0ad6b1cdd441140ae53c35613fc7" +checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498" dependencies = [ "libc", ] @@ -1541,9 +1588,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" [[package]] name = "oorandom" @@ -1568,9 +1615,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.2.0" +version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4" +checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" [[package]] name = "output_vt100" @@ -1620,9 +1667,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pest" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69486e2b8c2d2aeb9762db7b4e00b0331156393555cff467f4163ff06821eef8" +checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4" dependencies = [ "thiserror", "ucd-trie", @@ -1642,9 +1689,9 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "plotters" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9428003b84df1496fb9d6eeee9c5f8145cb41ca375eb0dad204328888832811f" +checksum = "716b4eeb6c4a1d3ecc956f75b43ec2e8e8ba80026413e70a3f41fd3313d3492b" dependencies = [ "num-traits", "plotters-backend", @@ -1661,9 +1708,9 @@ checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" [[package]] name = "plotters-svg" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0918736323d1baff32ee0eade54984f6f201ad7e97d5cfb5d6ab4a358529615" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" dependencies = [ "plotters-backend", ] @@ -1674,19 +1721,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" -[[package]] -name = "predicates" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49cfaf7fdaa3bfacc6fa3e7054e65148878354a5cfddcf661df4c851f8021df" -dependencies = [ - "difference", - "float-cmp", - "normalize-line-endings", - "predicates-core", - "regex", -] - [[package]] name = "predicates" version = "2.1.1" @@ -1694,8 +1728,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c" dependencies = [ "difflib", + "float-cmp", "itertools", + "normalize-line-endings", "predicates-core", + "regex", ] [[package]] @@ -2181,9 +2218,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.142" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e590c437916fb6b221e1d00df6e3294f3fccd70ca7e92541c475d6ed6ef5fee2" +checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" dependencies = [ "serde_derive", ] @@ -2209,9 +2246,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.142" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34b5b8d809babe02f538c2cfec6f2c1ed10804c0e5a6a041a049a4f5588ccc2e" +checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" dependencies = [ "proc-macro2", "quote", @@ -2220,9 +2257,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.83" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ "itoa 1.0.3", "ryu", @@ -2266,6 +2303,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -2617,6 +2665,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "ansi_term", + "chrono", + "lazy_static", + "matchers 0.0.1", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", ] [[package]] @@ -2625,7 +2717,7 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b" dependencies = [ - "matchers", + "matchers 0.1.0", "once_cell", "regex", "sharded-slab", @@ -2641,7 +2733,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" dependencies = [ "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.15", "wasm-bindgen", ] @@ -2729,6 +2821,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vec_map" version = "0.8.2" @@ -2756,6 +2854,12 @@ dependencies = [ "libc", ] +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + [[package]] name = "walkdir" version = "2.3.2" @@ -2886,9 +2990,9 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8905fd25fdadeb0e7e8bf43a9f46f9f972d6291ad0c7a32573b88dd13a6cfa6b" +checksum = "d443c5a7daae71697d97ec12ad70b4fe8766d3a0f4db16158ac8b781365892f7" dependencies = [ "leb128", ] @@ -2910,6 +3014,7 @@ name = "wasmer" version = "3.0.0-beta" dependencies = [ "anyhow", + "bytes", "cfg-if 1.0.0", "hashbrown 0.11.2", "indexmap", @@ -2996,7 +3101,7 @@ dependencies = [ "atty", "bytesize", "cfg-if 1.0.0", - "clap 3.2.16", + "clap 3.2.17", "colored 2.0.0", "dirs", "distance", @@ -3057,7 +3162,7 @@ dependencies = [ "atty", "bytesize", "cfg-if 1.0.0", - "clap 3.2.16", + "clap 3.2.17", "colored 2.0.0", "distance", "fern", @@ -3194,6 +3299,7 @@ dependencies = [ "enum-iterator", "enumset", "indexmap", + "memoffset", "more-asserts", "rkyv", "serde", @@ -3270,15 +3376,20 @@ dependencies = [ "bytes", "cfg-if 1.0.0", "chrono", + "cooked-waker", "derivative", "generational-arena", "getrandom", + "lazy_static", "libc", "serde", + "sha2", "thiserror", "tracing", + "tracing-subscriber 0.2.25", "tracing-wasm", "typetag", + "waker-fn", "wasm-bindgen", "wasm-bindgen-test", "wasmer", @@ -3355,7 +3466,7 @@ dependencies = [ "test-generator", "test-log", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.15", "wasi-test-generator", "wasmer", "wasmer-cache", @@ -3378,21 +3489,21 @@ checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" [[package]] name = "wasmparser" -version = "0.88.0" +version = "0.89.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb8cf7dd82407fe68161bedcd57fde15596f32ebf6e9b3bdbf3ae1da20e38e5e" +checksum = "ab5d3e08b13876f96dd55608d03cd4883a0545884932d5adf11925876c96daef" dependencies = [ "indexmap", ] [[package]] name = "wasmprinter" -version = "0.2.38" +version = "0.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f2786f19a25211ddfa331e28b7579a6d6880f5f4b18d21253cd90274aa4c21" +checksum = "aa9e5ee2f56cc8a5da489558114e8c118e5a8416d96aefe63dcf1b5b05b858c6" dependencies = [ "anyhow", - "wasmparser 0.88.0", + "wasmparser 0.89.1", ] [[package]] @@ -3415,23 +3526,23 @@ dependencies = [ [[package]] name = "wast" -version = "45.0.0" +version = "46.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186c474c4f9bb92756b566d592a16591b4526b1a4841171caa3f31d7fe330d96" +checksum = "ea0ab19660e3ea6891bba69167b9be40fad00fb1fe3dd39c5eebcee15607131b" dependencies = [ "leb128", "memchr", "unicode-width", - "wasm-encoder 0.15.0", + "wasm-encoder 0.16.0", ] [[package]] name = "wat" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2d4bc4724b4f02a482c8cab053dac5ef26410f264c06ce914958f9a42813556" +checksum = "8f775282def4d5bffd94d60d6ecd57bfe6faa46171cdbf8d32bd5458842b1e3e" dependencies = [ - "wast 45.0.0", + "wast 46.0.0", ] [[package]] @@ -3661,9 +3772,9 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "x11-dl" -version = "2.19.1" +version = "2.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" +checksum = "0c83627bc137605acc00bb399c7b908ef460b621fc37c953db2b09f88c449ea6" dependencies = [ "lazy_static", "libc", diff --git a/docs/migration_to_3.0.0.md b/docs/migration_to_3.0.0.md index 2a87147af62..d780749593f 100644 --- a/docs/migration_to_3.0.0.md +++ b/docs/migration_to_3.0.0.md @@ -139,14 +139,13 @@ import_object.define("env", "host_function", host_function); let instance = Instance::new(&mut store, &module, &import_object).expect("Could not instantiate module."); ``` -For WASI, don't forget to import memory to `WasiEnv` +For WASI, don't forget to initialize it ```rust let mut wasi_env = WasiState::new("hello").finalize()?; let import_object = wasi_env.import_object(&mut store, &module)?; let instance = Instance::new(&mut store, &module, &import_object).expect("Could not instantiate module."); -let memory = instance.exports.get_memory("memory")?; -wasi_env.data_mut(&mut store).set_memory(memory.clone()); +wasi_env.initialize(&mut store, &instance).unwrap(); ``` #### `ChainableNamedResolver` is removed diff --git a/examples/imports_function_env.rs b/examples/imports_function_env.rs index dc870625e69..0b235f93f49 100644 --- a/examples/imports_function_env.rs +++ b/examples/imports_function_env.rs @@ -80,8 +80,8 @@ fn main() -> Result<(), Box> { fn get_counter(env: FunctionEnvMut) -> i32 { *env.data().counter.lock().unwrap() } - fn add_to_counter(mut env: FunctionEnvMut, add: i32) -> i32 { - let mut counter_ref = env.data_mut().counter.lock().unwrap(); + fn add_to_counter(env: FunctionEnvMut, add: i32) -> i32 { + let mut counter_ref = env.data().counter.lock().unwrap(); *counter_ref += add; *counter_ref diff --git a/examples/wasi.rs b/examples/wasi.rs index e3232061148..b8880b5d5a5 100644 --- a/examples/wasi.rs +++ b/examples/wasi.rs @@ -39,7 +39,7 @@ fn main() -> Result<(), Box> { println!("Creating `WasiEnv`..."); // First, we create the `WasiEnv` - let wasi_env = WasiState::new("hello") + let mut wasi_env = WasiState::new("hello") // .args(&["world"]) // .env("KEY", "Value") .finalize(&mut store)?; @@ -50,10 +50,9 @@ fn main() -> Result<(), Box> { let import_object = wasi_env.import_object(&mut store, &module)?; let instance = Instance::new(&mut store, &module, &import_object)?; - println!("Attach WASI memory..."); - // Attach the memory export - let memory = instance.exports.get_memory("memory")?; - wasi_env.data_mut(&mut store).set_memory(memory.clone()); + println!("Initializing WASI environment..."); + // Initialize the WASI environment (which will attach memory) + wasi_env.initialize(&mut store, &instance).unwrap(); println!("Call WASI `_start` function..."); // And we just call the `_start` function! diff --git a/examples/wasi_pipes.rs b/examples/wasi_pipes.rs index ed7ef03a075..8f1c41c2614 100644 --- a/examples/wasi_pipes.rs +++ b/examples/wasi_pipes.rs @@ -49,10 +49,9 @@ fn main() -> Result<(), Box> { let import_object = wasi_env.import_object(&mut store, &module)?; let instance = Instance::new(&mut store, &module, &import_object)?; - println!("Attach WASI memory..."); - // Attach the memory export - let memory = instance.exports.get_memory("memory")?; - wasi_env.data_mut(&mut store).set_memory(memory.clone()); + println!("Initializing WASI environment..."); + // Initialize the WASI environment (which will attach memory) + wasi_env.initialize(&mut store, &instance).unwrap(); let msg = "racecar go zoom"; println!("Writing \"{}\" to the WASI stdin...", msg); diff --git a/lib/api/Cargo.toml b/lib/api/Cargo.toml index 36a6fb7eaa3..9bcb2c9b0a1 100644 --- a/lib/api/Cargo.toml +++ b/lib/api/Cargo.toml @@ -26,6 +26,7 @@ indexmap = { version = "1.6" } cfg-if = "1.0" thiserror = "1.0" more-asserts = "0.2" +bytes = "1" # - Optional shared dependencies. wat = { version = "1.0", optional = true } tracing = { version = "0.1", optional = true } diff --git a/lib/api/src/js/export.rs b/lib/api/src/js/export.rs index f396e617c53..1f99ea3e276 100644 --- a/lib/api/src/js/export.rs +++ b/lib/api/src/js/export.rs @@ -7,6 +7,7 @@ use std::fmt; use wasm_bindgen::{JsCast, JsValue}; use wasmer_types::{ExternType, FunctionType, GlobalType, MemoryType, TableType}; +/// Represents linear memory that is managed by the javascript runtime #[derive(Clone, Debug, PartialEq)] pub struct VMMemory { pub(crate) memory: Memory, @@ -17,9 +18,15 @@ unsafe impl Send for VMMemory {} unsafe impl Sync for VMMemory {} impl VMMemory { - pub(crate) fn new(memory: Memory, ty: MemoryType) -> Self { + /// Creates a new memory directly from a WebAssembly javascript object + pub fn new(memory: Memory, ty: MemoryType) -> Self { Self { memory, ty } } + + /// Attempts to clone this memory (if its clonable) + pub(crate) fn try_clone(&self) -> Option { + Some(self.clone()) + } } #[derive(Clone, Debug, PartialEq)] diff --git a/lib/api/src/js/exports.rs b/lib/api/src/js/exports.rs index 024ab8b9696..339095bafa0 100644 --- a/lib/api/src/js/exports.rs +++ b/lib/api/src/js/exports.rs @@ -53,6 +53,9 @@ pub enum ExportError { /// This error arises when an export is missing #[error("Missing export {0}")] Missing(String), + /// This error arises when an export is missing + #[error("Serialization failed {0}")] + SerializationFailed(String), } /// Exports is a special kind of map that allows easily unwrapping diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index 6c5229ce92f..2b66d8ed79b 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -6,7 +6,6 @@ use crate::js::{MemoryAccessError, MemoryType}; use std::marker::PhantomData; use std::mem::MaybeUninit; use std::slice; -use thiserror::Error; #[cfg(feature = "tracing")] use tracing::warn; @@ -16,22 +15,7 @@ use wasmer_types::Pages; use super::MemoryView; -/// Error type describing things that can go wrong when operating on Wasm Memories. -#[derive(Error, Debug, Clone, PartialEq, Hash)] -pub enum MemoryError { - /// The operation would cause the size of the memory to exceed the maximum or would cause - /// an overflow leading to unindexable memory. - #[error("The memory could not grow: current size {} pages, requested increase: {} pages", current.0, attempted_delta.0)] - CouldNotGrow { - /// The current size in pages. - current: Pages, - /// The attempted amount to grow by in pages. - attempted_delta: Pages, - }, - /// A user defined error value, used for error cases not listed above. - #[error("A user-defined error occurred: {0}")] - Generic(String), -} +pub use wasmer_types::MemoryError; #[wasm_bindgen] extern "C" { @@ -116,6 +100,17 @@ impl Memory { Ok(Self::from_vm_export(store, vm_memory)) } + /// Creates a new host `Memory` from provided JavaScript memory. + pub fn new_raw(store: &mut impl AsStoreMut, js_memory: js_sys::WebAssembly::Memory, ty: MemoryType) -> Result { + let vm_memory = VMMemory::new(js_memory, ty); + Ok(Self::from_vm_export(store, vm_memory)) + } + + /// Create a memory object from an existing memory and attaches it to the store + pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self { + Self::from_vm_export(new_store, memory) + } + /// Returns the [`MemoryType`] of the `Memory`. /// /// # Example @@ -210,6 +205,12 @@ impl Memory { } } + /// Attempts to clone this memory (if its clonable) + pub fn try_clone(&self, store: &impl AsStoreRef) -> Option { + let mem = self.handle.get(store.as_store_ref().objects()); + mem.try_clone() + } + /// Checks whether this `Global` can be used with the given context. pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { self.handle.store_id() == store.as_store_ref().objects().id() diff --git a/lib/api/src/js/function_env.rs b/lib/api/src/js/function_env.rs index 1705f1a4713..524fc7a2dbe 100644 --- a/lib/api/src/js/function_env.rs +++ b/lib/api/src/js/function_env.rs @@ -36,7 +36,7 @@ impl FunctionEnv { } /// Get the data as reference - pub fn as_ref<'a>(&self, store: &'a impl AsStoreMut) -> &'a T + pub fn as_ref<'a>(&self, store: &'a impl AsStoreRef) -> &'a T where T: Any + Send + 'static + Sized, { @@ -112,6 +112,11 @@ impl FunctionEnvMut<'_, T> { self.func_env.as_mut(&mut self.store_mut) } + /// Borrows a new immmutable reference + pub fn as_ref(&self) -> FunctionEnv { + self.func_env.clone() + } + /// Borrows a new mutable reference pub fn as_mut<'a>(&'a mut self) -> FunctionEnvMut<'a, T> { FunctionEnvMut { diff --git a/lib/api/src/js/imports.rs b/lib/api/src/js/imports.rs index 95a9930995c..d3b2c42efa5 100644 --- a/lib/api/src/js/imports.rs +++ b/lib/api/src/js/imports.rs @@ -174,6 +174,36 @@ impl Imports { } imports } + + /// Iterates through all the imports in this structure + pub fn iter<'a>(&'a self) -> ImportsIterator<'a> { + ImportsIterator::new(self) + } +} + +pub struct ImportsIterator<'a> { + iter: std::collections::hash_map::Iter<'a, (String, String), Extern> +} + +impl<'a> ImportsIterator<'a> +{ + fn new(imports: &'a Imports) -> Self { + let iter = imports.map.iter(); + Self { iter } + } +} + +impl<'a> Iterator +for ImportsIterator<'a> { + type Item = (&'a str, &'a str, &'a Extern); + + fn next(&mut self) -> Option { + self.iter + .next() + .map(|(k, v)| { + (k.0.as_str(), k.1.as_str(), v) + }) + } } impl IntoIterator for &Imports { diff --git a/lib/api/src/js/instance.rs b/lib/api/src/js/instance.rs index 6d2762adf66..fb849743a28 100644 --- a/lib/api/src/js/instance.rs +++ b/lib/api/src/js/instance.rs @@ -20,8 +20,6 @@ use std::fmt; pub struct Instance { _handle: StoreHandle, module: Module, - #[allow(dead_code)] - imports: Imports, /// The exports for an instance. pub exports: Exports, } @@ -65,12 +63,11 @@ impl Instance { module: &Module, imports: &Imports, ) -> Result { - let import_copy = imports.clone(); - let (instance, _imports): (StoreHandle, Vec) = module + let (instance, externs): (StoreHandle, Vec) = module .instantiate(&mut store, imports) .map_err(|e| InstantiationError::Start(e))?; - let self_instance = Self::from_module_and_instance(store, module, instance, import_copy)?; + let self_instance = Self::from_module_and_instance(store, module, externs, instance)?; //self_instance.init_envs(&imports.iter().map(Extern::to_export).collect::>())?; Ok(self_instance) } @@ -87,11 +84,11 @@ impl Instance { pub fn from_module_and_instance( mut store: &mut impl AsStoreMut, module: &Module, + externs: Vec, instance: StoreHandle, - imports: Imports, ) -> Result { let instance_exports = instance.get(store.as_store_ref().objects()).exports(); - let exports = module + let mut exports = module .exports() .map(|export_type| { let name = export_type.name(); @@ -110,10 +107,17 @@ impl Instance { }) .collect::>()?; + // If the memory is imported then also export it for backwards compatibility reasons + // (many will assume the memory is always exported) - later we can remove this + if exports.get_memory("memory").is_err() { + if let Some(memory) = externs.iter().filter(|a| a.ty(store).memory().is_some()).next() { + exports.insert("memory", memory.clone()); + } + } + Ok(Self { _handle: instance, module: module.clone(), - imports, exports, }) } diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index 14594839a15..a88509086e0 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -73,6 +73,12 @@ pub use crate::js::types::{ pub use crate::js::value::Value; pub use crate::js::value::Value as Val; +pub mod vm { + //! The `vm` module re-exports wasmer-vm types. + + pub use crate::js::export::VMMemory; +} + pub use wasmer_types::is_wasm; pub use wasmer_types::{ Bytes, ExportIndex, GlobalInit, LocalFunctionIndex, Pages, ValueType, WASM_MAX_PAGES, diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 975d1bee5d5..26972fc24f5 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -13,6 +13,8 @@ use js_sys::{Reflect, Uint8Array, WebAssembly}; use std::fmt; use std::io; use std::path::Path; +#[cfg(feature = "js-serializable-module")] +use bytes::Bytes; #[cfg(feature = "std")] use thiserror::Error; use wasm_bindgen::JsValue; @@ -20,6 +22,8 @@ use wasmer_types::{ ExportsIterator, ExternType, FunctionType, GlobalType, ImportsIterator, MemoryType, Mutability, Pages, TableType, Type, }; +#[cfg(feature = "tracing")] +use tracing::{debug, warn}; #[derive(Debug)] #[cfg_attr(feature = "std", derive(Error))] @@ -64,7 +68,33 @@ pub struct Module { // WebAssembly type hints type_hints: Option, #[cfg(feature = "js-serializable-module")] - raw_bytes: Option>, + raw_bytes: Option, +} + +pub trait IntoBytes +{ + fn into_bytes(self) -> Bytes; +} + +impl IntoBytes +for Bytes { + fn into_bytes(self) -> Bytes { + self + } +} + +impl IntoBytes +for Vec { + fn into_bytes(self) -> Bytes { + Bytes::from(self) + } +} + +impl IntoBytes +for &[u8] { + fn into_bytes(self) -> Bytes { + Bytes::from(self.to_vec()) + } } impl Module { @@ -128,15 +158,19 @@ impl Module { /// # } /// ``` #[allow(unreachable_code)] - pub fn new(_store: &impl AsStoreRef, bytes: impl AsRef<[u8]>) -> Result { + pub fn new(_store: &impl AsStoreRef, bytes: impl IntoBytes) -> Result { + let mut bytes = bytes.into_bytes(); #[cfg(feature = "wat")] - let bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| { - CompileError::Wasm(WasmError::Generic(format!( - "Error when converting wat: {}", - e - ))) - })?; - Self::from_binary(_store, bytes.as_ref()) + if bytes.starts_with(b"\0asm") == false { + let parsed_bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| { + CompileError::Wasm(WasmError::Generic(format!( + "Error when converting wat: {}", + e + ))) + })?; + bytes = Bytes::from(parsed_bytes.to_vec()); + } + Self::from_binary(_store, bytes) } /// Creates a new WebAssembly module from a file path. @@ -152,7 +186,8 @@ impl Module { /// Opposed to [`Module::new`], this function is not compatible with /// the WebAssembly text format (if the "wat" feature is enabled for /// this crate). - pub fn from_binary(_store: &impl AsStoreRef, binary: &[u8]) -> Result { + pub fn from_binary(_store: &impl AsStoreRef, binary: impl IntoBytes) -> Result { + let binary = binary.into_bytes(); // // Self::validate(store, binary)?; unsafe { Self::from_binary_unchecked(_store, binary) } @@ -165,16 +200,28 @@ impl Module { /// This is safe since the JS vm should be safe already. /// We maintain the `unsafe` to preserve the same API as Wasmer pub unsafe fn from_binary_unchecked( - _store: &impl AsStoreRef, - binary: &[u8], + store: &impl AsStoreRef, + binary: impl IntoBytes, ) -> Result { - let js_bytes = Uint8Array::view(binary); + let binary = binary.into_bytes(); + let js_bytes = Uint8Array::view(&binary[..]); let module = WebAssembly::Module::new(&js_bytes.into()).unwrap(); + Self::from_js_module(store, module, Bytes::from(binary)) + } + + /// Creates a new WebAssembly module skipping any kind of validation from a javascript module + /// + pub unsafe fn from_js_module( + _store: &impl AsStoreRef, + module: WebAssembly::Module, + binary: impl IntoBytes, + ) -> Result { + let binary = binary.into_bytes(); // The module is now validated, so we can safely parse it's types #[cfg(feature = "wasm-types-polyfill")] let (type_hints, name) = { - let info = crate::js::module_info_polyfill::translate_module(binary).unwrap(); + let info = crate::js::module_info_polyfill::translate_module(&binary[..]).unwrap(); ( Some(ModuleTypeHints { @@ -200,7 +247,7 @@ impl Module { type_hints, name, #[cfg(feature = "js-serializable-module")] - raw_bytes: Some(binary.to_vec()), + raw_bytes: Some(binary), }) } @@ -210,8 +257,9 @@ impl Module { /// This validation is normally pretty fast and checks the enabled /// WebAssembly features in the Store Engine to assure deterministic /// validation of the Module. - pub fn validate(_store: &impl AsStoreRef, binary: &[u8]) -> Result<(), CompileError> { - let js_bytes = unsafe { Uint8Array::view(binary) }; + pub fn validate(_store: &impl AsStoreRef, binary: impl IntoBytes) -> Result<(), CompileError> { + let binary = binary.into_bytes(); + let js_bytes = unsafe { Uint8Array::view(&binary[..]) }; match WebAssembly::validate(&js_bytes.into()) { Ok(true) => Ok(()), _ => Err(CompileError::Validate("Invalid Wasm file".to_owned())), @@ -236,6 +284,21 @@ impl Module { let mut import_externs: Vec = vec![]; for import_type in self.imports() { let resolved_import = imports.get_export(import_type.module(), import_type.name()); + #[allow(unused_variables)] + if let wasmer_types::ExternType::Memory(mem_ty) = import_type.ty() { + if resolved_import.is_some() { + #[cfg(feature = "tracing")] + debug!("imported shared memory {:?}", &mem_ty); + } else { + #[cfg(feature = "tracing")] + warn!( + "Error while importing {0:?}.{1:?}: memory. Expected {2:?}", + import_type.module(), + import_type.name(), + import_type.ty(), + ); + } + } if let Some(import) = resolved_import { let val = js_sys::Reflect::get(&imports_object, &import_type.module().into())?; if !val.is_undefined() { @@ -260,6 +323,9 @@ impl Module { )?; } import_externs.push(import); + } else { + #[cfg(feature = "tracing")] + warn!("import not found {}:{}", import_type.module(), import_type.name()); } // in case the import is not found, the JS Wasm VM will handle // the error for us, so we don't need to handle it @@ -300,7 +366,7 @@ impl Module { /// can later process via [`Module::deserialize`]. /// #[cfg(feature = "js-serializable-module")] - pub fn serialize(&self) -> Result, SerializeError> { + pub fn serialize(&self) -> Result { self.raw_bytes.clone().ok_or(SerializeError::Generic( "Not able to serialize module".to_string(), )) @@ -313,8 +379,9 @@ impl Module { #[cfg(feature = "js-serializable-module")] pub unsafe fn deserialize( _store: &impl AsStoreRef, - bytes: &[u8], + bytes: impl IntoBytes, ) -> Result { + let bytes = bytes.into_bytes(); Self::new(_store, bytes).map_err(|e| DeserializeError::Compiler(e)) } @@ -383,7 +450,8 @@ impl Module { let imports = WebAssembly::Module::imports(&self.module); let iter = imports .iter() - .map(move |val| { + .enumerate() + .map(move |(i, val)| { let module = Reflect::get(val.as_ref(), &"module".into()) .unwrap() .as_string() @@ -396,24 +464,34 @@ impl Module { .unwrap() .as_string() .unwrap(); - let extern_type = match kind.as_str() { - "function" => { - let func_type = FunctionType::new(vec![], vec![]); - ExternType::Function(func_type) - } - "global" => { - let global_type = GlobalType::new(Type::I32, Mutability::Const); - ExternType::Global(global_type) - } - "memory" => { - let memory_type = MemoryType::new(Pages(1), None, false); - ExternType::Memory(memory_type) - } - "table" => { - let table_type = TableType::new(Type::FuncRef, 1, None); - ExternType::Table(table_type) + let type_hint = self + .type_hints + .as_ref() + .map(|hints| hints.imports.get(i).unwrap().clone()); + let extern_type = if let Some(hint) = type_hint { + hint + } else { + match kind.as_str() { + "function" => { + let func_type = FunctionType::new(vec![], vec![]); + ExternType::Function(func_type) + } + "global" => { + let global_type = GlobalType::new(Type::I32, Mutability::Const); + ExternType::Global(global_type) + } + "memory" => { + // The javascript API does not yet expose these properties so without + // the type_hints we don't know what memory to import. + let memory_type = MemoryType::new(Pages(1), None, false); + ExternType::Memory(memory_type) + } + "table" => { + let table_type = TableType::new(Type::FuncRef, 1, None); + ExternType::Table(table_type) + } + _ => unimplemented!(), } - _ => unimplemented!(), }; ImportType::new(&module, &field, extern_type) }) @@ -525,6 +603,16 @@ impl Module { ExportsIterator::new(iter, exports.length() as usize) } + /// Returns true if the module is still ok - this will be + /// false if the module was passed between threads in a + /// way that it became undefined (JS does not share objects + /// between threads except via a post_message()) + pub fn is_ok(&self) -> bool { + let val = JsValue::from(&self.module); + !val.is_undefined() && + !val.is_null() + } + // /// Get the custom sections of the module given a `name`. // /// // /// # Important diff --git a/lib/api/src/js/native.rs b/lib/api/src/js/native.rs index 0e9066edac8..69b350652a1 100644 --- a/lib/api/src/js/native.rs +++ b/lib/api/src/js/native.rs @@ -11,7 +11,6 @@ use std::marker::PhantomData; use crate::js::externals::Function; use crate::js::store::{AsStoreMut, AsStoreRef, StoreHandle}; -use crate::js::FunctionEnv; use crate::js::{FromToNativeWasmType, RuntimeError, WasmTypeList}; // use std::panic::{catch_unwind, AssertUnwindSafe}; use crate::js::export::VMFunction; diff --git a/lib/api/src/js/store.rs b/lib/api/src/js/store.rs index b6c10e84627..a14a663d963 100644 --- a/lib/api/src/js/store.rs +++ b/lib/api/src/js/store.rs @@ -263,6 +263,11 @@ mod objects { self.id } + /// Sets the ID of this store + pub fn set_id(&mut self, id: StoreId) { + self.id = id; + } + /// Returns a pair of mutable references from two handles. /// /// Panics if both handles point to the same object. @@ -441,6 +446,7 @@ mod objects { Instance(NonNull), } + #[allow(dead_code)] impl MaybeInstanceOwned { /// Returns underlying pointer to the VM data. #[allow(dead_code)] diff --git a/lib/api/src/js/wasm_bindgen_polyfill.rs b/lib/api/src/js/wasm_bindgen_polyfill.rs index 1b5dad63a12..80f89a6a702 100644 --- a/lib/api/src/js/wasm_bindgen_polyfill.rs +++ b/lib/api/src/js/wasm_bindgen_polyfill.rs @@ -16,6 +16,7 @@ extern "C" { /// of the given type and value. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Global) + #[allow(unused_doc_comments)] #[wasm_bindgen(constructor, js_namespace = WebAssembly, catch)] pub fn new(global_descriptor: &Object, value: &JsValue) -> Result; @@ -23,6 +24,7 @@ extern "C" { /// returns the value of the global. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Global) + #[allow(unused_doc_comments)] #[wasm_bindgen(method, getter, structural, js_namespace = WebAssembly)] pub fn value(this: &Global) -> JsValue; diff --git a/lib/api/src/sys/exports.rs b/lib/api/src/sys/exports.rs index f744a21c61d..0141f8cd9ea 100644 --- a/lib/api/src/sys/exports.rs +++ b/lib/api/src/sys/exports.rs @@ -57,6 +57,9 @@ pub enum ExportError { /// This error arises when an export is missing #[error("Missing export {0}")] Missing(String), + /// This error arises when an export is missing + #[error("Serialization failed {0}")] + SerializationFailed(String), } /// Exports is a special kind of map that allows easily unwrapping @@ -183,18 +186,6 @@ impl Exports { } } - /// Like `get_with_generics` but with a WeakReference to the `InstanceRef` internally. - /// This is useful for passing data into Context data, for example. - pub fn get_with_generics_weak<'a, T, Args, Rets>(&'a self, name: &str) -> Result - where - Args: WasmTypeList, - Rets: WasmTypeList, - T: ExportableWithGenerics<'a, Args, Rets>, - { - let out: T = self.get_with_generics(name)?; - Ok(out) - } - /// Get an export as an `Extern`. pub fn get_extern(&self, name: &str) -> Option<&Extern> { self.map.get(name) diff --git a/lib/api/src/sys/externals/memory.rs b/lib/api/src/sys/externals/memory.rs index c0db55fa8af..64ab9a136e2 100644 --- a/lib/api/src/sys/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -10,7 +10,7 @@ use std::mem::MaybeUninit; use std::slice; #[cfg(feature = "tracing")] use tracing::warn; -use wasmer_types::Pages; +use wasmer_types::{Pages, LinearMemory}; use wasmer_vm::{InternalStoreHandle, MemoryError, StoreHandle, VMExtern, VMMemory}; use super::MemoryView; @@ -60,6 +60,13 @@ impl Memory { }) } + /// Create a memory object from an existing memory and attaches it to the store + pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self { + Self { + handle: StoreHandle::new(new_store.objects_mut(), memory) + } + } + /// Returns the [`MemoryType`] of the `Memory`. /// /// # Example @@ -142,6 +149,13 @@ impl Memory { self.handle.store_id() == store.as_store_ref().objects().id() } + /// Attempts to clone this memory (if its clonable) + pub fn try_clone(&self, store: &impl AsStoreRef) -> Option { + let mem = self.handle.get(store.as_store_ref().objects()); + mem.try_clone() + .map(|mem| mem.into()) + } + pub(crate) fn to_vm_extern(&self) -> VMExtern { VMExtern::Memory(self.handle.internal_handle()) } diff --git a/lib/api/src/sys/externals/memory_view.rs b/lib/api/src/sys/externals/memory_view.rs index 891700c0854..a638acb6b97 100644 --- a/lib/api/src/sys/externals/memory_view.rs +++ b/lib/api/src/sys/externals/memory_view.rs @@ -4,7 +4,7 @@ use std::convert::TryInto; use std::marker::PhantomData; use std::mem::MaybeUninit; use std::slice; -use wasmer_types::Pages; +use wasmer_types::{Pages, LinearMemory}; use super::memory::MemoryBuffer; use super::Memory; diff --git a/lib/api/src/sys/function_env.rs b/lib/api/src/sys/function_env.rs index deb5c0b4304..6ef7b48a3c9 100644 --- a/lib/api/src/sys/function_env.rs +++ b/lib/api/src/sys/function_env.rs @@ -29,7 +29,7 @@ impl FunctionEnv { } /// Get the data as reference - pub fn as_ref<'a>(&self, store: &'a impl AsStoreMut) -> &'a T + pub fn as_ref<'a>(&self, store: &'a impl AsStoreRef) -> &'a T where T: Any + Send + 'static + Sized, { @@ -105,6 +105,11 @@ impl FunctionEnvMut<'_, T> { self.func_env.as_mut(&mut self.store_mut) } + /// Borrows a new immmutable reference + pub fn as_ref(&self) -> FunctionEnv { + self.func_env.clone() + } + /// Borrows a new mutable reference pub fn as_mut(&mut self) -> FunctionEnvMut<'_, T> { FunctionEnvMut { diff --git a/lib/api/src/sys/imports.rs b/lib/api/src/sys/imports.rs index c9a9f22b917..82d44eb78da 100644 --- a/lib/api/src/sys/imports.rs +++ b/lib/api/src/sys/imports.rs @@ -1,11 +1,12 @@ //! The import module contains the implementation data structures and helper functions used to //! manipulate and access a wasm module's imports including memories, tables, globals, and //! functions. -use crate::{Exports, Extern, Module}; +use crate::{Exports, Extern, Module, AsStoreMut, Memory}; use std::collections::HashMap; use std::fmt; use wasmer_compiler::LinkError; use wasmer_types::ImportError; +use wasmer_vm::VMSharedMemory; /// All of the import data used when instantiating. /// @@ -111,6 +112,32 @@ impl Imports { .insert((ns.to_string(), name.to_string()), val.into()); } + /// Imports (any) shared memory into the imports. + /// (if the module does not import memory then this function is ignored) + pub fn import_shared_memory(&mut self, module: &Module, store: &mut impl AsStoreMut) -> Option { + // Determine if shared memory needs to be created and imported + let shared_memory = module + .imports() + .memories() + .next() + .map(|a| *a.ty()) + .map(|ty| { + let style = store + .as_store_ref() + .tunables() + .memory_style(&ty); + VMSharedMemory::new(&ty, &style) + .unwrap() + }); + + if let Some(memory) = shared_memory { + self.define("env", "memory", Memory::new_from_existing(store, memory.clone().into())); + Some(memory) + } else { + None + } + } + /// Returns the contents of a namespace as an `Exports`. /// /// Returns `None` if the namespace doesn't exist. @@ -149,6 +176,36 @@ impl Imports { } Ok(ret) } + + /// Iterates through all the imports in this structure + pub fn iter<'a>(&'a self) -> ImportsIterator<'a> { + ImportsIterator::new(self) + } +} + +pub struct ImportsIterator<'a> { + iter: std::collections::hash_map::Iter<'a, (String, String), Extern> +} + +impl<'a> ImportsIterator<'a> +{ + fn new(imports: &'a Imports) -> Self { + let iter = imports.map.iter(); + Self { iter } + } +} + +impl<'a> Iterator +for ImportsIterator<'a> { + type Item = (&'a str, &'a str, &'a Extern); + + fn next(&mut self) -> Option { + self.iter + .next() + .map(|(k, v)| { + (k.0.as_str(), k.1.as_str(), v) + }) + } } impl IntoIterator for &Imports { diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index ab8e9d5c293..3cc967530ac 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -115,11 +115,11 @@ impl Instance { module: &Module, imports: &Imports, ) -> Result { - let imports = imports + let externs = imports .imports_for_module(module) .map_err(InstantiationError::Link)?; - let mut handle = module.instantiate(store, &imports)?; - let exports = module + let mut handle = module.instantiate(store, &externs)?; + let mut exports = module .exports() .map(|export| { let name = export.name().to_string(); @@ -128,6 +128,14 @@ impl Instance { (name, extern_) }) .collect::(); + + // If the memory is imported then also export it for backwards compatibility reasons + // (many will assume the memory is always exported) - later we can remove this + if exports.get_memory("memory").is_err() { + if let Some(memory) = externs.iter().filter(|a| a.ty(store).memory().is_some()).next() { + exports.insert("memory", memory.clone()); + } + } let instance = Self { _handle: StoreHandle::new(store.objects_mut(), handle), @@ -154,9 +162,9 @@ impl Instance { module: &Module, externs: &[Extern], ) -> Result { - let imports = externs.to_vec(); - let mut handle = module.instantiate(store, &imports)?; - let exports = module + let externs = externs.to_vec(); + let mut handle = module.instantiate(store, &externs)?; + let mut exports = module .exports() .map(|export| { let name = export.name().to_string(); @@ -166,6 +174,14 @@ impl Instance { }) .collect::(); + // If the memory is imported then also export it for backwards compatibility reasons + // (many will assume the memory is always exported) - later we can remove this + if exports.get_memory("memory").is_err() { + if let Some(memory) = externs.iter().filter(|a| a.ty(store).memory().is_some()).next() { + exports.insert("memory", memory.clone()); + } + } + let instance = Self { _handle: StoreHandle::new(store.objects_mut(), handle), module: module.clone(), diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index 1c272a2a60e..e88c05b7a8c 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -58,7 +58,7 @@ pub mod vm { pub use wasmer_vm::{ MemoryError, MemoryStyle, TableStyle, VMExtern, VMMemory, VMMemoryDefinition, VMTable, - VMTableDefinition, + VMTableDefinition, VMOwnedMemory, VMSharedMemory }; } diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index b730a19b9dd..794e489484a 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -5,6 +5,7 @@ use std::fmt; use std::io; use std::path::Path; use std::sync::Arc; +use bytes::Bytes; use thiserror::Error; use wasmer_compiler::Artifact; use wasmer_compiler::ArtifactCreate; @@ -54,6 +55,32 @@ pub struct Module { module_info: Arc, } +pub trait IntoBytes +{ + fn into_bytes(self) -> Bytes; +} + +impl IntoBytes +for Bytes { + fn into_bytes(self) -> Bytes { + self + } +} + +impl IntoBytes +for Vec { + fn into_bytes(self) -> Bytes { + Bytes::from(self) + } +} + +impl IntoBytes +for &[u8] { + fn into_bytes(self) -> Bytes { + Bytes::from(self.to_vec()) + } +} + impl Module { #[cfg(feature = "compiler")] /// Creates a new WebAssembly Module given the configuration @@ -116,16 +143,19 @@ impl Module { /// # } /// ``` #[allow(unreachable_code)] - pub fn new(store: &impl AsStoreRef, bytes: impl AsRef<[u8]>) -> Result { + pub fn new(store: &impl AsStoreRef, bytes: impl IntoBytes) -> Result { + let mut bytes = bytes.into_bytes(); #[cfg(feature = "wat")] - let bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| { - CompileError::Wasm(WasmError::Generic(format!( - "Error when converting wat: {}", - e - ))) - })?; - - Self::from_binary(store, bytes.as_ref()) + if bytes.starts_with(b"\0asm") == false { + let parsed_bytes = wat::parse_bytes(&bytes[..]).map_err(|e| { + CompileError::Wasm(WasmError::Generic(format!( + "Error when converting wat: {}", + e + ))) + })?; + bytes = Bytes::from(parsed_bytes.to_vec()); + } + Self::from_binary(store, bytes) } #[cfg(feature = "compiler")] @@ -137,7 +167,7 @@ impl Module { let file_ref = file.as_ref(); let canonical = file_ref.canonicalize()?; let wasm_bytes = std::fs::read(file_ref)?; - let mut module = Self::new(store, &wasm_bytes)?; + let mut module = Self::new(store, wasm_bytes)?; // Set the module name to the absolute path of the filename. // This is useful for debugging the stack traces. let filename = canonical.as_path().to_str().unwrap(); @@ -151,8 +181,9 @@ impl Module { /// Opposed to [`Module::new`], this function is not compatible with /// the WebAssembly text format (if the "wat" feature is enabled for /// this crate). - pub fn from_binary(store: &impl AsStoreRef, binary: &[u8]) -> Result { - Self::validate(store, binary)?; + pub fn from_binary(store: &impl AsStoreRef, binary: impl IntoBytes) -> Result { + let binary = binary.into_bytes(); + Self::validate(store, binary.clone())?; unsafe { Self::from_binary_unchecked(store, binary) } } @@ -166,8 +197,9 @@ impl Module { /// beforehand. pub unsafe fn from_binary_unchecked( store: &impl AsStoreRef, - binary: &[u8], + binary: impl IntoBytes, ) -> Result { + let binary = binary.into_bytes(); let module = Self::compile(store, binary)?; Ok(module) } @@ -179,16 +211,18 @@ impl Module { /// This validation is normally pretty fast and checks the enabled /// WebAssembly features in the Store Engine to assure deterministic /// validation of the Module. - pub fn validate(store: &impl AsStoreRef, binary: &[u8]) -> Result<(), CompileError> { - store.as_store_ref().engine().validate(binary) + pub fn validate(store: &impl AsStoreRef, binary: impl IntoBytes) -> Result<(), CompileError> { + let binary = binary.into_bytes(); + store.as_store_ref().engine().validate(&binary[..]) } #[cfg(feature = "compiler")] - fn compile(store: &impl AsStoreRef, binary: &[u8]) -> Result { + fn compile(store: &impl AsStoreRef, binary: impl IntoBytes) -> Result { + let binary = binary.into_bytes(); let artifact = store .as_store_ref() .engine() - .compile(binary, store.as_store_ref().tunables())?; + .compile(&binary[..], store.as_store_ref().tunables())?; Ok(Self::from_artifact(artifact)) } @@ -206,8 +240,9 @@ impl Module { /// # Ok(()) /// # } /// ``` - pub fn serialize(&self) -> Result, SerializeError> { + pub fn serialize(&self) -> Result { self.artifact.serialize() + .map(|bytes| bytes.into()) } /// Serializes a module into a file that the `Engine` @@ -254,9 +289,9 @@ impl Module { /// ``` pub unsafe fn deserialize( store: &impl AsStoreRef, - bytes: &[u8], + bytes: impl AsRef<[u8]>, ) -> Result { - let artifact = store.as_store_ref().engine().deserialize(bytes)?; + let artifact = store.as_store_ref().engine().deserialize(bytes.as_ref())?; Ok(Self::from_artifact(artifact)) } @@ -438,6 +473,16 @@ impl Module { self.module_info.exports() } + /// Returns true if the module is still ok - this will be + /// false if the module was passed between threads in a + /// way that it became undefined (JS does not share objects + /// between threads except via a post_message()) + pub fn is_ok(&self) -> bool { + // As RUST is a type safe language modules in SYS are always ok + true + } + + /// Get the custom sections of the module given a `name`. /// /// # Important diff --git a/lib/api/src/sys/ptr.rs b/lib/api/src/sys/ptr.rs index f14383946d1..8e7935e2834 100644 --- a/lib/api/src/sys/ptr.rs +++ b/lib/api/src/sys/ptr.rs @@ -76,7 +76,7 @@ impl WasmPtr { /// Get the offset into Wasm linear memory for this `WasmPtr`. #[inline] - pub fn offset(self) -> M::Offset { + pub fn offset(&self) -> M::Offset { self.offset } @@ -97,7 +97,7 @@ impl WasmPtr { /// Checks whether the `WasmPtr` is null. #[inline] - pub fn is_null(self) -> bool { + pub fn is_null(&self) -> bool { self.offset.into() == 0 } @@ -142,19 +142,19 @@ impl WasmPtr { /// Creates a `WasmRef` from this `WasmPtr` which allows reading and /// mutating of the value being pointed to. #[inline] - pub fn deref<'a>(self, view: &'a MemoryView) -> WasmRef<'a, T> { + pub fn deref<'a>(&self, view: &'a MemoryView) -> WasmRef<'a, T> { WasmRef::new(view, self.offset.into()) } /// Reads the address pointed to by this `WasmPtr` in a memory. #[inline] - pub fn read(self, view: &MemoryView) -> Result { + pub fn read(&self, view: &MemoryView) -> Result { self.deref(view).read() } /// Writes to the address pointed to by this `WasmPtr` in a memory. #[inline] - pub fn write(self, view: &MemoryView, val: T) -> Result<(), MemoryAccessError> { + pub fn write(&self, view: &MemoryView, val: T) -> Result<(), MemoryAccessError> { self.deref(view).write(val) } @@ -165,7 +165,7 @@ impl WasmPtr { /// address. #[inline] pub fn slice<'a>( - self, + &self, view: &'a MemoryView, len: M::Offset, ) -> Result, MemoryAccessError> { @@ -178,7 +178,7 @@ impl WasmPtr { /// This last value is not included in the returned vector. #[inline] pub fn read_until( - self, + &self, view: &MemoryView, mut end: impl FnMut(&T) -> bool, ) -> Result, MemoryAccessError> { @@ -202,7 +202,7 @@ impl WasmPtr { /// modified. #[inline] pub fn read_utf8_string( - self, + &self, view: &MemoryView, len: M::Offset, ) -> Result { @@ -215,7 +215,7 @@ impl WasmPtr { /// This method is safe to call even if the memory is being concurrently /// modified. #[inline] - pub fn read_utf8_string_with_nul(self, view: &MemoryView) -> Result { + pub fn read_utf8_string_with_nul(&self, view: &MemoryView) -> Result { let vec = self.read_until(view, |&byte| byte == 0)?; Ok(String::from_utf8(vec)?) } diff --git a/lib/api/src/sys/store.rs b/lib/api/src/sys/store.rs index 542ef61f7e2..e90bbe48c81 100644 --- a/lib/api/src/sys/store.rs +++ b/lib/api/src/sys/store.rs @@ -1,6 +1,5 @@ use crate::sys::tunables::BaseTunables; use std::fmt; -use std::sync::{Arc, RwLock}; #[cfg(feature = "compiler")] use wasmer_compiler::{Engine, EngineBuilder, Tunables}; use wasmer_vm::{init_traps, TrapHandler, TrapHandlerFn}; @@ -33,7 +32,6 @@ pub struct Store { pub(crate) inner: Box, #[cfg(feature = "compiler")] engine: Engine, - trap_handler: Arc>>>>, } impl Store { @@ -80,7 +78,6 @@ impl Store { trap_handler: None, }), engine: engine.cloned(), - trap_handler: Arc::new(RwLock::new(None)), } } @@ -114,8 +111,8 @@ impl PartialEq for Store { unsafe impl TrapHandler for Store { fn custom_trap_handler(&self, call: &dyn Fn(&TrapHandlerFn) -> bool) -> bool { - if let Some(handler) = self.trap_handler.read().unwrap().as_ref() { - call(handler) + if let Some(handler) = self.inner.trap_handler.as_ref() { + call(handler.as_ref()) } else { false } @@ -242,7 +239,7 @@ impl<'a> StoreRef<'a> { self.inner .trap_handler .as_ref() - .map(|handler| handler as *const _) + .map(|handler| handler.as_ref() as *const _) } } diff --git a/lib/api/tests/sys_reference_types.rs b/lib/api/tests/sys_reference_types.rs index b481a07d8f9..22833b7ce11 100644 --- a/lib/api/tests/sys_reference_types.rs +++ b/lib/api/tests/sys_reference_types.rs @@ -44,15 +44,15 @@ mod sys { } let func_to_call = - Function::new_typed_with_env(&mut store, &env, |mut env: FunctionEnvMut| -> i32 { - env.data_mut().0.store(true, Ordering::SeqCst); + Function::new_typed_with_env(&mut store, &env, |env: FunctionEnvMut| -> i32 { + env.data().0.store(true, Ordering::SeqCst); 343 }); let call_set_value: &Function = instance.exports.get_function("call_set_value")?; let results: Box<[Value]> = call_set_value.call(&mut store, &[Value::FuncRef(Some(func_to_call))])?; assert!(env - .as_mut(&mut store.as_store_mut()) + .as_ref(&store.as_store_ref()) .0 .load(Ordering::SeqCst)); assert_eq!(&*results, &[Value::I32(343)]); diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 4501b83f44f..a4a40358f10 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -197,14 +197,6 @@ pub unsafe extern "C" fn wasi_env_new( #[no_mangle] pub extern "C" fn wasi_env_delete(_state: Option>) {} -/// Set the memory on a [`wasi_env_t`]. -#[no_mangle] -pub unsafe extern "C" fn wasi_env_set_memory(env: &mut wasi_env_t, memory: &wasm_memory_t) { - let mut store_mut = env.store.store_mut(); - let wasi_env = env.inner.data_mut(&mut store_mut); - wasi_env.set_memory(memory.extern_.memory()); -} - #[no_mangle] pub unsafe extern "C" fn wasi_env_read_stdout( env: &mut wasi_env_t, @@ -212,8 +204,8 @@ pub unsafe extern "C" fn wasi_env_read_stdout( buffer_len: usize, ) -> isize { let inner_buffer = slice::from_raw_parts_mut(buffer as *mut _, buffer_len as usize); - let mut store_mut = env.store.store_mut(); - let state = env.inner.data_mut(&mut store_mut).state(); + let store = env.store.store(); + let state = env.inner.data(&store).state(); if let Ok(mut stdout) = state.stdout() { if let Some(stdout) = stdout.as_mut() { @@ -382,11 +374,10 @@ pub unsafe extern "C" fn wasi_env_initialize_instance( store: &mut wasm_store_t, instance: &mut wasm_instance_t, ) -> bool { - let mem = c_try!(instance.inner.exports.get_memory("memory"); otherwise false); wasi_env .inner - .data_mut(&mut store.inner.store_mut()) - .set_memory(mem.clone()); + .initialize(&mut store.inner.store_mut(), &instance.inner) + .unwrap(); true } diff --git a/lib/cli/src/commands/run.rs b/lib/cli/src/commands/run.rs index 4c742306e00..5cbce9d0f3c 100644 --- a/lib/cli/src/commands/run.rs +++ b/lib/cli/src/commands/run.rs @@ -382,6 +382,9 @@ impl Run { name, suggestion ), + ExportError::SerializationFailed(err) => { + anyhow!("Failed to serialize the module - {}", err) + } } } })? diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index 2fd31666bed..a5c16169ed2 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -4,7 +4,7 @@ use std::collections::BTreeSet; use std::path::PathBuf; use wasmer::{AsStoreMut, FunctionEnv, Instance, Module, RuntimeError, Value}; use wasmer_wasi::{ - get_wasi_versions, import_object_for_all_wasi_versions, is_wasix_module, WasiEnv, WasiError, + get_wasi_versions, import_object_for_all_wasi_versions, WasiEnv, WasiError, WasiState, WasiVersion, }; @@ -69,7 +69,7 @@ impl Wasi { /// Helper function for instantiating a module with Wasi imports for the `Run` command. pub fn instantiate( &self, - store: &mut impl AsStoreMut, + mut store: &mut impl AsStoreMut, module: &Module, program_name: String, args: Vec, @@ -91,15 +91,12 @@ impl Wasi { } } - let wasi_env = wasi_state_builder.finalize(store)?; - wasi_env.env.as_mut(store).state.fs.is_wasix.store( - is_wasix_module(module), - std::sync::atomic::Ordering::Release, - ); - let import_object = import_object_for_all_wasi_versions(store, &wasi_env.env); + let mut wasi_env = wasi_state_builder.finalize(store)?; + let mut import_object = import_object_for_all_wasi_versions(store, &wasi_env.env); + import_object.import_shared_memory(module, &mut store); + let instance = Instance::new(store, module, &import_object)?; - let memory = instance.exports.get_memory("memory")?; - wasi_env.data_mut(store).set_memory(memory.clone()); + wasi_env.initialize(&mut store, &instance)?; Ok((wasi_env.env, instance)) } diff --git a/lib/cli/src/commands/wasmer_create_exe_main.c b/lib/cli/src/commands/wasmer_create_exe_main.c index a58fb5c73c2..a1966b106cc 100644 --- a/lib/cli/src/commands/wasmer_create_exe_main.c +++ b/lib/cli/src/commands/wasmer_create_exe_main.c @@ -149,23 +149,11 @@ int main(int argc, char *argv[]) { } #ifdef WASI - // Read the exports. - wasm_extern_vec_t exports; - wasm_instance_exports(instance, &exports); - wasm_memory_t* mem = NULL; - for (size_t i = 0; i < exports.size; i++) { - mem = wasm_extern_as_memory(exports.data[i]); - if (mem) { - break; - } - } - - if (!mem) { - fprintf(stderr, "Failed to create instance: Could not find memory in exports\n"); + if (!wasi_env_initialize_instance(wasi_env, store, instance)) { + fprintf(stderr, "Failed to initialize env\n"); print_wasmer_error(); return -1; } - wasi_env_set_memory(wasi_env, mem); own wasm_func_t *start_function = wasi_get_start_function(instance); if (!start_function) { diff --git a/lib/cli/src/commands/wasmer_static_create_exe_main.c b/lib/cli/src/commands/wasmer_static_create_exe_main.c index 2276ed3bc75..20e6d13bff5 100644 --- a/lib/cli/src/commands/wasmer_static_create_exe_main.c +++ b/lib/cli/src/commands/wasmer_static_create_exe_main.c @@ -144,23 +144,11 @@ int main(int argc, char *argv[]) { } #ifdef WASI - // Read the exports. - wasm_extern_vec_t exports; - wasm_instance_exports(instance, &exports); - wasm_memory_t* mem = NULL; - for (size_t i = 0; i < exports.size; i++) { - mem = wasm_extern_as_memory(exports.data[i]); - if (mem) { - break; - } - } - - if (!mem) { - fprintf(stderr, "Failed to create instance: Could not find memory in exports\n"); + if (!wasi_env_initialize_instance(wasi_env, store, instance)) { + fprintf(stderr, "Failed to initialize env\n"); print_wasmer_error(); return -1; } - wasi_env_set_memory(wasi_env, mem); own wasm_func_t *start_function = wasi_get_start_function(instance); if (!start_function) { diff --git a/lib/compiler-cranelift/src/translator/code_translator.rs b/lib/compiler-cranelift/src/translator/code_translator.rs index c750d6c3231..d432f074361 100644 --- a/lib/compiler-cranelift/src/translator/code_translator.rs +++ b/lib/compiler-cranelift/src/translator/code_translator.rs @@ -1063,15 +1063,24 @@ pub fn translate_operator( assert!(builder.func.dfg.value_type(expected) == implied_ty); // `fn translate_atomic_wait` can inspect the type of `expected` to figure out what // code it needs to generate, if it wants. - let res = environ.translate_atomic_wait( + match environ.translate_atomic_wait( builder.cursor(), heap_index, heap, addr, expected, timeout, - )?; - state.push1(res); + ) { + Ok(res) => { + state.push1(res); + }, + Err(wasmer_types::WasmError::Unsupported(_err)) => { + // If multiple threads hit a mutex then the function will fail + builder.ins().trap(ir::TrapCode::UnreachableCodeReached); + state.reachable = false; + }, + Err(err) => { return Err(err); } + }; } Operator::MemoryAtomicNotify { memarg } => { let heap_index = MemoryIndex::from_u32(memarg.memory); @@ -1079,9 +1088,19 @@ pub fn translate_operator( let count = state.pop1(); // 32 (fixed) let addr = state.pop1(); // 32 (fixed) let addr = fold_atomic_mem_addr(addr, memarg, I32, builder); - let res = - environ.translate_atomic_notify(builder.cursor(), heap_index, heap, addr, count)?; - state.push1(res); + match environ.translate_atomic_notify(builder.cursor(), heap_index, heap, addr, count) + { + Ok(res) => { + state.push1(res); + }, + Err(wasmer_types::WasmError::Unsupported(_err)) => { + // Simple return a zero as this function is needed for the __wasi_init_memory function + // but the equivalent notify.wait will not be called (as only one thread calls __start) + // hence these atomic operations are not needed + state.push1(builder.ins().iconst(I32, i64::from(0))); + }, + Err(err) => { return Err(err); } + }; } Operator::I32AtomicLoad { memarg } => { translate_atomic_load(I32, I32, memarg, builder, state, environ)? diff --git a/lib/compiler/src/engine/resolver.rs b/lib/compiler/src/engine/resolver.rs index 207380bb819..94d40a50229 100644 --- a/lib/compiler/src/engine/resolver.rs +++ b/lib/compiler/src/engine/resolver.rs @@ -4,7 +4,7 @@ use crate::LinkError; use more_asserts::assert_ge; use wasmer_types::entity::{BoxedSlice, EntityRef, PrimaryMap}; use wasmer_types::{ - ExternType, FunctionIndex, ImportError, ImportIndex, MemoryIndex, ModuleInfo, TableIndex, + ExternType, FunctionIndex, ImportError, ImportIndex, MemoryIndex, ModuleInfo, TableIndex, LinearMemory, }; use wasmer_vm::{ diff --git a/lib/compiler/src/translator/environ.rs b/lib/compiler/src/translator/environ.rs index e172d92b063..1615b87bcf8 100644 --- a/lib/compiler/src/translator/environ.rs +++ b/lib/compiler/src/translator/environ.rs @@ -1,7 +1,6 @@ // This file contains code from external sources. // Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md use super::state::ModuleTranslationState; -use crate::lib::std::borrow::ToOwned; use crate::lib::std::string::ToString; use crate::lib::std::{boxed::Box, string::String, vec::Vec}; use crate::translate_module; @@ -15,7 +14,7 @@ use wasmer_types::{ LocalFunctionIndex, MemoryIndex, MemoryType, ModuleInfo, SignatureIndex, TableIndex, TableInitializer, TableType, }; -use wasmer_types::{WasmError, WasmResult}; +use wasmer_types::WasmResult; /// Contains function data: bytecode and its offset in the module. #[derive(Hash)] @@ -254,11 +253,6 @@ impl<'data> ModuleEnvironment<'data> { } pub(crate) fn declare_memory(&mut self, memory: MemoryType) -> WasmResult<()> { - if memory.shared { - return Err(WasmError::Unsupported( - "shared memories are not supported yet".to_owned(), - )); - } self.module.memories.push(memory); Ok(()) } diff --git a/lib/derive/src/value_type.rs b/lib/derive/src/value_type.rs index 5e9fe23c826..0280f5ead13 100644 --- a/lib/derive/src/value_type.rs +++ b/lib/derive/src/value_type.rs @@ -1,7 +1,7 @@ use proc_macro2::TokenStream; use proc_macro_error::abort; use quote::quote; -use syn::{Data, DeriveInput, Fields, Member, Meta, MetaList, NestedMeta}; +use syn::{Data, DeriveInput, Member, Meta, MetaList, NestedMeta, Field}; /// We can only validate types that have a well defined layout. fn check_repr(input: &DeriveInput) { @@ -35,7 +35,7 @@ fn check_repr(input: &DeriveInput) { } /// Zero out any padding bytes between fields. -fn zero_padding(fields: &Fields) -> TokenStream { +fn zero_padding(fields: Vec<&Field>) -> TokenStream { let names: Vec<_> = fields .iter() .enumerate() @@ -93,18 +93,18 @@ pub fn impl_value_type(input: &DeriveInput) -> TokenStream { let struct_name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let fields = match &input.data { - Data::Struct(ds) => &ds.fields, + let zero_padding = match &input.data { + Data::Struct(ds) => zero_padding(ds.fields.iter().collect()), _ => abort!(input, "ValueType can only be derived for structs"), }; - let zero_padding = zero_padding(fields); - quote! { unsafe impl #impl_generics ::wasmer::ValueType for #struct_name #ty_generics #where_clause { #[inline] fn zero_padding_bytes(&self, _bytes: &mut [::core::mem::MaybeUninit]) { - #zero_padding + unsafe { + #zero_padding + } } } } diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 1e4b7af80ea..8a6a2f794f8 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -25,7 +25,7 @@ use std::sync::{Arc, Mutex, RwLock}; use wasmer::{ imports, namespace, AsStoreMut, ExportError, Exports, Function, FunctionEnv, FunctionEnvMut, FunctionType, Global, Imports, Instance, Memory, MemoryType, Module, Pages, RuntimeError, - Table, TableType, TypedFunction, Value, WasmPtr, + Table, TableType, TypedFunction, Value, WasmPtr, AsStoreRef, }; use wasmer_types::Type as ValType; @@ -98,7 +98,7 @@ impl EmEnv { } } - pub fn set_memory(&mut self, memory: Memory) { + pub fn set_memory(&self, memory: Memory) { let mut w = self.memory.write().unwrap(); *w = Some(memory); } @@ -108,12 +108,13 @@ impl EmEnv { (&*self.memory.read().unwrap()).as_ref().cloned().unwrap() } - pub fn set_functions(&mut self, funcs: EmscriptenFunctions) { - self.funcs = Arc::new(Mutex::new(funcs)); + pub fn set_functions(&self, funcs: EmscriptenFunctions) { + let mut w = self.funcs.lock().unwrap(); + *w = funcs; } pub fn set_data( - &mut self, + &self, data: &EmscriptenGlobalsData, mapped_dirs: HashMap, ) { @@ -823,7 +824,7 @@ pub fn run_emscripten_instance( if let Ok(func) = instance.exports.get_typed_function(&env, "setThrew") { emfuncs.set_threw = Some(func); } - env.data_mut().set_functions(emfuncs); + env.data().set_functions(emfuncs); set_up_emscripten(&mut env, instance)?; @@ -864,12 +865,12 @@ fn store_module_arguments(env: &mut FunctionEnvMut, args: Vec<&str>) -> ( } pub fn emscripten_set_up_memory( - store: &mut impl AsStoreMut, + store: &impl AsStoreRef, env: &FunctionEnv, memory: &Memory, globals: &EmscriptenGlobalsData, ) -> Result<(), String> { - env.as_mut(store).set_memory(memory.clone()); + env.as_ref(store).set_memory(memory.clone()); let memory = memory.view(store); let dynamictop_ptr = WasmPtr::::new(globals.dynamictop_ptr).deref(&memory); let dynamic_base = globals.dynamic_base; diff --git a/lib/emscripten/src/memory.rs b/lib/emscripten/src/memory.rs index 2c905e30c88..4294a42cbfc 100644 --- a/lib/emscripten/src/memory.rs +++ b/lib/emscripten/src/memory.rs @@ -110,6 +110,8 @@ pub fn sbrk(mut ctx: FunctionEnvMut, increment: i32) -> i32 { increment, total_memory ); + drop(dynamictop_ptr); + if increment > 0 && new_dynamic_top < old_dynamic_top || new_dynamic_top < 0 { abort_on_cannot_grow_memory_old(ctx); return -1; diff --git a/lib/types/Cargo.toml b/lib/types/Cargo.toml index e10aebf87df..3ee22d50426 100644 --- a/lib/types/Cargo.toml +++ b/lib/types/Cargo.toml @@ -21,6 +21,9 @@ enum-iterator = "0.7.0" target-lexicon = { version = "0.12.2", default-features = false } enumset = "1.0" +[dev-dependencies] +memoffset = "0.6" + [features] default = ["std"] std = [] diff --git a/lib/types/src/error.rs b/lib/types/src/error.rs index 53555d6239c..0e0a1eb12fd 100644 --- a/lib/types/src/error.rs +++ b/lib/types/src/error.rs @@ -1,5 +1,5 @@ //! The WebAssembly possible errors -use crate::ExternType; +use crate::{ExternType, Pages}; use std::io; use thiserror::Error; @@ -37,6 +37,48 @@ pub enum DeserializeError { Compiler(#[from] CompileError), } +/// Error type describing things that can go wrong when operating on Wasm Memories. +#[derive(Error, Debug, Clone, PartialEq, Hash)] +pub enum MemoryError { + /// Low level error with mmap. + #[error("Error when allocating memory: {0}")] + Region(String), + /// The operation would cause the size of the memory to exceed the maximum or would cause + /// an overflow leading to unindexable memory. + #[error("The memory could not grow: current size {} pages, requested increase: {} pages", current.0, attempted_delta.0)] + CouldNotGrow { + /// The current size in pages. + current: Pages, + /// The attempted amount to grow by in pages. + attempted_delta: Pages, + }, + /// The operation would cause the size of the memory size exceed the maximum. + #[error("The memory is invalid because {}", reason)] + InvalidMemory { + /// The reason why the provided memory is invalid. + reason: String, + }, + /// Caller asked for more minimum memory than we can give them. + #[error("The minimum requested ({} pages) memory is greater than the maximum allowed memory ({} pages)", min_requested.0, max_allowed.0)] + MinimumMemoryTooLarge { + /// The number of pages requested as the minimum amount of memory. + min_requested: Pages, + /// The maximum amount of memory we can allocate. + max_allowed: Pages, + }, + /// Caller asked for a maximum memory greater than we can give them. + #[error("The maximum requested memory ({} pages) is greater than the maximum allowed memory ({} pages)", max_requested.0, max_allowed.0)] + MaximumMemoryTooLarge { + /// The number of pages requested as the maximum amount of memory. + max_requested: Pages, + /// The number of pages requested as the maximum amount of memory. + max_allowed: Pages, + }, + /// A user defined error value, used for error cases not listed above. + #[error("A user-defined error occurred: {0}")] + Generic(String), +} + /// An ImportError. /// /// Note: this error is not standard to WebAssembly, but it's @@ -52,6 +94,10 @@ pub enum ImportError { /// This error occurs when an import was expected but not provided. #[error("unknown import. Expected {0:?}")] UnknownImport(ExternType), + + /// Memory Error + #[error("memory error. {0}")] + MemoryError(String), } /// An error while preinstantiating a module. diff --git a/lib/types/src/lib.rs b/lib/types/src/lib.rs index 3fcfbe9504d..3f71079c94c 100644 --- a/lib/types/src/lib.rs +++ b/lib/types/src/lib.rs @@ -77,7 +77,7 @@ pub use crate::compilation::target::{ pub use crate::serialize::{MetadataHeader, SerializableCompilation, SerializableModule}; pub use error::{ CompileError, DeserializeError, ImportError, MiddlewareError, ParseCpuFeatureError, - PreInstantiationError, SerializeError, WasmError, WasmResult, + PreInstantiationError, SerializeError, WasmError, WasmResult, MemoryError, }; /// The entity module, with common helpers for Rust structures @@ -103,7 +103,9 @@ pub use types::{ pub use value::{RawValue, ValueType}; pub use crate::libcalls::LibCall; -pub use crate::memory::MemoryStyle; +pub use crate::memory::{ + MemoryStyle, LinearMemory, VMMemoryDefinition +}; pub use crate::table::TableStyle; pub use crate::trapcode::TrapCode; pub use crate::vmoffsets::{TargetSharedSignatureIndex, VMBuiltinFunctionIndex, VMOffsets}; diff --git a/lib/types/src/memory.rs b/lib/types/src/memory.rs index fafcb955a8a..6ebac15e7e8 100644 --- a/lib/types/src/memory.rs +++ b/lib/types/src/memory.rs @@ -2,12 +2,16 @@ use crate::{Pages, ValueType}; use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; +use core::ptr::NonNull; use std::convert::{TryFrom, TryInto}; use std::iter::Sum; use std::ops::{Add, AddAssign}; +use super::MemoryType; +use super::MemoryError; + /// Implementation styles for WebAssembly linear memory. -#[derive(Debug, Clone, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] #[archive(as = "Self")] pub enum MemoryStyle { @@ -84,6 +88,9 @@ pub unsafe trait MemorySize: Copy { /// Zero value used for `WasmPtr::is_null`. const ZERO: Self::Offset; + /// One value used for counting. + const ONE: Self::Offset; + /// Convert an `Offset` to a `Native`. fn offset_to_native(offset: Self::Offset) -> Self::Native; @@ -98,6 +105,7 @@ unsafe impl MemorySize for Memory32 { type Offset = u32; type Native = i32; const ZERO: Self::Offset = 0; + const ONE: Self::Offset = 1; fn offset_to_native(offset: Self::Offset) -> Self::Native { offset as Self::Native } @@ -113,6 +121,7 @@ unsafe impl MemorySize for Memory64 { type Offset = u64; type Native = i64; const ZERO: Self::Offset = 0; + const ONE: Self::Offset = 1; fn offset_to_native(offset: Self::Offset) -> Self::Native { offset as Self::Native } @@ -120,3 +129,80 @@ unsafe impl MemorySize for Memory64 { native as Self::Offset } } + +/// Represents memory that is used by the WebAsssembly module +pub trait LinearMemory +where Self: std::fmt::Debug + Send +{ + /// Returns the type for this memory. + fn ty(&self) -> MemoryType; + + /// Returns the size of hte memory in pages + fn size(&self) -> Pages; + + /// Returns the memory style for this memory. + fn style(&self) -> MemoryStyle; + + /// Grow memory by the specified amount of wasm pages. + /// + /// Returns `None` if memory can't be grown by the specified amount + /// of wasm pages. + fn grow(&mut self, delta: Pages) -> Result; + + /// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code. + fn vmmemory(&self) -> NonNull; + + /// Attempts to clone this memory (if its clonable) + fn try_clone(&self) -> Option>; +} + +/// The fields compiled code needs to access to utilize a WebAssembly linear +/// memory defined within the instance, namely the start address and the +/// size in bytes. +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct VMMemoryDefinition { + /// The start address which is always valid, even if the memory grows. + pub base: *mut u8, + + /// The current logical size of this linear memory in bytes. + pub current_length: usize, +} + +/// # Safety +/// This data is safe to share between threads because it's plain data that +/// is the user's responsibility to synchronize. +unsafe impl Send for VMMemoryDefinition {} +/// # Safety +/// This data is safe to share between threads because it's plain data that +/// is the user's responsibility to synchronize. And it's `Copy` so there's +/// really no difference between passing it by reference or by value as far as +/// correctness in a multi-threaded context is concerned. +unsafe impl Sync for VMMemoryDefinition {} + +#[cfg(test)] +mod test_vmmemory_definition { + use super::VMMemoryDefinition; + use crate::VMOffsets; + use memoffset::offset_of; + use std::mem::size_of; + use crate::ModuleInfo; + + #[test] + fn check_vmmemory_definition_offsets() { + let module = ModuleInfo::new(); + let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module); + assert_eq!( + size_of::(), + usize::from(offsets.size_of_vmmemory_definition()) + ); + assert_eq!( + offset_of!(VMMemoryDefinition, base), + usize::from(offsets.vmmemory_definition_base()) + ); + assert_eq!( + offset_of!(VMMemoryDefinition, current_length), + usize::from(offsets.vmmemory_definition_current_length()) + ); + } +} diff --git a/lib/vbus/src/lib.rs b/lib/vbus/src/lib.rs index e51ec11ffac..0cda403e17b 100644 --- a/lib/vbus/src/lib.rs +++ b/lib/vbus/src/lib.rs @@ -5,8 +5,9 @@ use thiserror::Error; pub use wasmer_vfs::FileDescriptor; pub use wasmer_vfs::StdioMode; +use wasmer_vfs::VirtualFile; -pub type Result = std::result::Result; +pub type Result = std::result::Result; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] @@ -26,10 +27,14 @@ impl From for CallDescriptor { pub trait VirtualBus: fmt::Debug + Send + Sync + 'static { /// Starts a new WAPM sub process - fn new_spawn(&self) -> SpawnOptions; + fn new_spawn(&self) -> SpawnOptions { + SpawnOptions::new(Box::new(UnsupportedVirtualBusSpawner::default())) + } /// Creates a listener thats used to receive BUS commands - fn listen(&self) -> Result>; + fn listen<'a>(&'a self) -> Result<&'a dyn VirtualBusListener> { + Err(VirtualBusError::Unsupported) + } } pub trait VirtualBusSpawner { @@ -46,7 +51,7 @@ pub struct SpawnOptionsConfig { stdin_mode: StdioMode, stdout_mode: StdioMode, stderr_mode: StdioMode, - working_dir: String, + working_dir: Option, remote_instance: Option, access_token: Option, } @@ -80,8 +85,8 @@ impl SpawnOptionsConfig { self.stderr_mode } - pub fn working_dir(&self) -> &str { - self.working_dir.as_str() + pub fn working_dir(&self) -> Option<&str> { + self.working_dir.as_ref().map(|a| a.as_str()) } pub fn remote_instance(&self) -> Option<&str> { @@ -110,7 +115,7 @@ impl SpawnOptions { stdin_mode: StdioMode::Null, stdout_mode: StdioMode::Null, stderr_mode: StdioMode::Null, - working_dir: "/".to_string(), + working_dir: None, remote_instance: None, access_token: None, }, @@ -157,7 +162,7 @@ impl SpawnOptions { } pub fn working_dir(&mut self, working_dir: String) -> &mut Self { - self.conf.working_dir = working_dir; + self.conf.working_dir = Some(working_dir); self } @@ -179,8 +184,18 @@ impl SpawnOptions { #[derive(Debug)] pub struct BusSpawnedProcess { + /// Name of the spawned process + pub name: String, + /// Configuration applied to this spawned thread + pub config: SpawnOptionsConfig, /// Reference to the spawned instance - pub inst: Box, + pub inst: Box, + /// Virtual file used for stdin + pub stdin: Option>, + /// Virtual file used for stdout + pub stdout: Option>, + /// Virtual file used for stderr + pub stderr: Option>, } pub trait VirtualBusScope: fmt::Debug + Send + Sync + 'static { @@ -192,10 +207,15 @@ pub trait VirtualBusInvokable: fmt::Debug + Send + Sync + 'static { /// Invokes a service within this instance fn invoke( &self, - topic: String, + topic_hash: u128, format: BusDataFormat, - buf: &[u8], - ) -> Result>; + buf: Vec, + ) -> Box; +} + +pub trait VirtualBusInvoked: fmt::Debug + Unpin + 'static { + //// Returns once the bus has been invoked (or failed) + fn poll_invoked(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>>; } pub trait VirtualBusProcess: @@ -204,29 +224,117 @@ pub trait VirtualBusProcess: /// Returns the exit code if the instance has finished fn exit_code(&self) -> Option; - /// Returns a file descriptor used to read the STDIN - fn stdin_fd(&self) -> Option; - - /// Returns a file descriptor used to write to STDOUT - fn stdout_fd(&self) -> Option; - - /// Returns a file descriptor used to write to STDERR - fn stderr_fd(&self) -> Option; + /// Polls to check if the process is ready yet to receive commands + fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()>; } pub trait VirtualBusInvocation: - VirtualBusScope + VirtualBusInvokable + fmt::Debug + Send + Sync + 'static + VirtualBusInvokable + fmt::Debug + Send + Sync + Unpin + 'static { /// Polls for new listen events related to this context fn poll_event(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; } +#[derive(Debug)] +pub struct InstantInvocation +{ + val: Option, + err: Option, + call: Option>, +} + +impl InstantInvocation +{ + pub fn response(format: BusDataFormat, data: Vec) -> Self { + Self { + val: Some(BusInvocationEvent::Response { format, data }), + err: None, + call: None + } + } + + pub fn fault(err: VirtualBusError) -> Self { + Self { + val: None, + err: Some(err), + call: None + } + } + + pub fn call(val: Box) -> Self { + Self { + val: None, + err: None, + call: Some(val) + } + } +} + +impl VirtualBusInvoked +for InstantInvocation +{ + fn poll_invoked(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll>> { + if let Some(err) = self.err.take() { + return Poll::Ready(Err(err)); + } + if let Some(val) = self.val.take() { + return Poll::Ready(Ok(Box::new(InstantInvocation { + val: Some(val), + err: None, + call: None, + }))); + } + match self.call.take() { + Some(val) => { + Poll::Ready(Ok(val)) + }, + None => { + Poll::Ready(Err(VirtualBusError::AlreadyConsumed)) + } + } + } +} + +impl VirtualBusInvocation +for InstantInvocation +{ + fn poll_event(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + match self.val.take() { + Some(val) => { + Poll::Ready(val) + }, + None => { + Poll::Ready(BusInvocationEvent::Fault { fault: VirtualBusError::AlreadyConsumed }) + } + } + } +} + +impl VirtualBusInvokable +for InstantInvocation +{ + fn invoke( + &self, + _topic_hash: u128, + _format: BusDataFormat, + _buf: Vec, + ) -> Box { + Box::new( + InstantInvocation { + val: None, + err: Some(VirtualBusError::InvalidTopic), + call: None + } + ) + } +} + #[derive(Debug)] pub enum BusInvocationEvent { /// The server has sent some out-of-band data to you Callback { /// Topic that this call relates to - topic: String, + topic_hash: u128, /// Format of the data we received format: BusDataFormat, /// Data passed in the call @@ -239,34 +347,43 @@ pub enum BusInvocationEvent { /// Data returned by the call data: Vec, }, + /// The service has responded with a fault + Fault { + /// Fault code that was raised + fault: VirtualBusError + } } -pub trait VirtualBusListener: fmt::Debug + Send + Sync + 'static { +pub trait VirtualBusListener: fmt::Debug + Send + Sync + Unpin + 'static { /// Polls for new calls to this service - fn poll_call(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; + fn poll(self: Pin<&Self>, cx: &mut Context<'_>) -> Poll; } #[derive(Debug)] pub struct BusCallEvent { - /// Topic that this call relates to - pub topic: String, + /// Topic hash that this call relates to + pub topic_hash: u128, /// Reference to the call itself - pub called: Box, + pub called: Box, /// Format of the data we received pub format: BusDataFormat, /// Data passed in the call pub data: Vec, } -pub trait VirtualBusCalled: VirtualBusListener + fmt::Debug + Send + Sync + 'static { +pub trait VirtualBusCalled: fmt::Debug + Send + Sync + 'static +{ + /// Polls for new calls to this service + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; + /// Sends an out-of-band message back to the caller - fn callback(&self, topic: String, format: BusDataFormat, buf: &[u8]) -> Result<()>; + fn callback(&self, topic_hash: u128, format: BusDataFormat, buf: Vec); /// Informs the caller that their call has failed - fn fault(self, fault: BusError) -> Result<()>; + fn fault(self: Box, fault: VirtualBusError); /// Finishes the call and returns a particular response - fn reply(self, format: BusDataFormat, buf: &[u8]) -> Result<()>; + fn reply(&self, format: BusDataFormat, buf: Vec); } /// Format that the supplied data is in @@ -284,13 +401,6 @@ pub enum BusDataFormat { pub struct UnsupportedVirtualBus {} impl VirtualBus for UnsupportedVirtualBus { - fn new_spawn(&self) -> SpawnOptions { - SpawnOptions::new(Box::new(UnsupportedVirtualBusSpawner::default())) - } - - fn listen(&self) -> Result> { - Err(BusError::Unsupported) - } } #[derive(Debug, Default)] @@ -298,12 +408,12 @@ pub struct UnsupportedVirtualBusSpawner {} impl VirtualBusSpawner for UnsupportedVirtualBusSpawner { fn spawn(&mut self, _name: &str, _config: &SpawnOptionsConfig) -> Result { - Err(BusError::Unsupported) + Err(VirtualBusError::Unsupported) } } #[derive(Error, Copy, Clone, Debug, PartialEq, Eq)] -pub enum BusError { +pub enum VirtualBusError { /// Failed during serialization #[error("serialization failed")] Serialization, diff --git a/lib/vfs/src/host_fs.rs b/lib/vfs/src/host_fs.rs index 0cc9ddec068..fe980fb1189 100644 --- a/lib/vfs/src/host_fs.rs +++ b/lib/vfs/src/host_fs.rs @@ -421,11 +421,18 @@ impl VirtualFile for File { self.inner.sync_all().map_err(Into::into) } - fn bytes_available(&self) -> Result { + #[cfg(feature = "sys")] + fn bytes_available(&self) -> Result { host_file_bytes_available(self.inner.try_into_filedescriptor()?) } + + #[cfg(not(feature = "sys"))] + fn bytes_available(&self) -> Result { + Err(FsError::InvalidFd) + } } +#[allow(dead_code)] #[cfg(unix)] fn host_file_bytes_available(host_fd: FileDescriptor) -> Result { let mut bytes_found: libc::c_int = 0; @@ -441,6 +448,7 @@ fn host_file_bytes_available(host_fd: FileDescriptor) -> Result { } } +#[allow(dead_code)] #[cfg(not(unix))] fn host_file_bytes_available(_host_fd: FileDescriptor) -> Result { unimplemented!("host_file_bytes_available not yet implemented for non-Unix-like targets. This probably means the program tried to use wasi::poll_oneoff") @@ -533,13 +541,25 @@ impl VirtualFile for Stdout { Ok(()) } + #[cfg(feature = "sys")] fn bytes_available(&self) -> Result { host_file_bytes_available(io::stdout().try_into_filedescriptor()?) } + #[cfg(feature = "sys")] fn get_fd(&self) -> Option { io::stdout().try_into_filedescriptor().ok() } + + #[cfg(feature = "js")] + fn bytes_available(&self) -> Result { + Err(FsError::InvalidFd); + } + + #[cfg(feature = "js")] + fn get_fd(&self) -> Option { + None + } } /// A wrapper type around Stderr that implements `VirtualFile` and @@ -629,13 +649,25 @@ impl VirtualFile for Stderr { Ok(()) } + #[cfg(feature = "sys")] fn bytes_available(&self) -> Result { host_file_bytes_available(io::stderr().try_into_filedescriptor()?) } + #[cfg(feature = "sys")] fn get_fd(&self) -> Option { io::stderr().try_into_filedescriptor().ok() } + + #[cfg(feature = "js")] + fn bytes_available(&self) -> Result { + Err(FsError::InvalidFd); + } + + #[cfg(feature = "js")] + fn get_fd(&self) -> Option { + None + } } /// A wrapper type around Stdin that implements `VirtualFile` and @@ -724,11 +756,23 @@ impl VirtualFile for Stdin { Ok(()) } + #[cfg(feature = "sys")] fn bytes_available(&self) -> Result { host_file_bytes_available(io::stdin().try_into_filedescriptor()?) } + #[cfg(feature = "sys")] fn get_fd(&self) -> Option { io::stdin().try_into_filedescriptor().ok() } + + #[cfg(feature = "js")] + fn bytes_available(&self) -> Result { + Err(FsError::InvalidFd); + } + + #[cfg(feature = "js")] + fn get_fd(&self) -> Option { + None + } } diff --git a/lib/vm/src/instance/allocator.rs b/lib/vm/src/instance/allocator.rs index 29804c7460e..e00625f5e8c 100644 --- a/lib/vm/src/instance/allocator.rs +++ b/lib/vm/src/instance/allocator.rs @@ -1,11 +1,11 @@ use super::{Instance, InstanceHandle}; -use crate::vmcontext::{VMMemoryDefinition, VMTableDefinition}; +use crate::vmcontext::VMTableDefinition; use std::alloc::{self, Layout}; use std::convert::TryFrom; use std::mem; use std::ptr::{self, NonNull}; use wasmer_types::entity::EntityRef; -use wasmer_types::VMOffsets; +use wasmer_types::{VMOffsets, VMMemoryDefinition}; use wasmer_types::{LocalMemoryIndex, LocalTableIndex, ModuleInfo}; /// This is an intermediate type that manages the raw allocation and diff --git a/lib/vm/src/instance/mod.rs b/lib/vm/src/instance/mod.rs index bf0be8a295b..ab11b2b5501 100644 --- a/lib/vm/src/instance/mod.rs +++ b/lib/vm/src/instance/mod.rs @@ -10,14 +10,13 @@ mod allocator; use crate::export::VMExtern; use crate::imports::Imports; -use crate::memory::MemoryError; use crate::store::{InternalStoreHandle, StoreObjects}; use crate::table::TableElement; use crate::trap::{catch_traps, Trap, TrapCode}; use crate::vmcontext::{ VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionContext, - VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport, VMMemoryDefinition, - VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline, + VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport, + VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline, memory_copy, memory_fill, }; use crate::{FunctionBodyPtr, MaybeInstanceOwned, TrapHandlerFn, VMFunctionBody}; use crate::{VMFuncRef, VMFunction, VMGlobal, VMMemory, VMTable}; @@ -37,7 +36,8 @@ use wasmer_types::entity::{packed_option::ReservedValue, BoxedSlice, EntityRef, use wasmer_types::{ DataIndex, DataInitializer, ElemIndex, ExportIndex, FunctionIndex, GlobalIndex, GlobalInit, LocalFunctionIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, - ModuleInfo, Pages, SignatureIndex, TableIndex, TableInitializer, VMOffsets, + ModuleInfo, Pages, SignatureIndex, TableIndex, TableInitializer, VMOffsets, LinearMemory, + MemoryError, VMMemoryDefinition }; /// A WebAssembly instance. @@ -632,7 +632,7 @@ impl Instance { let memory = self.memory(memory_index); // The following memory copy is not synchronized and is not atomic: - unsafe { memory.memory_copy(dst, src, len) } + unsafe { memory_copy(&memory, dst, src, len) } } /// Perform a `memory.copy` on an imported memory. @@ -646,7 +646,7 @@ impl Instance { let import = self.imported_memory(memory_index); let memory = unsafe { import.definition.as_ref() }; // The following memory copy is not synchronized and is not atomic: - unsafe { memory.memory_copy(dst, src, len) } + unsafe { memory_copy(memory, dst, src, len) } } /// Perform the `memory.fill` operation on a locally defined memory. @@ -663,7 +663,7 @@ impl Instance { ) -> Result<(), Trap> { let memory = self.memory(memory_index); // The following memory fill is not synchronized and is not atomic: - unsafe { memory.memory_fill(dst, val, len) } + unsafe { memory_fill(&memory, dst, val, len) } } /// Perform the `memory.fill` operation on an imported memory. @@ -681,7 +681,7 @@ impl Instance { let import = self.imported_memory(memory_index); let memory = unsafe { import.definition.as_ref() }; // The following memory fill is not synchronized and is not atomic: - unsafe { memory.memory_fill(dst, val, len) } + unsafe { memory_fill(memory, dst, val, len) } } /// Performs the `memory.init` operation. diff --git a/lib/vm/src/lib.rs b/lib/vm/src/lib.rs index 1b30f1e61e4..9b9903c0e80 100644 --- a/lib/vm/src/lib.rs +++ b/lib/vm/src/lib.rs @@ -45,7 +45,8 @@ pub use crate::function_env::VMFunctionEnvironment; pub use crate::global::*; pub use crate::imports::Imports; pub use crate::instance::{InstanceAllocator, InstanceHandle}; -pub use crate::memory::{MemoryError, VMMemory}; +pub use crate::memory::{VMMemory, VMOwnedMemory, VMSharedMemory}; +pub use wasmer_types::MemoryError; pub use crate::mmap::Mmap; pub use crate::probestack::PROBESTACK; pub use crate::sig_registry::SignatureRegistry; @@ -56,11 +57,11 @@ pub use crate::table::{TableElement, VMTable}; pub use crate::trap::*; pub use crate::vmcontext::{ VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMFunctionContext, - VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport, VMMemoryDefinition, + VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline, }; pub use wasmer_types::LibCall; -pub use wasmer_types::MemoryStyle; +pub use wasmer_types::{MemoryStyle, VMMemoryDefinition}; use wasmer_types::RawValue; pub use wasmer_types::TableStyle; pub use wasmer_types::{TargetSharedSignatureIndex, VMBuiltinFunctionIndex, VMOffsets}; diff --git a/lib/vm/src/memory.rs b/lib/vm/src/memory.rs index 787d5f390b5..d67ec52c4f4 100644 --- a/lib/vm/src/memory.rs +++ b/lib/vm/src/memory.rs @@ -5,88 +5,173 @@ //! //! `Memory` is to WebAssembly linear memories what `Table` is to WebAssembly tables. -use crate::vmcontext::VMMemoryDefinition; use crate::{mmap::Mmap, store::MaybeInstanceOwned}; use more_asserts::assert_ge; use std::cell::UnsafeCell; use std::convert::TryInto; use std::ptr::NonNull; -use thiserror::Error; -use wasmer_types::{Bytes, MemoryStyle, MemoryType, Pages}; - -/// Error type describing things that can go wrong when operating on Wasm Memories. -#[derive(Error, Debug, Clone, Eq, PartialEq, Hash)] -pub enum MemoryError { - /// Low level error with mmap. - #[error("Error when allocating memory: {0}")] - Region(String), - /// The operation would cause the size of the memory to exceed the maximum or would cause - /// an overflow leading to unindexable memory. - #[error("The memory could not grow: current size {} pages, requested increase: {} pages", current.0, attempted_delta.0)] - CouldNotGrow { - /// The current size in pages. - current: Pages, - /// The attempted amount to grow by in pages. - attempted_delta: Pages, - }, - /// The operation would cause the size of the memory size exceed the maximum. - #[error("The memory is invalid because {}", reason)] - InvalidMemory { - /// The reason why the provided memory is invalid. - reason: String, - }, - /// Caller asked for more minimum memory than we can give them. - #[error("The minimum requested ({} pages) memory is greater than the maximum allowed memory ({} pages)", min_requested.0, max_allowed.0)] - MinimumMemoryTooLarge { - /// The number of pages requested as the minimum amount of memory. - min_requested: Pages, - /// The maximum amount of memory we can allocate. - max_allowed: Pages, - }, - /// Caller asked for a maximum memory greater than we can give them. - #[error("The maximum requested memory ({} pages) is greater than the maximum allowed memory ({} pages)", max_requested.0, max_allowed.0)] - MaximumMemoryTooLarge { - /// The number of pages requested as the maximum amount of memory. - max_requested: Pages, - /// The number of pages requested as the maximum amount of memory. - max_allowed: Pages, - }, - /// A user defined error value, used for error cases not listed above. - #[error("A user-defined error occurred: {0}")] - Generic(String), +use std::sync::{RwLock, Arc}; +use wasmer_types::{Bytes, MemoryStyle, MemoryType, Pages, MemoryError, LinearMemory, VMMemoryDefinition}; + +// The memory mapped area +#[derive(Debug)] +struct WasmMmap { + // Our OS allocation of mmap'd memory. + alloc: Mmap, + // The current logical size in wasm pages of this linear memory. + size: Pages, + /// The owned memory definition used by the generated code + vm_memory_definition: MaybeInstanceOwned, } -/// A linear memory instance. -pub struct VMMemory { - // The underlying allocation. - mmap: WasmMmap, +impl WasmMmap +{ + fn get_vm_memory_definition(&self) -> NonNull { + self.vm_memory_definition.as_ptr() + } + + fn size(&self) -> Pages { + unsafe { + let md_ptr = self.get_vm_memory_definition(); + let md = md_ptr.as_ref(); + Bytes::from(md.current_length).try_into().unwrap() + } + } + + fn grow(&mut self, delta: Pages, conf: VMMemoryConfig) -> Result { + // Optimization of memory.grow 0 calls. + if delta.0 == 0 { + return Ok(self.size); + } + + let new_pages = self + .size + .checked_add(delta) + .ok_or(MemoryError::CouldNotGrow { + current: self.size, + attempted_delta: delta, + })?; + let prev_pages = self.size; + + if let Some(maximum) = conf.maximum { + if new_pages > maximum { + return Err(MemoryError::CouldNotGrow { + current: self.size, + attempted_delta: delta, + }); + } + } + + // Wasm linear memories are never allowed to grow beyond what is + // indexable. If the memory has no maximum, enforce the greatest + // limit here. + if new_pages >= Pages::max_value() { + // Linear memory size would exceed the index range. + return Err(MemoryError::CouldNotGrow { + current: self.size, + attempted_delta: delta, + }); + } + let delta_bytes = delta.bytes().0; + let prev_bytes = prev_pages.bytes().0; + let new_bytes = new_pages.bytes().0; + + if new_bytes > self.alloc.len() - conf.offset_guard_size { + // If the new size is within the declared maximum, but needs more memory than we + // have on hand, it's a dynamic heap and it can move. + let guard_bytes = conf.offset_guard_size; + let request_bytes = + new_bytes + .checked_add(guard_bytes) + .ok_or_else(|| MemoryError::CouldNotGrow { + current: new_pages, + attempted_delta: Bytes(guard_bytes).try_into().unwrap(), + })?; + + let mut new_mmap = + Mmap::accessible_reserved(new_bytes, request_bytes).map_err(MemoryError::Region)?; + + let copy_len = self.alloc.len() - conf.offset_guard_size; + new_mmap.as_mut_slice()[..copy_len] + .copy_from_slice(&self.alloc.as_slice()[..copy_len]); + + self.alloc = new_mmap; + } else if delta_bytes > 0 { + // Make the newly allocated pages accessible. + self + .alloc + .make_accessible(prev_bytes, delta_bytes) + .map_err(MemoryError::Region)?; + } + + self.size = new_pages; + + // update memory definition + unsafe { + let mut md_ptr = self.vm_memory_definition.as_ptr(); + let md = md_ptr.as_mut(); + md.current_length = new_pages.bytes().0; + md.base = self.alloc.as_mut_ptr() as _; + } + + Ok(prev_pages) + } +} + +/// A linear memory instance. +#[derive(Debug, Clone)] +struct VMMemoryConfig { // The optional maximum size in wasm pages of this linear memory. maximum: Option, - /// The WebAssembly linear memory description. memory: MemoryType, - /// Our chosen implementation style. style: MemoryStyle, - // Size in bytes of extra guard pages after the end to optimize loads and stores with // constant offsets. offset_guard_size: usize, +} - /// The owned memory definition used by the generated code - vm_memory_definition: MaybeInstanceOwned, +impl VMMemoryConfig +{ + fn ty(&self, minimum: Pages) -> MemoryType { + let mut out = self.memory; + out.minimum = minimum; + + out + } + + fn style(&self) -> MemoryStyle { + self.style + } } +/// A linear memory instance. #[derive(Debug)] -struct WasmMmap { - // Our OS allocation of mmap'd memory. - alloc: Mmap, - // The current logical size in wasm pages of this linear memory. - size: Pages, +pub struct VMOwnedMemory { + // The underlying allocation. + mmap: WasmMmap, + // Configuration of this memory + config: VMMemoryConfig, } -impl VMMemory { +unsafe impl Send for VMOwnedMemory { } +unsafe impl Sync for VMOwnedMemory { } + +/// A shared linear memory instance. +#[derive(Debug, Clone)] +pub struct VMSharedMemory { + // The underlying allocation. + mmap: Arc>, + // Configuration of this memory + config: VMMemoryConfig, +} + +unsafe impl Send for VMSharedMemory { } +unsafe impl Sync for VMSharedMemory { } + +impl VMOwnedMemory { /// Create a new linear memory instance with specified minimum and maximum number of wasm pages. /// /// This creates a `Memory` with owned metadata: this can be used to create a memory @@ -154,18 +239,11 @@ impl VMMemory { let mapped_pages = memory.minimum; let mapped_bytes = mapped_pages.bytes(); - let mut mmap = WasmMmap { - alloc: Mmap::accessible_reserved(mapped_bytes.0, request_bytes) - .map_err(MemoryError::Region)?, - size: memory.minimum, - }; - - let base_ptr = mmap.alloc.as_mut_ptr(); + let mut alloc = Mmap::accessible_reserved(mapped_bytes.0, request_bytes) + .map_err(MemoryError::Region)?; + let base_ptr = alloc.as_mut_ptr(); let mem_length = memory.minimum.bytes().0; - Ok(Self { - mmap, - maximum: memory.maximum, - offset_guard_size: offset_guard_bytes, + let mmap = WasmMmap { vm_memory_definition: if let Some(mem_loc) = vm_memory_location { { let mut ptr = mem_loc; @@ -180,127 +258,257 @@ impl VMMemory { current_length: mem_length, }))) }, - memory: *memory, - style: style.clone(), + alloc, + size: memory.minimum, + }; + + Ok(Self { + mmap: mmap, + config: VMMemoryConfig { + maximum: memory.maximum, + offset_guard_size: offset_guard_bytes, + memory: *memory, + style: style.clone(), + } }) } +} - /// Get the `VMMemoryDefinition`. - fn get_vm_memory_definition(&self) -> NonNull { - self.vm_memory_definition.as_ptr() +impl VMOwnedMemory +{ + /// Converts this owned memory into shared memory + pub fn to_shared(self) -> VMSharedMemory + { + VMSharedMemory { + mmap: Arc::new(RwLock::new(self.mmap)), + config: self.config + } } +} +impl LinearMemory +for VMOwnedMemory +{ /// Returns the type for this memory. - pub fn ty(&self) -> MemoryType { - let minimum = self.size(); - let mut out = self.memory; - out.minimum = minimum; + fn ty(&self) -> MemoryType { + let minimum = self.mmap.size(); + self.config.ty(minimum) + } - out + /// Returns the size of hte memory in pages + fn size(&self) -> Pages { + self.mmap.size() } /// Returns the memory style for this memory. - pub fn style(&self) -> &MemoryStyle { - &self.style + fn style(&self) -> MemoryStyle { + self.config.style() } - /// Returns the number of allocated wasm pages. - pub fn size(&self) -> Pages { - // TODO: investigate this function for race conditions - unsafe { - let md_ptr = self.get_vm_memory_definition(); - let md = md_ptr.as_ref(); - Bytes::from(md.current_length).try_into().unwrap() - } + /// Grow memory by the specified amount of wasm pages. + /// + /// Returns `None` if memory can't be grown by the specified amount + /// of wasm pages. + fn grow(&mut self, delta: Pages) -> Result { + self.mmap.grow(delta, self.config.clone()) + } + + /// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code. + fn vmmemory(&self) -> NonNull { + self.mmap.vm_memory_definition.as_ptr() + } + + /// Owned memory can not be cloned (this will always return None) + fn try_clone(&self) -> Option> { + None + } +} + +impl Into +for VMOwnedMemory +{ + fn into(self) -> VMMemory { + VMMemory(Box::new(self)) + } +} + +impl VMSharedMemory +{ + /// Create a new linear memory instance with specified minimum and maximum number of wasm pages. + /// + /// This creates a `Memory` with owned metadata: this can be used to create a memory + /// that will be imported into Wasm modules. + pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result { + Ok( + VMOwnedMemory::new(memory, style)?.to_shared() + ) + } + + /// Create a new linear memory instance with specified minimum and maximum number of wasm pages. + /// + /// This creates a `Memory` with metadata owned by a VM, pointed to by + /// `vm_memory_location`: this can be used to create a local memory. + /// + /// # Safety + /// - `vm_memory_location` must point to a valid location in VM memory. + pub unsafe fn from_definition( + memory: &MemoryType, + style: &MemoryStyle, + vm_memory_location: NonNull, + ) -> Result { + Ok( + VMOwnedMemory::from_definition(memory, style, vm_memory_location)?.to_shared() + ) + } +} + +impl LinearMemory +for VMSharedMemory +{ + /// Returns the type for this memory. + fn ty(&self) -> MemoryType { + let minimum = { + let guard = self.mmap.read().unwrap(); + guard.size() + }; + self.config.ty(minimum) + } + + /// Returns the size of hte memory in pages + fn size(&self) -> Pages { + let guard = self.mmap.read().unwrap(); + guard.size() + } + + /// Returns the memory style for this memory. + fn style(&self) -> MemoryStyle { + self.config.style() } /// Grow memory by the specified amount of wasm pages. /// /// Returns `None` if memory can't be grown by the specified amount /// of wasm pages. - pub fn grow(&mut self, delta: Pages) -> Result { - // Optimization of memory.grow 0 calls. - if delta.0 == 0 { - return Ok(self.mmap.size); - } + fn grow(&mut self, delta: Pages) -> Result { + let mut guard = self.mmap.write().unwrap(); + guard.grow(delta, self.config.clone()) + } - let new_pages = self - .mmap - .size - .checked_add(delta) - .ok_or(MemoryError::CouldNotGrow { - current: self.mmap.size, - attempted_delta: delta, - })?; - let prev_pages = self.mmap.size; + /// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code. + fn vmmemory(&self) -> NonNull { + let guard = self.mmap.read().unwrap(); + guard.vm_memory_definition.as_ptr() + } - if let Some(maximum) = self.maximum { - if new_pages > maximum { - return Err(MemoryError::CouldNotGrow { - current: self.mmap.size, - attempted_delta: delta, - }); - } - } + /// Shared memory can always be cloned + fn try_clone(&self) -> Option> { + Some(Box::new(self.clone())) + } +} - // Wasm linear memories are never allowed to grow beyond what is - // indexable. If the memory has no maximum, enforce the greatest - // limit here. - if new_pages >= Pages::max_value() { - // Linear memory size would exceed the index range. - return Err(MemoryError::CouldNotGrow { - current: self.mmap.size, - attempted_delta: delta, - }); - } +impl Into +for VMSharedMemory +{ + fn into(self) -> VMMemory { + VMMemory(Box::new(self)) + } +} - let delta_bytes = delta.bytes().0; - let prev_bytes = prev_pages.bytes().0; - let new_bytes = new_pages.bytes().0; +/// Represents linear memory that can be either owned or shared +#[derive(Debug)] +pub struct VMMemory(Box); - if new_bytes > self.mmap.alloc.len() - self.offset_guard_size { - // If the new size is within the declared maximum, but needs more memory than we - // have on hand, it's a dynamic heap and it can move. - let guard_bytes = self.offset_guard_size; - let request_bytes = - new_bytes - .checked_add(guard_bytes) - .ok_or_else(|| MemoryError::CouldNotGrow { - current: new_pages, - attempted_delta: Bytes(guard_bytes).try_into().unwrap(), - })?; +impl Into +for Box +{ + fn into(self) -> VMMemory { + VMMemory(self) + } +} - let mut new_mmap = - Mmap::accessible_reserved(new_bytes, request_bytes).map_err(MemoryError::Region)?; +impl LinearMemory +for VMMemory +{ + /// Returns the type for this memory. + fn ty(&self) -> MemoryType { + self.0.ty() + } - let copy_len = self.mmap.alloc.len() - self.offset_guard_size; - new_mmap.as_mut_slice()[..copy_len] - .copy_from_slice(&self.mmap.alloc.as_slice()[..copy_len]); + /// Returns the size of hte memory in pages + fn size(&self) -> Pages { + self.0.size() + } - self.mmap.alloc = new_mmap; - } else if delta_bytes > 0 { - // Make the newly allocated pages accessible. - self.mmap - .alloc - .make_accessible(prev_bytes, delta_bytes) - .map_err(MemoryError::Region)?; - } + /// Grow memory by the specified amount of wasm pages. + /// + /// Returns `None` if memory can't be grown by the specified amount + /// of wasm pages. + fn grow(&mut self, delta: Pages) -> Result { + self.0.grow(delta) + } - self.mmap.size = new_pages; + /// Returns the memory style for this memory. + fn style(&self) -> MemoryStyle { + self.0.style() + } - // update memory definition - unsafe { - let mut md_ptr = self.get_vm_memory_definition(); - let md = md_ptr.as_mut(); - md.current_length = new_pages.bytes().0; - md.base = self.mmap.alloc.as_mut_ptr() as _; - } + /// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code. + fn vmmemory(&self) -> NonNull { + self.0.vmmemory() + } - Ok(prev_pages) + /// Attempts to clone this memory (if its clonable) + fn try_clone(&self) -> Option> { + self.0.try_clone() } +} - /// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code. - pub fn vmmemory(&self) -> NonNull { - self.get_vm_memory_definition() +impl VMMemory +{ + /// Creates a new linear memory instance of the correct type with specified + /// minimum and maximum number of wasm pages. + /// + /// This creates a `Memory` with owned metadata: this can be used to create a memory + /// that will be imported into Wasm modules. + pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result { + Ok( + if memory.shared { + Self(Box::new(VMSharedMemory::new(memory, style)?)) + } else { + Self(Box::new(VMOwnedMemory::new(memory, style)?)) + } + ) + } + + /// Create a new linear memory instance with specified minimum and maximum number of wasm pages. + /// + /// This creates a `Memory` with metadata owned by a VM, pointed to by + /// `vm_memory_location`: this can be used to create a local memory. + /// + /// # Safety + /// - `vm_memory_location` must point to a valid location in VM memory. + pub unsafe fn from_definition( + memory: &MemoryType, + style: &MemoryStyle, + vm_memory_location: NonNull, + ) -> Result { + Ok( + if memory.shared { + Self(Box::new(VMSharedMemory::from_definition(memory, style, vm_memory_location)?)) + } else { + Self(Box::new(VMOwnedMemory::from_definition(memory, style, vm_memory_location)?)) + } + ) + } + + /// Creates VMMemory from a custom implementation - the following into implementations + /// are natively supported + /// - VMOwnedMemory -> VMMemory + /// - VMSharedMemory -> VMMemory + /// - Box -> VMMemory + pub fn from_custom(memory: IntoVMMemory) -> VMMemory + where IntoVMMemory: Into + { + memory.into() } } diff --git a/lib/vm/src/store.rs b/lib/vm/src/store.rs index 4faee579a4d..93ae12e5511 100644 --- a/lib/vm/src/store.rs +++ b/lib/vm/src/store.rs @@ -78,6 +78,11 @@ impl StoreObjects { self.id } + /// Sets the ID of this store + pub fn set_id(&mut self, id: StoreId) { + self.id = id; + } + /// Returns a pair of mutable references from two handles. /// /// Panics if both handles point to the same object. @@ -266,3 +271,23 @@ impl MaybeInstanceOwned { } } } + +impl std::fmt::Debug +for MaybeInstanceOwned +where T: std::fmt::Debug +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MaybeInstanceOwned::Host(p) => { + write!(f, "host(")?; + p.as_ref().fmt(f)?; + write!(f, ")") + }, + MaybeInstanceOwned::Instance(p) => { + write!(f, "instance(")?; + unsafe { p.as_ref().fmt(f)? }; + write!(f, ")") + } + } + } +} diff --git a/lib/vm/src/vmcontext.rs b/lib/vm/src/vmcontext.rs index bb1cb6cc9fc..6940f43a265 100644 --- a/lib/vm/src/vmcontext.rs +++ b/lib/vm/src/vmcontext.rs @@ -15,7 +15,7 @@ use crate::{VMBuiltinFunctionIndex, VMFunction}; use std::convert::TryFrom; use std::ptr::{self, NonNull}; use std::u32; -use wasmer_types::RawValue; +use wasmer_types::{RawValue, VMMemoryDefinition}; /// Union representing the first parameter passed when calling a function. /// @@ -303,120 +303,67 @@ mod test_vmglobal_import { } } -/// The fields compiled code needs to access to utilize a WebAssembly linear -/// memory defined within the instance, namely the start address and the -/// size in bytes. -#[derive(Debug, Copy, Clone)] -#[repr(C)] -pub struct VMMemoryDefinition { - /// The start address which is always valid, even if the memory grows. - pub base: *mut u8, - - /// The current logical size of this linear memory in bytes. - pub current_length: usize, -} - -/// # Safety -/// This data is safe to share between threads because it's plain data that -/// is the user's responsibility to synchronize. -unsafe impl Send for VMMemoryDefinition {} +/// Do an unsynchronized, non-atomic `memory.copy` for the memory. +/// +/// # Errors +/// +/// Returns a `Trap` error when the source or destination ranges are out of +/// bounds. +/// /// # Safety -/// This data is safe to share between threads because it's plain data that -/// is the user's responsibility to synchronize. And it's `Copy` so there's -/// really no difference between passing it by reference or by value as far as -/// correctness in a multi-threaded context is concerned. -unsafe impl Sync for VMMemoryDefinition {} - -impl VMMemoryDefinition { - /// Do an unsynchronized, non-atomic `memory.copy` for the memory. - /// - /// # Errors - /// - /// Returns a `Trap` error when the source or destination ranges are out of - /// bounds. - /// - /// # Safety - /// The memory is not copied atomically and is not synchronized: it's the - /// caller's responsibility to synchronize. - pub(crate) unsafe fn memory_copy(&self, dst: u32, src: u32, len: u32) -> Result<(), Trap> { - // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy - if src +/// The memory is not copied atomically and is not synchronized: it's the +/// caller's responsibility to synchronize. +pub(crate) unsafe fn memory_copy(mem: &VMMemoryDefinition, dst: u32, src: u32, len: u32) -> Result<(), Trap> { + // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy + if src + .checked_add(len) + .map_or(true, |n| usize::try_from(n).unwrap() > mem.current_length) + || dst .checked_add(len) - .map_or(true, |n| usize::try_from(n).unwrap() > self.current_length) - || dst - .checked_add(len) - .map_or(true, |m| usize::try_from(m).unwrap() > self.current_length) - { - return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds)); - } - - let dst = usize::try_from(dst).unwrap(); - let src = usize::try_from(src).unwrap(); - - // Bounds and casts are checked above, by this point we know that - // everything is safe. - let dst = self.base.add(dst); - let src = self.base.add(src); - ptr::copy(src, dst, len as usize); - - Ok(()) + .map_or(true, |m| usize::try_from(m).unwrap() > mem.current_length) + { + return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds)); } - /// Perform the `memory.fill` operation for the memory in an unsynchronized, - /// non-atomic way. - /// - /// # Errors - /// - /// Returns a `Trap` error if the memory range is out of bounds. - /// - /// # Safety - /// The memory is not filled atomically and is not synchronized: it's the - /// caller's responsibility to synchronize. - pub(crate) unsafe fn memory_fill(&self, dst: u32, val: u32, len: u32) -> Result<(), Trap> { - if dst - .checked_add(len) - .map_or(true, |m| usize::try_from(m).unwrap() > self.current_length) - { - return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds)); - } + let dst = usize::try_from(dst).unwrap(); + let src = usize::try_from(src).unwrap(); - let dst = isize::try_from(dst).unwrap(); - let val = val as u8; + // Bounds and casts are checked above, by this point we know that + // everything is safe. + let dst = mem.base.add(dst); + let src = mem.base.add(src); + ptr::copy(src, dst, len as usize); - // Bounds and casts are checked above, by this point we know that - // everything is safe. - let dst = self.base.offset(dst); - ptr::write_bytes(dst, val, len as usize); + Ok(()) +} - Ok(()) +/// Perform the `memory.fill` operation for the memory in an unsynchronized, +/// non-atomic way. +/// +/// # Errors +/// +/// Returns a `Trap` error if the memory range is out of bounds. +/// +/// # Safety +/// The memory is not filled atomically and is not synchronized: it's the +/// caller's responsibility to synchronize. +pub(crate) unsafe fn memory_fill(mem: &VMMemoryDefinition, dst: u32, val: u32, len: u32) -> Result<(), Trap> { + if dst + .checked_add(len) + .map_or(true, |m| usize::try_from(m).unwrap() > mem.current_length) + { + return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds)); } -} -#[cfg(test)] -mod test_vmmemory_definition { - use super::VMMemoryDefinition; - use crate::VMOffsets; - use memoffset::offset_of; - use std::mem::size_of; - use wasmer_types::ModuleInfo; + let dst = isize::try_from(dst).unwrap(); + let val = val as u8; - #[test] - fn check_vmmemory_definition_offsets() { - let module = ModuleInfo::new(); - let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module); - assert_eq!( - size_of::(), - usize::from(offsets.size_of_vmmemory_definition()) - ); - assert_eq!( - offset_of!(VMMemoryDefinition, base), - usize::from(offsets.vmmemory_definition_base()) - ); - assert_eq!( - offset_of!(VMMemoryDefinition, current_length), - usize::from(offsets.vmmemory_definition_current_length()) - ); - } + // Bounds and casts are checked above, by this point we know that + // everything is safe. + let dst = mem.base.offset(dst); + ptr::write_bytes(dst, val, len as usize); + + Ok(()) } /// The fields compiled code needs to access to utilize a WebAssembly table diff --git a/lib/wasi-types/src/bus.rs b/lib/wasi-types/src/bus.rs index ff8bea2ecb3..33ff6e77ec4 100644 --- a/lib/wasi-types/src/bus.rs +++ b/lib/wasi-types/src/bus.rs @@ -1,6 +1,7 @@ use super::*; use wasmer_derive::ValueType; -use wasmer_types::MemorySize; + +pub type __wasi_hash_t = u128; pub type __wasi_busdataformat_t = u8; pub const __WASI_BUS_DATA_FORMAT_RAW: __wasi_busdataformat_t = 0; @@ -28,7 +29,7 @@ pub struct __wasi_option_bid_t { pub bid: __wasi_bid_t, } -pub type __wasi_cid_t = u8; +pub type __wasi_cid_t = u64; #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] #[repr(C)] @@ -62,23 +63,20 @@ pub struct __wasi_busevent_exit_t { #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] #[repr(C)] -pub struct __wasi_busevent_call_t { +pub struct __wasi_busevent_call_t { pub parent: __wasi_option_cid_t, pub cid: __wasi_cid_t, pub format: __wasi_busdataformat_t, - pub topic_ptr: M::Offset, - pub topic_len: M::Offset, - pub buf_ptr: M::Offset, - pub buf_len: M::Offset, + pub topic_hash: __wasi_hash_t, + pub fd: __wasi_fd_t, } #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] #[repr(C)] -pub struct __wasi_busevent_result_t { +pub struct __wasi_busevent_result_t { pub format: __wasi_busdataformat_t, pub cid: __wasi_cid_t, - pub buf_ptr: M::Offset, - pub buf_len: M::Offset, + pub fd: __wasi_fd_t, } #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] @@ -96,18 +94,25 @@ pub struct __wasi_busevent_close_t { #[derive(Copy, Clone)] #[repr(C)] -pub union __wasi_busevent_u { +pub union __wasi_busevent_u { pub noop: u8, pub exit: __wasi_busevent_exit_t, - pub call: __wasi_busevent_call_t, - pub result: __wasi_busevent_result_t, + pub call: __wasi_busevent_call_t, + pub result: __wasi_busevent_result_t, pub fault: __wasi_busevent_fault_t, pub close: __wasi_busevent_close_t, } +#[derive(Copy, Clone, ValueType)] +#[repr(C)] +pub struct __wasi_busevent_t { + pub tag: __wasi_buseventtype_t, + pub padding: [u8; 63], +} + #[derive(Copy, Clone)] #[repr(C)] -pub struct __wasi_busevent_t { +pub struct __wasi_busevent_t2 { pub tag: __wasi_buseventtype_t, - pub u: __wasi_busevent_u, + pub u: __wasi_busevent_u, } diff --git a/lib/wasi-types/src/file.rs b/lib/wasi-types/src/file.rs index 0d58ba9bbe4..92f0e74a6be 100644 --- a/lib/wasi-types/src/file.rs +++ b/lib/wasi-types/src/file.rs @@ -18,6 +18,9 @@ pub const __WASI_STDERR_FILENO: __wasi_fd_t = 2; pub type __wasi_pid_t = u32; pub type __wasi_tid_t = u32; +pub type __wasi_tl_key_t = u32; +pub type __wasi_tl_val_t = u64; + pub type __wasi_fdflags_t = u16; pub const __WASI_FDFLAG_APPEND: __wasi_fdflags_t = 1 << 0; pub const __WASI_FDFLAG_DSYNC: __wasi_fdflags_t = 1 << 1; diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index bfa746e2921..7f4a456d44c 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -31,6 +31,10 @@ bincode = { version = "1.3", optional = true } chrono = { version = "^0.4", default-features = false, features = [ "wasmbind", "std", "clock" ], optional = true } derivative = { version = "^2" } bytes = "1" +lazy_static = "1.4" +sha2 = { version = "0.10" } +waker-fn = { version = "1.1" } +cooked-waker = "^5" [target.'cfg(unix)'.dependencies] libc = { version = "^0.2", default-features = false } @@ -45,18 +49,23 @@ wasm-bindgen = "0.2.74" wasm-bindgen-test = "0.3.0" tracing-wasm = "0.2" +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] +tracing-subscriber = { version = "^0.2" } + [features] default = ["sys-default"] sys = ["wasmer/sys"] -sys-default = ["wasmer/wat", "wasmer/compiler", "sys", "logging", "host-fs", "sys-poll", "host-vnet" ] +sys-default = ["wasmer/wat", "wasmer/compiler", "sys", "logging", "host-fs", "sys-poll", "sys-thread", "host-vnet", "host-threads" ] sys-poll = [] +sys-thread = [] js = ["wasmer/js", "mem-fs", "wasmer-vfs/no-time", "getrandom/js", "chrono"] js-default = ["js", "wasmer/js-default"] test-js = ["js", "wasmer/js-default", "wasmer/wat"] host-vnet = [ "wasmer-wasi-local-networking" ] +host-threads = [] host-fs = ["wasmer-vfs/host-fs"] mem-fs = ["wasmer-vfs/mem-fs"] diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 4daeb25a47d..8c8f533388c 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -40,8 +40,6 @@ mod state; mod syscalls; mod utils; -use crate::syscalls::*; - pub use crate::state::{ Fd, Pipe, Stderr, Stdin, Stdout, WasiFs, WasiInodes, WasiState, WasiStateBuilder, WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD, @@ -50,6 +48,11 @@ pub use crate::syscalls::types; pub use crate::utils::{ get_wasi_version, get_wasi_versions, is_wasi_module, is_wasix_module, WasiVersion, }; +#[allow(unused_imports)] +#[cfg(feature = "js")] +use bytes::Bytes; +use derivative::Derivative; +use tracing::trace; pub use wasmer_vbus::{UnsupportedVirtualBus, VirtualBus}; #[deprecated(since = "2.1.0", note = "Please use `wasmer_vfs::FsError`")] pub use wasmer_vfs::FsError as WasiFsError; @@ -59,18 +62,19 @@ pub use wasmer_vfs::{FsError, VirtualFile}; pub use wasmer_vnet::{UnsupportedVirtualNetworking, VirtualNetworking}; use wasmer_wasi_types::__WASI_CLOCK_MONOTONIC; -use derivative::*; +use std::cell::RefCell; use std::ops::Deref; +use std::sync::atomic::{AtomicU32, Ordering}; use thiserror::Error; use wasmer::{ - imports, namespace, AsStoreMut, AsStoreRef, Exports, Function, FunctionEnv, Imports, Memory, - Memory32, MemoryAccessError, MemorySize, MemoryView, Module, TypedFunction, + imports, namespace, AsStoreMut, Exports, Function, FunctionEnv, Imports, Memory, Memory32, + MemoryAccessError, MemorySize, Module, TypedFunction, Memory64, MemoryView, AsStoreRef, Instance, ExportError }; pub use runtime::{ - PluggableRuntimeImplementation, WasiRuntimeImplementation, WasiThreadError, WasiTtyState, + PluggableRuntimeImplementation, WasiRuntimeImplementation, WasiThreadError, WasiTtyState }; -use std::sync::{mpsc, Arc, Mutex, RwLockReadGuard, RwLockWriteGuard}; +use std::sync::{Arc, RwLockReadGuard, RwLockWriteGuard}; use std::time::Duration; /// This is returned in `RuntimeError`. @@ -84,9 +88,20 @@ pub enum WasiError { } /// Represents the ID of a WASI thread -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct WasiThreadId(u32); +impl WasiThreadId { + pub fn raw(&self) -> u32 { + self.0 + } + + pub fn inc(&mut self) -> WasiThreadId { + self.0 += 1; + self.clone() + } +} + impl From for WasiThreadId { fn from(id: u32) -> Self { Self(id) @@ -98,203 +113,157 @@ impl From for u32 { } } -/// Represents the ID of a sub-process -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct WasiBusProcessId(u32); +/// Represents the ID of a WASI calling thread +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct WasiCallingId(u32); -impl From for WasiBusProcessId { - fn from(id: u32) -> Self { - Self(id) +impl WasiCallingId { + pub fn raw(&self) -> u32 { + self.0 } -} -impl From for u32 { - fn from(id: WasiBusProcessId) -> u32 { - id.0 as u32 - } -} -#[derive(Debug, Clone)] -pub struct WasiThread { - /// ID of this thread - #[allow(dead_code)] - id: WasiThreadId, - /// Signalers used to tell joiners that the thread has exited - exit: Arc>>>, - /// Event to wait on for the thread to join - join: Arc>>, + pub fn inc(&mut self) -> WasiCallingId { + self.0 += 1; + self.clone() + } } -impl WasiThread { - /// Waits for the thread to exit (false = timeout) - pub fn join(&self, timeout: Duration) -> bool { - let guard = self.join.lock().unwrap(); - let timeout = guard.recv_timeout(timeout); - match timeout { - Ok(_) => true, - Err(mpsc::RecvTimeoutError::Disconnected) => true, - Err(mpsc::RecvTimeoutError::Timeout) => false, - } +impl From for WasiCallingId { + fn from(id: u32) -> Self { + Self(id) } } - -pub struct WasiFunctionEnv { - pub env: FunctionEnv, +impl From for u32 { + fn from(t: WasiCallingId) -> u32 { + t.0 as u32 + } } -impl WasiFunctionEnv { - pub fn new(store: &mut impl AsStoreMut, env: WasiEnv) -> Self { - Self { - env: FunctionEnv::new(store, env), - } - } +/// Represents the ID of a sub-process +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct WasiBusProcessId(u32); - /// Get an `Imports` for a specific version of WASI detected in the module. - pub fn import_object( - &self, - store: &mut impl AsStoreMut, - module: &Module, - ) -> Result { - let wasi_version = get_wasi_version(module, false).ok_or(WasiError::UnknownWasiVersion)?; - Ok(generate_import_object_from_env( - store, - &self.env, - wasi_version, - )) +impl From for WasiBusProcessId { + fn from(id: u32) -> Self { + Self(id) } - - pub fn data_mut<'a>(&'a self, store: &'a mut impl AsStoreMut) -> &'a mut WasiEnv { - self.env.as_mut(store) +} +impl Into for WasiBusProcessId { + fn into(self) -> u32 { + self.0 as u32 } +} - /// Like `import_object` but containing all the WASI versions detected in - /// the module. - pub fn import_object_for_all_wasi_versions( - &self, - store: &mut impl AsStoreMut, - module: &Module, - ) -> Result { - let wasi_versions = - get_wasi_versions(module, false).ok_or(WasiError::UnknownWasiVersion)?; - - let mut resolver = Imports::new(); - for version in wasi_versions.iter() { - let new_import_object = generate_import_object_from_env(store, &self.env, *version); - for ((n, m), e) in new_import_object.into_iter() { - resolver.define(&n, &m, e); - } - } - - if is_wasix_module(module) { - self.data_mut(store) - .state - .fs - .is_wasix - .store(true, std::sync::atomic::Ordering::Release); - } - - Ok(resolver) - } +#[derive(Clone)] +pub struct WasiEnvInner +{ + /// Represents a reference to the memory + memory: Memory, + /// Represents the module that is being used (this is NOT send/sync) + /// however the code itself makes sure that it is used in a safe way + module: Module, + /// Represents the callback for spawning a thread (name = "_start_thread") + /// (due to limitations with i64 in browsers the parameters are broken into i32 pairs) + /// [this takes a user_data field] + thread_spawn: Option>, + /// Represents the callback for spawning a reactor (name = "_react") + /// (due to limitations with i64 in browsers the parameters are broken into i32 pairs) + /// [this takes a user_data field] + react: Option>, + /// Represents the callback for destroying a local thread variable (name = "_thread_local_destroy") + /// [this takes a pointer to the destructor and the data to be destroyed] + thread_local_destroy: Option>, } +/// The code itself makes safe use of the struct so multiple threads don't access +/// it (without this the JS code prevents the reference to the module from being stored +/// which is needed for the multithreading mode) +unsafe impl Send for WasiEnvInner { } +unsafe impl Sync for WasiEnvInner { } + /// The environment provided to the WASI imports. #[derive(Derivative, Clone)] #[derivative(Debug)] -#[allow(dead_code)] -pub struct WasiEnv { +pub struct WasiEnv +where +{ /// ID of this thread (zero is the main thread) id: WasiThreadId, - /// Represents a reference to the memory - memory: Option, - /// If the module has it then map the thread start - #[derivative(Debug = "ignore")] - thread_start: Option>, - #[derivative(Debug = "ignore")] - reactor_work: Option>, - #[derivative(Debug = "ignore")] - reactor_finish: Option>, - #[derivative(Debug = "ignore")] - malloc: Option>, - #[derivative(Debug = "ignore")] - free: Option>, /// Shared state of the WASI system. Manages all the data that the /// executing WASI program can see. pub state: Arc, + /// Inner functions and references that are loaded before the environment starts + #[derivative(Debug = "ignore")] + pub inner: Option, /// Implementation of the WASI runtime. pub(crate) runtime: Arc, } +// Represents the current thread ID for the executing method +thread_local!(static CALLER_ID: RefCell = RefCell::new(0)); +lazy_static::lazy_static! { + static ref CALLER_ID_SEED: Arc = Arc::new(AtomicU32::new(1)); +} + +/// Returns the current thread ID +pub fn current_caller_id() -> WasiCallingId { + CALLER_ID.with(|f| { + let mut caller_id = f.borrow_mut(); + if *caller_id == 0 { + *caller_id = CALLER_ID_SEED.fetch_add(1, Ordering::AcqRel); + } + *caller_id + }).into() +} + impl WasiEnv { - /// Create a new WasiEnv from a WasiState (memory will be set to None) pub fn new(state: WasiState) -> Self { - Self { + let state = Arc::new(state); + Self::new_ext(state) + } + + fn new_ext(state: Arc) -> Self { + let ret = Self { id: 0u32.into(), - state: Arc::new(state), - memory: None, - thread_start: None, - reactor_work: None, - reactor_finish: None, - malloc: None, - free: None, + state, + inner: None, runtime: Arc::new(PluggableRuntimeImplementation::default()), - } + }; + ret } - + /// Returns a copy of the current runtime implementation for this environment - pub fn runtime(&self) -> &(dyn WasiRuntimeImplementation) { + pub fn runtime<'a>(&'a self) -> &'a (dyn WasiRuntimeImplementation) { self.runtime.deref() } /// Overrides the runtime implementation for this environment - pub fn set_runtime(&mut self, runtime: R) + pub fn set_runtime(&mut self, runtime: R) where R: WasiRuntimeImplementation + Send + Sync + 'static, { self.runtime = Arc::new(runtime); } - /// Returns the current thread ID - pub fn current_thread_id(&self) -> WasiThreadId { - self.id - } - - /// Creates a new thread only this wasi environment - pub fn new_thread(&self) -> WasiThread { - let (tx, rx) = mpsc::channel(); - - let mut guard = self.state.threading.lock().unwrap(); - - guard.thread_seed += 1; - let next_id: WasiThreadId = guard.thread_seed.into(); - - let thread = WasiThread { - id: next_id, - exit: Arc::new(Mutex::new(Some(tx))), - join: Arc::new(Mutex::new(rx)), - }; - - guard.threads.insert(thread.id, thread.clone()); - thread - } - - /// Copy the lazy reference so that when it's initialized during the - /// export phase, all the other references get a copy of it - pub fn memory_clone(&self) -> Option { - self.memory.clone() + /// Returns the number of active threads + pub fn active_threads(&self) -> u32 { + let guard = self.state.threading.read().unwrap(); + guard.active_threads() } // Yields execution pub fn yield_now(&self) -> Result<(), WasiError> { - self.runtime.yield_now(self.id)?; + self.runtime.yield_now(current_caller_id())?; Ok(()) } // Sleeps for a period of time pub fn sleep(&self, duration: Duration) -> Result<(), WasiError> { let duration = duration.as_nanos(); - let start = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; + let start = syscalls::platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; self.yield_now()?; loop { - let now = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; + let now = syscalls::platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; let delta = match now.checked_sub(start) { Some(a) => a, None => { @@ -317,44 +286,46 @@ impl WasiEnv { } /// Accesses the virtual networking implementation - pub fn net(&self) -> &(dyn VirtualNetworking) { + pub fn net<'a>(&'a self) -> &'a (dyn VirtualNetworking) { self.runtime.networking() } /// Accesses the virtual bus implementation - pub fn bus(&self) -> &(dyn VirtualBus) { + pub fn bus<'a>(&'a self) -> &'a (dyn VirtualBus) { self.runtime.bus() } - /// Set the memory of the WasiEnv (can only be done once) - pub fn set_memory(&mut self, memory: Memory) { - if self.memory.is_some() { - panic!("Memory of a WasiEnv can only be set once!"); - } - self.memory = Some(memory); + /// Providers safe access to the initialized part of WasiEnv + /// (it must be initialized before it can be used) + pub fn inner(&self) -> &WasiEnvInner { + self.inner.as_ref() + .expect("You must initialize the WasiEnv before using it") } - + /// Providers safe access to the memory /// (it must be initialized before it can be used) pub fn memory_view<'a>(&'a self, store: &'a impl AsStoreRef) -> MemoryView<'a> { self.memory().view(store) } - /// Get memory, that needs to have been set fist + /// Providers safe access to the memory + /// (it must be initialized before it can be used) pub fn memory(&self) -> &Memory { - self.memory.as_ref().unwrap() + &self.inner().memory + } + + /// Copy the lazy reference so that when it's initialized during the + /// export phase, all the other references get a copy of it + pub fn memory_clone(&self) -> Memory { + self.memory().clone() } /// Get the WASI state pub fn state(&self) -> &WasiState { &self.state } - - pub(crate) fn get_memory_and_wasi_state<'a>( - &'a self, - store: &'a impl AsStoreRef, - _mem_index: u32, - ) -> (MemoryView<'a>, &WasiState) { + + pub(crate) fn get_memory_and_wasi_state<'a>(&'a self, store: &'a impl AsStoreRef, _mem_index: u32) -> (MemoryView<'a>, &WasiState) { let memory = self.memory_view(store); let state = self.state.deref(); (memory, state) @@ -383,23 +354,121 @@ impl WasiEnv { } } -/// Create an [`Imports`] from a [`Context`] +pub struct WasiFunctionEnv { + pub env: FunctionEnv, +} + +impl WasiFunctionEnv { + pub fn new(store: &mut impl AsStoreMut, env: WasiEnv) -> Self { + Self { + env: FunctionEnv::new(store, env), + } + } + + /// Get an `Imports` for a specific version of WASI detected in the module. + pub fn import_object( + &self, + store: &mut impl AsStoreMut, + module: &Module, + ) -> Result { + let wasi_version = get_wasi_version(module, false).ok_or(WasiError::UnknownWasiVersion)?; + Ok(generate_import_object_from_env( + store, + &self.env, + wasi_version, + )) + } + + /// Gets a reference to the WasiEnvironment + pub fn data<'a>(&'a self, store: &'a impl AsStoreRef) -> &'a WasiEnv { + self.env.as_ref(store) + } + + /// Gets a mutable- reference to the host state in this context. + pub fn data_mut<'a>(&'a mut self, store: &'a mut impl AsStoreMut) -> &'a mut WasiEnv { + self.env + .as_mut(store) + } + + /// Initializes the WasiEnv using the instance exports + /// (this must be executed before attempting to use it) + /// (as the stores can not by themselves be passed between threads we can store the module + /// in a thread-local variables and use it later - for multithreading) + pub fn initialize(&mut self, store: &mut impl AsStoreMut, instance: &Instance) -> Result<(), ExportError> + { + // List all the exports and imports + for ns in instance.module().exports() { + //trace!("module::export - {} ({:?})", ns.name(), ns.ty()); + trace!("module::export - {}", ns.name()); + } + for ns in instance.module().imports() { + trace!("module::import - {}::{}", ns.module(), ns.name()); + } + + // First we get the malloc function which if it exists will be used to + // create the pthread_self structure + let memory = instance.exports.get_memory("memory")?.clone(); + let new_inner = WasiEnvInner { + memory, + module: instance.module().clone(), + thread_spawn: instance.exports.get_typed_function(store, "_start_thread").ok(), + react: instance.exports.get_typed_function(store, "_react").ok(), + thread_local_destroy: instance.exports.get_typed_function(store, "_thread_local_destroy").ok(), + }; + + let env = self.data_mut(store); + env.inner.replace(new_inner); + + env.state.fs.is_wasix.store( + is_wasix_module(instance.module()), + std::sync::atomic::Ordering::Release, + ); + + Ok(()) + } + + /// Like `import_object` but containing all the WASI versions detected in + /// the module. + pub fn import_object_for_all_wasi_versions( + &self, + store: &mut impl AsStoreMut, + module: &Module, + ) -> Result { + let wasi_versions = + get_wasi_versions(module, false).ok_or(WasiError::UnknownWasiVersion)?; + + let mut resolver = Imports::new(); + for version in wasi_versions.iter() { + let new_import_object = generate_import_object_from_env(store, &self.env, *version); + for ((n, m), e) in new_import_object.into_iter() { + resolver.define(&n, &m, e); + } + } + + Ok(resolver) + } +} + +/// Create an [`Imports`] with an existing [`WasiEnv`]. `WasiEnv` +/// needs a [`WasiState`], that can be constructed from a +/// [`WasiStateBuilder`](state::WasiStateBuilder). pub fn generate_import_object_from_env( store: &mut impl AsStoreMut, - env: &FunctionEnv, + ctx: &FunctionEnv, version: WasiVersion, ) -> Imports { match version { - WasiVersion::Snapshot0 => generate_import_object_snapshot0(store, env), + WasiVersion::Snapshot0 => generate_import_object_snapshot0(store, ctx), WasiVersion::Snapshot1 | WasiVersion::Latest => { - generate_import_object_snapshot1(store, env) + generate_import_object_snapshot1(store, ctx) } - WasiVersion::Wasix32v1 => generate_import_object_wasix32_v1(store, env), - WasiVersion::Wasix64v1 => generate_import_object_wasix64_v1(store, env), + WasiVersion::Wasix32v1 => generate_import_object_wasix32_v1(store, ctx), + WasiVersion::Wasix64v1 => generate_import_object_wasix64_v1(store, ctx), } } fn wasi_unstable_exports(mut store: &mut impl AsStoreMut, env: &FunctionEnv) -> Exports { + use syscalls::*; let namespace = namespace! { "args_get" => Function::new_typed_with_env(&mut store, env, args_get::), "args_sizes_get" => Function::new_typed_with_env(&mut store, env, args_sizes_get::), @@ -454,6 +523,7 @@ fn wasi_snapshot_preview1_exports( mut store: &mut impl AsStoreMut, env: &FunctionEnv, ) -> Exports { + use syscalls::*; let namespace = namespace! { "args_get" => Function::new_typed_with_env(&mut store, env, args_get::), "args_sizes_get" => Function::new_typed_with_env(&mut store, env, args_sizes_get::), @@ -503,15 +573,270 @@ fn wasi_snapshot_preview1_exports( }; namespace } + +fn wasix_exports_32( + mut store: &mut impl AsStoreMut, + env: &FunctionEnv, +) -> Exports +{ + use syscalls::*; + let namespace = namespace! { + "args_get" => Function::new_typed_with_env(&mut store, env, args_get::), + "args_sizes_get" => Function::new_typed_with_env(&mut store, env, args_sizes_get::), + "clock_res_get" => Function::new_typed_with_env(&mut store, env, clock_res_get::), + "clock_time_get" => Function::new_typed_with_env(&mut store, env, clock_time_get::), + "environ_get" => Function::new_typed_with_env(&mut store, env, environ_get::), + "environ_sizes_get" => Function::new_typed_with_env(&mut store, env, environ_sizes_get::), + "fd_advise" => Function::new_typed_with_env(&mut store, env, fd_advise), + "fd_allocate" => Function::new_typed_with_env(&mut store, env, fd_allocate), + "fd_close" => Function::new_typed_with_env(&mut store, env, fd_close), + "fd_datasync" => Function::new_typed_with_env(&mut store, env, fd_datasync), + "fd_fdstat_get" => Function::new_typed_with_env(&mut store, env, fd_fdstat_get::), + "fd_fdstat_set_flags" => Function::new_typed_with_env(&mut store, env, fd_fdstat_set_flags), + "fd_fdstat_set_rights" => Function::new_typed_with_env(&mut store, env, fd_fdstat_set_rights), + "fd_filestat_get" => Function::new_typed_with_env(&mut store, env, fd_filestat_get::), + "fd_filestat_set_size" => Function::new_typed_with_env(&mut store, env, fd_filestat_set_size), + "fd_filestat_set_times" => Function::new_typed_with_env(&mut store, env, fd_filestat_set_times), + "fd_pread" => Function::new_typed_with_env(&mut store, env, fd_pread::), + "fd_prestat_get" => Function::new_typed_with_env(&mut store, env, fd_prestat_get::), + "fd_prestat_dir_name" => Function::new_typed_with_env(&mut store, env, fd_prestat_dir_name::), + "fd_pwrite" => Function::new_typed_with_env(&mut store, env, fd_pwrite::), + "fd_read" => Function::new_typed_with_env(&mut store, env, fd_read::), + "fd_readdir" => Function::new_typed_with_env(&mut store, env, fd_readdir::), + "fd_renumber" => Function::new_typed_with_env(&mut store, env, fd_renumber), + "fd_dup" => Function::new_typed_with_env(&mut store, env, fd_dup::), + "fd_event" => Function::new_typed_with_env(&mut store, env, fd_event::), + "fd_seek" => Function::new_typed_with_env(&mut store, env, fd_seek::), + "fd_sync" => Function::new_typed_with_env(&mut store, env, fd_sync), + "fd_tell" => Function::new_typed_with_env(&mut store, env, fd_tell::), + "fd_write" => Function::new_typed_with_env(&mut store, env, fd_write::), + "fd_pipe" => Function::new_typed_with_env(&mut store, env, fd_pipe::), + "path_create_directory" => Function::new_typed_with_env(&mut store, env, path_create_directory::), + "path_filestat_get" => Function::new_typed_with_env(&mut store, env, path_filestat_get::), + "path_filestat_set_times" => Function::new_typed_with_env(&mut store, env, path_filestat_set_times::), + "path_link" => Function::new_typed_with_env(&mut store, env, path_link::), + "path_open" => Function::new_typed_with_env(&mut store, env, path_open::), + "path_readlink" => Function::new_typed_with_env(&mut store, env, path_readlink::), + "path_remove_directory" => Function::new_typed_with_env(&mut store, env, path_remove_directory::), + "path_rename" => Function::new_typed_with_env(&mut store, env, path_rename::), + "path_symlink" => Function::new_typed_with_env(&mut store, env, path_symlink::), + "path_unlink_file" => Function::new_typed_with_env(&mut store, env, path_unlink_file::), + "poll_oneoff" => Function::new_typed_with_env(&mut store, env, poll_oneoff::), + "proc_exit" => Function::new_typed_with_env(&mut store, env, proc_exit), + "proc_raise" => Function::new_typed_with_env(&mut store, env, proc_raise), + "random_get" => Function::new_typed_with_env(&mut store, env, random_get::), + "tty_get" => Function::new_typed_with_env(&mut store, env, tty_get::), + "tty_set" => Function::new_typed_with_env(&mut store, env, tty_set::), + "getcwd" => Function::new_typed_with_env(&mut store, env, getcwd::), + "chdir" => Function::new_typed_with_env(&mut store, env, chdir::), + "thread_spawn" => Function::new_typed_with_env(&mut store, env, thread_spawn::), + "thread_local_create" => Function::new_typed_with_env(&mut store, env, thread_local_create::), + "thread_local_destroy" => Function::new_typed_with_env(&mut store, env, thread_local_destroy), + "thread_local_set" => Function::new_typed_with_env(&mut store, env, thread_local_set), + "thread_local_get" => Function::new_typed_with_env(&mut store, env, thread_local_get::), + "thread_sleep" => Function::new_typed_with_env(&mut store, env, thread_sleep), + "thread_id" => Function::new_typed_with_env(&mut store, env, thread_id::), + "thread_join" => Function::new_typed_with_env(&mut store, env, thread_join), + "thread_parallelism" => Function::new_typed_with_env(&mut store, env, thread_parallelism::), + "thread_exit" => Function::new_typed_with_env(&mut store, env, thread_exit), + "sched_yield" => Function::new_typed_with_env(&mut store, env, sched_yield), + "futex_wait" => Function::new_typed_with_env(&mut store, env, futex_wait::), + "futex_wake" => Function::new_typed_with_env(&mut store, env, futex_wake::), + "futex_wake_all" => Function::new_typed_with_env(&mut store, env, futex_wake_all::), + "getpid" => Function::new_typed_with_env(&mut store, env, getpid::), + "process_spawn" => Function::new_typed_with_env(&mut store, env, process_spawn::), + "bus_open_local" => Function::new_typed_with_env(&mut store, env, bus_open_local::), + "bus_open_remote" => Function::new_typed_with_env(&mut store, env, bus_open_remote::), + "bus_close" => Function::new_typed_with_env(&mut store, env, bus_close), + "bus_call" => Function::new_typed_with_env(&mut store, env, bus_call::), + "bus_subcall" => Function::new_typed_with_env(&mut store, env, bus_subcall::), + "bus_poll" => Function::new_typed_with_env(&mut store, env, bus_poll::), + "call_reply" => Function::new_typed_with_env(&mut store, env, call_reply::), + "call_fault" => Function::new_typed_with_env(&mut store, env, call_fault), + "call_close" => Function::new_typed_with_env(&mut store, env, call_close), + "ws_connect" => Function::new_typed_with_env(&mut store, env, ws_connect::), + "http_request" => Function::new_typed_with_env(&mut store, env, http_request::), + "http_status" => Function::new_typed_with_env(&mut store, env, http_status::), + "port_bridge" => Function::new_typed_with_env(&mut store, env, port_bridge::), + "port_unbridge" => Function::new_typed_with_env(&mut store, env, port_unbridge), + "port_dhcp_acquire" => Function::new_typed_with_env(&mut store, env, port_dhcp_acquire), + "port_addr_add" => Function::new_typed_with_env(&mut store, env, port_addr_add::), + "port_addr_remove" => Function::new_typed_with_env(&mut store, env, port_addr_remove::), + "port_addr_clear" => Function::new_typed_with_env(&mut store, env, port_addr_clear), + "port_addr_list" => Function::new_typed_with_env(&mut store, env, port_addr_list::), + "port_mac" => Function::new_typed_with_env(&mut store, env, port_mac::), + "port_gateway_set" => Function::new_typed_with_env(&mut store, env, port_gateway_set::), + "port_route_add" => Function::new_typed_with_env(&mut store, env, port_route_add::), + "port_route_remove" => Function::new_typed_with_env(&mut store, env, port_route_remove::), + "port_route_clear" => Function::new_typed_with_env(&mut store, env, port_route_clear), + "port_route_list" => Function::new_typed_with_env(&mut store, env, port_route_list::), + "sock_status" => Function::new_typed_with_env(&mut store, env, sock_status::), + "sock_addr_local" => Function::new_typed_with_env(&mut store, env, sock_addr_local::), + "sock_addr_peer" => Function::new_typed_with_env(&mut store, env, sock_addr_peer::), + "sock_open" => Function::new_typed_with_env(&mut store, env, sock_open::), + "sock_set_opt_flag" => Function::new_typed_with_env(&mut store, env, sock_set_opt_flag), + "sock_get_opt_flag" => Function::new_typed_with_env(&mut store, env, sock_get_opt_flag::), + "sock_set_opt_time" => Function::new_typed_with_env(&mut store, env, sock_set_opt_time::), + "sock_get_opt_time" => Function::new_typed_with_env(&mut store, env, sock_get_opt_time::), + "sock_set_opt_size" => Function::new_typed_with_env(&mut store, env, sock_set_opt_size), + "sock_get_opt_size" => Function::new_typed_with_env(&mut store, env, sock_get_opt_size::), + "sock_join_multicast_v4" => Function::new_typed_with_env(&mut store, env, sock_join_multicast_v4::), + "sock_leave_multicast_v4" => Function::new_typed_with_env(&mut store, env, sock_leave_multicast_v4::), + "sock_join_multicast_v6" => Function::new_typed_with_env(&mut store, env, sock_join_multicast_v6::), + "sock_leave_multicast_v6" => Function::new_typed_with_env(&mut store, env, sock_leave_multicast_v6::), + "sock_bind" => Function::new_typed_with_env(&mut store, env, sock_bind::), + "sock_listen" => Function::new_typed_with_env(&mut store, env, sock_listen::), + "sock_accept" => Function::new_typed_with_env(&mut store, env, sock_accept::), + "sock_connect" => Function::new_typed_with_env(&mut store, env, sock_connect::), + "sock_recv" => Function::new_typed_with_env(&mut store, env, sock_recv::), + "sock_recv_from" => Function::new_typed_with_env(&mut store, env, sock_recv_from::), + "sock_send" => Function::new_typed_with_env(&mut store, env, sock_send::), + "sock_send_to" => Function::new_typed_with_env(&mut store, env, sock_send_to::), + "sock_send_file" => Function::new_typed_with_env(&mut store, env, sock_send_file::), + "sock_shutdown" => Function::new_typed_with_env(&mut store, env, sock_shutdown), + "resolve" => Function::new_typed_with_env(&mut store, env, resolve::), + }; + namespace +} + +fn wasix_exports_64( + mut store: &mut impl AsStoreMut, + env: &FunctionEnv, +) -> Exports +{ + use syscalls::*; + let namespace = namespace! { + "args_get" => Function::new_typed_with_env(&mut store, env, args_get::), + "args_sizes_get" => Function::new_typed_with_env(&mut store, env, args_sizes_get::), + "clock_res_get" => Function::new_typed_with_env(&mut store, env, clock_res_get::), + "clock_time_get" => Function::new_typed_with_env(&mut store, env, clock_time_get::), + "environ_get" => Function::new_typed_with_env(&mut store, env, environ_get::), + "environ_sizes_get" => Function::new_typed_with_env(&mut store, env, environ_sizes_get::), + "fd_advise" => Function::new_typed_with_env(&mut store, env, fd_advise), + "fd_allocate" => Function::new_typed_with_env(&mut store, env, fd_allocate), + "fd_close" => Function::new_typed_with_env(&mut store, env, fd_close), + "fd_datasync" => Function::new_typed_with_env(&mut store, env, fd_datasync), + "fd_fdstat_get" => Function::new_typed_with_env(&mut store, env, fd_fdstat_get::), + "fd_fdstat_set_flags" => Function::new_typed_with_env(&mut store, env, fd_fdstat_set_flags), + "fd_fdstat_set_rights" => Function::new_typed_with_env(&mut store, env, fd_fdstat_set_rights), + "fd_filestat_get" => Function::new_typed_with_env(&mut store, env, fd_filestat_get::), + "fd_filestat_set_size" => Function::new_typed_with_env(&mut store, env, fd_filestat_set_size), + "fd_filestat_set_times" => Function::new_typed_with_env(&mut store, env, fd_filestat_set_times), + "fd_pread" => Function::new_typed_with_env(&mut store, env, fd_pread::), + "fd_prestat_get" => Function::new_typed_with_env(&mut store, env, fd_prestat_get::), + "fd_prestat_dir_name" => Function::new_typed_with_env(&mut store, env, fd_prestat_dir_name::), + "fd_pwrite" => Function::new_typed_with_env(&mut store, env, fd_pwrite::), + "fd_read" => Function::new_typed_with_env(&mut store, env, fd_read::), + "fd_readdir" => Function::new_typed_with_env(&mut store, env, fd_readdir::), + "fd_renumber" => Function::new_typed_with_env(&mut store, env, fd_renumber), + "fd_dup" => Function::new_typed_with_env(&mut store, env, fd_dup::), + "fd_event" => Function::new_typed_with_env(&mut store, env, fd_event::), + "fd_seek" => Function::new_typed_with_env(&mut store, env, fd_seek::), + "fd_sync" => Function::new_typed_with_env(&mut store, env, fd_sync), + "fd_tell" => Function::new_typed_with_env(&mut store, env, fd_tell::), + "fd_write" => Function::new_typed_with_env(&mut store, env, fd_write::), + "fd_pipe" => Function::new_typed_with_env(&mut store, env, fd_pipe::), + "path_create_directory" => Function::new_typed_with_env(&mut store, env, path_create_directory::), + "path_filestat_get" => Function::new_typed_with_env(&mut store, env, path_filestat_get::), + "path_filestat_set_times" => Function::new_typed_with_env(&mut store, env, path_filestat_set_times::), + "path_link" => Function::new_typed_with_env(&mut store, env, path_link::), + "path_open" => Function::new_typed_with_env(&mut store, env, path_open::), + "path_readlink" => Function::new_typed_with_env(&mut store, env, path_readlink::), + "path_remove_directory" => Function::new_typed_with_env(&mut store, env, path_remove_directory::), + "path_rename" => Function::new_typed_with_env(&mut store, env, path_rename::), + "path_symlink" => Function::new_typed_with_env(&mut store, env, path_symlink::), + "path_unlink_file" => Function::new_typed_with_env(&mut store, env, path_unlink_file::), + "poll_oneoff" => Function::new_typed_with_env(&mut store, env, poll_oneoff::), + "proc_exit" => Function::new_typed_with_env(&mut store, env, proc_exit), + "proc_raise" => Function::new_typed_with_env(&mut store, env, proc_raise), + "random_get" => Function::new_typed_with_env(&mut store, env, random_get::), + "tty_get" => Function::new_typed_with_env(&mut store, env, tty_get::), + "tty_set" => Function::new_typed_with_env(&mut store, env, tty_set::), + "getcwd" => Function::new_typed_with_env(&mut store, env, getcwd::), + "chdir" => Function::new_typed_with_env(&mut store, env, chdir::), + "thread_spawn" => Function::new_typed_with_env(&mut store, env, thread_spawn::), + "thread_local_create" => Function::new_typed_with_env(&mut store, env, thread_local_create::), + "thread_local_destroy" => Function::new_typed_with_env(&mut store, env, thread_local_destroy), + "thread_local_set" => Function::new_typed_with_env(&mut store, env, thread_local_set), + "thread_local_get" => Function::new_typed_with_env(&mut store, env, thread_local_get::), + "thread_sleep" => Function::new_typed_with_env(&mut store, env, thread_sleep), + "thread_id" => Function::new_typed_with_env(&mut store, env, thread_id::), + "thread_join" => Function::new_typed_with_env(&mut store, env, thread_join), + "thread_parallelism" => Function::new_typed_with_env(&mut store, env, thread_parallelism::), + "thread_exit" => Function::new_typed_with_env(&mut store, env, thread_exit), + "sched_yield" => Function::new_typed_with_env(&mut store, env, sched_yield), + "futex_wait" => Function::new_typed_with_env(&mut store, env, futex_wait::), + "futex_wake" => Function::new_typed_with_env(&mut store, env, futex_wake::), + "futex_wake_all" => Function::new_typed_with_env(&mut store, env, futex_wake_all::), + "getpid" => Function::new_typed_with_env(&mut store, env, getpid::), + "process_spawn" => Function::new_typed_with_env(&mut store, env, process_spawn::), + "bus_open_local" => Function::new_typed_with_env(&mut store, env, bus_open_local::), + "bus_open_remote" => Function::new_typed_with_env(&mut store, env, bus_open_remote::), + "bus_close" => Function::new_typed_with_env(&mut store, env, bus_close), + "bus_call" => Function::new_typed_with_env(&mut store, env, bus_call::), + "bus_subcall" => Function::new_typed_with_env(&mut store, env, bus_subcall::), + "bus_poll" => Function::new_typed_with_env(&mut store, env, bus_poll::), + "call_reply" => Function::new_typed_with_env(&mut store, env, call_reply::), + "call_fault" => Function::new_typed_with_env(&mut store, env, call_fault), + "call_close" => Function::new_typed_with_env(&mut store, env, call_close), + "ws_connect" => Function::new_typed_with_env(&mut store, env, ws_connect::), + "http_request" => Function::new_typed_with_env(&mut store, env, http_request::), + "http_status" => Function::new_typed_with_env(&mut store, env, http_status::), + "port_bridge" => Function::new_typed_with_env(&mut store, env, port_bridge::), + "port_unbridge" => Function::new_typed_with_env(&mut store, env, port_unbridge), + "port_dhcp_acquire" => Function::new_typed_with_env(&mut store, env, port_dhcp_acquire), + "port_addr_add" => Function::new_typed_with_env(&mut store, env, port_addr_add::), + "port_addr_remove" => Function::new_typed_with_env(&mut store, env, port_addr_remove::), + "port_addr_clear" => Function::new_typed_with_env(&mut store, env, port_addr_clear), + "port_addr_list" => Function::new_typed_with_env(&mut store, env, port_addr_list::), + "port_mac" => Function::new_typed_with_env(&mut store, env, port_mac::), + "port_gateway_set" => Function::new_typed_with_env(&mut store, env, port_gateway_set::), + "port_route_add" => Function::new_typed_with_env(&mut store, env, port_route_add::), + "port_route_remove" => Function::new_typed_with_env(&mut store, env, port_route_remove::), + "port_route_clear" => Function::new_typed_with_env(&mut store, env, port_route_clear), + "port_route_list" => Function::new_typed_with_env(&mut store, env, port_route_list::), + "sock_status" => Function::new_typed_with_env(&mut store, env, sock_status::), + "sock_addr_local" => Function::new_typed_with_env(&mut store, env, sock_addr_local::), + "sock_addr_peer" => Function::new_typed_with_env(&mut store, env, sock_addr_peer::), + "sock_open" => Function::new_typed_with_env(&mut store, env, sock_open::), + "sock_set_opt_flag" => Function::new_typed_with_env(&mut store, env, sock_set_opt_flag), + "sock_get_opt_flag" => Function::new_typed_with_env(&mut store, env, sock_get_opt_flag::), + "sock_set_opt_time" => Function::new_typed_with_env(&mut store, env, sock_set_opt_time::), + "sock_get_opt_time" => Function::new_typed_with_env(&mut store, env, sock_get_opt_time::), + "sock_set_opt_size" => Function::new_typed_with_env(&mut store, env, sock_set_opt_size), + "sock_get_opt_size" => Function::new_typed_with_env(&mut store, env, sock_get_opt_size::), + "sock_join_multicast_v4" => Function::new_typed_with_env(&mut store, env, sock_join_multicast_v4::), + "sock_leave_multicast_v4" => Function::new_typed_with_env(&mut store, env, sock_leave_multicast_v4::), + "sock_join_multicast_v6" => Function::new_typed_with_env(&mut store, env, sock_join_multicast_v6::), + "sock_leave_multicast_v6" => Function::new_typed_with_env(&mut store, env, sock_leave_multicast_v6::), + "sock_bind" => Function::new_typed_with_env(&mut store, env, sock_bind::), + "sock_listen" => Function::new_typed_with_env(&mut store, env, sock_listen::), + "sock_accept" => Function::new_typed_with_env(&mut store, env, sock_accept::), + "sock_connect" => Function::new_typed_with_env(&mut store, env, sock_connect::), + "sock_recv" => Function::new_typed_with_env(&mut store, env, sock_recv::), + "sock_recv_from" => Function::new_typed_with_env(&mut store, env, sock_recv_from::), + "sock_send" => Function::new_typed_with_env(&mut store, env, sock_send::), + "sock_send_to" => Function::new_typed_with_env(&mut store, env, sock_send_to::), + "sock_send_file" => Function::new_typed_with_env(&mut store, env, sock_send_file::), + "sock_shutdown" => Function::new_typed_with_env(&mut store, env, sock_shutdown), + "resolve" => Function::new_typed_with_env(&mut store, env, resolve::), + }; + namespace +} + pub fn import_object_for_all_wasi_versions( store: &mut impl AsStoreMut, env: &FunctionEnv, ) -> Imports { - let wasi_unstable_exports = wasi_unstable_exports(store, env); - let wasi_snapshot_preview1_exports = wasi_snapshot_preview1_exports(store, env); + let exports_wasi_unstable = wasi_unstable_exports(store, env); + let exports_wasi_snapshot_preview1 = wasi_snapshot_preview1_exports(store, env); + let exports_wasix_32v1 = wasix_exports_32(store, env); + let exports_wasix_64v1 = wasix_exports_64(store, env); imports! { - "wasi_unstable" => wasi_unstable_exports, - "wasi_snapshot_preview1" => wasi_snapshot_preview1_exports, + "wasi_unstable" => exports_wasi_unstable, + "wasi_snapshot_preview1" => exports_wasi_snapshot_preview1, + "wasix_32v1" => exports_wasix_32v1, + "wasix_64v1" => exports_wasix_64v1, } } @@ -520,9 +845,9 @@ fn generate_import_object_snapshot0( store: &mut impl AsStoreMut, env: &FunctionEnv, ) -> Imports { - let wasi_unstable_exports = wasi_unstable_exports(store, env); + let exports_unstable = wasi_unstable_exports(store, env); imports! { - "wasi_unstable" => wasi_unstable_exports + "wasi_unstable" => exports_unstable } } @@ -530,246 +855,30 @@ fn generate_import_object_snapshot1( store: &mut impl AsStoreMut, env: &FunctionEnv, ) -> Imports { - let wasi_snapshot_preview1_exports = wasi_snapshot_preview1_exports(store, env); + let exports_wasi_snapshot_preview1 = wasi_snapshot_preview1_exports(store, env); imports! { - "wasi_snapshot_preview1" => wasi_snapshot_preview1_exports + "wasi_snapshot_preview1" => exports_wasi_snapshot_preview1 } } /// Combines a state generating function with the import list for snapshot 1 fn generate_import_object_wasix32_v1( - mut store: &mut impl AsStoreMut, + store: &mut impl AsStoreMut, env: &FunctionEnv, ) -> Imports { - use self::wasix32::*; + let exports_wasix_32v1 = wasix_exports_32(store, env); imports! { - "wasix_32v1" => { - "args_get" => Function::new_typed_with_env(&mut store, env, args_get), - "args_sizes_get" => Function::new_typed_with_env(&mut store, env, args_sizes_get), - "clock_res_get" => Function::new_typed_with_env(&mut store, env, clock_res_get), - "clock_time_get" => Function::new_typed_with_env(&mut store, env, clock_time_get), - "environ_get" => Function::new_typed_with_env(&mut store, env, environ_get), - "environ_sizes_get" => Function::new_typed_with_env(&mut store, env, environ_sizes_get), - "fd_advise" => Function::new_typed_with_env(&mut store, env, fd_advise), - "fd_allocate" => Function::new_typed_with_env(&mut store, env, fd_allocate), - "fd_close" => Function::new_typed_with_env(&mut store, env, fd_close), - "fd_datasync" => Function::new_typed_with_env(&mut store, env, fd_datasync), - "fd_fdstat_get" => Function::new_typed_with_env(&mut store, env, fd_fdstat_get), - "fd_fdstat_set_flags" => Function::new_typed_with_env(&mut store, env, fd_fdstat_set_flags), - "fd_fdstat_set_rights" => Function::new_typed_with_env(&mut store, env, fd_fdstat_set_rights), - "fd_filestat_get" => Function::new_typed_with_env(&mut store, env, fd_filestat_get), - "fd_filestat_set_size" => Function::new_typed_with_env(&mut store, env, fd_filestat_set_size), - "fd_filestat_set_times" => Function::new_typed_with_env(&mut store, env, fd_filestat_set_times), - "fd_pread" => Function::new_typed_with_env(&mut store, env, fd_pread), - "fd_prestat_get" => Function::new_typed_with_env(&mut store, env, fd_prestat_get), - "fd_prestat_dir_name" => Function::new_typed_with_env(&mut store, env, fd_prestat_dir_name), - "fd_pwrite" => Function::new_typed_with_env(&mut store, env, fd_pwrite), - "fd_read" => Function::new_typed_with_env(&mut store, env, fd_read), - "fd_readdir" => Function::new_typed_with_env(&mut store, env, fd_readdir), - "fd_renumber" => Function::new_typed_with_env(&mut store, env, fd_renumber), - "fd_dup" => Function::new_typed_with_env(&mut store, env, fd_dup), - "fd_event" => Function::new_typed_with_env(&mut store, env, fd_event), - "fd_seek" => Function::new_typed_with_env(&mut store, env, fd_seek), - "fd_sync" => Function::new_typed_with_env(&mut store, env, fd_sync), - "fd_tell" => Function::new_typed_with_env(&mut store, env, fd_tell), - "fd_write" => Function::new_typed_with_env(&mut store, env, fd_write), - "fd_pipe" => Function::new_typed_with_env(&mut store, env, fd_pipe), - "path_create_directory" => Function::new_typed_with_env(&mut store, env, path_create_directory), - "path_filestat_get" => Function::new_typed_with_env(&mut store, env, path_filestat_get), - "path_filestat_set_times" => Function::new_typed_with_env(&mut store, env, path_filestat_set_times), - "path_link" => Function::new_typed_with_env(&mut store, env, path_link), - "path_open" => Function::new_typed_with_env(&mut store, env, path_open), - "path_readlink" => Function::new_typed_with_env(&mut store, env, path_readlink), - "path_remove_directory" => Function::new_typed_with_env(&mut store, env, path_remove_directory), - "path_rename" => Function::new_typed_with_env(&mut store, env, path_rename), - "path_symlink" => Function::new_typed_with_env(&mut store, env, path_symlink), - "path_unlink_file" => Function::new_typed_with_env(&mut store, env, path_unlink_file), - "poll_oneoff" => Function::new_typed_with_env(&mut store, env, poll_oneoff), - "proc_exit" => Function::new_typed_with_env(&mut store, env, proc_exit), - "proc_raise" => Function::new_typed_with_env(&mut store, env, proc_raise), - "random_get" => Function::new_typed_with_env(&mut store, env, random_get), - "tty_get" => Function::new_typed_with_env(&mut store, env, tty_get), - "tty_set" => Function::new_typed_with_env(&mut store, env, tty_set), - "getcwd" => Function::new_typed_with_env(&mut store, env, getcwd), - "chdir" => Function::new_typed_with_env(&mut store, env, chdir), - "thread_spawn" => Function::new_typed_with_env(&mut store, env, thread_spawn), - "thread_sleep" => Function::new_typed_with_env(&mut store, env, thread_sleep), - "thread_id" => Function::new_typed_with_env(&mut store, env, thread_id), - "thread_join" => Function::new_typed_with_env(&mut store, env, thread_join), - "thread_parallelism" => Function::new_typed_with_env(&mut store, env, thread_parallelism), - "thread_exit" => Function::new_typed_with_env(&mut store, env, thread_exit), - "sched_yield" => Function::new_typed_with_env(&mut store, env, sched_yield), - "getpid" => Function::new_typed_with_env(&mut store, env, getpid), - "process_spawn" => Function::new_typed_with_env(&mut store, env, process_spawn), - "bus_open_local" => Function::new_typed_with_env(&mut store, env, bus_open_local), - "bus_open_remote" => Function::new_typed_with_env(&mut store, env, bus_open_remote), - "bus_close" => Function::new_typed_with_env(&mut store, env, bus_close), - "bus_call" => Function::new_typed_with_env(&mut store, env, bus_call), - "bus_subcall" => Function::new_typed_with_env(&mut store, env, bus_subcall), - "bus_poll" => Function::new_typed_with_env(&mut store, env, bus_poll), - "call_reply" => Function::new_typed_with_env(&mut store, env, call_reply), - "call_fault" => Function::new_typed_with_env(&mut store, env, call_fault), - "call_close" => Function::new_typed_with_env(&mut store, env, call_close), - "ws_connect" => Function::new_typed_with_env(&mut store, env, ws_connect), - "http_request" => Function::new_typed_with_env(&mut store, env, http_request), - "http_status" => Function::new_typed_with_env(&mut store, env, http_status), - "port_bridge" => Function::new_typed_with_env(&mut store, env, port_bridge), - "port_unbridge" => Function::new_typed_with_env(&mut store, env, port_unbridge), - "port_dhcp_acquire" => Function::new_typed_with_env(&mut store, env, port_dhcp_acquire), - "port_addr_add" => Function::new_typed_with_env(&mut store, env, port_addr_add), - "port_addr_remove" => Function::new_typed_with_env(&mut store, env, port_addr_remove), - "port_addr_clear" => Function::new_typed_with_env(&mut store, env, port_addr_clear), - "port_addr_list" => Function::new_typed_with_env(&mut store, env, port_addr_list), - "port_mac" => Function::new_typed_with_env(&mut store, env, port_mac), - "port_gateway_set" => Function::new_typed_with_env(&mut store, env, port_gateway_set), - "port_route_add" => Function::new_typed_with_env(&mut store, env, port_route_add), - "port_route_remove" => Function::new_typed_with_env(&mut store, env, port_route_remove), - "port_route_clear" => Function::new_typed_with_env(&mut store, env, port_route_clear), - "port_route_list" => Function::new_typed_with_env(&mut store, env, port_route_list), - "sock_status" => Function::new_typed_with_env(&mut store, env, sock_status), - "sock_addr_local" => Function::new_typed_with_env(&mut store, env, sock_addr_local), - "sock_addr_peer" => Function::new_typed_with_env(&mut store, env, sock_addr_peer), - "sock_open" => Function::new_typed_with_env(&mut store, env, sock_open), - "sock_set_opt_flag" => Function::new_typed_with_env(&mut store, env, sock_set_opt_flag), - "sock_get_opt_flag" => Function::new_typed_with_env(&mut store, env, sock_get_opt_flag), - "sock_set_opt_time" => Function::new_typed_with_env(&mut store, env, sock_set_opt_time), - "sock_get_opt_time" => Function::new_typed_with_env(&mut store, env, sock_get_opt_time), - "sock_set_opt_size" => Function::new_typed_with_env(&mut store, env, sock_set_opt_size), - "sock_get_opt_size" => Function::new_typed_with_env(&mut store, env, sock_get_opt_size), - "sock_join_multicast_v4" => Function::new_typed_with_env(&mut store, env, sock_join_multicast_v4), - "sock_leave_multicast_v4" => Function::new_typed_with_env(&mut store, env, sock_leave_multicast_v4), - "sock_join_multicast_v6" => Function::new_typed_with_env(&mut store, env, sock_join_multicast_v6), - "sock_leave_multicast_v6" => Function::new_typed_with_env(&mut store, env, sock_leave_multicast_v6), - "sock_bind" => Function::new_typed_with_env(&mut store, env, sock_bind), - "sock_listen" => Function::new_typed_with_env(&mut store, env, sock_listen), - "sock_accept" => Function::new_typed_with_env(&mut store, env, sock_accept), - "sock_connect" => Function::new_typed_with_env(&mut store, env, sock_connect), - "sock_recv" => Function::new_typed_with_env(&mut store, env, sock_recv), - "sock_recv_from" => Function::new_typed_with_env(&mut store, env, sock_recv_from), - "sock_send" => Function::new_typed_with_env(&mut store, env, sock_send), - "sock_send_to" => Function::new_typed_with_env(&mut store, env, sock_send_to), - "sock_send_file" => Function::new_typed_with_env(&mut store, env, sock_send_file), - "sock_shutdown" => Function::new_typed_with_env(&mut store, env, sock_shutdown), - "resolve" => Function::new_typed_with_env(&mut store, env, resolve), - } + "wasix_32v1" => exports_wasix_32v1 } } fn generate_import_object_wasix64_v1( - mut store: &mut impl AsStoreMut, + store: &mut impl AsStoreMut, env: &FunctionEnv, ) -> Imports { - use self::wasix64::*; + let exports_wasix_64v1 = wasix_exports_64(store, env); imports! { - "wasix_64v1" => { - "args_get" => Function::new_typed_with_env(&mut store, env, args_get), - "args_sizes_get" => Function::new_typed_with_env(&mut store, env, args_sizes_get), - "clock_res_get" => Function::new_typed_with_env(&mut store, env, clock_res_get), - "clock_time_get" => Function::new_typed_with_env(&mut store, env, clock_time_get), - "environ_get" => Function::new_typed_with_env(&mut store, env, environ_get), - "environ_sizes_get" => Function::new_typed_with_env(&mut store, env, environ_sizes_get), - "fd_advise" => Function::new_typed_with_env(&mut store, env, fd_advise), - "fd_allocate" => Function::new_typed_with_env(&mut store, env, fd_allocate), - "fd_close" => Function::new_typed_with_env(&mut store, env, fd_close), - "fd_datasync" => Function::new_typed_with_env(&mut store, env, fd_datasync), - "fd_fdstat_get" => Function::new_typed_with_env(&mut store, env, fd_fdstat_get), - "fd_fdstat_set_flags" => Function::new_typed_with_env(&mut store, env, fd_fdstat_set_flags), - "fd_fdstat_set_rights" => Function::new_typed_with_env(&mut store, env, fd_fdstat_set_rights), - "fd_filestat_get" => Function::new_typed_with_env(&mut store, env, fd_filestat_get), - "fd_filestat_set_size" => Function::new_typed_with_env(&mut store, env, fd_filestat_set_size), - "fd_filestat_set_times" => Function::new_typed_with_env(&mut store, env, fd_filestat_set_times), - "fd_pread" => Function::new_typed_with_env(&mut store, env, fd_pread), - "fd_prestat_get" => Function::new_typed_with_env(&mut store, env, fd_prestat_get), - "fd_prestat_dir_name" => Function::new_typed_with_env(&mut store, env, fd_prestat_dir_name), - "fd_pwrite" => Function::new_typed_with_env(&mut store, env, fd_pwrite), - "fd_read" => Function::new_typed_with_env(&mut store, env, fd_read), - "fd_readdir" => Function::new_typed_with_env(&mut store, env, fd_readdir), - "fd_renumber" => Function::new_typed_with_env(&mut store, env, fd_renumber), - "fd_dup" => Function::new_typed_with_env(&mut store, env, fd_dup), - "fd_event" => Function::new_typed_with_env(&mut store, env, fd_event), - "fd_seek" => Function::new_typed_with_env(&mut store, env, fd_seek), - "fd_sync" => Function::new_typed_with_env(&mut store, env, fd_sync), - "fd_tell" => Function::new_typed_with_env(&mut store, env, fd_tell), - "fd_write" => Function::new_typed_with_env(&mut store, env, fd_write), - "fd_pipe" => Function::new_typed_with_env(&mut store, env, fd_pipe), - "path_create_directory" => Function::new_typed_with_env(&mut store, env, path_create_directory), - "path_filestat_get" => Function::new_typed_with_env(&mut store, env, path_filestat_get), - "path_filestat_set_times" => Function::new_typed_with_env(&mut store, env, path_filestat_set_times), - "path_link" => Function::new_typed_with_env(&mut store, env, path_link), - "path_open" => Function::new_typed_with_env(&mut store, env, path_open), - "path_readlink" => Function::new_typed_with_env(&mut store, env, path_readlink), - "path_remove_directory" => Function::new_typed_with_env(&mut store, env, path_remove_directory), - "path_rename" => Function::new_typed_with_env(&mut store, env, path_rename), - "path_symlink" => Function::new_typed_with_env(&mut store, env, path_symlink), - "path_unlink_file" => Function::new_typed_with_env(&mut store, env, path_unlink_file), - "poll_oneoff" => Function::new_typed_with_env(&mut store, env, poll_oneoff), - "proc_exit" => Function::new_typed_with_env(&mut store, env, proc_exit), - "proc_raise" => Function::new_typed_with_env(&mut store, env, proc_raise), - "random_get" => Function::new_typed_with_env(&mut store, env, random_get), - "tty_get" => Function::new_typed_with_env(&mut store, env, tty_get), - "tty_set" => Function::new_typed_with_env(&mut store, env, tty_set), - "getcwd" => Function::new_typed_with_env(&mut store, env, getcwd), - "chdir" => Function::new_typed_with_env(&mut store, env, chdir), - "thread_spawn" => Function::new_typed_with_env(&mut store, env, thread_spawn), - "thread_sleep" => Function::new_typed_with_env(&mut store, env, thread_sleep), - "thread_id" => Function::new_typed_with_env(&mut store, env, thread_id), - "thread_join" => Function::new_typed_with_env(&mut store, env, thread_join), - "thread_parallelism" => Function::new_typed_with_env(&mut store, env, thread_parallelism), - "thread_exit" => Function::new_typed_with_env(&mut store, env, thread_exit), - "sched_yield" => Function::new_typed_with_env(&mut store, env, sched_yield), - "getpid" => Function::new_typed_with_env(&mut store, env, getpid), - "process_spawn" => Function::new_typed_with_env(&mut store, env, process_spawn), - "bus_open_local" => Function::new_typed_with_env(&mut store, env, bus_open_local), - "bus_open_remote" => Function::new_typed_with_env(&mut store, env, bus_open_remote), - "bus_close" => Function::new_typed_with_env(&mut store, env, bus_close), - "bus_call" => Function::new_typed_with_env(&mut store, env, bus_call), - "bus_subcall" => Function::new_typed_with_env(&mut store, env, bus_subcall), - "bus_poll" => Function::new_typed_with_env(&mut store, env, bus_poll), - "call_reply" => Function::new_typed_with_env(&mut store, env, call_reply), - "call_fault" => Function::new_typed_with_env(&mut store, env, call_fault), - "call_close" => Function::new_typed_with_env(&mut store, env, call_close), - "ws_connect" => Function::new_typed_with_env(&mut store, env, ws_connect), - "http_request" => Function::new_typed_with_env(&mut store, env, http_request), - "http_status" => Function::new_typed_with_env(&mut store, env, http_status), - "port_bridge" => Function::new_typed_with_env(&mut store, env, port_bridge), - "port_unbridge" => Function::new_typed_with_env(&mut store, env, port_unbridge), - "port_dhcp_acquire" => Function::new_typed_with_env(&mut store, env, port_dhcp_acquire), - "port_addr_add" => Function::new_typed_with_env(&mut store, env, port_addr_add), - "port_addr_remove" => Function::new_typed_with_env(&mut store, env, port_addr_remove), - "port_addr_clear" => Function::new_typed_with_env(&mut store, env, port_addr_clear), - "port_addr_list" => Function::new_typed_with_env(&mut store, env, port_addr_list), - "port_mac" => Function::new_typed_with_env(&mut store, env, port_mac), - "port_gateway_set" => Function::new_typed_with_env(&mut store, env, port_gateway_set), - "port_route_add" => Function::new_typed_with_env(&mut store, env, port_route_add), - "port_route_remove" => Function::new_typed_with_env(&mut store, env, port_route_remove), - "port_route_clear" => Function::new_typed_with_env(&mut store, env, port_route_clear), - "port_route_list" => Function::new_typed_with_env(&mut store, env, port_route_list), - "sock_status" => Function::new_typed_with_env(&mut store, env, sock_status), - "sock_addr_local" => Function::new_typed_with_env(&mut store, env, sock_addr_local), - "sock_addr_peer" => Function::new_typed_with_env(&mut store, env, sock_addr_peer), - "sock_open" => Function::new_typed_with_env(&mut store, env, sock_open), - "sock_set_opt_flag" => Function::new_typed_with_env(&mut store, env, sock_set_opt_flag), - "sock_get_opt_flag" => Function::new_typed_with_env(&mut store, env, sock_get_opt_flag), - "sock_set_opt_time" => Function::new_typed_with_env(&mut store, env, sock_set_opt_time), - "sock_get_opt_time" => Function::new_typed_with_env(&mut store, env, sock_get_opt_time), - "sock_set_opt_size" => Function::new_typed_with_env(&mut store, env, sock_set_opt_size), - "sock_get_opt_size" => Function::new_typed_with_env(&mut store, env, sock_get_opt_size), - "sock_join_multicast_v4" => Function::new_typed_with_env(&mut store, env, sock_join_multicast_v4), - "sock_leave_multicast_v4" => Function::new_typed_with_env(&mut store, env, sock_leave_multicast_v4), - "sock_join_multicast_v6" => Function::new_typed_with_env(&mut store, env, sock_join_multicast_v6), - "sock_leave_multicast_v6" => Function::new_typed_with_env(&mut store, env, sock_leave_multicast_v6), - "sock_bind" => Function::new_typed_with_env(&mut store, env, sock_bind), - "sock_listen" => Function::new_typed_with_env(&mut store, env, sock_listen), - "sock_accept" => Function::new_typed_with_env(&mut store, env, sock_accept), - "sock_connect" => Function::new_typed_with_env(&mut store, env, sock_connect), - "sock_recv" => Function::new_typed_with_env(&mut store, env, sock_recv), - "sock_recv_from" => Function::new_typed_with_env(&mut store, env, sock_recv_from), - "sock_send" => Function::new_typed_with_env(&mut store, env, sock_send), - "sock_send_to" => Function::new_typed_with_env(&mut store, env, sock_send_to), - "sock_send_file" => Function::new_typed_with_env(&mut store, env, sock_send_file), - "sock_shutdown" => Function::new_typed_with_env(&mut store, env, sock_shutdown), - "resolve" => Function::new_typed_with_env(&mut store, env, resolve), - } + "wasix_64v1" => exports_wasix_64v1 } } diff --git a/lib/wasi/src/macros.rs b/lib/wasi/src/macros.rs index b9ec4245597..7df520bcab9 100644 --- a/lib/wasi/src/macros.rs +++ b/lib/wasi/src/macros.rs @@ -7,7 +7,6 @@ macro_rules! wasi_try { let res: Result<_, crate::syscalls::types::__wasi_errno_t> = $expr; match res { Ok(val) => { - tracing::trace!("wasi::wasi_try::val: {:?}", val); val } Err(err) => { @@ -25,7 +24,6 @@ macro_rules! wasi_try_ok { let res: Result<_, crate::syscalls::types::__wasi_errno_t> = $expr; match res { Ok(val) => { - tracing::trace!("wasi::wasi_try_ok::val: {:?}", val); val } Err(err) => { @@ -39,7 +37,6 @@ macro_rules! wasi_try_ok { let res: Result<_, crate::syscalls::types::__wasi_errno_t> = $expr; match res { Ok(val) => { - tracing::trace!("wasi::wasi_try_ok::val: {:?}", val); val } Err(err) => { @@ -60,7 +57,6 @@ macro_rules! wasi_try_bus { let res: Result<_, crate::syscalls::types::__bus_errno_t> = $expr; match res { Ok(val) => { - tracing::trace!("wasi::wasi_try_bus::val: {:?}", val); val } Err(err) => { @@ -71,6 +67,24 @@ macro_rules! wasi_try_bus { }}; } +/// Like the `try!` macro or `?` syntax: returns the value if the computation +/// succeeded or returns the error value. +macro_rules! wasi_try_bus_ok { + ($expr:expr) => {{ + let res: Result<_, crate::syscalls::types::__bus_errno_t> = $expr; + match res { + Ok(val) => { + //tracing::trace!("wasi::wasi_try_bus::val: {:?}", val); + val + } + Err(err) => { + tracing::debug!("wasi::wasi_try_bus::err: {:?}", err); + return Ok(err); + } + } + }}; +} + /// Like `wasi_try` but converts a `MemoryAccessError` to a __wasi_errno_t`. macro_rules! wasi_try_mem { ($expr:expr) => {{ @@ -85,6 +99,13 @@ macro_rules! wasi_try_mem_bus { }}; } +/// Like `wasi_try` but converts a `MemoryAccessError` to a __bus_errno_t`. +macro_rules! wasi_try_mem_bus_ok { + ($expr:expr) => {{ + wasi_try_bus_ok!($expr.map_err($crate::mem_error_to_bus)) + }}; +} + /// Like `wasi_try` but converts a `MemoryAccessError` to a __wasi_errno_t`. macro_rules! wasi_try_mem_ok { ($expr:expr) => {{ @@ -108,3 +129,9 @@ macro_rules! get_input_str_bus { wasi_try_mem_bus!($data.read_utf8_string($memory, $len)) }}; } + +macro_rules! get_input_str_bus_ok { + ($memory:expr, $data:expr, $len:expr) => {{ + wasi_try_mem_bus_ok!($data.read_utf8_string($memory, $len)) + }}; +} diff --git a/lib/wasi/src/runtime.rs b/lib/wasi/src/runtime.rs index 00c208bd166..1837a6003d8 100644 --- a/lib/wasi/src/runtime.rs +++ b/lib/wasi/src/runtime.rs @@ -2,9 +2,13 @@ use std::fmt; use std::ops::Deref; use std::sync::atomic::{AtomicU32, Ordering}; use thiserror::Error; +use wasmer::{Module, Store}; +use wasmer::vm::VMMemory; use wasmer_vbus::{UnsupportedVirtualBus, VirtualBus}; use wasmer_vnet::VirtualNetworking; +use crate::WasiCallingId; + use super::types::*; use super::WasiError; use super::WasiThreadId; @@ -15,6 +19,11 @@ pub enum WasiThreadError { Unsupported, #[error("The method named is not an exported function")] MethodNotFound, + #[error("Failed to create the requested memory")] + MemoryCreateFailed, + /// This will happen if WASM is running in a thread has not been created by the spawn_wasm call + #[error("WASM context is invalid")] + InvalidWasmContext, } impl From for __wasi_errno_t { @@ -22,6 +31,8 @@ impl From for __wasi_errno_t { match a { WasiThreadError::Unsupported => __WASI_ENOTSUP, WasiThreadError::MethodNotFound => __WASI_EINVAL, + WasiThreadError::MemoryCreateFailed => __WASI_EFAULT, + WasiThreadError::InvalidWasmContext => __WASI_ENOEXEC, } } } @@ -41,7 +52,9 @@ pub struct WasiTtyState { /// Represents an implementation of the WASI runtime - by default everything is /// unimplemented. -pub trait WasiRuntimeImplementation: fmt::Debug + Sync { +pub trait WasiRuntimeImplementation +where Self: fmt::Debug + Sync, +{ /// For WASI runtimes that support it they can implement a message BUS implementation /// which allows runtimes to pass serialized messages between each other similar to /// RPC's. BUS implementation can be implemented that communicate across runtimes @@ -76,8 +89,12 @@ pub trait WasiRuntimeImplementation: fmt::Debug + Sync { /// Spawns a new thread by invoking the fn thread_spawn( &self, - _callback: Box, - ) -> Result<(), WasiThreadError> { + _callback: Box, + _store: Store, + _existing_module: Module, + _existing_memory: VMMemory, + ) -> Result<(), WasiThreadError> + { Err(WasiThreadError::Unsupported) } @@ -89,7 +106,7 @@ pub trait WasiRuntimeImplementation: fmt::Debug + Sync { /// Invokes whenever a WASM thread goes idle. In some runtimes (like singlethreaded /// execution environments) they will need to do asynchronous work whenever the main /// thread goes idle and this is the place to hook for that. - fn yield_now(&self, _id: WasiThreadId) -> Result<(), WasiError> { + fn yield_now(&self, _id: WasiCallingId) -> Result<(), WasiError> { std::thread::yield_now(); Ok(()) } @@ -101,13 +118,15 @@ pub trait WasiRuntimeImplementation: fmt::Debug + Sync { } #[derive(Debug)] -pub struct PluggableRuntimeImplementation { +pub struct PluggableRuntimeImplementation +{ pub bus: Box, pub networking: Box, pub thread_id_seed: AtomicU32, } -impl PluggableRuntimeImplementation { +impl PluggableRuntimeImplementation +{ pub fn set_bus_implementation(&mut self, bus: I) where I: VirtualBus + Sync, @@ -123,7 +142,9 @@ impl PluggableRuntimeImplementation { } } -impl Default for PluggableRuntimeImplementation { +impl Default +for PluggableRuntimeImplementation +{ fn default() -> Self { Self { #[cfg(not(feature = "host-vnet"))] @@ -136,16 +157,40 @@ impl Default for PluggableRuntimeImplementation { } } -impl WasiRuntimeImplementation for PluggableRuntimeImplementation { - fn bus(&self) -> &(dyn VirtualBus) { +impl WasiRuntimeImplementation +for PluggableRuntimeImplementation +{ + fn bus<'a>(&'a self) -> &'a (dyn VirtualBus) { self.bus.deref() } - fn networking(&self) -> &(dyn VirtualNetworking) { + fn networking<'a>(&'a self) -> &'a (dyn VirtualNetworking) { self.networking.deref() } fn thread_generate_id(&self) -> WasiThreadId { self.thread_id_seed.fetch_add(1, Ordering::Relaxed).into() } + + #[cfg(feature = "sys-thread")] + fn thread_spawn( + &self, + callback: Box, + store: Store, + existing_module: Module, + existing_memory: VMMemory, + ) -> Result<(), WasiThreadError> + { + let existing_module = existing_module.clone(); + std::thread::spawn(move || { + callback(store, existing_module, existing_memory) + }); + Ok(()) + } + + fn thread_parallelism(&self) -> Result { + std::thread::available_parallelism() + .map(|a| usize::from(a)) + .map_err(|_| WasiThreadError::Unsupported) + } } diff --git a/lib/wasi/src/state/builder.rs b/lib/wasi/src/state/builder.rs index 61e2451d807..4507060e092 100644 --- a/lib/wasi/src/state/builder.rs +++ b/lib/wasi/src/state/builder.rs @@ -468,6 +468,8 @@ impl WasiStateBuilder { inodes: Arc::new(inodes), args: self.args.clone(), threading: Default::default(), + futexs: Default::default(), + bus: Default::default(), envs: self .envs .iter() diff --git a/lib/wasi/src/state/mod.rs b/lib/wasi/src/state/mod.rs index 4b1a75a718d..d38f078b9ae 100644 --- a/lib/wasi/src/state/mod.rs +++ b/lib/wasi/src/state/mod.rs @@ -20,26 +20,44 @@ mod guard; mod pipe; mod socket; mod types; +mod thread; +mod parking; pub use self::builder::*; pub use self::guard::*; pub use self::pipe::*; pub use self::socket::*; pub use self::types::*; +pub use self::guard::*; +pub use self::thread::*; +pub use self::parking::*; +use crate::WasiCallingId; +use crate::WasiFunctionEnv; +use crate::WasiThreadId; use crate::syscalls::types::*; use crate::utils::map_io_err; use crate::WasiBusProcessId; -use crate::WasiThread; -use crate::WasiThreadId; +use cooked_waker::ViaRawPointer; +use cooked_waker::Wake; +use cooked_waker::WakeRef; +use derivative::Derivative; use generational_arena::Arena; pub use generational_arena::Index as Inode; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; +use wasmer::Store; +use wasmer_vbus::VirtualBusCalled; +use wasmer_vbus::VirtualBusInvocation; use std::borrow::Cow; +use std::cell::RefCell; use std::collections::HashMap; use std::collections::VecDeque; +use std::sync::Condvar; +use std::sync::MutexGuard; use std::sync::mpsc; use std::sync::Arc; +use std::task::Waker; +use std::time::Duration; use std::{ borrow::Borrow, io::Write, @@ -83,7 +101,7 @@ pub const MAX_SYMLINKS: u32 = 128; pub struct InodeVal { pub stat: RwLock<__wasi_filestat_t>, pub is_preopened: bool, - pub name: String, + pub name: Cow<'static, str>, pub kind: RwLock, } @@ -654,8 +672,7 @@ impl WasiFs { for c in path.components() { let segment_name = c.as_os_str().to_string_lossy().to_string(); let guard = inodes.arena[cur_inode].read(); - let deref = guard.deref(); - match deref { + match guard.deref() { Kind::Dir { ref entries, .. } | Kind::Root { ref entries } => { if let Some(_entry) = entries.get(&segment_name) { // TODO: this should be fixed @@ -673,14 +690,13 @@ impl WasiFs { inodes, kind, false, - segment_name.clone(), + segment_name.clone().into(), ); // reborrow to insert { let mut guard = inodes.arena[cur_inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::Dir { ref mut entries, .. } @@ -727,8 +743,7 @@ impl WasiFs { let base_inode = self.get_fd_inode(base).map_err(fs_error_from_wasi_err)?; let guard = inodes.arena[base_inode].read(); - let deref = guard.deref(); - match deref { + match guard.deref() { Kind::Dir { ref entries, .. } | Kind::Root { ref entries } => { if let Some(_entry) = entries.get(&name) { // TODO: eventually change the logic here to allow overwrites @@ -748,8 +763,7 @@ impl WasiFs { { let mut guard = inodes.arena[base_inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::Dir { ref mut entries, .. } @@ -794,8 +808,7 @@ impl WasiFs { _ => { let base_inode = self.get_fd_inode(fd).map_err(fs_error_from_wasi_err)?; let mut guard = inodes.arena[base_inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { ref mut handle, .. } => { std::mem::swap(handle, &mut ret); } @@ -815,8 +828,7 @@ impl WasiFs { ) -> Result<__wasi_filesize_t, __wasi_errno_t> { let inode = self.get_fd_inode(fd)?; let mut guard = inodes.arena[inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { handle, .. } => { if let Some(h) = handle { let new_size = h.size(); @@ -905,8 +917,7 @@ impl WasiFs { // loading inodes as necessary 'symlink_resolution: while symlink_count < MAX_SYMLINKS { let mut guard = inodes.arena[cur_inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::Buffer { .. } => unimplemented!("state::get_inode_at_path for buffers"), Kind::Dir { ref mut entries, @@ -1011,7 +1022,7 @@ impl WasiFs { inodes, kind, false, - file.to_string_lossy().to_string(), + file.to_string_lossy().to_string().into(), __wasi_filestat_t { st_filetype: file_type, ..__wasi_filestat_t::default() @@ -1172,12 +1183,10 @@ impl WasiFs { let mut res = BaseFdAndRelPath::None; // for each preopened directory let preopen_fds = self.preopen_fds.read().unwrap(); - let deref = preopen_fds.deref(); - for po_fd in deref { + for po_fd in preopen_fds.deref() { let po_inode = self.fd_map.read().unwrap()[po_fd].inode; let guard = inodes.arena[po_inode].read(); - let deref = guard.deref(); - let po_path = match deref { + let po_path = match guard.deref() { Kind::Dir { path, .. } => &**path, Kind::Root { .. } => Path::new("/"), _ => unreachable!("Preopened FD that's not a directory or the root"), @@ -1219,8 +1228,7 @@ impl WasiFs { while cur_inode != base_inode { counter += 1; let guard = inodes.arena[cur_inode].read(); - let deref = guard.deref(); - match deref { + match guard.deref() { Kind::Dir { parent, .. } => { if let Some(p) = parent { cur_inode = *p; @@ -1355,9 +1363,8 @@ impl WasiFs { debug!("fdstat: {:?}", fd); let guard = inodes.arena[fd.inode].read(); - let deref = guard.deref(); Ok(__wasi_fdstat_t { - fs_filetype: match deref { + fs_filetype: match guard.deref() { Kind::File { .. } => __WASI_FILETYPE_REGULAR_FILE, Kind::Dir { .. } => __WASI_FILETYPE_DIRECTORY, Kind::Symlink { .. } => __WASI_FILETYPE_SYMBOLIC_LINK, @@ -1419,8 +1426,7 @@ impl WasiFs { } let mut guard = inodes.arena[fd.inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { handle: Some(file), .. } => file.flush().map_err(|_| __WASI_EIO)?, @@ -1444,7 +1450,7 @@ impl WasiFs { name: String, ) -> Result { let stat = self.get_stat_for_kind(inodes, &kind)?; - Ok(self.create_inode_with_stat(inodes, kind, is_preopened, name, stat)) + Ok(self.create_inode_with_stat(inodes, kind, is_preopened, name.into(), stat)) } /// Creates an inode and inserts it given a Kind, does not assume the file exists. @@ -1453,7 +1459,7 @@ impl WasiFs { inodes: &mut WasiInodes, kind: Kind, is_preopened: bool, - name: String, + name: Cow<'static, str>, ) -> Inode { let stat = __wasi_filestat_t::default(); self.create_inode_with_stat(inodes, kind, is_preopened, name, stat) @@ -1465,7 +1471,7 @@ impl WasiFs { inodes: &mut WasiInodes, kind: Kind, is_preopened: bool, - name: String, + name: Cow<'static, str>, mut stat: __wasi_filestat_t, ) -> Inode { stat.st_ino = self.get_next_inode_index(); @@ -1543,7 +1549,7 @@ impl WasiFs { inodes.arena.insert(InodeVal { stat: RwLock::new(stat), is_preopened: true, - name: "/".to_string(), + name: "/".into(), kind: RwLock::new(root_kind), }) } @@ -1602,7 +1608,7 @@ impl WasiFs { inodes.arena.insert(InodeVal { stat: RwLock::new(stat), is_preopened: true, - name: name.to_string(), + name: name.to_string().into(), kind: RwLock::new(kind), }) }; @@ -1655,8 +1661,7 @@ impl WasiFs { let base_po_inode = &self.fd_map.read().unwrap()[base_po_dir].inode; let base_po_inode_v = &inodes.arena[*base_po_inode]; let guard = base_po_inode_v.read(); - let deref = guard.deref(); - match deref { + match guard.deref() { Kind::Root { .. } => { self.fs_backing.symlink_metadata(path_to_symlink).map_err(fs_error_into_wasi_err)? } @@ -1698,8 +1703,7 @@ impl WasiFs { let is_preopened = inodeval.is_preopened; let mut guard = inodeval.write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { ref mut handle, .. } => { let mut empty_handle = None; std::mem::swap(handle, &mut empty_handle); @@ -1721,16 +1725,14 @@ impl WasiFs { if let Some(p) = *parent { drop(guard); let mut guard = inodes.arena[p].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::Dir { entries, .. } | Kind::Root { entries } => { self.fd_map.write().unwrap().remove(&fd).unwrap(); if is_preopened { let mut idx = None; { let preopen_fds = self.preopen_fds.read().unwrap(); - let preopen_fds_iter = preopen_fds.iter().enumerate(); - for (i, po_fd) in preopen_fds_iter { + for (i, po_fd) in preopen_fds.iter().enumerate() { if *po_fd == fd { idx = Some(i); break; @@ -1814,21 +1816,152 @@ impl WasiState { } } +pub(crate) struct WasiThreadContext { + pub ctx: WasiFunctionEnv, + pub store: RefCell, +} + +/// The code itself makes safe use of the struct so multiple threads don't access +/// it (without this the JS code prevents the reference to the module from being stored +/// which is needed for the multithreading mode) +unsafe impl Send for WasiThreadContext { } +unsafe impl Sync for WasiThreadContext { } + /// Structures used for the threading and sub-processes /// /// These internal implementation details are hidden away from the /// consumer who should instead implement the vbus trait on the runtime -#[derive(Debug, Default)] + +#[derive(Derivative, Default)] +#[derivative(Debug)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub(crate) struct WasiStateThreading { - #[cfg_attr(feature = "enable-serde", serde(skip))] - pub threads: HashMap, - pub thread_seed: u32, - #[cfg_attr(feature = "enable-serde", serde(skip))] - pub processes: HashMap, - #[cfg_attr(feature = "enable-serde", serde(skip))] + threads: Arc>>, + thread_count: Arc, + pub processes: HashMap>, pub process_reuse: HashMap, WasiBusProcessId>, pub process_seed: u32, + pub thread_seed: WasiThreadId, + pub thread_local: HashMap<(WasiThreadId, u32), u64>, + pub thread_local_user_data: HashMap, + pub thread_local_seed: u32, + #[derivative(Debug = "ignore")] + pub thread_ctx: HashMap>, +} + +impl WasiStateThreading +{ + /// Creates a a thread and returns it + pub fn new_thread(&mut self) -> WasiThreadHandle { + let id = self.thread_seed.inc(); + let ctrl = WasiThread::default(); + { + let mut guard = self.threads.write().unwrap(); + guard.insert(id, ctrl); + } + self.thread_count.fetch_add(1, Ordering::AcqRel); + + WasiThreadHandle { + id, + threads: self.threads.clone(), + thread_count: self.thread_count.clone() + } + } + + pub fn get(&self, tid: &WasiThreadId) -> Option { + let guard = self.threads.read().unwrap(); + guard.get(tid).map(|a| a.clone()) + } + + pub fn active_threads(&self) -> u32 { + self.thread_count.load(Ordering::Acquire) + } +} + +#[derive(Debug, Clone)] +pub struct WasiThreadHandle { + id: WasiThreadId, + threads: Arc>>, + pub(crate) thread_count: Arc, +} + +impl WasiThreadHandle { + pub fn id(&self) -> WasiThreadId { + self.id + } +} + +impl Drop +for WasiThreadHandle { + fn drop(&mut self) { + if let Some(ctrl) = { + let mut guard = self.threads.write().unwrap(); + guard.remove(&self.id) + } { + ctrl.mark_finished(); + } + self.thread_count.fetch_sub(1, Ordering::AcqRel); + } +} + +/// Represents a futex which will make threads wait for completion in a more +/// CPU efficient manner +#[derive(Debug, Clone)] +pub struct WasiFutex { + pub(crate) refcnt: Arc, + pub(crate) inner: Arc<(Mutex<()>, Condvar)>, +} + +#[derive(Debug)] +pub struct WasiBusCall +{ + pub bid: WasiBusProcessId, + pub invocation: Box, +} + +/// Protected area of the BUS state +#[derive(Debug, Default)] +pub struct WasiBusProtectedState +{ + pub call_seed: u64, + pub called: HashMap>, + pub calls: HashMap, +} + +/// Structure that holds the state of BUS calls to this process and from +/// this process. BUS calls are the equivalent of RPC's with support +/// for all the major serializers +#[derive(Debug, Default)] +pub struct WasiBusState +{ + protected: Mutex, + poll_waker: WasiParkingLot, +} + +impl WasiBusState +{ + /// Gets a reference to the waker that can be used for + /// asynchronous calls + pub fn get_poll_waker(&self) -> Waker { + self.poll_waker.get_waker() + } + + /// Wakes one of the reactors thats currently waiting + pub fn poll_wake(&self) { + self.poll_waker.wake() + } + + /// Will wait until either the reactor is triggered + /// or the timeout occurs + pub fn poll_wait(&self, timeout: Duration) -> bool { + self.poll_waker.wait(timeout) + } + + /// Locks the protected area of the BUS and returns a guard that + /// can be used to access it + pub fn protected<'a>(&'a self) -> MutexGuard<'a, WasiBusProtectedState> { + self.protected.lock().unwrap() + } } /// Top level data type containing all* the state with which WASI can @@ -1864,7 +1997,9 @@ pub(crate) struct WasiStateThreading { pub struct WasiState { pub fs: WasiFs, pub inodes: Arc>, - pub(crate) threading: Mutex, + pub(crate) threading: RwLock, + pub(crate) futexs: Mutex>, + pub(crate) bus: WasiBusState, pub args: Vec>, pub envs: Vec>, } @@ -1941,10 +2076,10 @@ impl WasiState { fd: __wasi_fd_t, ) -> Result>, FsError> { let ret = WasiStateFileGuard::new(self, fd)?.map(|a| { - let ret = Box::new(a); - let ret: Box = ret; - ret - }); + let ret = Box::new(a); + let ret: Box = ret; + ret + }); Ok(ret) } } @@ -1961,3 +2096,27 @@ pub fn virtual_file_type_to_wasi_file_type(file_type: wasmer_vfs::FileType) -> _ __WASI_FILETYPE_UNKNOWN } } + +#[derive(Debug, Clone)] +pub struct WasiDummyWaker; + +impl WakeRef for WasiDummyWaker { + fn wake_by_ref(&self) { + } +} + +impl Wake for WasiDummyWaker { + fn wake(self) { + } +} + +unsafe impl ViaRawPointer for WasiDummyWaker { + type Target = (); + fn into_raw(self) -> *mut () { + std::mem::forget(self); + std::ptr::null_mut() + } + unsafe fn from_raw(_ptr: *mut ()) -> Self { + WasiDummyWaker + } +} diff --git a/lib/wasi/src/state/parking.rs b/lib/wasi/src/state/parking.rs new file mode 100644 index 00000000000..bb25f5d8f95 --- /dev/null +++ b/lib/wasi/src/state/parking.rs @@ -0,0 +1,82 @@ +use std::{ + task::Waker, + sync::{ + Mutex, + Arc, + Condvar + }, + time::Duration +}; + +/// Represents a waker that can be used to put a thread to +/// sleep while it waits for an event to occur +#[derive(Debug)] +pub struct WasiParkingLot +{ + waker: Waker, + run: Arc<(Mutex, Condvar)>, +} + +impl Default +for WasiParkingLot +{ + fn default() -> Self + { + Self::new(true) + } +} + +impl WasiParkingLot +{ + /// Creates a new parking lot with a specific value + pub fn new(initial_val: bool) -> Self + { + let run = Arc::new((Mutex::new(initial_val), Condvar::default())); + let waker = { + let run = run.clone(); + waker_fn::waker_fn(move || + { + let mut guard = run.0.lock().unwrap(); + *guard = true; + run.1.notify_one(); + }) + }; + + Self { + waker, + run, + } + } + + /// Gets a reference to the waker that can be used for + /// asynchronous calls + pub fn get_waker(&self) -> Waker { + self.waker.clone() + } + + /// Wakes one of the reactors thats currently waiting + pub fn wake(&self) { + self.waker.wake_by_ref(); + } + + /// Will wait until either the reactor is triggered + /// or the timeout occurs + pub fn wait(&self, timeout: Duration) -> bool { + let mut run = self.run.0.lock().unwrap(); + if *run == true { + *run = false; + return true; + } + loop { + let woken = self.run.1.wait_timeout(run, timeout).unwrap(); + if woken.1.timed_out() { + return false; + } + run = woken.0; + if *run == true { + *run = false; + return true; + } + } + } +} \ No newline at end of file diff --git a/lib/wasi/src/state/thread.rs b/lib/wasi/src/state/thread.rs new file mode 100644 index 00000000000..0b3185163ca --- /dev/null +++ b/lib/wasi/src/state/thread.rs @@ -0,0 +1,56 @@ +use std::{ + sync::{ + Mutex, + Arc, + Condvar + }, + time::Duration +}; + +/// Represents a running thread which allows a joiner to +/// wait for the thread to exit +#[derive(Debug, Clone)] +pub struct WasiThread +{ + finished: Arc<(Mutex, Condvar)>, +} + +impl Default +for WasiThread +{ + fn default() -> Self + { + Self { + finished: Arc::new((Mutex::new(false), Condvar::default())), + } + } +} + +impl WasiThread +{ + /// Marks the thread as finished (which will cause anyone that + /// joined on it to wake up) + pub fn mark_finished(&self) { + let mut guard = self.finished.0.lock().unwrap(); + *guard = true; + self.finished.1.notify_all(); + } + + /// Waits until the thread is finished or the timeout is reached + pub fn join(&self, timeout: Duration) -> bool { + let mut finished = self.finished.0.lock().unwrap(); + if *finished == true { + return true; + } + loop { + let woken = self.finished.1.wait_timeout(finished, timeout).unwrap(); + if woken.1.timed_out() { + return false; + } + finished = woken.0; + if *finished == true { + return true; + } + } + } +} diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index 462a008f19f..695d4977f76 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -10,7 +10,7 @@ use std::{ sync::{Arc, Mutex}, time::Duration, }; -use wasmer_vbus::BusError; +use wasmer_vbus::VirtualBusError; #[cfg(feature = "host-fs")] pub use wasmer_vfs::host_fs::{Stderr, Stdin, Stdout}; @@ -102,8 +102,8 @@ pub fn net_error_into_wasi_err(net_error: NetworkError) -> __wasi_errno_t { } } -pub fn bus_error_into_wasi_err(bus_error: BusError) -> __bus_errno_t { - use BusError::*; +pub fn bus_error_into_wasi_err(bus_error: VirtualBusError) -> __bus_errno_t { + use VirtualBusError::*; match bus_error { Serialization => __BUS_ESER, Deserialization => __BUS_EDES, @@ -127,8 +127,8 @@ pub fn bus_error_into_wasi_err(bus_error: BusError) -> __bus_errno_t { } } -pub fn wasi_error_into_bus_err(bus_error: __bus_errno_t) -> BusError { - use BusError::*; +pub fn wasi_error_into_bus_err(bus_error: __bus_errno_t) -> VirtualBusError { + use VirtualBusError::*; match bus_error { __BUS_ESER => Serialization, __BUS_EDES => Deserialization, @@ -148,10 +148,24 @@ pub fn wasi_error_into_bus_err(bus_error: __bus_errno_t) -> BusError { __BUS_EINVOKE => InvokeFailed, __BUS_ECONSUMED => AlreadyConsumed, __BUS_EMEMVIOLATION => MemoryAccessViolation, - /*__BUS_EUNKNOWN |*/ _ => UnknownError, + __BUS_EUNKNOWN | _ => UnknownError, } } +pub(crate) fn bus_read_rights() -> __wasi_rights_t { + __WASI_RIGHT_FD_FDSTAT_SET_FLAGS + | __WASI_RIGHT_FD_FILESTAT_GET + | __WASI_RIGHT_FD_READ + | __WASI_RIGHT_POLL_FD_READWRITE +} + +pub(crate) fn bus_write_rights() -> __wasi_rights_t { + __WASI_RIGHT_FD_FDSTAT_SET_FLAGS + | __WASI_RIGHT_FD_FILESTAT_GET + | __WASI_RIGHT_FD_WRITE + | __WASI_RIGHT_POLL_FD_READWRITE +} + #[derive(Debug, Clone)] #[allow(clippy::enum_variant_names)] pub enum PollEvent { diff --git a/lib/wasi/src/syscalls/legacy/snapshot0.rs b/lib/wasi/src/syscalls/legacy/snapshot0.rs index 033abe11e04..ae69976923d 100644 --- a/lib/wasi/src/syscalls/legacy/snapshot0.rs +++ b/lib/wasi/src/syscalls/legacy/snapshot0.rs @@ -1,6 +1,6 @@ use crate::syscalls; use crate::syscalls::types::{self, snapshot0}; -use crate::{mem_error_to_wasi, Memory32, MemorySize, WasiEnv, WasiError, WasiThread}; +use crate::{mem_error_to_wasi, Memory32, MemorySize, WasiEnv, WasiError}; use wasmer::{AsStoreMut, FunctionEnvMut, WasmPtr}; /// Wrapper around `syscalls::fd_filestat_get` with extra logic to handle the size @@ -27,7 +27,7 @@ pub fn fd_filestat_get( // Set up complete, make the call with the pointer that will write to the // struct and some unrelated memory after the struct. - let result = syscalls::fd_filestat_get::(ctx.as_mut(), fd, new_buf); + let result = syscalls::fd_filestat_get_internal::(&mut ctx, fd, new_buf); // reborrow memory let env = ctx.data(); @@ -130,40 +130,43 @@ pub fn poll_oneoff( // in this case the new type is smaller than the old type, so it all fits into memory, // we just need to readjust and copy it - // we start by adjusting `in_` into a format that the new code can understand - let env = ctx.data(); - let memory = env.memory_view(&ctx); let nsubscriptions_offset: u32 = nsubscriptions; - let in_origs = wasi_try_mem_ok!(in_.slice(&memory, nsubscriptions_offset)); - let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec()); - - // get a pointer to the smaller new type - let in_new_type_ptr: WasmPtr = in_.cast(); - - for (in_sub_new, orig) in - wasi_try_mem_ok!(in_new_type_ptr.slice(&memory, nsubscriptions_offset)) - .iter() - .zip(in_origs.iter()) - { - wasi_try_mem_ok!(in_sub_new.write(types::__wasi_subscription_t { - userdata: orig.userdata, - type_: orig.type_, - u: if orig.type_ == types::__WASI_EVENTTYPE_CLOCK { - types::__wasi_subscription_u { - clock: types::__wasi_subscription_clock_t { - clock_id: unsafe { orig.u.clock.clock_id }, - timeout: unsafe { orig.u.clock.timeout }, - precision: unsafe { orig.u.clock.precision }, - flags: unsafe { orig.u.clock.flags }, - }, - } - } else { - types::__wasi_subscription_u { - fd_readwrite: unsafe { orig.u.fd_readwrite }, - } - }, - })); - } + let in_new_type_ptr = { + // we start by adjusting `in_` into a format that the new code can understand + let env = ctx.data(); + let memory = env.memory_view(&ctx); + let in_origs = wasi_try_mem_ok!(in_.slice(&memory, nsubscriptions_offset)); + let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec()); + + // get a pointer to the smaller new type + let in_new_type_ptr: WasmPtr = in_.cast(); + + for (in_sub_new, orig) in + wasi_try_mem_ok!(in_new_type_ptr.slice(&memory, nsubscriptions_offset)) + .iter() + .zip(in_origs.iter()) + { + wasi_try_mem_ok!(in_sub_new.write(types::__wasi_subscription_t { + userdata: orig.userdata, + type_: orig.type_, + u: if orig.type_ == types::__WASI_EVENTTYPE_CLOCK { + types::__wasi_subscription_u { + clock: types::__wasi_subscription_clock_t { + clock_id: unsafe { orig.u.clock.clock_id }, + timeout: unsafe { orig.u.clock.timeout }, + precision: unsafe { orig.u.clock.precision }, + flags: unsafe { orig.u.clock.flags }, + }, + } + } else { + types::__wasi_subscription_u { + fd_readwrite: unsafe { orig.u.fd_readwrite }, + } + }, + })); + } + in_new_type_ptr + }; // make the call let result = syscalls::poll_oneoff::( @@ -172,11 +175,13 @@ pub fn poll_oneoff( out_, nsubscriptions, nevents, - ); + )?; // replace the old values of in, in case the calling code reuses the memory let env = ctx.data(); let memory = env.memory_view(&ctx); + let in_origs = wasi_try_mem_ok!(in_.slice(&memory, nsubscriptions_offset)); + let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec()); for (in_sub, orig) in wasi_try_mem_ok!(in_.slice(&memory, nsubscriptions_offset)) .iter() @@ -185,5 +190,5 @@ pub fn poll_oneoff( wasi_try_mem_ok!(in_sub.write(orig)); } - result + Ok(result) } diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 0c5266e6efc..966e8ff9090 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -11,20 +11,17 @@ pub mod types { target_vendor = "apple" ))] pub mod unix; -#[cfg(any(target_arch = "wasm32"))] -pub mod wasm32; +#[cfg(any(target_family = "wasm"))] +pub mod wasm; #[cfg(any(target_os = "windows"))] pub mod windows; pub mod legacy; -//pub mod wasi; -pub mod wasix32; -pub mod wasix64; use self::types::*; -use crate::state::{bus_error_into_wasi_err, wasi_error_into_bus_err, InodeHttpSocketType}; +use crate::state::{bus_error_into_wasi_err, wasi_error_into_bus_err, InodeHttpSocketType, WasiFutex, bus_write_rights, bus_read_rights, WasiBusCall, WasiThreadContext, WasiParkingLot, WasiDummyWaker}; use crate::utils::map_io_err; -use crate::WasiBusProcessId; +use crate::{WasiBusProcessId, WasiEnvInner, import_object_for_all_wasi_versions, WasiFunctionEnv, current_caller_id}; use crate::{ mem_error_to_wasi, state::{ @@ -32,25 +29,34 @@ use crate::{ virtual_file_type_to_wasi_file_type, Fd, Inode, InodeSocket, InodeSocketKind, InodeVal, Kind, PollEvent, PollEventBuilder, WasiPipe, WasiState, MAX_SYMLINKS, }, - WasiEnv, WasiError, WasiThread, WasiThreadId, + WasiEnv, WasiError, WasiThreadId, }; use bytes::Bytes; +use cooked_waker::IntoWaker; +use sha2::Sha256; +use wasmer::vm::VMMemory; use std::borrow::{Borrow, Cow}; +use std::cell::RefCell; +use std::collections::HashSet; +use std::collections::hash_map::Entry; use std::convert::{Infallible, TryInto}; use std::io::{self, Read, Seek, Write}; use std::mem::transmute; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; use std::ops::{Deref, DerefMut}; -use std::sync::atomic::AtomicU64; +use std::pin::Pin; +use std::sync::atomic::{AtomicU64, AtomicU32}; use std::sync::{atomic::Ordering, Mutex}; -use std::sync::{mpsc, Arc}; +use std::sync::{mpsc, Arc, Condvar}; +use std::task::{Poll, Context}; +use std::thread::LocalKey; use std::time::Duration; use tracing::{debug, error, trace, warn}; use wasmer::{ - AsStoreMut, Extern, FunctionEnv, FunctionEnvMut, Instance, Memory, Memory32, Memory64, - MemorySize, MemoryView, Module, RuntimeError, Value, WasmPtr, WasmSlice, + AsStoreMut, FunctionEnvMut, Memory, Memory32, Memory64, MemorySize, RuntimeError, Value, + WasmPtr, WasmSlice, FunctionEnv, Instance, Module, Extern, MemoryView, TypedFunction, Store, Pages, Global, AsStoreRef, }; -use wasmer_vbus::{FileDescriptor, StdioMode}; +use wasmer_vbus::{FileDescriptor, StdioMode, BusDataFormat, BusInvocationEvent}; use wasmer_vfs::{FsError, VirtualFile}; use wasmer_vnet::{SocketHttpRequest, StreamSecurity}; @@ -65,8 +71,8 @@ pub use unix::*; #[cfg(any(target_os = "windows"))] pub use windows::*; -#[cfg(any(target_arch = "wasm32"))] -pub use wasm32::*; +#[cfg(any(target_family = "wasm"))] +pub use wasm::*; fn to_offset(offset: usize) -> Result { let ret: M::Offset = offset.try_into().map_err(|_| __WASI_EINVAL)?; @@ -164,8 +170,7 @@ where let inode = &inodes.arena[inode_idx]; let mut guard = inode.read(); - let deref = guard.deref(); - match deref { + match guard.deref() { Kind::Socket { socket } => actor(socket)?, _ => { return Err(__WASI_ENOTSOCK); @@ -198,8 +203,7 @@ where let inode = &inodes.arena[inode_idx]; let mut guard = inode.write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::Socket { socket } => actor(socket)?, _ => { return Err(__WASI_ENOTSOCK); @@ -233,8 +237,7 @@ where let inode = &inodes.arena[inode_idx]; let mut guard = inode.write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::Socket { socket } => { let new_socket = actor(socket)?; @@ -393,7 +396,7 @@ pub fn clock_time_get( precision: __wasi_timestamp_t, time: WasmPtr<__wasi_timestamp_t, M>, ) -> __wasi_errno_t { - debug!( + trace!( "wasi::clock_time_get clock_id: {}, precision: {}", clock_id, precision ); @@ -425,7 +428,7 @@ pub fn environ_get( environ: WasmPtr, M>, environ_buf: WasmPtr, ) -> __wasi_errno_t { - debug!( + trace!( "wasi::environ_get. Environ: {:?}, environ_buf: {:?}", environ, environ_buf ); @@ -523,8 +526,7 @@ pub fn fd_allocate( let new_size = wasi_try!(offset.checked_add(len).ok_or(__WASI_EINVAL)); { let mut guard = inodes.arena[inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { handle, .. } => { if let Some(handle) = handle { wasi_try!(handle.set_len(new_size).map_err(fs_error_into_wasi_err)); @@ -689,7 +691,23 @@ pub fn fd_fdstat_set_rights( /// - `__wasi_filestat_t *buf` /// Where the metadata from `fd` will be written pub fn fd_filestat_get( - ctx: FunctionEnvMut<'_, WasiEnv>, + mut ctx: FunctionEnvMut<'_, WasiEnv>, + fd: __wasi_fd_t, + buf: WasmPtr<__wasi_filestat_t, M>, +) -> __wasi_errno_t { + fd_filestat_get_internal(&mut ctx, fd, buf) +} + +/// ### `fd_filestat_get()` +/// Get the metadata of an open file +/// Input: +/// - `__wasi_fd_t fd` +/// The open file descriptor whose metadata will be read +/// Output: +/// - `__wasi_filestat_t *buf` +/// Where the metadata from `fd` will be written +pub(crate) fn fd_filestat_get_internal( + ctx: &mut FunctionEnvMut<'_, WasiEnv>, fd: __wasi_fd_t, buf: WasmPtr<__wasi_filestat_t, M>, ) -> __wasi_errno_t { @@ -733,8 +751,7 @@ pub fn fd_filestat_set_size( { let mut guard = inodes.arena[inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { handle, .. } => { if let Some(handle) = handle { wasi_try!(handle.set_len(st_size).map_err(fs_error_into_wasi_err)); @@ -873,8 +890,7 @@ pub fn fd_pread( return Ok(__WASI_EACCES); } let mut guard = inodes.arena[inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { handle, .. } => { if let Some(h) = handle { wasi_try_ok!( @@ -897,7 +913,10 @@ pub fn fd_pread( Kind::Dir { .. } | Kind::Root { .. } => return Ok(__WASI_EISDIR), Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_pread"), Kind::Buffer { buffer } => { - wasi_try_ok!(read_bytes(&buffer[(offset as usize)..], &memory, iovs), env) + wasi_try_ok!( + read_bytes(&buffer[(offset as usize)..], &memory, iovs), + env + ) } } } @@ -927,14 +946,13 @@ pub fn fd_prestat_get( let (memory, mut state, inodes) = env.get_memory_and_wasi_state_and_inodes(&ctx, 0); let prestat_ptr = buf.deref(&memory); - wasi_try_mem!( - prestat_ptr.write(wasi_try!(state.fs.prestat_fd(inodes.deref(), fd).map_err( - |code| { + wasi_try_mem!(prestat_ptr.write(wasi_try!( + state.fs.prestat_fd(inodes.deref(), fd) + .map_err(|code| { debug!("fd_prestat_get failed (fd={}) - errno={}", fd, code); code - } - ))) - ); + }) + ))); __WASI_ESUCCESS } @@ -961,8 +979,7 @@ pub fn fd_prestat_dir_name( trace!("=> inode: {:?}", inode_val); let guard = inode_val.read(); - let deref = guard.deref(); - match deref { + match guard.deref() { Kind::Dir { .. } | Kind::Root { .. } => { // TODO: verify this: null termination, etc let path_len: u64 = path_len.into(); @@ -1057,8 +1074,7 @@ pub fn fd_pwrite( let inode = &inodes.arena[inode_idx]; let mut guard = inode.write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { handle, .. } => { if let Some(handle) = handle { wasi_try_ok!( @@ -1157,8 +1173,7 @@ pub fn fd_read( let bytes_read = { let mut guard = inode.write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { handle, .. } => { if let Some(handle) = handle { wasi_try_ok!( @@ -1252,7 +1267,9 @@ pub fn fd_read( bytes_read } }; + let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| __WASI_EOVERFLOW)); + trace!("wasi::fd_read: bytes_read={}", bytes_read); wasi_try_mem_ok!(nread_ref.write(bytes_read)); Ok(__WASI_ESUCCESS) @@ -1295,8 +1312,7 @@ pub fn fd_readdir( let entries: Vec<(String, u8, u64)> = { let guard = inodes.arena[working_dir.inode].read(); - let deref = guard.deref(); - match deref { + match guard.deref() { Kind::Dir { path, entries, .. } => { debug!("Reading dir {:?}", path); // TODO: refactor this code @@ -1477,7 +1493,7 @@ pub fn fd_event( inodes.deref_mut(), kind, false, - "event".to_string(), + "event".into(), ); let rights = __WASI_RIGHT_FD_READ | __WASI_RIGHT_FD_WRITE | __WASI_RIGHT_POLL_FD_READWRITE; let fd = wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode)); @@ -1527,8 +1543,7 @@ pub fn fd_seek( use std::io::SeekFrom; let inode_idx = fd_entry.inode; let mut guard = inodes.arena[inode_idx].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { ref mut handle, .. } => { if let Some(handle) = handle { let end = @@ -1598,8 +1613,7 @@ pub fn fd_sync(ctx: FunctionEnvMut<'_, WasiEnv>, fd: __wasi_fd_t) -> __wasi_errn // TODO: implement this for more than files { let mut guard = inodes.arena[inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { handle, .. } => { if let Some(h) = handle { wasi_try!(h.sync_to_disk().map_err(fs_error_into_wasi_err)); @@ -1715,8 +1729,7 @@ pub fn fd_write( let bytes_written = { let mut guard = inode.write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { handle, .. } => { if let Some(handle) = handle { wasi_try_ok!( @@ -1744,7 +1757,8 @@ pub fn fd_write( counter, wakers, .. } => { let mut val = 0u64.to_ne_bytes(); - let written = wasi_try_ok!(write_bytes(&mut val[..], &memory, iovs_arr)); + let written = + wasi_try_ok!(write_bytes(&mut val[..], &memory, iovs_arr)); if written != val.len() { return Ok(__WASI_EINVAL); } @@ -1764,7 +1778,10 @@ pub fn fd_write( } Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_write"), Kind::Buffer { buffer } => { - wasi_try_ok!(write_bytes(&mut buffer[offset..], &memory, iovs_arr), env) + wasi_try_ok!( + write_bytes(&mut buffer[offset..], &memory, iovs_arr), + env + ) } } }; @@ -1811,13 +1828,13 @@ pub fn fd_pipe( inodes.deref_mut(), Kind::Pipe { pipe: pipe1 }, false, - "pipe".to_string(), + "pipe".into(), ); let inode2 = state.fs.create_inode_with_default_stat( inodes.deref_mut(), Kind::Pipe { pipe: pipe2 }, false, - "pipe".to_string(), + "pipe".into(), ); let rights = super::state::all_socket_rights(); @@ -1886,8 +1903,7 @@ pub fn path_create_directory( for comp in &path_vec { debug!("Creating dir {}", comp); let mut guard = inodes.arena[cur_dir_inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::Dir { ref mut entries, path, @@ -2189,8 +2205,7 @@ pub fn path_link( } { let mut guard = inodes.arena[target_parent_inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::Dir { entries, .. } => { if entries.contains_key(&new_entry_name) { return __WASI_EEXIST; @@ -2295,8 +2310,7 @@ pub fn path_open( let inode = if let Ok(inode) = maybe_inode { // Happy path, we found the file we're trying to open let mut guard = inodes.arena[inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { ref mut handle, path, @@ -2383,8 +2397,7 @@ pub fn path_open( )); let new_file_host_path = { let guard = inodes.arena[parent_inode].read(); - let deref = guard.deref(); - match deref { + match guard.deref() { Kind::Dir { path, .. } => { let mut new_path = path.clone(); new_path.push(&new_entity_name); @@ -2444,10 +2457,6 @@ pub fn path_open( } }; - { - debug!("inode {:?} value {:#?} found!", inode, inodes.arena[inode]); - } - // TODO: check and reduce these // TODO: ensure a mutable fd to root can never be opened let out_fd = wasi_try!(state.fs.create_fd( @@ -2514,7 +2523,8 @@ pub fn path_readlink( } let bytes: Vec<_> = bytes.collect(); - let out = wasi_try_mem!(buf.slice(&memory, wasi_try!(to_offset::(bytes.len())))); + let out = + wasi_try_mem!(buf.slice(&memory, wasi_try!(to_offset::(bytes.len())))); wasi_try_mem!(out.write_slice(&bytes)); // should we null terminate this? @@ -2556,8 +2566,7 @@ pub fn path_remove_directory( let host_path_to_remove = { let guard = inodes.arena[inode].read(); - let deref = guard.deref(); - match deref { + match guard.deref() { Kind::Dir { entries, path, .. } => { if !entries.is_empty() || wasi_try!(state.fs_read_dir(path)).count() != 0 { return __WASI_ENOTEMPTY; @@ -2571,8 +2580,7 @@ pub fn path_remove_directory( { let mut guard = inodes.arena[parent_inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::Dir { ref mut entries, .. } => { @@ -2676,10 +2684,10 @@ pub fn path_rename( wasi_try!(state .fs .get_parent_inode_at_path(inodes.deref_mut(), new_fd, target_path, true)); + let host_adjusted_target_path = { let guard = inodes.arena[target_parent_inode].read(); - let deref = guard.deref(); - match deref { + match guard.deref() { Kind::Dir { entries, path, .. } => { if entries.contains_key(&target_entry_name) { return __WASI_EEXIST; @@ -2700,8 +2708,7 @@ pub fn path_rename( let source_entry = { let mut guard = inodes.arena[source_parent_inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::Dir { entries, .. } => { wasi_try!(entries.remove(&source_entry_name).ok_or(__WASI_ENOENT)) } @@ -2717,8 +2724,7 @@ pub fn path_rename( { let mut guard = inodes.arena[source_entry].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { handle, ref path, .. } => { @@ -2840,8 +2846,7 @@ pub fn path_symlink( // short circuit if anything is wrong, before we create an inode { let guard = inodes.arena[target_parent_inode].read(); - let deref = guard.deref(); - match deref { + match guard.deref() { Kind::Dir { entries, .. } => { if entries.contains_key(&entry_name) { return __WASI_EEXIST; @@ -2878,7 +2883,7 @@ pub fn path_symlink( inodes.deref_mut(), kind, false, - entry_name.clone(), + entry_name.clone().into(), ); { @@ -2932,8 +2937,7 @@ pub fn path_unlink_file( let removed_inode = { let mut guard = inodes.arena[parent_inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::Dir { ref mut entries, .. } => { @@ -2958,8 +2962,7 @@ pub fn path_unlink_file( if st_nlink == 0 { { let mut guard = inodes.arena[removed_inode].write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { handle, path, .. } => { if let Some(h) = handle { wasi_try!(h.unlink().map_err(fs_error_into_wasi_err)); @@ -3119,8 +3122,7 @@ pub fn poll_oneoff( { let guard = inodes.arena[inode].read(); - let deref = guard.deref(); - match deref { + match guard.deref() { Kind::File { handle, .. } => { if let Some(h) = handle { crate::state::InodeValFileReadGuard { guard } @@ -3494,83 +3496,364 @@ pub fn chdir( /// Returns the thread index of the newly created thread /// (indices always start from zero) pub fn thread_spawn( - ctx: FunctionEnvMut<'_, WasiEnv>, - method: WasmPtr, - method_len: M::Offset, + mut ctx: FunctionEnvMut<'_, WasiEnv>, user_data: u64, reactor: __wasi_bool_t, ret_tid: WasmPtr<__wasi_tid_t, M>, ) -> __wasi_errno_t { - debug!("wasi::thread_spawn"); + debug!("wasi::thread_spawn (reactor={}, thread_id={}, caller_id={})", reactor, ctx.data().id.raw(), current_caller_id().raw()); + + // Now we use the environment and memory references let env = ctx.data(); let memory = env.memory_view(&ctx); - let method = unsafe { get_input_str!(&memory, method, method_len) }; + let runtime = env.runtime.clone(); - // Load the callback function - if method.as_str() != "_thread_start" { - return __WASI_ENOTCAPABLE; + // Create the handle that represents this thread + let mut thread_handle = { + let mut guard = env.state.threading.write().unwrap(); + guard.new_thread() }; - /* - let funct = unsafe { - if env.thread_start_ref().is_none() { - return __WASI_EADDRNOTAVAIL; + let thread_id: __wasi_tid_t = thread_handle.id().into(); + + // We need a copy of the process memory and a packaged store in order to + // launch threads and reactors + let thread_memory = wasi_try!( + ctx.data() + .memory() + .try_clone(&ctx) + .ok_or_else(|| { + error!("thread failed - the memory could not be cloned"); + __WASI_ENOTCAPABLE + }) + ); + #[cfg(feature = "compiler")] + let engine = ctx.as_store_ref().engine().clone(); + + // Build a new store that will be passed to the thread + #[cfg(feature = "compiler")] + let mut store = Store::new(engine); + #[cfg(not(feature = "compiler"))] + let mut store = Store::default(); + + // This function takes in memory and a store and creates a context that + // can be used to call back into the process + let create_ctx = { + let state = env.state.clone(); + let wasi_env = env.clone(); + let thread_id = thread_handle.id(); + move |mut store: Store, module: Module, memory: VMMemory| + { + // We need to reconstruct some things + let module = module.clone(); + let memory = Memory::new_from_existing(&mut store, memory); + + // Build the context object and import the memory + let mut ctx = WasiFunctionEnv::new(&mut store, wasi_env.clone()); + ctx.data_mut(&mut store).id = thread_id; + + let mut import_object = import_object_for_all_wasi_versions(&mut store, &ctx.env); + import_object.define("env", "memory", memory.clone()); + + let instance = match Instance::new(&mut store, &module, &import_object) { + Ok(a) => a, + Err(err) => { + error!("thread failed - clone instance failed: {}", err); + return Err(__WASI_ENOEXEC as u32); + } + }; + + // Set the current thread ID + ctx.data_mut(&mut store).inner = Some( + WasiEnvInner { + module, + memory, + thread_spawn: instance.exports.get_typed_function(&store, "_start_thread").ok(), + react: instance.exports.get_typed_function(&store, "_react").ok(), + thread_local_destroy: instance.exports.get_typed_function(&store, "_thread_local_destroy").ok(), + } + ); + trace!("threading: new context created for thread_id = {}", thread_id.raw()); + Ok(WasiThreadContext { + ctx, + store: RefCell::new(store) + }) } - env.thread_start_ref_unchecked() }; - */ - let reactor = match reactor { - __WASI_BOOL_FALSE => false, - __WASI_BOOL_TRUE => true, - _ => return __WASI_EINVAL, - }; + // This function calls into the module + let call_module = move |ctx: &WasiFunctionEnv, store: &mut Store| + { + // We either call the reactor callback or the thread spawn callback + //trace!("threading: invoking thread callback (reactor={})", reactor); + let spawn = match reactor { + __WASI_BOOL_FALSE => ctx.data(&store).inner().thread_spawn.clone().unwrap(), + __WASI_BOOL_TRUE => ctx.data(&store).inner().react.clone().unwrap(), + _ => { + debug!("thread failed - failed as the reactor type is not value"); + return __WASI_ENOEXEC as u32; + } + }; + + let user_data_low: u32 = (user_data & 0xFFFFFFFF) as u32; + let user_data_high: u32 = (user_data >> 32) as u32; - // Create the sub-thread - let mut sub_env = env.clone(); - let mut sub_thread = env.new_thread(); - sub_env.id = sub_thread.id; - - let child = { - let id = sub_thread.id; - wasi_try!(env - .runtime - .thread_spawn(Box::new(move || { - /* - if let Some(funct) = sub_env.thread_start_ref() { - if let Err(err) = funct.call(user_data) { - warn!("thread failed: {}", err); - std::mem::forget(sub_thread); - return; + let mut ret = __WASI_ESUCCESS; + if let Err(err) = spawn.call(store, user_data_low as i32, user_data_high as i32) { + debug!("thread failed - start: {}", err); + ret = __WASI_ENOEXEC; + } + //trace!("threading: thread callback finished (reactor={}, ret={})", reactor, ret); + + // If we are NOT a reactor then we will only run once and need to clean up + if reactor == __WASI_BOOL_FALSE + { + trace!("threading: cleaning up local thread variables"); + + // Destroy all the local thread variables that were allocated for this thread + let to_local_destroy = { + let thread_id = ctx.data(store).id; + let mut to_local_destroy = Vec::new(); + let mut guard = ctx.data(store).state.threading.write().unwrap(); + for ((thread, key), val) in guard.thread_local.iter() { + if *thread == thread_id { + if let Some(user_data) = guard.thread_local_user_data.get(key) { + to_local_destroy.push((*user_data, *val)) + } } - } else { - warn!("failed to start thread: missing callback '__wasix_thread_start'"); - std::mem::forget(sub_thread); - return; } - */ + guard.thread_local.retain(|(t, _), _| *t != thread_id); + to_local_destroy + }; + if to_local_destroy.len() > 0 { + if let Some(thread_local_destroy) = ctx.data(store).inner().thread_local_destroy.as_ref().map(|a| a.clone()) { + for (user_data, val) in to_local_destroy { + let user_data_low: u32 = (user_data & 0xFFFFFFFF) as u32; + let user_data_high: u32 = (user_data >> 32) as u32; + + let val_low: u32 = (val & 0xFFFFFFFF) as u32; + let val_high: u32 = (val >> 32) as u32; + let _ = thread_local_destroy.call(store, user_data_low as i32, user_data_high as i32, val_low as i32, val_high as i32); + } + } + } + } + + // Return the result + ret as u32 + }; + + // This next function gets a context for the local thread and then + // calls into the process + let mut execute_module = { + let state = env.state.clone(); + move |store: &mut Option, module: Module, memory: &mut Option| + { + // We capture the thread handle here, it is used to notify + // anyone that is interested when this thread has terminated + let _captured_handle = Box::new(&mut thread_handle); + + // Given that it is not safe to assume this delegate will run on the + // same thread we need to capture a simple process that will create + // context objects on demand and reuse them + let caller_id = current_caller_id(); + + // We loop because read locks are held while functions run which need + // to be relocked in the case of a miss hit. + loop { let thread = { - let mut guard = sub_env.state.threading.lock().unwrap(); - let thread = guard.threads.remove(&id); - drop(guard); - thread + let guard = state.threading.read().unwrap(); + guard.thread_ctx.get(&caller_id).map(|a| a.clone()) }; - - if let Some(thread) = thread { - let mut thread_guard = thread.exit.lock().unwrap(); - thread_guard.take(); + if let Some(thread) = thread + { + let mut store = thread.store.borrow_mut(); + let ret = call_module(&thread.ctx, store.deref_mut()); + return ret; } - drop(sub_thread); - })) - .map_err(|err| { - let err: __wasi_errno_t = err.into(); - err - })); - id + + // Otherwise we need to create a new context under a write lock + debug!("encountered a new caller (ref={}) - creating WASM execution context...", caller_id.raw()); + + // We can only create the context once per thread + let memory = match memory.take() { + Some(m) => m, + None => { + debug!("thread failed - memory can only be consumed once per context creation"); + return __WASI_ENOEXEC as u32; + } + }; + let store = match store.take() { + Some(s) => s, + None => { + debug!("thread failed - store can only be consumed once per context creation"); + return __WASI_ENOEXEC as u32; + } + }; + + // Now create the context and hook it up + let mut guard = state.threading.write().unwrap(); + let ctx = match create_ctx(store, module.clone(), memory) { + Ok(c) => c, + Err(err) => { + return err; + } + }; + guard.thread_ctx.insert(caller_id, Arc::new(ctx)); + } + } + }; + + // If we are a reactor then instead of launching the thread now + // we store it in the state machine and only launch it whenever + // work arrives that needs to be processed + match reactor { + __WASI_BOOL_TRUE => { + warn!("thread failed - reactors are not currently supported"); + return __WASI_ENOTCAPABLE; + }, + __WASI_BOOL_FALSE => { + // If the process does not export a thread spawn function then obviously + // we can't spawn a background thread + if env.inner().thread_spawn.is_none() { + warn!("thread failed - the program does not export a _start_thread function"); + return __WASI_ENOTCAPABLE; + } + + // Now spawn a thread + trace!("threading: spawning background thread"); + let thread_module = env.inner().module.clone(); + wasi_try!(runtime + .thread_spawn(Box::new(move |store: Store, module: Module, thread_memory: VMMemory| { + let mut thread_memory = Some(thread_memory); + let mut store = Some(store); + execute_module(&mut store, module, &mut thread_memory); + }), store, thread_module, thread_memory) + .map_err(|err| { + let err: __wasi_errno_t = err.into(); + err + })); + }, + _ => { + warn!("thread failed - invalid reactor parameter value"); + return __WASI_ENOTCAPABLE; + } + } + + // Success + let memory = ctx.data().memory_view(&ctx); + wasi_try_mem!(ret_tid.write(&memory, thread_id)); + __WASI_ESUCCESS +} + +/// ### `thread_local_create()` +/// Create a thread local variable +/// If The web assembly process exports function named '_thread_local_destroy' +/// then it will be invoked when the thread goes out of scope and dies. +/// +/// ## Parameters +/// +/// * `user_data` - User data that will be passed to the destructor +/// when the thread variable goes out of scope +pub fn thread_local_create( + ctx: FunctionEnvMut<'_, WasiEnv>, + user_data: u64, + ret_key: WasmPtr<__wasi_tl_key_t, M>, +) -> __wasi_errno_t { + trace!("wasi::thread_local_create (user_data={})", user_data); + let env = ctx.data(); + + let key = { + let mut guard = env.state.threading.write().unwrap(); + guard.thread_local_seed += 1; + let key = guard.thread_local_seed; + guard.thread_local_user_data.insert(key, user_data); + key }; - let child: __wasi_tid_t = child.into(); + + let memory = env.memory_view(&ctx); + wasi_try_mem!(ret_key.write(&memory, key)); + __WASI_ESUCCESS +} - wasi_try_mem!(ret_tid.write(&memory, child)); +/// ### `thread_local_destroy()` +/// Destroys a thread local variable +/// +/// ## Parameters +/// +/// * `user_data` - User data that will be passed to the destructor +/// when the thread variable goes out of scope +/// * `key` - Thread key that was previously created +pub fn thread_local_destroy( + mut ctx: FunctionEnvMut<'_, WasiEnv>, + key: __wasi_tl_key_t +) -> __wasi_errno_t { + trace!("wasi::thread_local_destroy (key={})", key); + let state = ctx.data().state.clone(); + let mut guard = state.threading.write().unwrap(); + if let Some(user_data) = guard.thread_local_user_data.remove(&key) { + if let Some(thread_local_destroy) = ctx.data().inner().thread_local_destroy.as_ref().map(|a| a.clone()) { + guard.thread_local + .iter() + .filter(|((_, k), _)| *k == key) + .for_each(|((_, _), val)| { + let user_data_low: u32 = (user_data & 0xFFFFFFFF) as u32; + let user_data_high: u32 = (user_data >> 32) as u32; + + let val_low: u32 = (val & 0xFFFFFFFF) as u32; + let val_high: u32 = (val >> 32) as u32; + + let _ = thread_local_destroy.call(&mut ctx, user_data_low as i32, user_data_high as i32, val_low as i32, val_high as i32); + }); + } + } + guard.thread_local.retain(|(_, k), _| *k != key); + __WASI_ESUCCESS +} + +/// ### `thread_local_set()` +/// Sets the value of a thread local variable +/// +/// ## Parameters +/// +/// * `key` - Thread key that this local variable will be associated with +/// * `val` - Value to be set for the thread local variable +pub fn thread_local_set( + ctx: FunctionEnvMut<'_, WasiEnv>, + key: __wasi_tl_key_t, + val: __wasi_tl_val_t +) -> __wasi_errno_t { + //trace!("wasi::thread_local_set (key={}, val={})", key, val); + let env = ctx.data(); + + let current_thread = ctx.data().id; + let mut guard = env.state.threading.write().unwrap(); + guard.thread_local.insert((current_thread, key), val); + __WASI_ESUCCESS +} + +/// ### `thread_local_get()` +/// Gets the value of a thread local variable +/// +/// ## Parameters +/// +/// * `key` - Thread key that this local variable that was previous set +pub fn thread_local_get( + ctx: FunctionEnvMut<'_, WasiEnv>, + key: __wasi_tl_key_t, + ret_val: WasmPtr<__wasi_tl_val_t, M>, +) -> __wasi_errno_t { + //trace!("wasi::thread_local_get (key={})", key); + let env = ctx.data(); + + let val = { + let current_thread = ctx.data().id; + let guard = env.state.threading.read().unwrap(); + guard.thread_local.get(&(current_thread, key)).map(|a| a.clone()) + }; + let val = val.unwrap_or_default(); + let memory = env.memory_view(&ctx); + wasi_try_mem!(ret_val.write(&memory, val)); __WASI_ESUCCESS } @@ -3584,7 +3867,7 @@ pub fn thread_sleep( ctx: FunctionEnvMut<'_, WasiEnv>, duration: __wasi_timestamp_t, ) -> Result<__wasi_errno_t, WasiError> { - debug!("wasi::thread_sleep"); + //trace!("wasi::thread_sleep"); let env = ctx.data(); let duration = Duration::from_nanos(duration as u64); @@ -3599,7 +3882,7 @@ pub fn thread_id( ctx: FunctionEnvMut<'_, WasiEnv>, ret_tid: WasmPtr<__wasi_tid_t, M>, ) -> __wasi_errno_t { - debug!("wasi::thread_id"); + //trace!("wasi::thread_id"); let env = ctx.data(); let tid: __wasi_tid_t = env.id.into(); @@ -3624,15 +3907,15 @@ pub fn thread_join( let env = ctx.data(); let tid: WasiThreadId = tid.into(); let other_thread = { - let guard = env.state.threading.lock().unwrap(); - guard.threads.get(&tid).cloned() + let guard = env.state.threading.read().unwrap(); + guard.get(&tid) }; if let Some(other_thread) = other_thread { loop { - if other_thread.join(Duration::from_millis(5)) { + env.yield_now()?; + if other_thread.join(Duration::from_millis(50)) { break; } - env.yield_now()?; } Ok(__WASI_ESUCCESS) } else { @@ -3660,6 +3943,161 @@ pub fn thread_parallelism( __WASI_ESUCCESS } +/// Wait for a futex_wake operation to wake us. +/// Returns with EINVAL if the futex doesn't hold the expected value. +/// Returns false on timeout, and true in all other cases. +/// +/// ## Parameters +/// +/// * `futex` - Memory location that holds the value that will be checked +/// * `expected` - Expected value that should be currently held at the memory location +/// * `timeout` - Timeout should the futex not be triggered in the allocated time +pub fn futex_wait( + ctx: FunctionEnvMut<'_, WasiEnv>, + futex_ptr: WasmPtr, + expected: u32, + timeout: WasmPtr<__wasi_option_timestamp_t, M>, + ret_woken: WasmPtr<__wasi_bool_t, M>, +) -> Result<__wasi_errno_t, WasiError> { + trace!("wasi::futex_wait(offset={})", futex_ptr.offset()); + let env = ctx.data(); + let state = env.state.deref(); + + let pointer: u64 = wasi_try_ok!(futex_ptr.offset().try_into().map_err(|_| __WASI_EOVERFLOW)); + + // Register the waiting futex + let futex = { + use std::collections::hash_map::Entry; + let mut guard = state.futexs.lock().unwrap(); + match guard.entry(pointer) { + Entry::Occupied(entry) => { + entry.get().clone() + }, + Entry::Vacant(entry) => { + let futex = WasiFutex { + refcnt: Arc::new(AtomicU32::new(1)), + inner: Arc::new((Mutex::new(()), Condvar::new())) + }; + entry.insert(futex.clone()); + futex + } + } + }; + + // Loop until we either hit a yield error or the futex is woken + let mut yielded = Ok(()); + loop { + let futex_lock = futex.inner.0.lock().unwrap(); + + // If the value of the memory is no longer the expected value + // then terminate from the loop (we do this under a futex lock + // so that its protected) + { + let view = env.memory_view(&ctx); + let val = wasi_try_mem_ok!(futex_ptr.read(&view)); + if val != expected { + break; + } + } + + let result = futex.inner.1.wait_timeout(futex_lock, Duration::from_millis(50)).unwrap(); + if result.1.timed_out() { + yielded = env.yield_now(); + if yielded.is_err() { + break; + } + } else { + break; + } + } + + // Drop the reference count to the futex (and remove it if the refcnt hits zero) + { + let mut guard = state.futexs.lock().unwrap(); + if guard.get(&pointer) + .map(|futex| futex.refcnt.fetch_sub(1, Ordering::AcqRel) == 1) + .unwrap_or(false) + { + guard.remove(&pointer); + } + } + + // We may have a yield error (such as a terminate) + yielded?; + + Ok(__WASI_ESUCCESS) +} + +/// Wake up one thread that's blocked on futex_wait on this futex. +/// Returns true if this actually woke up such a thread, +/// or false if no thread was waiting on this futex. +/// +/// ## Parameters +/// +/// * `futex` - Memory location that holds a futex that others may be waiting on +pub fn futex_wake( + ctx: FunctionEnvMut<'_, WasiEnv>, + futex: WasmPtr, + ret_woken: WasmPtr<__wasi_bool_t, M>, +) -> __wasi_errno_t { + trace!("wasi::futex_wake(offset={})", futex.offset()); + let env = ctx.data(); + let memory = env.memory_view(&ctx); + let state = env.state.deref(); + + let pointer: u64 = wasi_try!(futex.offset().try_into().map_err(|_| __WASI_EOVERFLOW)); + let mut woken = false; + + let mut guard = state.futexs.lock().unwrap(); + if let Some(futex) = guard.get(&pointer) { + futex.inner.1.notify_one(); + woken = true; + } else { + trace!("wasi::futex_wake - nothing waiting!"); + } + + let woken = match woken { + false => __WASI_BOOL_FALSE, + true => __WASI_BOOL_TRUE, + }; + wasi_try_mem!(ret_woken.write(&memory, woken)); + + __WASI_ESUCCESS +} + +/// Wake up all threads that are waiting on futex_wait on this futex. +/// +/// ## Parameters +/// +/// * `futex` - Memory location that holds a futex that others may be waiting on +pub fn futex_wake_all( + ctx: FunctionEnvMut<'_, WasiEnv>, + futex: WasmPtr, + ret_woken: WasmPtr<__wasi_bool_t, M>, +) -> __wasi_errno_t { + trace!("wasi::futex_wake_all(offset={})", futex.offset()); + let env = ctx.data(); + let memory = env.memory_view(&ctx); + let state = env.state.deref(); + + let pointer: u64 = wasi_try!(futex.offset().try_into().map_err(|_| __WASI_EOVERFLOW)); + let mut woken = false; + + let mut guard = state.futexs.lock().unwrap(); + if let Some(futex) = guard.remove(&pointer) { + futex.inner.1.notify_all(); + woken = true; + } + + let woken = match woken { + false => __WASI_BOOL_FALSE, + true => __WASI_BOOL_TRUE, + }; + wasi_try_mem!(ret_woken.write(&memory, woken)); + + __WASI_ESUCCESS +} + /// ### `getpid()` /// Returns the handle of the current process pub fn getpid( @@ -3752,10 +4190,10 @@ pub fn process_spawn( __WASI_STDIO_MODE_PIPED => StdioMode::Piped, __WASI_STDIO_MODE_INHERIT => StdioMode::Inherit, __WASI_STDIO_MODE_LOG => StdioMode::Log, - /*__WASI_STDIO_MODE_NULL |*/ _ => StdioMode::Null, + __WASI_STDIO_MODE_NULL | _ => StdioMode::Null, }; - let process = wasi_try_bus!(bus + let mut process = wasi_try_bus!(bus .new_spawn() .chroot(chroot) .args(args) @@ -3767,7 +4205,54 @@ pub fn process_spawn( .spawn(name.as_str()) .map_err(bus_error_into_wasi_err)); - let conv_stdio_fd = |a: Option| match a { + // Create the file descriptors used to access this process + let (fd_stdin, fd_stdout, fd_stderr) = { + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); + + // Register the inodes for the stdio for this sub process + let fd_stdin = match process.stdin.take() { + Some(handle) => Some( + wasi_try_bus!(state.fs.create_fd(bus_write_rights(), bus_write_rights(), 0, 0, + state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + Kind::File { handle: Some(handle), path: "/dev/stdin".into(), fd: None }, + false, + "stdin".into(), + ) + ).map_err(|_| __BUS_EINTERNAL)) + ), + None => None, + }; + let fd_stdout = match process.stdout.take() { + Some(handle) => Some( + wasi_try_bus!(state.fs.create_fd(bus_read_rights(), bus_read_rights(), 0, 0, + state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + Kind::File { handle: Some(handle), path: "/dev/stdout".into(), fd: None }, + false, + "stdout".into(), + ) + ).map_err(|_| __BUS_EINTERNAL)) + ), + None => None + }; + let fd_stderr = match process.stderr.take() { + Some(handle) => Some( + wasi_try_bus!(state.fs.create_fd(bus_read_rights(), bus_read_rights(), 0, 0, + state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + Kind::File { handle: Some(handle), path: "/dev/stderr".into(), fd: None }, + false, + "stderr".into(), + ) + ).map_err(|_| __BUS_EINTERNAL)) + ), + None => None + }; + (fd_stdin, fd_stdout, fd_stderr) + }; + + let conv_stdio_fd = |a: Option<__wasi_fd_t>| match a { Some(fd) => __wasi_option_fd_t { tag: __WASI_OPTION_SOME, fd: fd.into(), @@ -3777,18 +4262,18 @@ pub fn process_spawn( fd: 0, }, }; - + // Convert the stdio - let stdin = conv_stdio_fd(process.inst.stdin_fd()); - let stdout = conv_stdio_fd(process.inst.stdout_fd()); - let stderr = conv_stdio_fd(process.inst.stderr_fd()); + let stdin = conv_stdio_fd(fd_stdin); + let stdout = conv_stdio_fd(fd_stdout); + let stderr = conv_stdio_fd(fd_stderr); // Add the process to the environment state let bid = { - let mut guard = env.state.threading.lock().unwrap(); + let mut guard = env.state.threading.write().unwrap(); guard.process_seed += 1; let bid = guard.process_seed; - guard.processes.insert(bid.into(), process); + guard.processes.insert(bid.into(), Box::new(process)); bid }; @@ -3822,15 +4307,15 @@ pub fn bus_open_local( name_len: M::Offset, reuse: __wasi_bool_t, ret_bid: WasmPtr<__wasi_bid_t, M>, -) -> __bus_errno_t { +) -> Result<__bus_errno_t, WasiError> { let env = ctx.data(); let bus = env.runtime.bus(); let memory = env.memory_view(&ctx); - let name = unsafe { get_input_str_bus!(&memory, name, name_len) }; + let name = unsafe { get_input_str_bus_ok!(&memory, name, name_len) }; let reuse = reuse == __WASI_BOOL_TRUE; debug!("wasi::bus_open_local (name={}, reuse={})", name, reuse); - bus_open_local_internal(ctx, name, reuse, None, None, ret_bid) + bus_open_internal(ctx, name, reuse, None, None, ret_bid) } /// Spawns a new bus process for a particular web WebAssembly @@ -3857,30 +4342,30 @@ pub fn bus_open_remote( token: WasmPtr, token_len: M::Offset, ret_bid: WasmPtr<__wasi_bid_t, M>, -) -> __bus_errno_t { +) -> Result<__bus_errno_t, WasiError> { let env = ctx.data(); let bus = env.runtime.bus(); let memory = env.memory_view(&ctx); - let name = unsafe { get_input_str_bus!(&memory, name, name_len) }; - let instance = unsafe { get_input_str_bus!(&memory, instance, instance_len) }; - let token = unsafe { get_input_str_bus!(&memory, token, token_len) }; + let name = unsafe { get_input_str_bus_ok!(&memory, name, name_len) }; + let instance = unsafe { get_input_str_bus_ok!(&memory, instance, instance_len) }; + let token = unsafe { get_input_str_bus_ok!(&memory, token, token_len) }; let reuse = reuse == __WASI_BOOL_TRUE; debug!( "wasi::bus_open_remote (name={}, reuse={}, instance={})", name, reuse, instance ); - bus_open_local_internal(ctx, name, reuse, Some(instance), Some(token), ret_bid) + bus_open_internal(ctx, name, reuse, Some(instance), Some(token), ret_bid) } -fn bus_open_local_internal( +fn bus_open_internal( ctx: FunctionEnvMut<'_, WasiEnv>, name: String, reuse: bool, instance: Option, token: Option, ret_bid: WasmPtr<__wasi_bid_t, M>, -) -> __bus_errno_t { +) -> Result<__bus_errno_t, WasiError> { let env = ctx.data(); let bus = env.runtime.bus(); let memory = env.memory_view(&ctx); @@ -3888,11 +4373,11 @@ fn bus_open_local_internal( // Check if it already exists if reuse { - let guard = env.state.threading.lock().unwrap(); + let guard = env.state.threading.read().unwrap(); if let Some(bid) = guard.process_reuse.get(&name) { if guard.processes.contains_key(bid) { - wasi_try_mem_bus!(ret_bid.write(&memory, (*bid).into())); - return __BUS_ESUCCESS; + wasi_try_mem_bus_ok!(ret_bid.write(&memory, bid.clone().into())); + return Ok(__BUS_ESUCCESS); } } } @@ -3912,23 +4397,24 @@ fn bus_open_local_internal( process.access_token(token); } - let process = wasi_try_bus!(process + // Spawn the process + let mut process = wasi_try_bus_ok!(process .spawn(name.as_ref()) .map_err(bus_error_into_wasi_err)); // Add the process to the environment state let bid = { - let mut guard = env.state.threading.lock().unwrap(); + let mut guard = env.state.threading.write().unwrap(); guard.process_seed += 1; let bid: WasiBusProcessId = guard.process_seed.into(); - guard.processes.insert(bid, process); + guard.processes.insert(bid, Box::new(process)); guard.process_reuse.insert(name, bid); bid }; - wasi_try_mem_bus!(ret_bid.write(&memory, bid.into())); + wasi_try_mem_bus_ok!(ret_bid.write(&memory, bid.into())); - __BUS_ESUCCESS + Ok(__BUS_ESUCCESS) } /// Closes a bus process and releases all associated resources @@ -3941,10 +4427,13 @@ pub fn bus_close(ctx: FunctionEnvMut<'_, WasiEnv>, bid: __wasi_bid_t) -> __bus_e let bid: WasiBusProcessId = bid.into(); let env = ctx.data(); - let mut guard = env.state.threading.lock().unwrap(); - guard.processes.remove(&bid); + let mut guard = env.state.threading.write().unwrap(); + if let Some(process) = guard.processes.remove(&bid) { + let name: Cow<'static, str> = process.name.clone().into(); + guard.process_reuse.remove(&name); + } - __BUS_EUNSUPPORTED + __BUS_ESUCCESS } /// Invokes a call within a running bus process. @@ -3961,27 +4450,102 @@ pub fn bus_close(ctx: FunctionEnvMut<'_, WasiEnv>, bid: __wasi_bid_t) -> __bus_e pub fn bus_call( ctx: FunctionEnvMut<'_, WasiEnv>, bid: __wasi_bid_t, - keep_alive: __wasi_bool_t, - topic: WasmPtr, - topic_len: M::Offset, + topic_hash: WasmPtr<__wasi_hash_t>, format: __wasi_busdataformat_t, buf: WasmPtr, buf_len: M::Offset, ret_cid: WasmPtr<__wasi_cid_t, M>, -) -> __bus_errno_t { +) -> Result<__bus_errno_t, WasiError> { let env = ctx.data(); let bus = env.runtime.bus(); let memory = env.memory_view(&ctx); - let topic = unsafe { get_input_str_bus!(&memory, topic, topic_len) }; - let keep_alive = keep_alive == __WASI_BOOL_TRUE; + let topic_hash = wasi_try_mem_bus_ok!(topic_hash.read(&memory)); + let buf_slice = wasi_try_mem_bus_ok!(buf.slice(&memory, buf_len)); trace!( - "wasi::bus_call (bid={}, topic={}, buf_len={})", + "wasi::bus_call (bid={}, buf_len={})", bid, - topic, buf_len ); - __BUS_EUNSUPPORTED + // Get the process that we'll invoke this call for + let mut guard = env.state.threading.read().unwrap(); + let bid: WasiBusProcessId = bid.into(); + let process = if let Some(process) = { + guard.processes.get(&bid).map(|p| p.clone()) + } { process } else { + return Ok(__BUS_EBADHANDLE); + }; + + // Invoke the bus process + let format = wasi_try_bus_ok!(conv_bus_format_from(format)); + + // Check if the process has finished + if let Some(code) = process.inst.exit_code() { + debug!("process has already exited (code = {})", code); + return Ok(__BUS_EABORTED); + } + + // Invoke the call + let buf = wasi_try_mem_bus_ok!(buf_slice.read_to_vec()); + let mut invoked = process.inst.invoke(topic_hash, format, buf); + drop(process); + drop(guard); + + // Poll the invocation until it does its thing + let mut invocation; + { + // Fast path (does not have to create a futex creation) + let waker = WasiDummyWaker.into_waker(); + let mut cx = Context::from_waker(&waker); + let pinned_invoked = Pin::new(invoked.deref_mut()); + match pinned_invoked.poll_invoked(&mut cx) { + Poll::Ready(i) => { + invocation = wasi_try_bus_ok!(i + .map_err(bus_error_into_wasi_err)); + }, + Poll::Pending => { + // Slow path (will put the thread to sleep) + let parking = WasiParkingLot::default(); + let waker = parking.get_waker(); + let mut cx = Context::from_waker(&waker); + loop { + let pinned_invoked = Pin::new(invoked.deref_mut()); + match pinned_invoked.poll_invoked(&mut cx) { + Poll::Ready(i) => { + invocation = wasi_try_bus_ok!(i + .map_err(bus_error_into_wasi_err)); + break; + }, + Poll::Pending => { + env.yield_now()?; + parking.wait(Duration::from_millis(5)); + } + } + } + } + } + } + + // Record the invocation + let cid = { + let mut guard = env.state.bus.protected(); + guard.call_seed += 1; + let cid = guard.call_seed; + guard.calls.insert(cid, WasiBusCall { + bid, + invocation + }); + cid + }; + + // Now we wake any BUS pollers so that they can drive forward the + // call to completion - when they poll the call they will also + // register a BUS waker + env.state.bus.poll_wake(); + + // Return the CID and success to the caller + wasi_try_mem_bus_ok!(ret_cid.write(&memory, cid)); + Ok(__BUS_ESUCCESS) } /// Invokes a call within the context of another call @@ -3998,27 +4562,121 @@ pub fn bus_call( pub fn bus_subcall( ctx: FunctionEnvMut<'_, WasiEnv>, parent: __wasi_cid_t, - keep_alive: __wasi_bool_t, - topic: WasmPtr, - topic_len: M::Offset, + topic_hash: WasmPtr<__wasi_hash_t>, format: __wasi_busdataformat_t, buf: WasmPtr, buf_len: M::Offset, ret_cid: WasmPtr<__wasi_cid_t, M>, -) -> __bus_errno_t { +) -> Result<__bus_errno_t, WasiError> { let env = ctx.data(); let bus = env.runtime.bus(); let memory = env.memory_view(&ctx); - let topic = unsafe { get_input_str_bus!(&memory, topic, topic_len) }; - let keep_alive = keep_alive == __WASI_BOOL_TRUE; + let topic_hash = wasi_try_mem_bus_ok!(topic_hash.read(&memory)); + let buf_slice = wasi_try_mem_bus_ok!(buf.slice(&memory, buf_len)); trace!( - "wasi::bus_subcall (parent={}, topic={}, buf_len={})", + "wasi::bus_subcall (parent={}, buf_len={})", parent, - topic, buf_len ); - __BUS_EUNSUPPORTED + let format = wasi_try_bus_ok!(conv_bus_format_from(format)); + let buf = wasi_try_mem_bus_ok!(buf_slice.read_to_vec()); + + // Get the parent call that we'll invoke this call for + let mut guard = env.state.bus.protected(); + if let Some(parent) = guard.calls.get(&parent) + { + let bid = parent.bid.clone(); + + // Invoke the sub-call in the existing parent call + let mut invoked = parent.invocation.invoke(topic_hash, format, buf); + drop(parent); + drop(guard); + + // Poll the invocation until it does its thing + let invocation; + { + // Fast path (does not have to create a futex creation) + let waker = WasiDummyWaker.into_waker(); + let mut cx = Context::from_waker(&waker); + let pinned_invoked = Pin::new(invoked.deref_mut()); + match pinned_invoked.poll_invoked(&mut cx) { + Poll::Ready(i) => { + invocation = wasi_try_bus_ok!(i + .map_err(bus_error_into_wasi_err)); + }, + Poll::Pending => { + // Slow path (will put the thread to sleep) + let parking = WasiParkingLot::default(); + let waker = parking.get_waker(); + let mut cx = Context::from_waker(&waker); + loop { + let pinned_invoked = Pin::new(invoked.deref_mut()); + match pinned_invoked.poll_invoked(&mut cx) { + Poll::Ready(i) => { + invocation = wasi_try_bus_ok!(i + .map_err(bus_error_into_wasi_err)); + break; + }, + Poll::Pending => { + env.yield_now()?; + parking.wait(Duration::from_millis(5)); + } + } + } + } + } + } + + // Add the call and return the ID + let cid = { + let mut guard = env.state.bus.protected(); + guard.call_seed += 1; + let cid = guard.call_seed; + guard.calls.insert(cid, WasiBusCall { + bid, + invocation + }); + cid + }; + + // Now we wake any BUS pollers so that they can drive forward the + // call to completion - when they poll the call they will also + // register a BUS waker + env.state.bus.poll_wake(); + + // Return the CID and success to the caller + wasi_try_mem_bus_ok!(ret_cid.write(&memory, cid)); + Ok(__BUS_ESUCCESS) + } else { + Ok(__BUS_EBADHANDLE) + } +} + +// Function for converting the format +fn conv_bus_format(format: BusDataFormat) -> __wasi_busdataformat_t { + match format { + BusDataFormat::Raw => __WASI_BUS_DATA_FORMAT_RAW, + BusDataFormat::Bincode => __WASI_BUS_DATA_FORMAT_BINCODE, + BusDataFormat::MessagePack => __WASI_BUS_DATA_FORMAT_MESSAGE_PACK, + BusDataFormat::Json => __WASI_BUS_DATA_FORMAT_JSON, + BusDataFormat::Yaml => __WASI_BUS_DATA_FORMAT_YAML, + BusDataFormat::Xml => __WASI_BUS_DATA_FORMAT_XML, + } +} + +fn conv_bus_format_from(format: __wasi_busdataformat_t) -> Result { + Ok( + match format { + __WASI_BUS_DATA_FORMAT_RAW => BusDataFormat::Raw, + __WASI_BUS_DATA_FORMAT_BINCODE => BusDataFormat::Bincode, + __WASI_BUS_DATA_FORMAT_MESSAGE_PACK => BusDataFormat::MessagePack, + __WASI_BUS_DATA_FORMAT_JSON => BusDataFormat::Json, + __WASI_BUS_DATA_FORMAT_YAML => BusDataFormat::Yaml, + __WASI_BUS_DATA_FORMAT_XML => BusDataFormat::Xml, + _ => { return Err(__BUS_EDES); } + } + ) } /// Polls for any outstanding events from a particular @@ -4038,19 +4696,346 @@ pub fn bus_subcall( pub fn bus_poll( ctx: FunctionEnvMut<'_, WasiEnv>, timeout: __wasi_timestamp_t, - events: WasmPtr, - nevents: M::Offset, - malloc: WasmPtr, - malloc_len: M::Offset, + events: WasmPtr<__wasi_busevent_t, M>, + maxevents: M::Offset, ret_nevents: WasmPtr, -) -> __bus_errno_t { +) -> Result<__bus_errno_t, WasiError> { let env = ctx.data(); let bus = env.runtime.bus(); let memory = env.memory_view(&ctx); - let malloc = unsafe { get_input_str_bus!(&memory, malloc, malloc_len) }; - trace!("wasi::bus_poll (timeout={}, malloc={})", timeout, malloc); + trace!("wasi::bus_poll (timeout={})", timeout); + + // Lets start by processing events for calls that are already running + let mut nevents = M::ZERO; + let events = wasi_try_mem_bus_ok!(events.slice(&memory, maxevents)); + + let state = env.state.clone(); + let start = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; + loop + { + // The waker will wake this thread should any work arrive + // or need further processing (i.e. async operation) + let waker = state.bus.get_poll_waker(); + let mut cx = Context::from_waker(&waker); + + // Check if any of the processes have closed + let mut exited_bids = HashSet::new(); + { + let mut guard = env.state.threading.write().unwrap(); + for (pid, process) in guard.processes.iter_mut() { + let pinned_process = Pin::new(process.inst.as_mut()); + if pinned_process.poll_finished(&mut cx) == Poll::Ready(()) { + exited_bids.insert(*pid); + } + } + for pid in exited_bids.iter() { + guard.processes.remove(pid); + } + } + + { + // The waker will trigger the reactors when work arrives from the BUS + let mut guard = env.state.bus.protected(); + + // Function that hashes the topic using SHA256 + let hash_topic = |topic: Cow<'static, str>| -> __wasi_hash_t { + use sha2::{Sha256, Digest}; + let mut hasher = Sha256::new(); + hasher.update(&topic.bytes().collect::>()); + let hash: [u8; 16] = hasher.finalize()[..16].try_into().unwrap(); + u128::from_le_bytes(hash) + }; + + // Function that turns a buffer into a readable file handle + let buf_to_fd = { + let state = env.state.clone(); + let inodes = state.inodes.clone(); + move |data: Vec| -> __wasi_fd_t { + let mut inodes = inodes.write().unwrap(); + let inode = state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + Kind::Buffer { buffer: data }, + false, + "bus".into(), + ); + let rights = super::state::bus_read_rights(); + wasi_try_bus!(state.fs.create_fd(rights, rights, 0, 0, inode) + .map_err(|err| { + debug!("failed to create file descriptor for BUS event buffer - {}", err); + __BUS_EALLOC + })) + } + }; + + // Grab all the events we can from all the existing calls up to the limit of + // maximum events that the user requested + if nevents < maxevents { + let mut drop_calls = Vec::new(); + let mut call_seed = guard.call_seed; + for (key, call) in guard.calls.iter_mut() { + let cid: __wasi_cid_t = (*key).into(); + + if nevents >= maxevents { + break; + } + + // If the process that is hosting the call is finished then so is the call + if exited_bids.contains(&call.bid) { + drop_calls.push(*key); + trace!("wasi::bus_poll (aborted, cid={})", cid); + let evt = unsafe { + std::mem::transmute(__wasi_busevent_t2 { + tag: __WASI_BUS_EVENT_TYPE_FAULT, + u: __wasi_busevent_u { + fault: __wasi_busevent_fault_t { + cid, + err: __BUS_EABORTED + } + } + }) + }; + + let nevents64: u64 = wasi_try_bus_ok!(nevents.try_into().map_err(|_| __BUS_EINTERNAL)); + wasi_try_mem_bus_ok!(events.write(nevents64, evt)); + + nevents += M::ONE; + continue; + } + + // Otherwise lets poll for events + while nevents < maxevents { + let mut finished = false; + let call = Pin::new(call.invocation.as_mut()); + match call.poll_event(&mut cx) { + Poll::Ready(evt) => + { + let evt = match evt { + BusInvocationEvent::Callback { topic_hash, format, data } => { + let sub_cid = { + call_seed += 1; + call_seed + }; + + trace!("wasi::bus_poll (callback, parent={}, cid={}, topic={})", cid, sub_cid, topic_hash); + __wasi_busevent_t2 { + tag: __WASI_BUS_EVENT_TYPE_CALL, + u: __wasi_busevent_u { + call: __wasi_busevent_call_t { + parent: __wasi_option_cid_t { + tag: __WASI_OPTION_SOME, + cid, + }, + cid: sub_cid, + format: conv_bus_format(format), + topic_hash, + fd: buf_to_fd(data), + } + } + } + }, + BusInvocationEvent::Response { format, data } => { + drop_calls.push(*key); + finished = true; + + trace!("wasi::bus_poll (response, cid={}, len={})", cid, data.len()); + __wasi_busevent_t2 { + tag: __WASI_BUS_EVENT_TYPE_RESULT, + u: __wasi_busevent_u { + result: __wasi_busevent_result_t { + format: conv_bus_format(format), + cid, + fd: buf_to_fd(data), + } + } + } + }, + BusInvocationEvent::Fault { fault } => { + drop_calls.push(*key); + finished = true; + + trace!("wasi::bus_poll (fault, cid={}, err={})", cid, fault); + __wasi_busevent_t2 { + tag: __WASI_BUS_EVENT_TYPE_FAULT, + u: __wasi_busevent_u { + fault: __wasi_busevent_fault_t { + cid, + err: bus_error_into_wasi_err(fault) + } + } + } + } + }; + let evt = unsafe { + std::mem::transmute(evt) + }; + + let nevents64: u64 = wasi_try_bus_ok!(nevents.try_into().map_err(|_| __BUS_EINTERNAL)); + wasi_try_mem_bus_ok!(events.write(nevents64, evt)); + + nevents += M::ONE; + + if finished { + break; + } + }, + Poll::Pending => { break; } + } + } + } + guard.call_seed = call_seed; + + // Drop any calls that are no longer in scope + if drop_calls.is_empty() == false { + for key in drop_calls { + guard.calls.remove(&key); + } + } + } + + if nevents < maxevents { + let mut call_seed = guard.call_seed; + let mut to_add = Vec::new(); + for (key, call) in guard.called.iter_mut() { + let cid: __wasi_cid_t = (*key).into(); + while nevents < maxevents { + let call = Pin::new(call.deref_mut()); + match call.poll(&mut cx) { + Poll::Ready(event) => { + // Register the call + let sub_cid = { + call_seed += 1; + to_add.push((call_seed, event.called)); + call_seed + }; + + let event = __wasi_busevent_t2 { + tag: __WASI_BUS_EVENT_TYPE_CALL, + u: __wasi_busevent_u { + call: __wasi_busevent_call_t { + parent: __wasi_option_cid_t { + tag: __WASI_OPTION_SOME, + cid, + }, + cid: sub_cid, + format: conv_bus_format(event.format), + topic_hash: event.topic_hash, + fd: buf_to_fd(event.data), + } + } + }; + let event = unsafe { + std::mem::transmute(event) + }; + + let nevents64: u64 = wasi_try_bus_ok!(nevents.try_into().map_err(|_| __BUS_EINTERNAL)); + wasi_try_mem_bus_ok!(events.write(nevents64, event)); + nevents += M::ONE; + }, + Poll::Pending => { break; } + }; + } + if nevents >= maxevents { + break; + } + } + + guard.call_seed = call_seed; + for (cid, called) in to_add { + guard.called.insert(cid, called); + } + } - __BUS_EUNSUPPORTED + while nevents < maxevents + { + // Check the listener (if none exists then one is created) + let event = { + let listener = wasi_try_bus_ok!(env.runtime + .bus() + .listen() + .map_err(bus_error_into_wasi_err)); + let listener = Pin::new(listener.deref()); + listener.poll(&mut cx) + }; + + // Process the event returned by the listener or exit the poll loop + let event = match event { + Poll::Ready(event) => { + + // Register the call + let sub_cid = { + guard.call_seed += 1; + let cid = guard.call_seed; + guard.called.insert(cid, event.called); + cid + }; + + __wasi_busevent_t2 { + tag: __WASI_BUS_EVENT_TYPE_CALL, + u: __wasi_busevent_u { + call: __wasi_busevent_call_t { + parent: __wasi_option_cid_t { + tag: __WASI_OPTION_NONE, + cid: 0, + }, + cid: sub_cid, + format: conv_bus_format(event.format), + topic_hash: event.topic_hash, + fd: buf_to_fd(event.data), + } + } + } + }, + Poll::Pending => { break; } + }; + let event = unsafe { + std::mem::transmute(event) + }; + + let nevents64: u64 = wasi_try_bus_ok!(nevents.try_into().map_err(|_| __BUS_EINTERNAL)); + wasi_try_mem_bus_ok!(events.write(nevents64, event)); + nevents += M::ONE; + } + } + + // If we still have no events + if nevents >= M::ONE { + break; + } + + // Determine the interval we will wake to check things like timeouts + // or the thread terminating + let now = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; + let delta = match now.checked_sub(start) { + Some(a) => Duration::from_nanos(a as u64), + None => Duration::ZERO, + }; + let interval = Duration::from_millis(5).min(delta); + + // Every 50 milliseconds we check if the thread needs to terminate (20 times a second) + // or for timeout, otherwise the reactor has to be woken + loop { + // Check for timeout (zero will mean the loop will not wait) + let now = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; + let delta = (now - start) as __wasi_timestamp_t; + if delta >= timeout { + trace!("wasi::bus_poll (timeout)"); + wasi_try_mem_bus_ok!(ret_nevents.write(&memory, nevents)); + return Ok(__BUS_ESUCCESS); + } + + env.yield_now()?; + state.bus.poll_wait(interval); + break; + } + } + if nevents > M::ZERO { + trace!("wasi::bus_poll (return nevents={})", nevents); + } else { + trace!("wasi::bus_poll (idle - no events)"); + } + + wasi_try_mem_bus_ok!(ret_nevents.write(&memory, nevents)); + Ok(__BUS_ESUCCESS) } /// Replies to a call that was made to this process @@ -4071,6 +5056,7 @@ pub fn call_reply( buf_len: M::Offset, ) -> __bus_errno_t { let env = ctx.data(); + let memory = env.memory_view(&ctx); let bus = env.runtime.bus(); trace!( "wasi::call_reply (cid={}, format={}, data_len={})", @@ -4078,8 +5064,19 @@ pub fn call_reply( format, buf_len ); + let buf_slice = wasi_try_mem_bus!(buf.slice(&memory, buf_len)); + let buf = wasi_try_mem_bus!(buf_slice.read_to_vec()); + + let mut guard = env.state.bus.protected(); + if let Some(call) = guard.called.remove(&cid) { + drop(guard); - __BUS_EUNSUPPORTED + let format = wasi_try_bus!(conv_bus_format_from(format)); + call.reply(format, buf); + __BUS_ESUCCESS + } else { + __BUS_EBADHANDLE + } } /// Causes a fault on a particular call that was made @@ -4093,13 +5090,19 @@ pub fn call_reply( pub fn call_fault( ctx: FunctionEnvMut<'_, WasiEnv>, cid: __wasi_cid_t, - fault: __bus_errno_t, -) -> __bus_errno_t { + fault: __bus_errno_t) +{ let env = ctx.data(); let bus = env.runtime.bus(); debug!("wasi::call_fault (cid={}, fault={})", cid, fault); - __BUS_EUNSUPPORTED + let mut guard = env.state.bus.protected(); + guard.calls.remove(&cid); + + if let Some(call) = guard.called.remove(&cid) { + drop(guard); + call.fault(wasi_error_into_bus_err(fault)); + } } /// Closes a bus call based on its bus call handle @@ -4107,12 +5110,17 @@ pub fn call_fault( /// ## Parameters /// /// * `cid` - Handle of the bus call handle to be dropped -pub fn call_close(ctx: FunctionEnvMut<'_, WasiEnv>, cid: __wasi_cid_t) -> __bus_errno_t { +pub fn call_close( + ctx: FunctionEnvMut<'_, WasiEnv>, + cid: __wasi_cid_t +) { let env = ctx.data(); let bus = env.runtime.bus(); trace!("wasi::call_close (cid={})", cid); - __BUS_EUNSUPPORTED + let mut guard = env.state.bus.protected(); + guard.calls.remove(&cid); + guard.called.remove(&cid); } /// ### `ws_connect()` @@ -4151,7 +5159,7 @@ pub fn ws_connect( inodes.deref_mut(), kind, false, - "socket".to_string(), + "socket".into(), ); let rights = super::state::all_socket_rights(); let fd = wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode)); @@ -4249,19 +5257,19 @@ pub fn http_request( inodes.deref_mut(), kind_req, false, - "http_request".to_string(), + "http_request".into(), ); let inode_res = state.fs.create_inode_with_default_stat( inodes.deref_mut(), kind_res, false, - "http_response".to_string(), + "http_response".into(), ); let inode_hdr = state.fs.create_inode_with_default_stat( inodes.deref_mut(), kind_hdr, false, - "http_headers".to_string(), + "http_headers".into(), ); let rights = super::state::all_socket_rights(); @@ -4571,7 +5579,8 @@ pub fn port_route_list( let max_routes: usize = wasi_try!(wasi_try_mem!(nroutes.read()) .try_into() .map_err(|_| __WASI_EINVAL)); - let ref_routes = wasi_try_mem!(routes.slice(&memory, wasi_try!(to_offset::(max_routes)))); + let ref_routes = + wasi_try_mem!(routes.slice(&memory, wasi_try!(to_offset::(max_routes)))); let routes = wasi_try!(env.net().route_list().map_err(net_error_into_wasi_err)); @@ -4768,7 +5777,7 @@ pub fn sock_open( inodes.deref_mut(), kind, false, - "socket".to_string(), + "socket".into(), ); let rights = super::state::all_socket_rights(); let fd = wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode)); @@ -5221,7 +6230,7 @@ pub fn sock_accept( inodes.deref_mut(), kind, false, - "socket".to_string(), + "socket".into(), ); let rights = super::state::all_socket_rights(); @@ -5251,12 +6260,10 @@ pub fn sock_accept( /// * `fd` - Socket descriptor /// * `addr` - Address of the socket to connect to pub fn sock_connect( - ctx: FunctionEnvMut<'_, WasiEnv>, + ctx: FunctionEnvMut, sock: __wasi_fd_t, addr: WasmPtr<__wasi_addr_port_t, M>, ) -> __wasi_errno_t { - debug!("wasi::sock_connect"); - let env = ctx.data(); let memory = env.memory_view(&ctx); let addr = wasi_try!(super::state::read_ip_port(&memory, addr)); @@ -5302,7 +6309,7 @@ pub fn sock_recv( &ctx, sock, __WASI_RIGHT_SOCK_RECV, - |socket| { socket.recv(&memory, iovs_arr) } + |socket| { socket.recv(& memory, iovs_arr) } )); let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| __WASI_EOVERFLOW)); @@ -5451,8 +6458,8 @@ pub fn sock_send_to( /// ## Return /// /// Number of bytes transmitted. -pub unsafe fn sock_send_file( - mut ctx: FunctionEnvMut<'_, WasiEnv>, +pub fn sock_send_file( + ctx: FunctionEnvMut<'_, WasiEnv>, sock: __wasi_fd_t, in_fd: __wasi_fd_t, offset: __wasi_filesize_t, @@ -5505,8 +6512,7 @@ pub unsafe fn sock_send_file( let bytes_read = { let mut guard = inode.write(); - let deref_mut = guard.deref_mut(); - match deref_mut { + match guard.deref_mut() { Kind::File { handle, .. } => { if let Some(handle) = handle { wasi_try_ok!( diff --git a/lib/wasi/src/syscalls/wasi.rs b/lib/wasi/src/syscalls/wasi.rs deleted file mode 100644 index b2575f6e53c..00000000000 --- a/lib/wasi/src/syscalls/wasi.rs +++ /dev/null @@ -1,450 +0,0 @@ -#![deny(dead_code)] -use crate::{WasiEnv, WasiError, WasiState, WasiThread}; -use wasmer::{StoreMut, Memory, Memory32, MemorySize, WasmPtr, WasmSlice}; -use wasmer_wasi_types::*; - -type MemoryType = Memory32; -type MemoryOffset = u32; - -pub(crate) fn args_get( - ctx: FunctionEnvMut, - argv: WasmPtr, MemoryType>, - argv_buf: WasmPtr, -) -> __wasi_errno_t { - super::args_get::(ctx, argv, argv_buf) -} - -pub(crate) fn args_sizes_get( - ctx: FunctionEnvMut, - argc: WasmPtr, - argv_buf_size: WasmPtr, -) -> __wasi_errno_t { - super::args_sizes_get::(ctx, argc, argv_buf_size) -} - -pub(crate) fn clock_res_get( - ctx: FunctionEnvMut, - clock_id: __wasi_clockid_t, - resolution: WasmPtr<__wasi_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::clock_res_get::(ctx, clock_id, resolution) -} - -pub(crate) fn clock_time_get( - ctx: FunctionEnvMut, - clock_id: __wasi_clockid_t, - precision: __wasi_timestamp_t, - time: WasmPtr<__wasi_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::clock_time_get::(ctx, clock_id, precision, time) -} - -pub(crate) fn environ_get( - ctx: FunctionEnvMut, - environ: WasmPtr, MemoryType>, - environ_buf: WasmPtr, -) -> __wasi_errno_t { - super::environ_get::(ctx, environ, environ_buf) -} - -pub(crate) fn environ_sizes_get( - ctx: FunctionEnvMut, - environ_count: WasmPtr, - environ_buf_size: WasmPtr, -) -> __wasi_errno_t { - super::environ_sizes_get::(ctx, environ_count, environ_buf_size) -} - -pub(crate) fn fd_advise( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filesize_t, - len: __wasi_filesize_t, - advice: __wasi_advice_t, -) -> __wasi_errno_t { - super::fd_advise(ctx, fd, offset, len, advice) -} - -pub(crate) fn fd_allocate( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filesize_t, - len: __wasi_filesize_t, -) -> __wasi_errno_t { - super::fd_allocate(ctx, fd, offset, len) -} - -pub(crate) fn fd_close(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_close(ctx, fd) -} - -pub(crate) fn fd_datasync(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_datasync(ctx, fd) -} - -pub(crate) fn fd_fdstat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf_ptr: WasmPtr<__wasi_fdstat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_fdstat_get::(ctx, fd, buf_ptr) -} - -pub(crate) fn fd_fdstat_set_flags( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_fdflags_t, -) -> __wasi_errno_t { - super::fd_fdstat_set_flags(ctx, fd, flags) -} - -pub(crate) fn fd_fdstat_set_rights( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - fs_rights_base: __wasi_rights_t, - fs_rights_inheriting: __wasi_rights_t, -) -> __wasi_errno_t { - super::fd_fdstat_set_rights(ctx, fd, fs_rights_base, fs_rights_inheriting) -} - -pub(crate) fn fd_filestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr<__wasi_filestat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_filestat_get::(ctx, fd, buf) -} - -pub(crate) fn fd_filestat_set_size( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - st_size: __wasi_filesize_t, -) -> __wasi_errno_t { - super::fd_filestat_set_size(ctx, fd, st_size) -} - -pub(crate) fn fd_filestat_set_times( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - st_atim: __wasi_timestamp_t, - st_mtim: __wasi_timestamp_t, - fst_flags: __wasi_fstflags_t, -) -> __wasi_errno_t { - super::fd_filestat_set_times(ctx, fd, st_atim, st_mtim, fst_flags) -} - -pub(crate) fn fd_pread( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_iovec_t, MemoryType>, - iovs_len: MemoryOffset, - offset: __wasi_filesize_t, - nread: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_pread::(ctx, fd, iovs, iovs_len, offset, nread) -} - -pub(crate) fn fd_prestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr<__wasi_prestat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_prestat_get::(ctx, fd, buf) -} - -pub(crate) fn fd_prestat_dir_name( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::fd_prestat_dir_name::(ctx, fd, path, path_len) -} - -pub(crate) fn fd_pwrite( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, - iovs_len: MemoryOffset, - offset: __wasi_filesize_t, - nwritten: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_pwrite::(ctx, fd, iovs, iovs_len, offset, nwritten) -} - -pub(crate) fn fd_read( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_iovec_t, MemoryType>, - iovs_len: MemoryOffset, - nread: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_read::(ctx, fd, iovs, iovs_len, nread) -} - -pub(crate) fn fd_readdir( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr, - buf_len: MemoryOffset, - cookie: __wasi_dircookie_t, - bufused: WasmPtr, -) -> __wasi_errno_t { - super::fd_readdir::(ctx, fd, buf, buf_len, cookie, bufused) -} - -pub(crate) fn fd_renumber( - ctx: FunctionEnvMut, - from: __wasi_fd_t, - to: __wasi_fd_t, -) -> __wasi_errno_t { - super::fd_renumber(ctx, from, to) -} - -pub(crate) fn fd_seek( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filedelta_t, - whence: __wasi_whence_t, - newoffset: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_seek::(ctx, fd, offset, whence, newoffset) -} - -pub(crate) fn fd_sync(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_sync(ctx, fd) -} - -pub(crate) fn fd_tell( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_tell::(ctx, fd, offset) -} - -pub(crate) fn fd_write( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, - iovs_len: MemoryOffset, - nwritten: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_write::(ctx, fd, iovs, iovs_len, nwritten) -} - -pub(crate) fn path_create_directory( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_create_directory::(ctx, fd, path, path_len) -} - -pub(crate) fn path_filestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - buf: WasmPtr<__wasi_filestat_t, MemoryType>, -) -> __wasi_errno_t { - super::path_filestat_get::(ctx, fd, flags, path, path_len, buf) -} - -pub(crate) fn path_filestat_set_times( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - st_atim: __wasi_timestamp_t, - st_mtim: __wasi_timestamp_t, - fst_flags: __wasi_fstflags_t, -) -> __wasi_errno_t { - super::path_filestat_set_times::( - ctx, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, - ) -} - -pub(crate) fn path_link( - ctx: FunctionEnvMut, - old_fd: __wasi_fd_t, - old_flags: __wasi_lookupflags_t, - old_path: WasmPtr, - old_path_len: MemoryOffset, - new_fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_link::( - ctx, - old_fd, - old_flags, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len, - ) -} - -pub(crate) fn path_open( - ctx: FunctionEnvMut, - dirfd: __wasi_fd_t, - dirflags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - o_flags: __wasi_oflags_t, - fs_rights_base: __wasi_rights_t, - fs_rights_inheriting: __wasi_rights_t, - fs_flags: __wasi_fdflags_t, - fd: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::path_open::( - ctx, - dirfd, - dirflags, - path, - path_len, - o_flags, - fs_rights_base, - fs_rights_inheriting, - fs_flags, - fd, - ) -} - -pub(crate) fn path_readlink( - ctx: FunctionEnvMut, - dir_fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, - buf: WasmPtr, - buf_len: MemoryOffset, - buf_used: WasmPtr, -) -> __wasi_errno_t { - super::path_readlink::(ctx, dir_fd, path, path_len, buf, buf_len, buf_used) -} - -pub(crate) fn path_remove_directory( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_remove_directory::(ctx, fd, path, path_len) -} - -pub(crate) fn path_rename( - ctx: FunctionEnvMut, - old_fd: __wasi_fd_t, - old_path: WasmPtr, - old_path_len: MemoryOffset, - new_fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_rename::( - ctx, - old_fd, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len, - ) -} - -pub(crate) fn path_symlink( - ctx: FunctionEnvMut, - old_path: WasmPtr, - old_path_len: MemoryOffset, - fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_symlink::(ctx, old_path, old_path_len, fd, new_path, new_path_len) -} - -pub(crate) fn path_unlink_file( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_unlink_file::(ctx, fd, path, path_len) -} - -pub(crate) fn poll_oneoff( - ctx: FunctionEnvMut, - in_: WasmPtr<__wasi_subscription_t, MemoryType>, - out_: WasmPtr<__wasi_event_t, MemoryType>, - nsubscriptions: MemoryOffset, - nevents: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::poll_oneoff::(ctx, in_, out_, nsubscriptions, nevents) -} - -pub(crate) fn proc_exit( - ctx: FunctionEnvMut, - code: __wasi_exitcode_t, -) -> Result<(), WasiError> { - super::proc_exit(ctx, code) -} - -pub(crate) fn proc_raise(ctx: FunctionEnvMut, sig: __wasi_signal_t) -> __wasi_errno_t { - super::proc_raise(ctx, sig) -} - -pub(crate) fn random_get( - ctx: FunctionEnvMut, - buf: WasmPtr, - buf_len: MemoryOffset, -) -> __wasi_errno_t { - super::random_get::(ctx, buf, buf_len) -} - -pub(crate) fn sched_yield(ctx: FunctionEnvMut) -> Result<__wasi_errno_t, WasiError> { - super::sched_yield(ctx) -} - -pub(crate) fn sock_recv( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, - ri_data_len: MemoryOffset, - ri_flags: __wasi_riflags_t, - ro_data_len: WasmPtr, - ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv::( - ctx, - sock, - ri_data, - ri_data_len, - ri_flags, - ro_data_len, - ro_flags, - ) -} - -pub(crate) fn sock_send( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, - si_data_len: MemoryOffset, - si_flags: __wasi_siflags_t, - ret_data_len: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_send::(ctx, sock, si_data, si_data_len, si_flags, ret_data_len) -} - -pub(crate) fn sock_shutdown( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - how: __wasi_sdflags_t, -) -> __wasi_errno_t { - super::sock_shutdown(ctx, sock, how) -} diff --git a/lib/wasi/src/syscalls/wasix32.rs b/lib/wasi/src/syscalls/wasix32.rs deleted file mode 100644 index 5cb6899c3ef..00000000000 --- a/lib/wasi/src/syscalls/wasix32.rs +++ /dev/null @@ -1,1060 +0,0 @@ -#![deny(dead_code)] -use crate::{WasiEnv, WasiError, WasiState, WasiThread}; -use wasmer::{FunctionEnvMut, Memory, Memory32, MemorySize, StoreMut, WasmPtr, WasmSlice}; -use wasmer_wasi_types::*; - -type MemoryType = Memory32; -type MemoryOffset = u32; - -pub(crate) fn args_get( - ctx: FunctionEnvMut, - argv: WasmPtr, MemoryType>, - argv_buf: WasmPtr, -) -> __wasi_errno_t { - super::args_get::(ctx, argv, argv_buf) -} - -pub(crate) fn args_sizes_get( - ctx: FunctionEnvMut, - argc: WasmPtr, - argv_buf_size: WasmPtr, -) -> __wasi_errno_t { - super::args_sizes_get::(ctx, argc, argv_buf_size) -} - -pub(crate) fn clock_res_get( - ctx: FunctionEnvMut, - clock_id: __wasi_clockid_t, - resolution: WasmPtr<__wasi_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::clock_res_get::(ctx, clock_id, resolution) -} - -pub(crate) fn clock_time_get( - ctx: FunctionEnvMut, - clock_id: __wasi_clockid_t, - precision: __wasi_timestamp_t, - time: WasmPtr<__wasi_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::clock_time_get::(ctx, clock_id, precision, time) -} - -pub(crate) fn environ_get( - ctx: FunctionEnvMut, - environ: WasmPtr, MemoryType>, - environ_buf: WasmPtr, -) -> __wasi_errno_t { - super::environ_get::(ctx, environ, environ_buf) -} - -pub(crate) fn environ_sizes_get( - ctx: FunctionEnvMut, - environ_count: WasmPtr, - environ_buf_size: WasmPtr, -) -> __wasi_errno_t { - super::environ_sizes_get::(ctx, environ_count, environ_buf_size) -} - -pub(crate) fn fd_advise( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filesize_t, - len: __wasi_filesize_t, - advice: __wasi_advice_t, -) -> __wasi_errno_t { - super::fd_advise(ctx, fd, offset, len, advice) -} - -pub(crate) fn fd_allocate( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filesize_t, - len: __wasi_filesize_t, -) -> __wasi_errno_t { - super::fd_allocate(ctx, fd, offset, len) -} - -pub(crate) fn fd_close(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_close(ctx, fd) -} - -pub(crate) fn fd_datasync(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_datasync(ctx, fd) -} - -pub(crate) fn fd_fdstat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf_ptr: WasmPtr<__wasi_fdstat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_fdstat_get::(ctx, fd, buf_ptr) -} - -pub(crate) fn fd_fdstat_set_flags( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_fdflags_t, -) -> __wasi_errno_t { - super::fd_fdstat_set_flags(ctx, fd, flags) -} - -pub(crate) fn fd_fdstat_set_rights( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - fs_rights_base: __wasi_rights_t, - fs_rights_inheriting: __wasi_rights_t, -) -> __wasi_errno_t { - super::fd_fdstat_set_rights(ctx, fd, fs_rights_base, fs_rights_inheriting) -} - -pub(crate) fn fd_filestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr<__wasi_filestat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_filestat_get::(ctx, fd, buf) -} - -pub(crate) fn fd_filestat_set_size( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - st_size: __wasi_filesize_t, -) -> __wasi_errno_t { - super::fd_filestat_set_size(ctx, fd, st_size) -} - -pub(crate) fn fd_filestat_set_times( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - st_atim: __wasi_timestamp_t, - st_mtim: __wasi_timestamp_t, - fst_flags: __wasi_fstflags_t, -) -> __wasi_errno_t { - super::fd_filestat_set_times(ctx, fd, st_atim, st_mtim, fst_flags) -} - -pub(crate) fn fd_pread( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_iovec_t, MemoryType>, - iovs_len: MemoryOffset, - offset: __wasi_filesize_t, - nread: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_pread::(ctx, fd, iovs, iovs_len, offset, nread) -} - -pub(crate) fn fd_prestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr<__wasi_prestat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_prestat_get::(ctx, fd, buf) -} - -pub(crate) fn fd_prestat_dir_name( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::fd_prestat_dir_name::(ctx, fd, path, path_len) -} - -pub(crate) fn fd_pwrite( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, - iovs_len: MemoryOffset, - offset: __wasi_filesize_t, - nwritten: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_pwrite::(ctx, fd, iovs, iovs_len, offset, nwritten) -} - -pub(crate) fn fd_read( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_iovec_t, MemoryType>, - iovs_len: MemoryOffset, - nread: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_read::(ctx, fd, iovs, iovs_len, nread) -} - -pub(crate) fn fd_readdir( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr, - buf_len: MemoryOffset, - cookie: __wasi_dircookie_t, - bufused: WasmPtr, -) -> __wasi_errno_t { - super::fd_readdir::(ctx, fd, buf, buf_len, cookie, bufused) -} - -pub(crate) fn fd_renumber( - ctx: FunctionEnvMut, - from: __wasi_fd_t, - to: __wasi_fd_t, -) -> __wasi_errno_t { - super::fd_renumber(ctx, from, to) -} - -pub(crate) fn fd_seek( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filedelta_t, - whence: __wasi_whence_t, - newoffset: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_seek::(ctx, fd, offset, whence, newoffset) -} - -pub(crate) fn fd_sync(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_sync(ctx, fd) -} - -pub(crate) fn fd_tell( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_tell::(ctx, fd, offset) -} - -pub(crate) fn fd_write( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, - iovs_len: MemoryOffset, - nwritten: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_write::(ctx, fd, iovs, iovs_len, nwritten) -} - -pub(crate) fn path_create_directory( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_create_directory::(ctx, fd, path, path_len) -} - -pub(crate) fn path_filestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - buf: WasmPtr<__wasi_filestat_t, MemoryType>, -) -> __wasi_errno_t { - super::path_filestat_get::(ctx, fd, flags, path, path_len, buf) -} - -pub(crate) fn path_filestat_set_times( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - st_atim: __wasi_timestamp_t, - st_mtim: __wasi_timestamp_t, - fst_flags: __wasi_fstflags_t, -) -> __wasi_errno_t { - super::path_filestat_set_times::( - ctx, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, - ) -} - -pub(crate) fn path_link( - ctx: FunctionEnvMut, - old_fd: __wasi_fd_t, - old_flags: __wasi_lookupflags_t, - old_path: WasmPtr, - old_path_len: MemoryOffset, - new_fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_link::( - ctx, - old_fd, - old_flags, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len, - ) -} - -pub(crate) fn path_open( - ctx: FunctionEnvMut, - dirfd: __wasi_fd_t, - dirflags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - o_flags: __wasi_oflags_t, - fs_rights_base: __wasi_rights_t, - fs_rights_inheriting: __wasi_rights_t, - fs_flags: __wasi_fdflags_t, - fd: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::path_open::( - ctx, - dirfd, - dirflags, - path, - path_len, - o_flags, - fs_rights_base, - fs_rights_inheriting, - fs_flags, - fd, - ) -} - -pub(crate) fn path_readlink( - ctx: FunctionEnvMut, - dir_fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, - buf: WasmPtr, - buf_len: MemoryOffset, - buf_used: WasmPtr, -) -> __wasi_errno_t { - super::path_readlink::(ctx, dir_fd, path, path_len, buf, buf_len, buf_used) -} - -pub(crate) fn path_remove_directory( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_remove_directory::(ctx, fd, path, path_len) -} - -pub(crate) fn path_rename( - ctx: FunctionEnvMut, - old_fd: __wasi_fd_t, - old_path: WasmPtr, - old_path_len: MemoryOffset, - new_fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_rename::( - ctx, - old_fd, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len, - ) -} - -pub(crate) fn path_symlink( - ctx: FunctionEnvMut, - old_path: WasmPtr, - old_path_len: MemoryOffset, - fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_symlink::(ctx, old_path, old_path_len, fd, new_path, new_path_len) -} - -pub(crate) fn path_unlink_file( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_unlink_file::(ctx, fd, path, path_len) -} - -pub(crate) fn poll_oneoff( - ctx: FunctionEnvMut, - in_: WasmPtr<__wasi_subscription_t, MemoryType>, - out_: WasmPtr<__wasi_event_t, MemoryType>, - nsubscriptions: MemoryOffset, - nevents: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::poll_oneoff::(ctx, in_, out_, nsubscriptions, nevents) -} - -pub(crate) fn proc_exit( - ctx: FunctionEnvMut, - code: __wasi_exitcode_t, -) -> Result<(), WasiError> { - super::proc_exit(ctx, code) -} - -pub(crate) fn proc_raise(ctx: FunctionEnvMut, sig: __wasi_signal_t) -> __wasi_errno_t { - super::proc_raise(ctx, sig) -} - -pub(crate) fn random_get( - ctx: FunctionEnvMut, - buf: WasmPtr, - buf_len: MemoryOffset, -) -> __wasi_errno_t { - super::random_get::(ctx, buf, buf_len) -} - -pub(crate) fn fd_dup( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_dup::(ctx, fd, ret_fd) -} - -pub(crate) fn fd_event( - ctx: FunctionEnvMut, - initial_val: u64, - flags: __wasi_eventfdflags, - ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_event(ctx, initial_val, flags, ret_fd) -} - -pub(crate) fn fd_pipe( - ctx: FunctionEnvMut, - ro_fd1: WasmPtr<__wasi_fd_t, MemoryType>, - ro_fd2: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_pipe::(ctx, ro_fd1, ro_fd2) -} - -pub(crate) fn tty_get( - ctx: FunctionEnvMut, - tty_state: WasmPtr<__wasi_tty_t, MemoryType>, -) -> __wasi_errno_t { - super::tty_get::(ctx, tty_state) -} - -pub(crate) fn tty_set( - ctx: FunctionEnvMut, - tty_state: WasmPtr<__wasi_tty_t, MemoryType>, -) -> __wasi_errno_t { - super::tty_set::(ctx, tty_state) -} - -pub(crate) fn getcwd( - ctx: FunctionEnvMut, - path: WasmPtr, - path_len: WasmPtr, -) -> __wasi_errno_t { - super::getcwd::(ctx, path, path_len) -} - -pub(crate) fn chdir( - ctx: FunctionEnvMut, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::chdir::(ctx, path, path_len) -} - -pub(crate) fn thread_spawn( - ctx: FunctionEnvMut, - method: WasmPtr, - method_len: MemoryOffset, - user_data: u64, - reactor: __wasi_bool_t, - ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, -) -> __wasi_errno_t { - super::thread_spawn::(ctx, method, method_len, user_data, reactor, ret_tid) -} - -pub(crate) fn thread_sleep( - ctx: FunctionEnvMut, - duration: __wasi_timestamp_t, -) -> Result<__wasi_errno_t, WasiError> { - super::thread_sleep(ctx, duration) -} - -pub(crate) fn thread_id( - ctx: FunctionEnvMut, - ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, -) -> __wasi_errno_t { - super::thread_id::(ctx, ret_tid) -} - -pub(crate) fn thread_join( - ctx: FunctionEnvMut, - tid: __wasi_tid_t, -) -> Result<__wasi_errno_t, WasiError> { - super::thread_join(ctx, tid) -} - -pub(crate) fn thread_parallelism( - ctx: FunctionEnvMut, - ret_parallelism: WasmPtr, -) -> __wasi_errno_t { - super::thread_parallelism::(ctx, ret_parallelism) -} - -pub(crate) fn thread_exit( - ctx: FunctionEnvMut, - exitcode: __wasi_exitcode_t, -) -> Result<__wasi_errno_t, WasiError> { - super::thread_exit(ctx, exitcode) -} - -pub(crate) fn sched_yield(ctx: FunctionEnvMut) -> Result<__wasi_errno_t, WasiError> { - super::sched_yield(ctx) -} - -pub(crate) fn getpid( - ctx: FunctionEnvMut, - ret_pid: WasmPtr<__wasi_pid_t, MemoryType>, -) -> __wasi_errno_t { - super::getpid::(ctx, ret_pid) -} - -pub(crate) fn process_spawn( - ctx: FunctionEnvMut, - name: WasmPtr, - name_len: MemoryOffset, - chroot: __wasi_bool_t, - args: WasmPtr, - args_len: MemoryOffset, - preopen: WasmPtr, - preopen_len: MemoryOffset, - stdin: __wasi_stdiomode_t, - stdout: __wasi_stdiomode_t, - stderr: __wasi_stdiomode_t, - working_dir: WasmPtr, - working_dir_len: MemoryOffset, - ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, -) -> __bus_errno_t { - super::process_spawn::( - ctx, - name, - name_len, - chroot, - args, - args_len, - preopen, - preopen_len, - stdin, - stdout, - stderr, - working_dir, - working_dir_len, - ret_handles, - ) -} - -pub(crate) fn bus_open_local( - ctx: FunctionEnvMut, - name: WasmPtr, - name_len: MemoryOffset, - reuse: __wasi_bool_t, - ret_bid: WasmPtr<__wasi_bid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_open_local::(ctx, name, name_len, reuse, ret_bid) -} - -pub(crate) fn bus_open_remote( - ctx: FunctionEnvMut, - name: WasmPtr, - name_len: MemoryOffset, - reuse: __wasi_bool_t, - instance: WasmPtr, - instance_len: MemoryOffset, - token: WasmPtr, - token_len: MemoryOffset, - ret_bid: WasmPtr<__wasi_bid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_open_remote::( - ctx, - name, - name_len, - reuse, - instance, - instance_len, - token, - token_len, - ret_bid, - ) -} - -pub(crate) fn bus_close(ctx: FunctionEnvMut, bid: __wasi_bid_t) -> __bus_errno_t { - super::bus_close(ctx, bid) -} - -pub(crate) fn bus_call( - ctx: FunctionEnvMut, - bid: __wasi_bid_t, - keep_alive: __wasi_bool_t, - topic: WasmPtr, - topic_len: MemoryOffset, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: MemoryOffset, - ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_call::( - ctx, bid, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, - ) -} - -pub(crate) fn bus_subcall( - ctx: FunctionEnvMut, - parent: __wasi_cid_t, - keep_alive: __wasi_bool_t, - topic: WasmPtr, - topic_len: MemoryOffset, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: MemoryOffset, - ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_subcall::( - ctx, parent, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, - ) -} - -pub(crate) fn bus_poll( - ctx: FunctionEnvMut, - timeout: __wasi_timestamp_t, - events: WasmPtr, - nevents: MemoryOffset, - malloc: WasmPtr, - malloc_len: MemoryOffset, - ret_nevents: WasmPtr, -) -> __bus_errno_t { - super::bus_poll::( - ctx, - timeout, - events, - nevents, - malloc, - malloc_len, - ret_nevents, - ) -} - -pub(crate) fn call_reply( - ctx: FunctionEnvMut, - cid: __wasi_cid_t, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: MemoryOffset, -) -> __bus_errno_t { - super::call_reply::(ctx, cid, format, buf, buf_len) -} - -pub(crate) fn call_fault( - ctx: FunctionEnvMut, - cid: __wasi_cid_t, - fault: __bus_errno_t, -) -> __bus_errno_t { - super::call_fault(ctx, cid, fault) -} - -pub(crate) fn call_close(ctx: FunctionEnvMut, cid: __wasi_cid_t) -> __bus_errno_t { - super::call_close(ctx, cid) -} - -pub(crate) fn port_bridge( - ctx: FunctionEnvMut, - network: WasmPtr, - network_len: MemoryOffset, - token: WasmPtr, - token_len: MemoryOffset, - security: __wasi_streamsecurity_t, -) -> __wasi_errno_t { - super::port_bridge::(ctx, network, network_len, token, token_len, security) -} - -pub(crate) fn port_unbridge(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_unbridge(ctx) -} - -pub(crate) fn port_dhcp_acquire(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_dhcp_acquire(ctx) -} - -pub(crate) fn port_addr_add( - ctx: FunctionEnvMut, - addr: WasmPtr<__wasi_cidr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_addr_add::(ctx, addr) -} - -pub(crate) fn port_addr_remove( - ctx: FunctionEnvMut, - addr: WasmPtr<__wasi_addr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_addr_remove::(ctx, addr) -} - -pub(crate) fn port_addr_clear(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_addr_clear(ctx) -} - -pub(crate) fn port_addr_list( - ctx: FunctionEnvMut, - addrs: WasmPtr<__wasi_cidr_t, MemoryType>, - naddrs: WasmPtr, -) -> __wasi_errno_t { - super::port_addr_list::(ctx, addrs, naddrs) -} - -pub(crate) fn port_mac( - ctx: FunctionEnvMut, - ret_mac: WasmPtr<__wasi_hardwareaddress_t, MemoryType>, -) -> __wasi_errno_t { - super::port_mac::(ctx, ret_mac) -} - -pub(crate) fn port_gateway_set( - ctx: FunctionEnvMut, - ip: WasmPtr<__wasi_addr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_gateway_set::(ctx, ip) -} - -pub(crate) fn port_route_add( - ctx: FunctionEnvMut, - cidr: WasmPtr<__wasi_cidr_t, MemoryType>, - via_router: WasmPtr<__wasi_addr_t, MemoryType>, - preferred_until: WasmPtr<__wasi_option_timestamp_t, MemoryType>, - expires_at: WasmPtr<__wasi_option_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::port_route_add::(ctx, cidr, via_router, preferred_until, expires_at) -} - -pub(crate) fn port_route_remove( - ctx: FunctionEnvMut, - ip: WasmPtr<__wasi_addr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_route_remove::(ctx, ip) -} - -pub(crate) fn port_route_clear(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_route_clear(ctx) -} - -pub(crate) fn port_route_list( - ctx: FunctionEnvMut, - routes: WasmPtr<__wasi_route_t, MemoryType>, - nroutes: WasmPtr, -) -> __wasi_errno_t { - super::port_route_list::(ctx, routes, nroutes) -} - -pub(crate) fn ws_connect( - ctx: FunctionEnvMut, - url: WasmPtr, - url_len: MemoryOffset, - ret_sock: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::ws_connect::(ctx, url, url_len, ret_sock) -} - -pub(crate) fn http_request( - ctx: FunctionEnvMut, - url: WasmPtr, - url_len: MemoryOffset, - method: WasmPtr, - method_len: MemoryOffset, - headers: WasmPtr, - headers_len: MemoryOffset, - gzip: __wasi_bool_t, - ret_handles: WasmPtr<__wasi_http_handles_t, MemoryType>, -) -> __wasi_errno_t { - super::http_request::( - ctx, - url, - url_len, - method, - method_len, - headers, - headers_len, - gzip, - ret_handles, - ) -} - -pub(crate) fn http_status( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - status: WasmPtr<__wasi_http_status_t, MemoryType>, - status_text: WasmPtr, - status_text_len: WasmPtr, - headers: WasmPtr, - headers_len: WasmPtr, -) -> __wasi_errno_t { - super::http_status::(ctx, sock, status) -} - -pub(crate) fn sock_status( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ret_status: WasmPtr<__wasi_sockstatus_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_status::(ctx, sock, ret_status) -} - -pub(crate) fn sock_addr_local( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ret_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_addr_local::(ctx, sock, ret_addr) -} - -pub(crate) fn sock_addr_peer( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_addr_peer::(ctx, sock, ro_addr) -} - -pub(crate) fn sock_open( - ctx: FunctionEnvMut, - af: __wasi_addressfamily_t, - ty: __wasi_socktype_t, - pt: __wasi_sockproto_t, - ro_sock: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_open::(ctx, af, ty, pt, ro_sock) -} - -pub(crate) fn sock_set_opt_flag( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - flag: __wasi_bool_t, -) -> __wasi_errno_t { - super::sock_set_opt_flag(ctx, sock, opt, flag) -} - -pub(crate) fn sock_get_opt_flag( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - ret_flag: WasmPtr<__wasi_bool_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_get_opt_flag::(ctx, sock, opt, ret_flag) -} - -pub fn sock_set_opt_time( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_set_opt_time(ctx, sock, opt, time) -} - -pub fn sock_get_opt_time( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - ret_time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_get_opt_time(ctx, sock, opt, ret_time) -} - -pub fn sock_set_opt_size( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - size: __wasi_filesize_t, -) -> __wasi_errno_t { - super::sock_set_opt_size(ctx, sock, opt, size) -} - -pub fn sock_get_opt_size( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - ret_size: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_get_opt_size(ctx, sock, opt, ret_size) -} - -pub(crate) fn sock_join_multicast_v4( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, - iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_join_multicast_v4::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_leave_multicast_v4( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, - iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_leave_multicast_v4::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_join_multicast_v6( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, - iface: u32, -) -> __wasi_errno_t { - super::sock_join_multicast_v6::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_leave_multicast_v6( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, - iface: u32, -) -> __wasi_errno_t { - super::sock_leave_multicast_v6::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_bind( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_bind::(ctx, sock, addr) -} - -pub(crate) fn sock_listen( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - backlog: MemoryOffset, -) -> __wasi_errno_t { - super::sock_listen::(ctx, sock, backlog) -} - -pub(crate) fn sock_accept( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - fd_flags: __wasi_fdflags_t, - ro_fd: WasmPtr<__wasi_fd_t, MemoryType>, - ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_accept::(ctx, sock, fd_flags, ro_fd, ro_addr) -} - -pub(crate) fn sock_connect( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_connect::(ctx, sock, addr) -} - -pub(crate) fn sock_recv( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, - ri_data_len: MemoryOffset, - ri_flags: __wasi_riflags_t, - ro_data_len: WasmPtr, - ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv::( - ctx, - sock, - ri_data, - ri_data_len, - ri_flags, - ro_data_len, - ro_flags, - ) -} - -pub(crate) fn sock_recv_from( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, - ri_data_len: MemoryOffset, - ri_flags: __wasi_riflags_t, - ro_data_len: WasmPtr, - ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, - ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv_from::( - ctx, - sock, - ri_data, - ri_data_len, - ri_flags, - ro_data_len, - ro_flags, - ro_addr, - ) -} - -pub(crate) fn sock_send( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, - si_data_len: MemoryOffset, - si_flags: __wasi_siflags_t, - ret_data_len: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_send::(ctx, sock, si_data, si_data_len, si_flags, ret_data_len) -} - -pub(crate) fn sock_send_to( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, - si_data_len: MemoryOffset, - si_flags: __wasi_siflags_t, - addr: WasmPtr<__wasi_addr_port_t, MemoryType>, - ret_data_len: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_send_to::( - ctx, - sock, - si_data, - si_data_len, - si_flags, - addr, - ret_data_len, - ) -} - -pub(crate) fn sock_send_file( - ctx: FunctionEnvMut, - out_fd: __wasi_fd_t, - in_fd: __wasi_fd_t, - offset: __wasi_filesize_t, - count: __wasi_filesize_t, - ret_sent: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - unsafe { super::sock_send_file::(ctx, out_fd, in_fd, offset, count, ret_sent) } -} - -pub(crate) fn sock_shutdown( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - how: __wasi_sdflags_t, -) -> __wasi_errno_t { - super::sock_shutdown(ctx, sock, how) -} - -pub(crate) fn resolve( - ctx: FunctionEnvMut, - host: WasmPtr, - host_len: MemoryOffset, - port: u16, - ips: WasmPtr<__wasi_addr_t, MemoryType>, - nips: MemoryOffset, - ret_nips: WasmPtr, -) -> __wasi_errno_t { - super::resolve::(ctx, host, host_len, port, ips, nips, ret_nips) -} diff --git a/lib/wasi/src/syscalls/wasix64.rs b/lib/wasi/src/syscalls/wasix64.rs deleted file mode 100644 index b42307e0da8..00000000000 --- a/lib/wasi/src/syscalls/wasix64.rs +++ /dev/null @@ -1,1060 +0,0 @@ -#![deny(dead_code)] -use crate::{WasiEnv, WasiError, WasiState, WasiThread}; -use wasmer::{FunctionEnvMut, Memory, Memory64, MemorySize, StoreMut, WasmPtr, WasmSlice}; -use wasmer_wasi_types::*; - -type MemoryType = Memory64; -type MemoryOffset = u64; - -pub(crate) fn args_get( - ctx: FunctionEnvMut, - argv: WasmPtr, MemoryType>, - argv_buf: WasmPtr, -) -> __wasi_errno_t { - super::args_get::(ctx, argv, argv_buf) -} - -pub(crate) fn args_sizes_get( - ctx: FunctionEnvMut, - argc: WasmPtr, - argv_buf_size: WasmPtr, -) -> __wasi_errno_t { - super::args_sizes_get::(ctx, argc, argv_buf_size) -} - -pub(crate) fn clock_res_get( - ctx: FunctionEnvMut, - clock_id: __wasi_clockid_t, - resolution: WasmPtr<__wasi_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::clock_res_get::(ctx, clock_id, resolution) -} - -pub(crate) fn clock_time_get( - ctx: FunctionEnvMut, - clock_id: __wasi_clockid_t, - precision: __wasi_timestamp_t, - time: WasmPtr<__wasi_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::clock_time_get::(ctx, clock_id, precision, time) -} - -pub(crate) fn environ_get( - ctx: FunctionEnvMut, - environ: WasmPtr, MemoryType>, - environ_buf: WasmPtr, -) -> __wasi_errno_t { - super::environ_get::(ctx, environ, environ_buf) -} - -pub(crate) fn environ_sizes_get( - ctx: FunctionEnvMut, - environ_count: WasmPtr, - environ_buf_size: WasmPtr, -) -> __wasi_errno_t { - super::environ_sizes_get::(ctx, environ_count, environ_buf_size) -} - -pub(crate) fn fd_advise( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filesize_t, - len: __wasi_filesize_t, - advice: __wasi_advice_t, -) -> __wasi_errno_t { - super::fd_advise(ctx, fd, offset, len, advice) -} - -pub(crate) fn fd_allocate( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filesize_t, - len: __wasi_filesize_t, -) -> __wasi_errno_t { - super::fd_allocate(ctx, fd, offset, len) -} - -pub(crate) fn fd_close(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_close(ctx, fd) -} - -pub(crate) fn fd_datasync(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_datasync(ctx, fd) -} - -pub(crate) fn fd_fdstat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf_ptr: WasmPtr<__wasi_fdstat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_fdstat_get::(ctx, fd, buf_ptr) -} - -pub(crate) fn fd_fdstat_set_flags( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_fdflags_t, -) -> __wasi_errno_t { - super::fd_fdstat_set_flags(ctx, fd, flags) -} - -pub(crate) fn fd_fdstat_set_rights( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - fs_rights_base: __wasi_rights_t, - fs_rights_inheriting: __wasi_rights_t, -) -> __wasi_errno_t { - super::fd_fdstat_set_rights(ctx, fd, fs_rights_base, fs_rights_inheriting) -} - -pub(crate) fn fd_filestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr<__wasi_filestat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_filestat_get::(ctx, fd, buf) -} - -pub(crate) fn fd_filestat_set_size( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - st_size: __wasi_filesize_t, -) -> __wasi_errno_t { - super::fd_filestat_set_size(ctx, fd, st_size) -} - -pub(crate) fn fd_filestat_set_times( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - st_atim: __wasi_timestamp_t, - st_mtim: __wasi_timestamp_t, - fst_flags: __wasi_fstflags_t, -) -> __wasi_errno_t { - super::fd_filestat_set_times(ctx, fd, st_atim, st_mtim, fst_flags) -} - -pub(crate) fn fd_pread( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_iovec_t, MemoryType>, - iovs_len: MemoryOffset, - offset: __wasi_filesize_t, - nread: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_pread::(ctx, fd, iovs, iovs_len, offset, nread) -} - -pub(crate) fn fd_prestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr<__wasi_prestat_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_prestat_get::(ctx, fd, buf) -} - -pub(crate) fn fd_prestat_dir_name( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::fd_prestat_dir_name::(ctx, fd, path, path_len) -} - -pub(crate) fn fd_pwrite( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, - iovs_len: MemoryOffset, - offset: __wasi_filesize_t, - nwritten: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_pwrite::(ctx, fd, iovs, iovs_len, offset, nwritten) -} - -pub(crate) fn fd_read( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_iovec_t, MemoryType>, - iovs_len: MemoryOffset, - nread: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_read::(ctx, fd, iovs, iovs_len, nread) -} - -pub(crate) fn fd_readdir( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - buf: WasmPtr, - buf_len: MemoryOffset, - cookie: __wasi_dircookie_t, - bufused: WasmPtr, -) -> __wasi_errno_t { - super::fd_readdir::(ctx, fd, buf, buf_len, cookie, bufused) -} - -pub(crate) fn fd_renumber( - ctx: FunctionEnvMut, - from: __wasi_fd_t, - to: __wasi_fd_t, -) -> __wasi_errno_t { - super::fd_renumber(ctx, from, to) -} - -pub(crate) fn fd_seek( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: __wasi_filedelta_t, - whence: __wasi_whence_t, - newoffset: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_seek::(ctx, fd, offset, whence, newoffset) -} - -pub(crate) fn fd_sync(ctx: FunctionEnvMut, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_sync(ctx, fd) -} - -pub(crate) fn fd_tell( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - offset: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_tell::(ctx, fd, offset) -} - -pub(crate) fn fd_write( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, - iovs_len: MemoryOffset, - nwritten: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::fd_write::(ctx, fd, iovs, iovs_len, nwritten) -} - -pub(crate) fn path_create_directory( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_create_directory::(ctx, fd, path, path_len) -} - -pub(crate) fn path_filestat_get( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - buf: WasmPtr<__wasi_filestat_t, MemoryType>, -) -> __wasi_errno_t { - super::path_filestat_get::(ctx, fd, flags, path, path_len, buf) -} - -pub(crate) fn path_filestat_set_times( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - flags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - st_atim: __wasi_timestamp_t, - st_mtim: __wasi_timestamp_t, - fst_flags: __wasi_fstflags_t, -) -> __wasi_errno_t { - super::path_filestat_set_times::( - ctx, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, - ) -} - -pub(crate) fn path_link( - ctx: FunctionEnvMut, - old_fd: __wasi_fd_t, - old_flags: __wasi_lookupflags_t, - old_path: WasmPtr, - old_path_len: MemoryOffset, - new_fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_link::( - ctx, - old_fd, - old_flags, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len, - ) -} - -pub(crate) fn path_open( - ctx: FunctionEnvMut, - dirfd: __wasi_fd_t, - dirflags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: MemoryOffset, - o_flags: __wasi_oflags_t, - fs_rights_base: __wasi_rights_t, - fs_rights_inheriting: __wasi_rights_t, - fs_flags: __wasi_fdflags_t, - fd: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::path_open::( - ctx, - dirfd, - dirflags, - path, - path_len, - o_flags, - fs_rights_base, - fs_rights_inheriting, - fs_flags, - fd, - ) -} - -pub(crate) fn path_readlink( - ctx: FunctionEnvMut, - dir_fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, - buf: WasmPtr, - buf_len: MemoryOffset, - buf_used: WasmPtr, -) -> __wasi_errno_t { - super::path_readlink::(ctx, dir_fd, path, path_len, buf, buf_len, buf_used) -} - -pub(crate) fn path_remove_directory( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_remove_directory::(ctx, fd, path, path_len) -} - -pub(crate) fn path_rename( - ctx: FunctionEnvMut, - old_fd: __wasi_fd_t, - old_path: WasmPtr, - old_path_len: MemoryOffset, - new_fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_rename::( - ctx, - old_fd, - old_path, - old_path_len, - new_fd, - new_path, - new_path_len, - ) -} - -pub(crate) fn path_symlink( - ctx: FunctionEnvMut, - old_path: WasmPtr, - old_path_len: MemoryOffset, - fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_symlink::(ctx, old_path, old_path_len, fd, new_path, new_path_len) -} - -pub(crate) fn path_unlink_file( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::path_unlink_file::(ctx, fd, path, path_len) -} - -pub(crate) fn poll_oneoff( - ctx: FunctionEnvMut, - in_: WasmPtr<__wasi_subscription_t, MemoryType>, - out_: WasmPtr<__wasi_event_t, MemoryType>, - nsubscriptions: MemoryOffset, - nevents: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::poll_oneoff::(ctx, in_, out_, nsubscriptions, nevents) -} - -pub(crate) fn proc_exit( - ctx: FunctionEnvMut, - code: __wasi_exitcode_t, -) -> Result<(), WasiError> { - super::proc_exit(ctx, code) -} - -pub(crate) fn proc_raise(ctx: FunctionEnvMut, sig: __wasi_signal_t) -> __wasi_errno_t { - super::proc_raise(ctx, sig) -} - -pub(crate) fn random_get( - ctx: FunctionEnvMut, - buf: WasmPtr, - buf_len: MemoryOffset, -) -> __wasi_errno_t { - super::random_get::(ctx, buf, buf_len) -} - -pub(crate) fn fd_dup( - ctx: FunctionEnvMut, - fd: __wasi_fd_t, - ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_dup::(ctx, fd, ret_fd) -} - -pub(crate) fn fd_event( - ctx: FunctionEnvMut, - initial_val: u64, - flags: __wasi_eventfdflags, - ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_event(ctx, initial_val, flags, ret_fd) -} - -pub(crate) fn fd_pipe( - ctx: FunctionEnvMut, - ro_fd1: WasmPtr<__wasi_fd_t, MemoryType>, - ro_fd2: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::fd_pipe::(ctx, ro_fd1, ro_fd2) -} - -pub(crate) fn tty_get( - ctx: FunctionEnvMut, - tty_state: WasmPtr<__wasi_tty_t, MemoryType>, -) -> __wasi_errno_t { - super::tty_get::(ctx, tty_state) -} - -pub(crate) fn tty_set( - ctx: FunctionEnvMut, - tty_state: WasmPtr<__wasi_tty_t, MemoryType>, -) -> __wasi_errno_t { - super::tty_set::(ctx, tty_state) -} - -pub(crate) fn getcwd( - ctx: FunctionEnvMut, - path: WasmPtr, - path_len: WasmPtr, -) -> __wasi_errno_t { - super::getcwd::(ctx, path, path_len) -} - -pub(crate) fn chdir( - ctx: FunctionEnvMut, - path: WasmPtr, - path_len: MemoryOffset, -) -> __wasi_errno_t { - super::chdir::(ctx, path, path_len) -} - -pub(crate) fn thread_spawn( - ctx: FunctionEnvMut, - method: WasmPtr, - method_len: MemoryOffset, - user_data: u64, - reactor: __wasi_bool_t, - ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, -) -> __wasi_errno_t { - super::thread_spawn::(ctx, method, method_len, user_data, reactor, ret_tid) -} - -pub(crate) fn thread_sleep( - ctx: FunctionEnvMut, - duration: __wasi_timestamp_t, -) -> Result<__wasi_errno_t, WasiError> { - super::thread_sleep(ctx, duration) -} - -pub(crate) fn thread_id( - ctx: FunctionEnvMut, - ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, -) -> __wasi_errno_t { - super::thread_id::(ctx, ret_tid) -} - -pub(crate) fn thread_join( - ctx: FunctionEnvMut, - tid: __wasi_tid_t, -) -> Result<__wasi_errno_t, WasiError> { - super::thread_join(ctx, tid) -} - -pub(crate) fn thread_parallelism( - ctx: FunctionEnvMut, - ret_parallelism: WasmPtr, -) -> __wasi_errno_t { - super::thread_parallelism::(ctx, ret_parallelism) -} - -pub(crate) fn thread_exit( - ctx: FunctionEnvMut, - exitcode: __wasi_exitcode_t, -) -> Result<__wasi_errno_t, WasiError> { - super::thread_exit(ctx, exitcode) -} - -pub(crate) fn sched_yield(ctx: FunctionEnvMut) -> Result<__wasi_errno_t, WasiError> { - super::sched_yield(ctx) -} - -pub(crate) fn getpid( - ctx: FunctionEnvMut, - ret_pid: WasmPtr<__wasi_pid_t, MemoryType>, -) -> __wasi_errno_t { - super::getpid::(ctx, ret_pid) -} - -pub(crate) fn process_spawn( - ctx: FunctionEnvMut, - name: WasmPtr, - name_len: MemoryOffset, - chroot: __wasi_bool_t, - args: WasmPtr, - args_len: MemoryOffset, - preopen: WasmPtr, - preopen_len: MemoryOffset, - stdin: __wasi_stdiomode_t, - stdout: __wasi_stdiomode_t, - stderr: __wasi_stdiomode_t, - working_dir: WasmPtr, - working_dir_len: MemoryOffset, - ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, -) -> __bus_errno_t { - super::process_spawn::( - ctx, - name, - name_len, - chroot, - args, - args_len, - preopen, - preopen_len, - stdin, - stdout, - stderr, - working_dir, - working_dir_len, - ret_handles, - ) -} - -pub(crate) fn bus_open_local( - ctx: FunctionEnvMut, - name: WasmPtr, - name_len: MemoryOffset, - reuse: __wasi_bool_t, - ret_bid: WasmPtr<__wasi_bid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_open_local::(ctx, name, name_len, reuse, ret_bid) -} - -pub(crate) fn bus_open_remote( - ctx: FunctionEnvMut, - name: WasmPtr, - name_len: MemoryOffset, - reuse: __wasi_bool_t, - instance: WasmPtr, - instance_len: MemoryOffset, - token: WasmPtr, - token_len: MemoryOffset, - ret_bid: WasmPtr<__wasi_bid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_open_remote::( - ctx, - name, - name_len, - reuse, - instance, - instance_len, - token, - token_len, - ret_bid, - ) -} - -pub(crate) fn bus_close(ctx: FunctionEnvMut, bid: __wasi_bid_t) -> __bus_errno_t { - super::bus_close(ctx, bid) -} - -pub(crate) fn bus_call( - ctx: FunctionEnvMut, - bid: __wasi_bid_t, - keep_alive: __wasi_bool_t, - topic: WasmPtr, - topic_len: MemoryOffset, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: MemoryOffset, - ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_call::( - ctx, bid, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, - ) -} - -pub(crate) fn bus_subcall( - ctx: FunctionEnvMut, - parent: __wasi_cid_t, - keep_alive: __wasi_bool_t, - topic: WasmPtr, - topic_len: MemoryOffset, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: MemoryOffset, - ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, -) -> __bus_errno_t { - super::bus_subcall::( - ctx, parent, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, - ) -} - -pub(crate) fn bus_poll( - ctx: FunctionEnvMut, - timeout: __wasi_timestamp_t, - events: WasmPtr, - nevents: MemoryOffset, - malloc: WasmPtr, - malloc_len: MemoryOffset, - ret_nevents: WasmPtr, -) -> __bus_errno_t { - super::bus_poll::( - ctx, - timeout, - events, - nevents, - malloc, - malloc_len, - ret_nevents, - ) -} - -pub(crate) fn call_reply( - ctx: FunctionEnvMut, - cid: __wasi_cid_t, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: MemoryOffset, -) -> __bus_errno_t { - super::call_reply::(ctx, cid, format, buf, buf_len) -} - -pub(crate) fn call_fault( - ctx: FunctionEnvMut, - cid: __wasi_cid_t, - fault: __bus_errno_t, -) -> __bus_errno_t { - super::call_fault(ctx, cid, fault) -} - -pub(crate) fn call_close(ctx: FunctionEnvMut, cid: __wasi_cid_t) -> __bus_errno_t { - super::call_close(ctx, cid) -} - -pub(crate) fn port_bridge( - ctx: FunctionEnvMut, - network: WasmPtr, - network_len: MemoryOffset, - token: WasmPtr, - token_len: MemoryOffset, - security: __wasi_streamsecurity_t, -) -> __wasi_errno_t { - super::port_bridge::(ctx, network, network_len, token, token_len, security) -} - -pub(crate) fn port_unbridge(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_unbridge(ctx) -} - -pub(crate) fn port_dhcp_acquire(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_dhcp_acquire(ctx) -} - -pub(crate) fn port_addr_add( - ctx: FunctionEnvMut, - addr: WasmPtr<__wasi_cidr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_addr_add::(ctx, addr) -} - -pub(crate) fn port_addr_remove( - ctx: FunctionEnvMut, - addr: WasmPtr<__wasi_addr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_addr_remove::(ctx, addr) -} - -pub(crate) fn port_addr_clear(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_addr_clear(ctx) -} - -pub(crate) fn port_addr_list( - ctx: FunctionEnvMut, - addrs: WasmPtr<__wasi_cidr_t, MemoryType>, - naddrs: WasmPtr, -) -> __wasi_errno_t { - super::port_addr_list::(ctx, addrs, naddrs) -} - -pub(crate) fn port_mac( - ctx: FunctionEnvMut, - ret_mac: WasmPtr<__wasi_hardwareaddress_t, MemoryType>, -) -> __wasi_errno_t { - super::port_mac::(ctx, ret_mac) -} - -pub(crate) fn port_gateway_set( - ctx: FunctionEnvMut, - ip: WasmPtr<__wasi_addr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_gateway_set::(ctx, ip) -} - -pub(crate) fn port_route_add( - ctx: FunctionEnvMut, - cidr: WasmPtr<__wasi_cidr_t, MemoryType>, - via_router: WasmPtr<__wasi_addr_t, MemoryType>, - preferred_until: WasmPtr<__wasi_option_timestamp_t, MemoryType>, - expires_at: WasmPtr<__wasi_option_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::port_route_add::(ctx, cidr, via_router, preferred_until, expires_at) -} - -pub(crate) fn port_route_remove( - ctx: FunctionEnvMut, - ip: WasmPtr<__wasi_addr_t, MemoryType>, -) -> __wasi_errno_t { - super::port_route_remove::(ctx, ip) -} - -pub(crate) fn port_route_clear(ctx: FunctionEnvMut) -> __wasi_errno_t { - super::port_route_clear(ctx) -} - -pub(crate) fn port_route_list( - ctx: FunctionEnvMut, - routes: WasmPtr<__wasi_route_t, MemoryType>, - nroutes: WasmPtr, -) -> __wasi_errno_t { - super::port_route_list::(ctx, routes, nroutes) -} - -pub(crate) fn ws_connect( - ctx: FunctionEnvMut, - url: WasmPtr, - url_len: MemoryOffset, - ret_sock: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::ws_connect::(ctx, url, url_len, ret_sock) -} - -pub(crate) fn http_request( - ctx: FunctionEnvMut, - url: WasmPtr, - url_len: MemoryOffset, - method: WasmPtr, - method_len: MemoryOffset, - headers: WasmPtr, - headers_len: MemoryOffset, - gzip: __wasi_bool_t, - ret_handles: WasmPtr<__wasi_http_handles_t, MemoryType>, -) -> __wasi_errno_t { - super::http_request::( - ctx, - url, - url_len, - method, - method_len, - headers, - headers_len, - gzip, - ret_handles, - ) -} - -pub(crate) fn http_status( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - status: WasmPtr<__wasi_http_status_t, MemoryType>, - status_text: WasmPtr, - status_text_len: WasmPtr, - headers: WasmPtr, - headers_len: WasmPtr, -) -> __wasi_errno_t { - super::http_status::(ctx, sock, status) -} - -pub(crate) fn sock_status( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ret_status: WasmPtr<__wasi_sockstatus_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_status::(ctx, sock, ret_status) -} - -pub(crate) fn sock_addr_local( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ret_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_addr_local::(ctx, sock, ret_addr) -} - -pub(crate) fn sock_addr_peer( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_addr_peer::(ctx, sock, ro_addr) -} - -pub(crate) fn sock_open( - ctx: FunctionEnvMut, - af: __wasi_addressfamily_t, - ty: __wasi_socktype_t, - pt: __wasi_sockproto_t, - ro_sock: WasmPtr<__wasi_fd_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_open::(ctx, af, ty, pt, ro_sock) -} - -pub(crate) fn sock_set_opt_flag( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - flag: __wasi_bool_t, -) -> __wasi_errno_t { - super::sock_set_opt_flag(ctx, sock, opt, flag) -} - -pub(crate) fn sock_get_opt_flag( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - ret_flag: WasmPtr<__wasi_bool_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_get_opt_flag::(ctx, sock, opt, ret_flag) -} - -pub fn sock_set_opt_time( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_set_opt_time(ctx, sock, opt, time) -} - -pub fn sock_get_opt_time( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - ret_time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_get_opt_time(ctx, sock, opt, ret_time) -} - -pub fn sock_set_opt_size( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - size: __wasi_filesize_t, -) -> __wasi_errno_t { - super::sock_set_opt_size(ctx, sock, opt, size) -} - -pub fn sock_get_opt_size( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - opt: __wasi_sockoption_t, - ret_size: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_get_opt_size(ctx, sock, opt, ret_size) -} - -pub(crate) fn sock_join_multicast_v4( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, - iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_join_multicast_v4::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_leave_multicast_v4( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, - iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_leave_multicast_v4::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_join_multicast_v6( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, - iface: u32, -) -> __wasi_errno_t { - super::sock_join_multicast_v6::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_leave_multicast_v6( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, - iface: u32, -) -> __wasi_errno_t { - super::sock_leave_multicast_v6::(ctx, sock, multiaddr, iface) -} - -pub(crate) fn sock_bind( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_bind::(ctx, sock, addr) -} - -pub(crate) fn sock_listen( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - backlog: MemoryOffset, -) -> __wasi_errno_t { - super::sock_listen::(ctx, sock, backlog) -} - -pub(crate) fn sock_accept( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - fd_flags: __wasi_fdflags_t, - ro_fd: WasmPtr<__wasi_fd_t, MemoryType>, - ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_accept::(ctx, sock, fd_flags, ro_fd, ro_addr) -} - -pub(crate) fn sock_connect( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> __wasi_errno_t { - super::sock_connect::(ctx, sock, addr) -} - -pub(crate) fn sock_recv( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, - ri_data_len: MemoryOffset, - ri_flags: __wasi_riflags_t, - ro_data_len: WasmPtr, - ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv::( - ctx, - sock, - ri_data, - ri_data_len, - ri_flags, - ro_data_len, - ro_flags, - ) -} - -pub(crate) fn sock_recv_from( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, - ri_data_len: MemoryOffset, - ri_flags: __wasi_riflags_t, - ro_data_len: WasmPtr, - ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, - ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv_from::( - ctx, - sock, - ri_data, - ri_data_len, - ri_flags, - ro_data_len, - ro_flags, - ro_addr, - ) -} - -pub(crate) fn sock_send( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, - si_data_len: MemoryOffset, - si_flags: __wasi_siflags_t, - ret_data_len: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_send::(ctx, sock, si_data, si_data_len, si_flags, ret_data_len) -} - -pub(crate) fn sock_send_to( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, - si_data_len: MemoryOffset, - si_flags: __wasi_siflags_t, - addr: WasmPtr<__wasi_addr_port_t, MemoryType>, - ret_data_len: WasmPtr, -) -> Result<__wasi_errno_t, WasiError> { - super::sock_send_to::( - ctx, - sock, - si_data, - si_data_len, - si_flags, - addr, - ret_data_len, - ) -} - -pub(crate) fn sock_send_file( - ctx: FunctionEnvMut, - out_fd: __wasi_fd_t, - in_fd: __wasi_fd_t, - offset: __wasi_filesize_t, - count: __wasi_filesize_t, - ret_sent: WasmPtr<__wasi_filesize_t, MemoryType>, -) -> Result<__wasi_errno_t, WasiError> { - unsafe { super::sock_send_file::(ctx, out_fd, in_fd, offset, count, ret_sent) } -} - -pub(crate) fn sock_shutdown( - ctx: FunctionEnvMut, - sock: __wasi_fd_t, - how: __wasi_sdflags_t, -) -> __wasi_errno_t { - super::sock_shutdown(ctx, sock, how) -} - -pub(crate) fn resolve( - ctx: FunctionEnvMut, - host: WasmPtr, - host_len: MemoryOffset, - port: u16, - ips: WasmPtr<__wasi_addr_t, MemoryType>, - nips: MemoryOffset, - ret_nips: WasmPtr, -) -> __wasi_errno_t { - super::resolve::(ctx, host, host_len, port, ips, nips, ret_nips) -} diff --git a/lib/wasi/src/syscalls/wasm32.rs b/lib/wasi/src/syscalls/wasm.rs similarity index 100% rename from lib/wasi/src/syscalls/wasm32.rs rename to lib/wasi/src/syscalls/wasm.rs diff --git a/lib/wasi/tests/catsay.rs b/lib/wasi/tests/catsay.rs new file mode 100644 index 00000000000..4d4901840ba --- /dev/null +++ b/lib/wasi/tests/catsay.rs @@ -0,0 +1,146 @@ +#![cfg(feature = "sys")] +#![cfg(target_os = "linux")] +use std::{io::{Read, Write}, time::Duration}; + +#[allow(unused_imports)] +use tracing::{debug, info, metadata::LevelFilter}; +#[cfg(feature = "sys")] +use tracing_subscriber::fmt::SubscriberBuilder; +use wasmer::{Instance, Module, Store, Cranelift, EngineBuilder}; +use wasmer_wasi::{Pipe, WasiState, import_object_for_all_wasi_versions, WasiError}; + +#[cfg(feature = "sys")] +mod sys { + #[test] + fn test_catsay() { + super::test_catsay() + } +} + +#[cfg(feature = "js")] +mod js { + use wasm_bindgen_test::*; + #[wasm_bindgen_test] + fn test_catsay() { + super::test_catsay() + } +} + +fn test_catsay() { + + info!("Creating engine"); + let compiler = Cranelift::default(); + let engine = EngineBuilder::new(compiler.clone()); + + #[allow(unused_mut)] + let mut store = Store::new(engine); + + info!("Compiling module"); + let module = Module::new(&store, include_bytes!("catsay.wasm")).unwrap(); + + #[cfg(feature = "js")] + tracing_wasm::set_as_global_default_with_config({ + let mut builder = tracing_wasm::WASMLayerConfigBuilder::new(); + builder.set_console_config(tracing_wasm::ConsoleConfig::ReportWithoutConsoleColor); + builder.build() + }); + + #[cfg(feature = "sys")] + SubscriberBuilder::default() + .with_max_level(LevelFilter::TRACE) + .init(); + + + let engine = store.engine().clone(); + for _ in 0..10 { + let module = module.clone(); + run_test(store, module); + + store = Store::new(engine.clone()); + } + + // TODO: This version will SIGSEGV (users must reuse engines) + for _ in 0..10 { + let module = module.clone(); + run_test(store, module); + + let engine = EngineBuilder::new(compiler.clone()); + store = Store::new(engine); + } +} + +fn run_test(mut store: Store, module: Module) +{ + // Create the `WasiEnv`. + let mut stdout = Pipe::new(); + let mut wasi_state_builder = WasiState::new("catsay"); + + let mut stdin_pipe = Pipe::new(); + + let mut wasi_env = wasi_state_builder + .stdin(Box::new(stdin_pipe.clone())) + .stdout(Box::new(stdout.clone())) + .stderr(Box::new(stdout.clone())) + .finalize(&mut store) + .unwrap(); + + // Start a thread that will dump STDOUT to info + #[cfg(feature = "sys")] + std::thread::spawn(move || { + loop { + let mut buf = [0u8; 8192]; + if let Ok(amt) = stdout.read(&mut buf[..]) { + if amt > 0 { + let msg = String::from_utf8_lossy(&buf[0..amt]); + for line in msg.lines() { + info!("{}", line); + } + } else { + std::thread::sleep(Duration::from_millis(1)); + } + } else { + break; + } + } + }); + + // Write some text to catsay stdin + stdin_pipe.write_all("hi there".as_bytes()).unwrap(); + drop(stdin_pipe); + + // Generate an `ImportObject`. + let mut import_object = import_object_for_all_wasi_versions(&mut store, &wasi_env.env); + import_object.import_shared_memory(&module, &mut store); + + // Let's instantiate the module with the imports. + let instance = Instance::new(&mut store, &module, &import_object).unwrap(); + wasi_env.initialize(&mut store, &instance).unwrap(); + + // Let's call the `_start` function, which is our `main` function in Rust. + let start = instance.exports.get_function("_start").unwrap(); + let ret = start.call(&mut store, &[]); + if let Err(e) = ret { + match e.downcast::() { + Ok(WasiError::Exit(0)) => { } + Ok(WasiError::Exit(code)) => { + assert!(false, "The call should have returned Err(WasiError::Exit(0)) but returned {}", code); + } + Ok(WasiError::UnknownWasiVersion) => { + assert!(false, "The call should have returned Err(WasiError::Exit(0)) but returned UnknownWasiVersion"); + } + Err(err) => { + assert!(false, "The call returned an error {:?}", err); + } + } + } + + #[cfg(feature = "js")] + { + let mut stdout_str = String::new(); + stdout.read_to_string(&mut stdout_str).unwrap(); + let stdout_as_str = stdout_str.as_str(); + for line in stdout_str.lines() { + info!("{}", line); + } + } +} diff --git a/lib/wasi/tests/catsay.wasm b/lib/wasi/tests/catsay.wasm new file mode 100755 index 00000000000..bb103f01429 Binary files /dev/null and b/lib/wasi/tests/catsay.wasm differ diff --git a/lib/wasi/tests/condvar.rs b/lib/wasi/tests/condvar.rs new file mode 100644 index 00000000000..c3a9863762d --- /dev/null +++ b/lib/wasi/tests/condvar.rs @@ -0,0 +1,120 @@ +#![cfg(feature = "sys")] +#![cfg(target_os = "linux")] +use std::{io::Read, time::Duration}; + +#[allow(unused_imports)] +use tracing::{debug, info, metadata::LevelFilter}; +#[cfg(feature = "sys")] +use tracing_subscriber::fmt::SubscriberBuilder; +use wasmer::{Instance, Module, Store, Features, Cranelift, EngineBuilder}; +use wasmer_wasi::{Pipe, WasiState, import_object_for_all_wasi_versions, WasiError}; + +#[cfg(feature = "sys")] +mod sys { + #[test] + fn test_condvar() { + super::test_condvar() + } +} + +#[cfg(feature = "js")] +mod js { + use wasm_bindgen_test::*; + #[wasm_bindgen_test] + fn test_condvar() { + super::test_condvar() + } +} + +fn test_condvar() { + let mut features = Features::new(); + features + .threads(true); + + info!("Creating engine"); + let compiler = Cranelift::default(); + let engine = EngineBuilder::new(compiler) + .set_features(Some(features)); + + let store = Store::new(engine); + + info!("Compiling module"); + let module = Module::new(&store, include_bytes!("condvar.wasm")).unwrap(); + + #[cfg(feature = "js")] + tracing_wasm::set_as_global_default_with_config({ + let mut builder = tracing_wasm::WASMLayerConfigBuilder::new(); + builder.set_console_config(tracing_wasm::ConsoleConfig::ReportWithoutConsoleColor); + builder.build() + }); + + #[cfg(feature = "sys")] + SubscriberBuilder::default() + .with_max_level(LevelFilter::TRACE) + .init(); + + run_test(store, module); +} + +fn run_test(mut store: Store, module: Module) +{ + // Create the `WasiEnv`. + let mut stdout = Pipe::new(); + let mut wasi_state_builder = WasiState::new("multi-threading"); + + let mut wasi_env = wasi_state_builder + .stdout(Box::new(stdout.clone())) + .stderr(Box::new(stdout.clone())) + .finalize(&mut store) + .unwrap(); + + // Start a thread that will dump STDOUT to info + #[cfg(feature = "sys")] + std::thread::spawn(move || { + loop { + let mut buf = [0u8; 8192]; + if let Ok(amt) = stdout.read(&mut buf[..]) { + if amt > 0 { + let msg = String::from_utf8_lossy(&buf[0..amt]); + for line in msg.lines() { + info!("{}", line); + } + } else { + std::thread::sleep(Duration::from_millis(1)); + } + } else { + break; + } + } + }); + + // Generate an `ImportObject`. + let mut import_object = import_object_for_all_wasi_versions(&mut store, &wasi_env.env); + import_object.import_shared_memory(&module, &mut store); + + // Let's instantiate the module with the imports. + let instance = Instance::new(&mut store, &module, &import_object).unwrap(); + wasi_env.initialize(&mut store, &instance).unwrap(); + + // Let's call the `_start` function, which is our `main` function in Rust. + let start = instance.exports.get_function("_start").unwrap(); + let ret = start.call(&mut store, &[]); + if let Err(e) = ret { + match e.downcast::() { + Ok(WasiError::Exit(0)) => { } + _ => { + assert!(false, "The call should have returned Err(WasiError::Exit(0))"); + } + } + } + + #[cfg(feature = "js")] + { + let mut stdout_str = String::new(); + stdout.read_to_string(&mut stdout_str).unwrap(); + let stdout_as_str = stdout_str.as_str(); + for line in stdout_str.lines() { + info!("{}", line); + } + } +} diff --git a/lib/wasi/tests/condvar.wasm b/lib/wasi/tests/condvar.wasm new file mode 100755 index 00000000000..b11fe82dfed Binary files /dev/null and b/lib/wasi/tests/condvar.wasm differ diff --git a/lib/wasi/tests/coreutils.rs b/lib/wasi/tests/coreutils.rs new file mode 100644 index 00000000000..883dca43b31 --- /dev/null +++ b/lib/wasi/tests/coreutils.rs @@ -0,0 +1,106 @@ +#![cfg(feature = "sys")] +#![cfg(target_os = "linux")] +use std::io::Read; + +#[allow(unused_imports)] +use tracing::{debug, info, metadata::LevelFilter}; +#[cfg(feature = "sys")] +use tracing_subscriber::fmt::SubscriberBuilder; +use wasmer::{Instance, Module, Store, Features, Cranelift, EngineBuilder}; +use wasmer_wasi::{Pipe, WasiState, import_object_for_all_wasi_versions, WasiError}; + +#[cfg(feature = "sys")] +mod sys { + #[test] + fn test_coreutils() { + super::test_coreutils() + } +} + +#[cfg(feature = "js")] +mod js { + use wasm_bindgen_test::*; + #[wasm_bindgen_test] + fn test_coreutils() { + super::test_coreutils() + } +} + +fn test_coreutils() { + let mut features = Features::new(); + features + .threads(true); + + info!("Creating engine"); + let compiler = Cranelift::default(); + let engine = EngineBuilder::new(compiler) + .set_features(Some(features)) + .engine(); + + let store = Store::new(engine.clone()); + + info!("Compiling module"); + let module = Module::new(&store, include_bytes!("coreutils.wasm")).unwrap(); + + #[cfg(feature = "js")] + tracing_wasm::set_as_global_default_with_config({ + let mut builder = tracing_wasm::WASMLayerConfigBuilder::new(); + builder.set_console_config(tracing_wasm::ConsoleConfig::ReportWithoutConsoleColor); + builder.build() + }); + + #[cfg(feature = "sys")] + SubscriberBuilder::default() + .with_max_level(LevelFilter::DEBUG) + .init(); + + // We do it many times (to make sure the compiled modules are reusable) + for n in 0..2 + { + let store = Store::new(engine.clone()); + let module = module.clone(); + + // Run the test itself + info!("Test Round {}", n); + run_test(store, module); + } +} + +fn run_test(mut store: Store, module: Module) +{ + // Create the `WasiEnv`. + let mut stdout = Pipe::new(); + let mut wasi_state_builder = WasiState::new("echo"); + wasi_state_builder + .args(&["apple"]); + + let mut wasi_env = wasi_state_builder + .stdout(Box::new(stdout.clone())) + .finalize(&mut store) + .unwrap(); + + // Generate an `ImportObject`. + let mut import_object = import_object_for_all_wasi_versions(&mut store, &wasi_env.env); + import_object.import_shared_memory(&module, &mut store); + + // Let's instantiate the module with the imports. + let instance = Instance::new(&mut store, &module, &import_object).unwrap(); + wasi_env.initialize(&mut store, &instance).unwrap(); + + // Let's call the `_start` function, which is our `main` function in Rust. + let start = instance.exports.get_function("_start").unwrap(); + let ret = start.call(&mut store, &[]); + if let Err(e) = ret { + match e.downcast::() { + Ok(WasiError::Exit(0)) => { } + _ => { + assert!(false, "The call should have returned Err(WasiError::Exit(0))"); + } + } + } + + let mut stdout_str = String::new(); + stdout.read_to_string(&mut stdout_str).unwrap(); + let stdout_as_str = stdout_str.as_str(); + assert_eq!(stdout_as_str, "apple\n"); +} diff --git a/lib/wasi/tests/coreutils.wasm b/lib/wasi/tests/coreutils.wasm new file mode 100755 index 00000000000..0a056a48329 Binary files /dev/null and b/lib/wasi/tests/coreutils.wasm differ diff --git a/lib/wasi/tests/multi-threading.rs b/lib/wasi/tests/multi-threading.rs new file mode 100644 index 00000000000..8a4e1f6a8e5 --- /dev/null +++ b/lib/wasi/tests/multi-threading.rs @@ -0,0 +1,119 @@ +#![cfg(feature = "sys")] +#![cfg(target_os = "linux")] +use std::{io::Read, time::Duration}; + +#[allow(unused_imports)] +use tracing::{debug, info, metadata::LevelFilter}; +#[cfg(feature = "sys")] +use tracing_subscriber::fmt::SubscriberBuilder; +use wasmer::{Instance, Module, Store, Features, Cranelift, EngineBuilder}; +use wasmer_wasi::{Pipe, WasiState, import_object_for_all_wasi_versions, WasiError}; + +mod sys { + #[test] + fn test_multithreading() { + super::test_multithreading() + } +} + +fn test_multithreading() { + let mut features = Features::new(); + features + .threads(true); + + info!("Creating engine"); + let compiler = Cranelift::default(); + let engine = EngineBuilder::new(compiler) + .set_features(Some(features)) + .engine(); + + let store = Store::new(engine.clone()); + + info!("Compiling module"); + let module = Module::new(&store, include_bytes!("multi-threading.wasm")).unwrap(); + + #[cfg(feature = "js")] + tracing_wasm::set_as_global_default_with_config({ + let mut builder = tracing_wasm::WASMLayerConfigBuilder::new(); + builder.set_console_config(tracing_wasm::ConsoleConfig::ReportWithoutConsoleColor); + builder.build() + }); + + #[cfg(feature = "sys")] + SubscriberBuilder::default() + .with_max_level(LevelFilter::TRACE) + .init(); + + // We do it many times (to make sure the compiled modules are reusable) + for n in 0..2 + { + let store = Store::new(engine.clone()); + let module = module.clone(); + + info!("Test Round {}", n); + run_test(store, module); + } +} + +fn run_test(mut store: Store, module: Module) +{ + // Create the `WasiEnv`. + let mut stdout = Pipe::new(); + let mut wasi_state_builder = WasiState::new("multi-threading"); + + let mut wasi_env = wasi_state_builder + .stdout(Box::new(stdout.clone())) + .stderr(Box::new(stdout.clone())) + .finalize(&mut store) + .unwrap(); + + // Start a thread that will dump STDOUT to info + #[cfg(feature = "sys")] + std::thread::spawn(move || { + loop { + let mut buf = [0u8; 8192]; + if let Ok(amt) = stdout.read(&mut buf[..]) { + if amt > 0 { + let msg = String::from_utf8_lossy(&buf[0..amt]); + for line in msg.lines() { + info!("{}", line); + } + } else { + std::thread::sleep(Duration::from_millis(1)); + } + } else { + break; + } + } + }); + + // Generate an `ImportObject`. + let mut import_object = import_object_for_all_wasi_versions(&mut store, &wasi_env.env); + import_object.import_shared_memory(&module, &mut store); + + // Let's instantiate the module with the imports. + let instance = Instance::new(&mut store, &module, &import_object).unwrap(); + wasi_env.initialize(&mut store, &instance).unwrap(); + + // Let's call the `_start` function, which is our `main` function in Rust. + let start = instance.exports.get_function("_start").unwrap(); + let ret = start.call(&mut store, &[]); + if let Err(e) = ret { + match e.downcast::() { + Ok(WasiError::Exit(0)) => { } + _ => { + assert!(false, "The call should have returned Err(WasiError::Exit(0))"); + } + } + } + + #[cfg(feature = "js")] + { + let mut stdout_str = String::new(); + stdout.read_to_string(&mut stdout_str).unwrap(); + let stdout_as_str = stdout_str.as_str(); + for line in stdout_str.lines() { + info!("{}", line); + } + } +} diff --git a/lib/wasi/tests/multi-threading.wasm b/lib/wasi/tests/multi-threading.wasm new file mode 100644 index 00000000000..6cdb6c08489 Binary files /dev/null and b/lib/wasi/tests/multi-threading.wasm differ diff --git a/lib/wasi/tests/stdio.rs b/lib/wasi/tests/stdio.rs index 78b93520e1a..218a477d2b4 100644 --- a/lib/wasi/tests/stdio.rs +++ b/lib/wasi/tests/stdio.rs @@ -23,7 +23,6 @@ mod sys { #[cfg(feature = "js")] mod js { use wasm_bindgen_test::*; - #[wasm_bindgen_test] fn test_stdout() { super::test_stdout() @@ -74,7 +73,7 @@ fn test_stdout() { // Create the `WasiEnv`. let mut stdout = Pipe::default(); - let wasi_env = WasiState::new("command-name") + let mut wasi_env = WasiState::new("command-name") .args(&["Gordon"]) .stdout(Box::new(stdout.clone())) .finalize(&mut store) @@ -85,8 +84,7 @@ fn test_stdout() { // Let's instantiate the module with the imports. let instance = Instance::new(&mut store, &module, &import_object).unwrap(); - let memory = instance.exports.get_memory("memory").unwrap(); - wasi_env.data_mut(&mut store).set_memory(memory.clone()); + wasi_env.initialize(&mut store, &instance).unwrap(); // Let's call the `_start` function, which is our `main` function in Rust. let start = instance.exports.get_function("_start").unwrap(); @@ -118,7 +116,7 @@ fn test_env() { .env("TEST", "VALUE") .env("TEST2", "VALUE2"); // panic!("envs: {:?}", wasi_state_builder.envs); - let wasi_env = wasi_state_builder + let mut wasi_env = wasi_state_builder .stdout(Box::new(stdout.clone())) .finalize(&mut store) .unwrap(); @@ -128,8 +126,7 @@ fn test_env() { // Let's instantiate the module with the imports. let instance = Instance::new(&mut store, &module, &import_object).unwrap(); - let memory = instance.exports.get_memory("memory").unwrap(); - wasi_env.data_mut(&mut store).set_memory(memory.clone()); + wasi_env.initialize(&mut store, &instance).unwrap(); // Let's call the `_start` function, which is our `main` function in Rust. let start = instance.exports.get_function("_start").unwrap(); @@ -147,7 +144,7 @@ fn test_stdin() { // Create the `WasiEnv`. let mut stdin = Pipe::new(); - let wasi_env = WasiState::new("command-name") + let mut wasi_env = WasiState::new("command-name") .stdin(Box::new(stdin.clone())) .finalize(&mut store) .unwrap(); @@ -161,8 +158,7 @@ fn test_stdin() { // Let's instantiate the module with the imports. let instance = Instance::new(&mut store, &module, &import_object).unwrap(); - let memory = instance.exports.get_memory("memory").unwrap(); - wasi_env.data_mut(&mut store).set_memory(memory.clone()); + wasi_env.initialize(&mut store, &instance).unwrap(); // Let's call the `_start` function, which is our `main` function in Rust. let start = instance.exports.get_function("_start").unwrap(); diff --git a/lib/wasi/wia/wasixx_32v1.txt b/lib/wasi/wia/wasixx_32v1.txt new file mode 100644 index 00000000000..da5e31e220b --- /dev/null +++ b/lib/wasi/wia/wasixx_32v1.txt @@ -0,0 +1,116 @@ +(interface "wasix_32v1" + (func (import "wasix_32v1" "args_get") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "args_sizes_get") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "environ_get") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "environ_sizes_get") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "clock_res_get") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "clock_time_get") (param i32 i64 i32) (result i32)) + (func (import "wasix_32v1" "fd_advise") (param i32 i64 i64 i32) (result i32)) + (func (import "wasix_32v1" "fd_allocate") (param i32 i64 i64) (result i32)) + (func (import "wasix_32v1" "fd_close") (param i32) (result i32)) + (func (import "wasix_32v1" "fd_datasync") (param i32) (result i32)) + (func (import "wasix_32v1" "fd_fdstat_get") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "fd_fdstat_set_flags") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "fd_fdstat_set_rights") (param i32 i64 i64) (result i32)) + (func (import "wasix_32v1" "fd_filestat_get") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "fd_filestat_set_size") (param i32 i64) (result i32)) + (func (import "wasix_32v1" "fd_filestat_set_times") (param i32 i64 i64 i32) (result i32)) + (func (import "wasix_32v1" "fd_pread") (param i32 i32 i32 i64 i32) (result i32)) + (func (import "wasix_32v1" "fd_prestat_get") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "fd_prestat_dir_name") (param i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "fd_pwrite") (param i32 i32 i32 i64 i32) (result i32)) + (func (import "wasix_32v1" "fd_read") (param i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "fd_readdir") (param i32 i32 i32 i64 i32) (result i32)) + (func (import "wasix_32v1" "fd_renumber") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "fd_dup") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "fd_event") (param i64 i32 i32) (result i32)) + (func (import "wasix_32v1" "fd_seek") (param i32 i64 i32 i32) (result i32)) + (func (import "wasix_32v1" "fd_sync") (param i32) (result i32)) + (func (import "wasix_32v1" "fd_tell") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "fd_write") (param i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "pipe") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "path_create_directory") (param i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "path_filestat_get") (param i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "path_filestat_set_times") (param i32 i32 i32 i32 i64 i64 i32) (result i32)) + (func (import "wasix_32v1" "path_link") (param i32 i32 i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "path_open") (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32)) + (func (import "wasix_32v1" "path_readlink") (param i32 i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "path_remove_directory") (param i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "path_rename") (param i32 i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "path_symlink") (param i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "path_unlink_file") (param i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "poll_oneoff") (param i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "proc_exit") (param i32) + (func (import "wasix_32v1" "proc_raise") (param i32) (result i32)) + (func (import "wasix_32v1" "sched_yield") (result i32)) + (func (import "wasix_32v1" "random_get") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "tty_get") (param i32) (result i32)) + (func (import "wasix_32v1" "tty_set") (param i32) (result i32)) + (func (import "wasix_32v1" "getcwd") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "chdir") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "thread_spawn") (param i64 i32 i32) (result i32)) + (func (import "wasix_32v1" "thread_sleep") (param i64) (result i32)) + (func (import "wasix_32v1" "thread_id") (param i32) (result i32)) + (func (import "wasix_32v1" "thread_local_create") (param i64 i32) (result i32)) + (func (import "wasix_32v1" "thread_local_destroy") (param i32) (result i32)) + (func (import "wasix_32v1" "thread_local_set") (param i32 i64) (result i32)) + (func (import "wasix_32v1" "thread_local_get") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "thread_join") (param i32) (result i32)) + (func (import "wasix_32v1" "thread_parallelism") (param i32) (result i32)) + (func (import "wasix_32v1" "futex_wait") (param i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "futex_wake") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "futex_wake_all") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "getpid") (param i32) (result i32)) + (func (import "wasix_32v1" "thread_exit") (param i32) + (func (import "wasix_32v1" "process_spawn") (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "bus_open_local") (param i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "bus_open_remote") (param 32 i32 i32 i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "bus_close") (param i32) (result i32)) + (func (import "wasix_32v1" "bus_call") (param i32 i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "bus_subcall") (param i32 i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "bus_poll") (param i64 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "call_reply") (param i64 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "call_fault") (param i64 i32) + (func (import "wasix_32v1" "call_close") (param i64) + (func (import "wasix_32v1" "ws_connect") (param i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "http_request") (param i32 i32 i32 i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "http_status") (param i32 i32) + (func (import "wasix_32v1" "port_bridge") (param i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "port_unbridge") (result i32)) + (func (import "wasix_32v1" "port_dhcp_acquire") (result i32)) + (func (import "wasix_32v1" "port_addr_add") (param i32) (result i32)) + (func (import "wasix_32v1" "port_addr_remove") (param i32) (result i32)) + (func (import "wasix_32v1" "port_addr_clear") (result i32)) + (func (import "wasix_32v1" "port_mac") (param i32) (result i32)) + (func (import "wasix_32v1" "port_addr_list") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "port_gateway_set") (param i32) (result i32)) + (func (import "wasix_32v1" "port_route_add") (param i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "port_route_remove") (param i32) (result i32)) + (func (import "wasix_32v1" "port_route_clear") (result i32)) + (func (import "wasix_32v1" "port_route_list") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_shutdown") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_status") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_addr_local") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_addr_peer") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_open") (param i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_set_opt_flag") (param i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_get_opt_flag") (param i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_set_opt_time") (param i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_get_opt_time") (param i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_set_opt_size") (param i32 i32 i64) (result i32)) + (func (import "wasix_32v1" "sock_get_opt_size") (param i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_join_multicast_v4") (param i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_leave_multicast_v4") (param i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_join_multicast_v6") (param i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_leave_multicast_v6") (param i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_bind") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_listen") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_accept") (param i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_connect") (param i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_recv") (param i32 i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_recv_from") (param i32 i32 i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_send") (param i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_send_to") (param i32 i32 i32 i32 i32 i32) (result i32)) + (func (import "wasix_32v1" "sock_send_file") (param i32 i32 i64 i64 i64) (result i32)) + (func (import "wasix_32v1" "resolve") (param i32 i32 i32 i32 i32 i32) (result i32)) +) diff --git a/lib/wasi/wia/wasixx_64v1.txt b/lib/wasi/wia/wasixx_64v1.txt new file mode 100644 index 00000000000..e904bbb1968 --- /dev/null +++ b/lib/wasi/wia/wasixx_64v1.txt @@ -0,0 +1,116 @@ +(interface "wasix_64v1" + (func (import "wasix_64v1" "args_get") (param i64 i64) (result i32)) + (func (import "wasix_64v1" "args_sizes_get") (param i64 i64) (result i32)) + (func (import "wasix_64v1" "environ_get") (param i64 i64) (result i32)) + (func (import "wasix_64v1" "environ_sizes_get") (param i64 i64) (result i32)) + (func (import "wasix_64v1" "clock_res_get") (param i32 i64) (result i32)) + (func (import "wasix_64v1" "clock_time_get") (param i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "fd_advise") (param i32 i64 i64 i32) (result i32)) + (func (import "wasix_64v1" "fd_allocate") (param i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "fd_close") (param i32) (result i32)) + (func (import "wasix_64v1" "fd_datasync") (param i32) (result i32)) + (func (import "wasix_64v1" "fd_fdstat_get") (param i32 i64) (result i32)) + (func (import "wasix_64v1" "fd_fdstat_set_flags") (param i32 i32) (result i32)) + (func (import "wasix_64v1" "fd_fdstat_set_rights") (param i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "fd_filestat_get") (param i32 i64) (result i32)) + (func (import "wasix_64v1" "fd_filestat_set_size") (param i32 i64) (result i32)) + (func (import "wasix_64v1" "fd_filestat_set_times") (param i32 i64 i64 i32) (result i32)) + (func (import "wasix_64v1" "fd_pread") (param i32 i64 i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "fd_prestat_get") (param i32 i64) (result i32)) + (func (import "wasix_64v1" "fd_prestat_dir_name") (param i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "fd_pwrite") (param i32 i64 i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "fd_read") (param i32 i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "fd_readdir") (param i32 i64 i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "fd_renumber") (param i32 i32) (result i32)) + (func (import "wasix_64v1" "fd_dup") (param i32 i64) (result i32)) + (func (import "wasix_64v1" "fd_event") (param i64 i32 i64) (result i32)) + (func (import "wasix_64v1" "fd_seek") (param i32 i64 i32 i64) (result i32)) + (func (import "wasix_64v1" "fd_sync") (param i32) (result i32)) + (func (import "wasix_64v1" "fd_tell") (param i32 i64) (result i32)) + (func (import "wasix_64v1" "fd_write") (param i32 i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "pipe") (param i64 i64) (result i32)) + (func (import "wasix_64v1" "path_create_directory") (param i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "path_filestat_get") (param i32 i32 i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "path_filestat_set_times") (param i32 i32 i64 i64 i64 i64 i32) (result i32)) + (func (import "wasix_64v1" "path_link") (param i32 i32 i64 i64 i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "path_open") (param i32 i32 i64 i64 i32 i64 i64 i32 i64) (result i32)) + (func (import "wasix_64v1" "path_readlink") (param i32 i64 i64 i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "path_remove_directory") (param i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "path_rename") (param i32 i64 i64 i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "path_symlink") (param i64 i64 i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "path_unlink_file") (param i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "poll_oneoff") (param i64 i64 i32 i64) (result i32)) + (func (import "wasix_64v1" "proc_exit") (param i32) + (func (import "wasix_64v1" "proc_raise") (param i32) (result i32)) + (func (import "wasix_64v1" "sched_yield") (result i32)) + (func (import "wasix_64v1" "random_get") (param i64 i64) (result i32)) + (func (import "wasix_64v1" "tty_get") (param i64) (result i32)) + (func (import "wasix_64v1" "tty_set") (param i64) (result i32)) + (func (import "wasix_64v1" "getcwd") (param i64 i64) (result i32)) + (func (import "wasix_64v1" "chdir") (param i64 i64) (result i32)) + (func (import "wasix_64v1" "thread_spawn") (param i64 i32 i64) (result i32)) + (func (import "wasix_64v1" "thread_sleep") (param i64) (result i32)) + (func (import "wasix_64v1" "thread_id") (param i64) (result i32)) + (func (import "wasix_64v1" "thread_local_create") (param i64 i64) (result i32)) + (func (import "wasix_64v1" "thread_local_destroy") (param i32) (result i32)) + (func (import "wasix_64v1" "thread_local_set") (param i32 i64) (result i32)) + (func (import "wasix_64v1" "thread_local_get") (param i32 i64) (result i32)) + (func (import "wasix_64v1" "thread_join") (param i32) (result i32)) + (func (import "wasix_64v1" "thread_parallelism") (param i64) (result i32)) + (func (import "wasix_64v1" "futex_wait") (param i64 i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "futex_wake") (param i64 i64) (result i32)) + (func (import "wasix_64v1" "futex_wake_all") (param i64 i64) (result i32)) + (func (import "wasix_64v1" "getpid") (param i64) (result i32)) + (func (import "wasix_64v1" "thread_exit") (param i32) + (func (import "wasix_64v1" "process_spawn") (param i64 i64 i32 i64 i64 i64 i64 i32 i32 i32 i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "bus_open_local") (param i64 i64 i32 i64) (result i32)) + (func (import "wasix_64v1" "bus_open_remote") (param i64 i64 i32 i64 i64 i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "bus_close") (param i32) (result i32)) + (func (import "wasix_64v1" "bus_call") (param i32 i64 i32 i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "bus_subcall") (param i64 i64 i32 i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "bus_poll") (param i64 i64 i32 i64) (result i32)) + (func (import "wasix_64v1" "call_reply") (param i64 i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "call_fault") (param i64 i32) + (func (import "wasix_64v1" "call_close") (param i64) + (func (import "wasix_64v1" "ws_connect") (param i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "http_request") (param i64 i64 i64 i64 i64 i64 i32 i64) (result i32)) + (func (import "wasix_64v1" "http_status") (param i32 i64) + (func (import "wasix_64v1" "port_bridge") (param i64 i64 i64 i64 i32) (result i32)) + (func (import "wasix_64v1" "port_unbridge") (result i32)) + (func (import "wasix_64v1" "port_dhcp_acquire") (result i32)) + (func (import "wasix_64v1" "port_addr_add") (param i64) (result i32)) + (func (import "wasix_64v1" "port_addr_remove") (param i64) (result i32)) + (func (import "wasix_64v1" "port_addr_clear") (result i32)) + (func (import "wasix_64v1" "port_mac") (param i64) (result i32)) + (func (import "wasix_64v1" "port_addr_list") (param i64 i64) (result i32)) + (func (import "wasix_64v1" "port_gateway_set") (param i64) (result i32)) + (func (import "wasix_64v1" "port_route_add") (param i64 i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "port_route_remove") (param i64) (result i32)) + (func (import "wasix_64v1" "port_route_clear") (result i32)) + (func (import "wasix_64v1" "port_route_list") (param i64 i64) (result i32)) + (func (import "wasix_64v1" "sock_shutdown") (param i32 i32) (result i32)) + (func (import "wasix_64v1" "sock_status") (param i32 i64) (result i32)) + (func (import "wasix_64v1" "sock_addr_local") (param i32 i64) (result i32)) + (func (import "wasix_64v1" "sock_addr_peer") (param i32 i64) (result i32)) + (func (import "wasix_64v1" "sock_open") (param i32 i32 i32 i64) (result i32)) + (func (import "wasix_64v1" "sock_set_opt_flag") (param i32 i32 i32) (result i32)) + (func (import "wasix_64v1" "sock_get_opt_flag") (param i32 i32 i64) (result i32)) + (func (import "wasix_64v1" "sock_set_opt_time") (param i32 i32 i64) (result i32)) + (func (import "wasix_64v1" "sock_get_opt_time") (param i32 i32 i64) (result i32)) + (func (import "wasix_64v1" "sock_set_opt_size") (param i32 i32 i64) (result i32)) + (func (import "wasix_64v1" "sock_get_opt_size") (param i32 i32 i64) (result i32)) + (func (import "wasix_64v1" "sock_join_multicast_v4") (param i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "sock_leave_multicast_v4") (param i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "sock_join_multicast_v6") (param i32 i64 i32) (result i32)) + (func (import "wasix_64v1" "sock_leave_multicast_v6") (param i32 i64 i32) (result i32)) + (func (import "wasix_64v1" "sock_bind") (param i32 i64) (result i32)) + (func (import "wasix_64v1" "sock_listen") (param i32 i32) (result i32)) + (func (import "wasix_64v1" "sock_accept") (param i32 i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "sock_connect") (param i32 i64) (result i32)) + (func (import "wasix_64v1" "sock_recv") (param i32 i64 i64 i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "sock_recv_from") (param i32 i64 i64 i32 i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "sock_send") (param i32 i64 i64 i32 i64) (result i32)) + (func (import "wasix_64v1" "sock_send_to") (param i32 i64 i64 i32 i64 i64) (result i32)) + (func (import "wasix_64v1" "sock_send_file") (param i32 i32 i64 i64 i64) (result i32)) + (func (import "wasix_64v1" "resolve") (param i64 i64 i32 i64 i32 i64) (result i32)) +) diff --git a/lib/wasi/wia/wasm_bus.txt b/lib/wasi/wia/wasm_bus.txt new file mode 100644 index 00000000000..64d0637e4e4 --- /dev/null +++ b/lib/wasi/wia/wasm_bus.txt @@ -0,0 +1,14 @@ +(interface "wasm-bus" + (func (import "wasm-bus" "wasm_bus_drop") (param i32) + (func (import "wasm-bus" "wasm_bus_handle") (result i32)) + (func (import "wasm-bus" "wasm_bus_listen") (param i32 i32) + (func (import "wasm-bus" "wasm_bus_callback") (param i32 i32 i32 i32) + (func (import "wasm-bus" "wasm_bus_fault") (param i32 i32) + (func (import "wasm-bus" "wasm_bus_poll") + (func (import "wasm-bus" "wasm_bus_fork") + (func (import "wasm-bus" "wasm_bus_reply") (param i32 i32 i32) + (func (import "wasm-bus" "wasm_bus_reply_callback") (param i32 i32 i32 i32 i32) + (func (import "wasm-bus" "wasm_bus_call") (param i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32)) + (func (import "wasm-bus" "wasm_bus_call_instance") (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32)) + (func (import "wasm-bus" "wasm_bus_thread_id") (result i32)) +) diff --git a/tests/compilers/issues.rs b/tests/compilers/issues.rs index e8d5dfb56a6..226085ce91f 100644 --- a/tests/compilers/issues.rs +++ b/tests/compilers/issues.rs @@ -25,7 +25,7 @@ fn issue_2329(mut config: crate::Config) -> Result<()> { } pub fn read_memory(mut ctx: FunctionEnvMut, guest_ptr: u32) -> u32 { - dbg!(ctx.data_mut().memory.as_ref()); + dbg!(ctx.data().memory.as_ref()); dbg!(guest_ptr); 0 } @@ -101,7 +101,7 @@ fn call_with_static_data_pointers(mut config: crate::Config) -> Result<()> { ) -> u64 { println!("{:?}", (a, b, c, d, e, f, g, h)); let mut buf = vec![0; d as usize]; - let memory = ctx.data_mut().memory.as_ref().unwrap().clone(); + let memory = ctx.data().memory.as_ref().unwrap().clone(); memory.view(&ctx).read(e, &mut buf).unwrap(); let input_string = std::str::from_utf8(&buf).unwrap(); assert_eq!(input_string, "bananapeach"); diff --git a/tests/compilers/typed_functions.rs b/tests/compilers/typed_functions.rs index c6c09b07272..e4b48af1913 100644 --- a/tests/compilers/typed_functions.rs +++ b/tests/compilers/typed_functions.rs @@ -307,7 +307,7 @@ fn static_host_function_with_env(config: crate::Config) -> anyhow::Result<()> { let mut store = config.store(); fn f(mut env: FunctionEnvMut, a: i32, b: i64, c: f32, d: f64) -> (f64, f32, i64, i32) { - let mut guard = env.data_mut().0.lock().unwrap(); + let mut guard = env.data().0.lock().unwrap(); assert_eq!(*guard, 100); *guard = 101; @@ -321,7 +321,7 @@ fn static_host_function_with_env(config: crate::Config) -> anyhow::Result<()> { c: f32, d: f64, ) -> Result<(f64, f32, i64, i32), Infallible> { - let mut guard = env.data_mut().0.lock().unwrap(); + let mut guard = env.data().0.lock().unwrap(); assert_eq!(*guard, 100); *guard = 101; @@ -446,7 +446,7 @@ fn dynamic_host_function_with_env(config: crate::Config) -> anyhow::Result<()> { ], ), |mut env, values| { - let mut guard = env.data_mut().0.lock().unwrap(); + let mut guard = env.data().0.lock().unwrap(); assert_eq!(*guard, 100); *guard = 101; diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 6b2e13aac4c..cf956eec1d2 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -83,16 +83,16 @@ impl<'a> WasiTest<'a> { out }; let module = Module::new(store, &wasm_bytes)?; - let (env, _tempdirs, stdout_rx, stderr_rx) = + let (mut env, _tempdirs, stdout_rx, stderr_rx) = self.create_wasi_env(store, filesystem_kind)?; let imports = self.get_imports(store, &env.env, &module)?; let instance = Instance::new(&mut store, &module, &imports)?; - let start = instance.exports.get_function("_start")?; - let memory = instance.exports.get_memory("memory")?; - let wasi_env = env.data_mut(&mut store); - wasi_env.set_memory(memory.clone()); + env.initialize(&mut store, &instance).unwrap(); + let wasi_env = env.data(&store); + let start = instance.exports.get_function("_start")?; + if let Some(stdin) = &self.stdin { let state = wasi_env.state(); let mut wasi_stdin = state.stdin().unwrap().unwrap();