From e074c5d6142dbe0cf7992c894829c2cce463157e Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Wed, 27 Mar 2024 11:26:12 +0100 Subject: [PATCH 01/15] Release 0.6.0 tinywasm@0.6.0 tinywasm-cli@0.6.0 tinywasm-parser@0.6.0 tinywasm-types@0.6.0 wasm-testsuite@0.3.0 Generated by cargo-workspaces --- Cargo.lock | 10 +++++----- Cargo.toml | 2 +- crates/cli/Cargo.toml | 2 +- crates/parser/Cargo.toml | 2 +- crates/tinywasm/Cargo.toml | 4 ++-- crates/tinywasm/tests/testsuite/run.rs | 4 ++-- crates/tinywasm/tests/testsuite/util.rs | 4 ++-- crates/wasm-testsuite/Cargo.toml | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 61a20c8..27fa197 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2054,7 +2054,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tinywasm" -version = "0.5.0" +version = "0.6.0" dependencies = [ "eyre", "libm", @@ -2071,7 +2071,7 @@ dependencies = [ [[package]] name = "tinywasm-cli" -version = "0.5.0" +version = "0.6.0" dependencies = [ "argh", "color-eyre", @@ -2083,7 +2083,7 @@ dependencies = [ [[package]] name = "tinywasm-parser" -version = "0.5.0" +version = "0.6.0" dependencies = [ "log", "tinywasm-types", @@ -2102,7 +2102,7 @@ dependencies = [ [[package]] name = "tinywasm-types" -version = "0.5.0" +version = "0.6.0" dependencies = [ "bytecheck 0.7.0", "log", @@ -2307,7 +2307,7 @@ dependencies = [ [[package]] name = "wasm-testsuite" -version = "0.2.2" +version = "0.3.0" dependencies = [ "rust-embed", ] diff --git a/Cargo.toml b/Cargo.toml index bb3275c..c5fca68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ panic="abort" inherits="release" [workspace.package] -version="0.5.0" +version="0.6.0" edition="2021" license="MIT OR Apache-2.0" authors=["Henry Gressmann "] diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 7d54ced..0012483 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -14,7 +14,7 @@ path="src/bin.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tinywasm={version="0.5.0", path="../tinywasm", features=["std", "parser"]} +tinywasm={version="0.6.0", path="../tinywasm", features=["std", "parser"]} argh="0.1" color-eyre={version="0.6", default-features=false} log="0.4" diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 6ba7461..6057c30 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace=true # fork of wasmparser with no_std support, see https://github.com/bytecodealliance/wasmtime/issues/3495 wasmparser={version="0.202.0", package="tinywasm-wasmparser", default-features=false} log={version="0.4", optional=true} -tinywasm-types={version="0.5.0", path="../types", default-features=false} +tinywasm-types={version="0.6.0", path="../types", default-features=false} [features] default=["std", "logging"] diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 0af1d0c..81d0eeb 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -14,8 +14,8 @@ path="src/lib.rs" [dependencies] _log={version="0.4", optional=true, package="log"} -tinywasm-parser={version="0.5.0", path="../parser", default-features=false, optional=true} -tinywasm-types={version="0.5.0", path="../types", default-features=false} +tinywasm-parser={version="0.6.0", path="../parser", default-features=false, optional=true} +tinywasm-types={version="0.6.0", path="../types", default-features=false} libm={version="0.2", default-features=false} [dev-dependencies] diff --git a/crates/tinywasm/tests/testsuite/run.rs b/crates/tinywasm/tests/testsuite/run.rs index 2b2bbc4..aed23bd 100644 --- a/crates/tinywasm/tests/testsuite/run.rs +++ b/crates/tinywasm/tests/testsuite/run.rs @@ -291,7 +291,7 @@ impl TestSuite { )?; return Ok(()); } - wast::WastExecute::Get { module: _, global: _ } => { + wast::WastExecute::Get { module: _, global: _, .. } => { panic!("get not supported"); } wast::WastExecute::Invoke(invoke) => invoke, @@ -395,7 +395,7 @@ impl TestSuite { let invoke = match match exec { wast::WastExecute::Wat(_) => Err(eyre!("wat not supported")), - wast::WastExecute::Get { module: module_id, global } => { + wast::WastExecute::Get { module: module_id, global, .. } => { let module = registered_modules.get(module_id, &store); let Some(module) = module else { test_group.add_result( diff --git a/crates/tinywasm/tests/testsuite/util.rs b/crates/tinywasm/tests/testsuite/util.rs index a45c59f..7b3ff1e 100644 --- a/crates/tinywasm/tests/testsuite/util.rs +++ b/crates/tinywasm/tests/testsuite/util.rs @@ -155,7 +155,7 @@ trait FloatToken { } } } -impl FloatToken for wast::token::Float32 { +impl FloatToken for wast::token::F32 { fn bits(&self) -> Bits { Bits::U32(self.bits) } @@ -168,7 +168,7 @@ impl FloatToken for wast::token::Float32 { WasmValue::F32(f32::NAN) } } -impl FloatToken for wast::token::Float64 { +impl FloatToken for wast::token::F64 { fn bits(&self) -> Bits { Bits::U64(self.bits) } diff --git a/crates/wasm-testsuite/Cargo.toml b/crates/wasm-testsuite/Cargo.toml index 2e2fc21..3e12db5 100644 --- a/crates/wasm-testsuite/Cargo.toml +++ b/crates/wasm-testsuite/Cargo.toml @@ -1,6 +1,6 @@ [package] name="wasm-testsuite" -version="0.2.2" +version="0.3.0" description="Mirror of the WebAssembly core testsuite for use in testing WebAssembly implementations" license="Apache-2.0" readme="README.md" From 059fc95274f80e8b9aec7e124505811b506adc71 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Mon, 15 Apr 2024 22:26:33 +0200 Subject: [PATCH 02/15] chore: update dependencies Signed-off-by: Henry Gressmann --- BENCHMARKS.md | 1 + Cargo.lock | 302 ++++++++++++++---------- Cargo.toml | 2 +- benchmarks/Cargo.toml | 2 +- crates/cli/Cargo.toml | 2 +- crates/tinywasm/Cargo.toml | 2 +- crates/tinywasm/tests/generated/mvp.csv | 1 + rust-toolchain.toml | 2 +- 8 files changed, 187 insertions(+), 127 deletions(-) diff --git a/BENCHMARKS.md b/BENCHMARKS.md index 3a85e19..c34e16c 100644 --- a/BENCHMARKS.md +++ b/BENCHMARKS.md @@ -22,6 +22,7 @@ All runtimes are compiled with the following settings: - `unsafe` features are enabled. - `opt-level` is set to 3, `lto` is set to `thin`, `codegen-units` is set to 1. +- No CPU-specific optimizations are used as AVX2 can reduce performance by more than 50% on some CPUs. ## Versions diff --git a/Cargo.lock b/Cargo.lock index 27fa197..bdbad0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,7 +96,7 @@ dependencies = [ "argh_shared", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.59", ] [[package]] @@ -219,9 +219,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytecheck" @@ -293,9 +293,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.90" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" [[package]] name = "cfg-if" @@ -305,16 +305,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.35" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -700,7 +700,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.59", ] [[package]] @@ -711,7 +711,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.55", + "syn 2.0.59", ] [[package]] @@ -781,9 +781,9 @@ dependencies = [ [[package]] name = "downcast-rs" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dwrote" @@ -825,9 +825,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "enum-iterator" @@ -867,7 +867,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.59", ] [[package]] @@ -976,6 +976,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "freetype" version = "0.7.1" @@ -1024,9 +1033,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -1075,9 +1084,9 @@ dependencies = [ [[package]] name = "half" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", @@ -1142,6 +1151,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "image" version = "0.24.9" @@ -1254,7 +1273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -1265,13 +1284,12 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.5.0", "libc", - "redox_syscall", ] [[package]] @@ -1310,9 +1328,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memmap2" @@ -1334,9 +1352,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.9.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" dependencies = [ "autocfg", ] @@ -1447,11 +1465,17 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pkg-config" @@ -1554,9 +1578,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "a56dea16b0a29e94408b9aa5e2940a4eedbd128a1ba20e8f7ae60fd3d465af0e" dependencies = [ "unicode-ident", ] @@ -1583,9 +1607,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1633,9 +1657,9 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", "libredox", @@ -1679,9 +1703,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "region" @@ -1754,7 +1778,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.55", + "syn 2.0.59", "walkdir", ] @@ -1859,7 +1883,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.59", ] [[package]] @@ -1958,9 +1982,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.55" +version = "2.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +checksum = "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a" dependencies = [ "proc-macro2", "quote", @@ -2005,7 +2029,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.59", ] [[package]] @@ -2066,7 +2090,7 @@ dependencies = [ "tinywasm-parser", "tinywasm-types", "wasm-testsuite", - "wast 202.0.0", + "wast", ] [[package]] @@ -2078,7 +2102,7 @@ dependencies = [ "log", "pretty_env_logger", "tinywasm", - "wast 202.0.0", + "wast", ] [[package]] @@ -2141,7 +2165,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.59", ] [[package]] @@ -2187,18 +2211,44 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-width" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "uuid" version = "1.8.0" @@ -2254,10 +2304,33 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.59", "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-downcast" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dac026d43bcca6e7ce1c0956ba68f59edf6403e8e930a5d891be72c31a44340" +dependencies = [ + "js-sys", + "once_cell", + "wasm-bindgen", + "wasm-bindgen-downcast-macros", +] + +[[package]] +name = "wasm-bindgen-downcast-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5020cfa87c7cecefef118055d44e3c1fc122c7ec25701d528ee458a0b45f38f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.92" @@ -2276,7 +2349,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.59", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2289,18 +2362,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-encoder" -version = "0.32.0" +version = "0.203.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba64e81215916eaeb48fee292f29401d69235d62d8b8fd92a7b2844ec5ae5f7" -dependencies = [ - "leb128", -] - -[[package]] -name = "wasm-encoder" -version = "0.202.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd106365a7f5f7aa3c1916a98cbb3ad477f5ff96ddb130285a91c6e7429e67a" +checksum = "87e3b46a0d9d9143d57aa926c42e2af284b5cb8f0c7b71079afc7a6fca42db50" dependencies = [ "leb128", ] @@ -2314,9 +2378,9 @@ dependencies = [ [[package]] name = "wasmer" -version = "4.2.6" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c15724dc25d1ee57962334aea8e41ade2675e5ea2ac6b8d42da6051b0face66" +checksum = "0e626f958755a90a6552b9528f59b58a62ae288e6c17fcf40e99495bc33c60f0" dependencies = [ "bytes", "cfg-if", @@ -2330,8 +2394,8 @@ dependencies = [ "shared-buffer", "target-lexicon", "thiserror", - "tracing", "wasm-bindgen", + "wasm-bindgen-downcast", "wasmer-compiler", "wasmer-compiler-cranelift", "wasmer-compiler-singlepass", @@ -2344,9 +2408,9 @@ dependencies = [ [[package]] name = "wasmer-compiler" -version = "4.2.6" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a7f3b3a96f8d844c25e2c032af9572306dd63fa93dc17bcca4c5458ac569bd" +checksum = "848e1922694cf97f4df680a0534c9d72c836378b5eb2313c1708fe1a75b40044" dependencies = [ "backtrace", "bytes", @@ -2371,9 +2435,9 @@ dependencies = [ [[package]] name = "wasmer-compiler-cranelift" -version = "4.2.6" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "102e2c5bacac69495c4025767e2fa26797ffb27f242dccb7cf57d9cefd944386" +checksum = "3d96bce6fad15a954edcfc2749b59e47ea7de524b6ef3df392035636491a40b4" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -2390,9 +2454,9 @@ dependencies = [ [[package]] name = "wasmer-compiler-singlepass" -version = "4.2.6" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2071db9b993508dac72d12f7a9372e0c095fbdc173e0009c4b75886bed4a855e" +checksum = "ebaa865b40ffb3351b03dab9fe9930a5248c25daebd55b464b79b862d9b55ccd" dependencies = [ "byteorder", "dynasm", @@ -2409,9 +2473,9 @@ dependencies = [ [[package]] name = "wasmer-derive" -version = "4.2.6" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea737fa08f95d6abc4459f42a70a9833e8974b814e74971d77ef473814f4d4c" +checksum = "7f08f80d166a9279671b7af7a09409c28ede2e0b4e3acabbf0e3cb22c8038ba7" dependencies = [ "proc-macro-error", "proc-macro2", @@ -2421,9 +2485,9 @@ dependencies = [ [[package]] name = "wasmer-types" -version = "4.2.6" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0689110e291b0f07fc665f2824e5ff81df120848e8a9acfbf1a9bf7990773f9" +checksum = "ae2c892882f0b416783fb4310e5697f5c30587f6f9555f9d4f2be85ab39d5d3d" dependencies = [ "bytecheck 0.6.12", "enum-iterator", @@ -2437,9 +2501,9 @@ dependencies = [ [[package]] name = "wasmer-vm" -version = "4.2.6" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd41f822a1ac4242d478754e8ceba2806a00ea5072803622e1fe91e8e28b2a1" +checksum = "7c0a9a57b627fb39e5a491058d4365f099bc9b140031c000fded24a3306d9480" dependencies = [ "backtrace", "cc", @@ -2496,13 +2560,12 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.121.2" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" +checksum = "f2ea896273ea99b15132414be1da01ab0d8836415083298ecaffbe308eaac87a" dependencies = [ - "bitflags 2.5.0", - "indexmap 2.2.6", - "semver", + "indexmap 1.9.3", + "url", ] [[package]] @@ -2516,36 +2579,24 @@ dependencies = [ [[package]] name = "wast" -version = "64.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a259b226fd6910225aa7baeba82f9d9933b6d00f2ce1b49b80fa4214328237cc" -dependencies = [ - "leb128", - "memchr", - "unicode-width", - "wasm-encoder 0.32.0", -] - -[[package]] -name = "wast" -version = "202.0.0" +version = "203.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbcb11204515c953c9b42ede0a46a1c5e17f82af05c4fae201a8efff1b0f4fe" +checksum = "872020f79fa7a09aeaec308d0ba60816e2f808d9b402e2f89d2a9c76eda482cd" dependencies = [ "bumpalo", "leb128", "memchr", "unicode-width", - "wasm-encoder 0.202.0", + "wasm-encoder", ] [[package]] name = "wat" -version = "1.0.71" +version = "1.203.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53253d920ab413fca1c7dc2161d601c79b4fdf631d0ba51dd4343bf9b556c3f6" +checksum = "e2913b554125048798744fce03832d5330d87624782f8ec6ad8c9716a1ef7a37" dependencies = [ - "wast 64.0.0", + "wast", ] [[package]] @@ -2601,7 +2652,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -2623,7 +2674,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -2643,17 +2694,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -2664,9 +2716,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -2682,9 +2734,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -2700,9 +2752,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -2718,9 +2776,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -2736,9 +2794,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -2748,9 +2806,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -2766,9 +2824,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "wio" @@ -2817,5 +2875,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.59", ] diff --git a/Cargo.toml b/Cargo.toml index c5fca68..0f66fa9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ test=false [dev-dependencies] color-eyre="0.6" tinywasm={path="crates/tinywasm", features=["unsafe"]} -wat={version="1.0"} +wat={version="1.203"} pretty_env_logger="0.5" [profile.bench] diff --git a/benchmarks/Cargo.toml b/benchmarks/Cargo.toml index a374713..b678fc0 100644 --- a/benchmarks/Cargo.toml +++ b/benchmarks/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace=true [dependencies] criterion={version="0.5", features=["html_reports"]} tinywasm={path="../crates/tinywasm", features=["unsafe"]} -wat={version="1.0"} +wat={version="1.203"} wasmi={version="0.31", features=["std"]} wasmer={version="4.2", features=["cranelift", "singlepass"]} argon2={version="0.5"} diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 0012483..9606e51 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -19,7 +19,7 @@ argh="0.1" color-eyre={version="0.6", default-features=false} log="0.4" pretty_env_logger="0.5" -wast={version="202.0", optional=true} +wast={version="203.0", optional=true} [features] default=["wat"] diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 81d0eeb..ab12470 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -20,7 +20,7 @@ libm={version="0.2", default-features=false} [dev-dependencies] wasm-testsuite={path="../wasm-testsuite"} -wast={version="202.0"} +wast={version="203.0"} owo-colors={version="4.0"} eyre={version="0.6"} serde_json={version="1.0"} diff --git a/crates/tinywasm/tests/generated/mvp.csv b/crates/tinywasm/tests/generated/mvp.csv index 90dfa04..9830c15 100644 --- a/crates/tinywasm/tests/generated/mvp.csv +++ b/crates/tinywasm/tests/generated/mvp.csv @@ -6,3 +6,4 @@ 0.4.0,20254,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":183,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.4.1,20257,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.5.0,20272,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.6.0,20272,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 7d876a7..a84b93a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel="nightly-2024-03-11" +channel="nightly-2024-04-15" From 8c5a36200b13ca1d04e98048f807a01d2939670c Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Sun, 21 Apr 2024 23:28:50 +0200 Subject: [PATCH 03/15] chore: update dependencies Signed-off-by: Henry Gressmann --- Cargo.lock | 70 +++++++++++++++++++------------------- Cargo.toml | 2 +- benchmarks/Cargo.toml | 2 +- crates/cli/Cargo.toml | 2 +- crates/tinywasm/Cargo.toml | 2 +- 5 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bdbad0d..72b37de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,7 +96,7 @@ dependencies = [ "argh_shared", "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.60", ] [[package]] @@ -293,9 +293,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" +checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" [[package]] name = "cfg-if" @@ -700,7 +700,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.60", ] [[package]] @@ -711,7 +711,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.59", + "syn 2.0.60", ] [[package]] @@ -867,7 +867,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.60", ] [[package]] @@ -1578,9 +1578,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56dea16b0a29e94408b9aa5e2940a4eedbd128a1ba20e8f7ae60fd3d465af0e" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] @@ -1778,7 +1778,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.59", + "syn 2.0.60", "walkdir", ] @@ -1857,9 +1857,9 @@ checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" dependencies = [ "serde_derive", ] @@ -1877,20 +1877,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.60", ] [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "itoa", "ryu", @@ -1982,9 +1982,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.59" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -2014,22 +2014,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.60", ] [[package]] @@ -2165,7 +2165,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.60", ] [[package]] @@ -2304,7 +2304,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.60", "wasm-bindgen-shared", ] @@ -2349,7 +2349,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.60", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2362,9 +2362,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-encoder" -version = "0.203.0" +version = "0.205.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e3b46a0d9d9143d57aa926c42e2af284b5cb8f0c7b71079afc7a6fca42db50" +checksum = "90e95b3563d164f33c1cfb0a7efbd5940c37710019be10cd09f800fdec8b0e5c" dependencies = [ "leb128", ] @@ -2570,18 +2570,18 @@ dependencies = [ [[package]] name = "wasmparser-nostd" -version = "0.100.1" +version = "0.100.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157cab83003221bfd385833ab587a039f5d6fa7304854042ba358a3b09e0724" +checksum = "d5a015fe95f3504a94bb1462c717aae75253e39b9dd6c3fb1062c934535c64aa" dependencies = [ "indexmap-nostd", ] [[package]] name = "wast" -version = "203.0.0" +version = "205.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "872020f79fa7a09aeaec308d0ba60816e2f808d9b402e2f89d2a9c76eda482cd" +checksum = "441a6a195b3b5245e26d450bbcc91366c6b652382a22f63cbe3c73240e13b2bb" dependencies = [ "bumpalo", "leb128", @@ -2592,9 +2592,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.203.0" +version = "1.205.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2913b554125048798744fce03832d5330d87624782f8ec6ad8c9716a1ef7a37" +checksum = "19832624d606e7c6bf3cd4caa73578ecec5eac30c768269256d19c79900beb18" dependencies = [ "wast", ] @@ -2875,5 +2875,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.59", + "syn 2.0.60", ] diff --git a/Cargo.toml b/Cargo.toml index 0f66fa9..2902cd9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ test=false [dev-dependencies] color-eyre="0.6" tinywasm={path="crates/tinywasm", features=["unsafe"]} -wat={version="1.203"} +wat={version="1.205"} pretty_env_logger="0.5" [profile.bench] diff --git a/benchmarks/Cargo.toml b/benchmarks/Cargo.toml index b678fc0..96802ed 100644 --- a/benchmarks/Cargo.toml +++ b/benchmarks/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace=true [dependencies] criterion={version="0.5", features=["html_reports"]} tinywasm={path="../crates/tinywasm", features=["unsafe"]} -wat={version="1.203"} +wat={version="1.205"} wasmi={version="0.31", features=["std"]} wasmer={version="4.2", features=["cranelift", "singlepass"]} argon2={version="0.5"} diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 9606e51..f83ac55 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -19,7 +19,7 @@ argh="0.1" color-eyre={version="0.6", default-features=false} log="0.4" pretty_env_logger="0.5" -wast={version="203.0", optional=true} +wast={version="205.0", optional=true} [features] default=["wat"] diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index ab12470..bd1e91f 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -20,7 +20,7 @@ libm={version="0.2", default-features=false} [dev-dependencies] wasm-testsuite={path="../wasm-testsuite"} -wast={version="203.0"} +wast={version="205.0"} owo-colors={version="4.0"} eyre={version="0.6"} serde_json={version="1.0"} From 704a8da24bb9e85e712fbb745ff4d4e1b54b6914 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Wed, 1 May 2024 16:34:47 +0200 Subject: [PATCH 04/15] chore: update dependencies Signed-off-by: Henry Gressmann --- Cargo.lock | 145 +++++++++++-------------------------- Cargo.toml | 2 +- benchmarks/Cargo.toml | 2 +- crates/cli/Cargo.toml | 2 +- crates/tinywasm/Cargo.toml | 2 +- 5 files changed, 48 insertions(+), 105 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72b37de..adc7151 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -293,9 +293,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.95" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" +checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" [[package]] name = "cfg-if" @@ -314,7 +314,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.5", + "windows-targets", ] [[package]] @@ -721,7 +721,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", @@ -916,9 +916,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -987,9 +987,9 @@ dependencies = [ [[package]] name = "freetype" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efc8599a3078adf8edeb86c71e9f8fa7d88af5ca31e806a867756081f90f5d83" +checksum = "5a440748e063798e4893ceb877151e84acef9bea9a8c6800645cf3f1b3a7806e" dependencies = [ "freetype-sys", "libc", @@ -997,9 +997,9 @@ dependencies = [ [[package]] name = "freetype-sys" -version = "0.19.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66ee28c39a43d89fbed8b4798fb4ba56722cfd2b5af81f9326c27614ba88ecd5" +checksum = "0e7edc5b9669349acfda99533e9e0bcf26a51862ab43b08ee7745c55d28eb134" dependencies = [ "cc", "libc", @@ -1103,9 +1103,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash 0.8.11", ] @@ -1198,7 +1198,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -1262,9 +1262,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libloading" @@ -1273,7 +1273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.52.5", + "windows-targets", ] [[package]] @@ -1294,9 +1294,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1419,15 +1419,15 @@ checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -1648,11 +1648,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", ] [[package]] @@ -1857,9 +1857,9 @@ checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.198" +version = "1.0.199" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" dependencies = [ "serde_derive", ] @@ -1877,9 +1877,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.198" +version = "1.0.199" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" dependencies = [ "proc-macro2", "quote", @@ -2141,7 +2141,7 @@ checksum = "b02b9566a3c8b98f29dd9821d0584de1ad0290cdc9132296f66fbf4015001bb1" dependencies = [ "ahash 0.8.11", "bitflags 2.5.0", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "indexmap 2.2.6", "semver", ] @@ -2234,9 +2234,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "url" @@ -2362,9 +2362,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-encoder" -version = "0.205.0" +version = "0.206.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e95b3563d164f33c1cfb0a7efbd5940c37710019be10cd09f800fdec8b0e5c" +checksum = "d759312e1137f199096d80a70be685899cd7d3d09c572836bb2e9b69b4dc3b1e" dependencies = [ "leb128", ] @@ -2579,9 +2579,9 @@ dependencies = [ [[package]] name = "wast" -version = "205.0.0" +version = "206.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "441a6a195b3b5245e26d450bbcc91366c6b652382a22f63cbe3c73240e13b2bb" +checksum = "68586953ee4960b1f5d84ebf26df3b628b17e6173bc088e0acfbce431469795a" dependencies = [ "bumpalo", "leb128", @@ -2592,9 +2592,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.205.0" +version = "1.206.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19832624d606e7c6bf3cd4caa73578ecec5eac30c768269256d19c79900beb18" +checksum = "da4c6f2606276c6e991aebf441b2fc92c517807393f039992a3e0ad873efe4ad" dependencies = [ "wast", ] @@ -2633,11 +2633,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -2652,7 +2652,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.5", + "windows-targets", ] [[package]] @@ -2674,22 +2674,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -2698,22 +2683,16 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_gnullvm", "windows_aarch64_msvc 0.52.5", "windows_i686_gnu 0.52.5", "windows_i686_gnullvm", "windows_i686_msvc 0.52.5", "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_gnullvm", "windows_x86_64_msvc 0.52.5", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.5" @@ -2726,12 +2705,6 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd761fd3eb9ab8cc1ed81e56e567f02dd82c4c837e48ac3b2181b9ffc5060807" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.5" @@ -2744,12 +2717,6 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cab0cf703a96bab2dc0c02c0fa748491294bf9b7feb27e1f4f96340f208ada0e" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.5" @@ -2768,12 +2735,6 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cfdbe89cc9ad7ce618ba34abc34bbb6c36d99e96cae2245b7943cd75ee773d0" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.5" @@ -2786,24 +2747,12 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4dd9b0c0e9ece7bb22e84d70d01b71c6d6248b81a3c60d11869451b4cb24784" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.5" @@ -2816,12 +2765,6 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff1e4aa646495048ec7f3ffddc411e1d829c026a2ec62b39da15c1055e406eaa" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.5" diff --git a/Cargo.toml b/Cargo.toml index 2902cd9..8972894 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ test=false [dev-dependencies] color-eyre="0.6" tinywasm={path="crates/tinywasm", features=["unsafe"]} -wat={version="1.205"} +wat={version="1.206"} pretty_env_logger="0.5" [profile.bench] diff --git a/benchmarks/Cargo.toml b/benchmarks/Cargo.toml index 96802ed..f2cfe69 100644 --- a/benchmarks/Cargo.toml +++ b/benchmarks/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace=true [dependencies] criterion={version="0.5", features=["html_reports"]} tinywasm={path="../crates/tinywasm", features=["unsafe"]} -wat={version="1.205"} +wat={version="1.206"} wasmi={version="0.31", features=["std"]} wasmer={version="4.2", features=["cranelift", "singlepass"]} argon2={version="0.5"} diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index f83ac55..ab0324f 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -19,7 +19,7 @@ argh="0.1" color-eyre={version="0.6", default-features=false} log="0.4" pretty_env_logger="0.5" -wast={version="205.0", optional=true} +wast={version="206.0", optional=true} [features] default=["wat"] diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index bd1e91f..f601ef5 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -20,7 +20,7 @@ libm={version="0.2", default-features=false} [dev-dependencies] wasm-testsuite={path="../wasm-testsuite"} -wast={version="205.0"} +wast={version="206.0"} owo-colors={version="4.0"} eyre={version="0.6"} serde_json={version="1.0"} From 81dc6e7062ed86945a6253c6edaffe62ddabc631 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Wed, 1 May 2024 17:35:52 +0200 Subject: [PATCH 05/15] feat: switch back to upstream wasmparser Signed-off-by: Henry Gressmann --- Cargo.lock | 60 ++++++++++---------------------------- crates/parser/Cargo.toml | 5 ++-- crates/parser/src/lib.rs | 8 +++-- crates/parser/src/visit.rs | 22 +++++++++++--- examples/rust/build.sh | 2 +- 5 files changed, 41 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index adc7151..27486ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,7 +35,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "const-random", "once_cell", "version_check", "zerocopy", @@ -408,26 +407,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6" -[[package]] -name = "const-random" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" -dependencies = [ - "const-random-macro", -] - -[[package]] -name = "const-random-macro" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" -dependencies = [ - "getrandom", - "once_cell", - "tiny-keccak", -] - [[package]] name = "core-foundation" version = "0.9.4" @@ -2042,15 +2021,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - [[package]] name = "tinytemplate" version = "1.2.1" @@ -2111,7 +2081,7 @@ version = "0.6.0" dependencies = [ "log", "tinywasm-types", - "tinywasm-wasmparser", + "wasmparser 0.206.0", ] [[package]] @@ -2133,19 +2103,6 @@ dependencies = [ "rkyv", ] -[[package]] -name = "tinywasm-wasmparser" -version = "0.202.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b02b9566a3c8b98f29dd9821d0584de1ad0290cdc9132296f66fbf4015001bb1" -dependencies = [ - "ahash 0.8.11", - "bitflags 2.5.0", - "hashbrown 0.14.5", - "indexmap 2.2.6", - "semver", -] - [[package]] name = "tracing" version = "0.1.40" @@ -2429,7 +2386,7 @@ dependencies = [ "thiserror", "wasmer-types", "wasmer-vm", - "wasmparser", + "wasmparser 0.95.0", "winapi", ] @@ -2568,6 +2525,19 @@ dependencies = [ "url", ] +[[package]] +name = "wasmparser" +version = "0.206.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39192edb55d55b41963db40fd49b0b542156f04447b5b512744a91d38567bdbc" +dependencies = [ + "ahash 0.8.11", + "bitflags 2.5.0", + "hashbrown 0.14.5", + "indexmap 2.2.6", + "semver", +] + [[package]] name = "wasmparser-nostd" version = "0.100.2" diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 6057c30..7d726d4 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -8,12 +8,11 @@ authors.workspace=true repository.workspace=true [dependencies] -# fork of wasmparser with no_std support, see https://github.com/bytecodealliance/wasmtime/issues/3495 -wasmparser={version="0.202.0", package="tinywasm-wasmparser", default-features=false} +wasmparser={version="0.206", default-features=false} log={version="0.4", optional=true} tinywasm-types={version="0.6.0", path="../types", default-features=false} [features] default=["std", "logging"] logging=["log"] -std=["tinywasm-types/std"] +std=["tinywasm-types/std", "wasmparser/std"] diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 5fb3c48..dd10f4d 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -35,7 +35,7 @@ use alloc::{string::ToString, vec::Vec}; pub use error::*; use module::ModuleReader; use tinywasm_types::WasmFunction; -use wasmparser::{Validator, WasmFeatures}; +use wasmparser::{Validator, WasmFeaturesInflated}; pub use tinywasm_types::TinyWasmModule; @@ -50,7 +50,7 @@ impl Parser { } fn create_validator(&self) -> Validator { - let features = WasmFeatures { + let features = WasmFeaturesInflated { bulk_memory: true, floats: true, multi_value: true, @@ -73,8 +73,10 @@ impl Parser { tail_call: false, threads: false, multi_memory: false, // should be working mostly + custom_page_sizes: false, + shared_everything_threads: false, }; - Validator::new_with_features(features) + Validator::new_with_features(features.into()) } /// Parse a [`TinyWasmModule`] from bytes diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index c5743b8..80dc789 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -117,12 +117,26 @@ impl FunctionBuilder { } } +macro_rules! impl_visit_operator { + ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => { + $(impl_visit_operator!(@@$proposal $op $({ $($arg: $argty),* })? => $visit);)* + }; + + (@@mvp $($rest:tt)* ) => {}; + (@@reference_types $($rest:tt)* ) => {}; + (@@sign_extension $($rest:tt)* ) => {}; + (@@saturating_float_to_int $($rest:tt)* ) => {}; + (@@bulk_memory $($rest:tt)* ) => {}; + (@@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident) => { + fn $visit(&mut self $($(,$arg: $argty)*)?) -> Result<()>{ + self.unsupported(stringify!($visit)) + } + }; +} + impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { type Output = Result<()>; - - fn visit_default(&mut self, op: &str) -> Self::Output { - self.unsupported(op) - } + wasmparser::for_each_operator!(impl_visit_operator); define_primitive_operands! { visit_br, Instruction::Br, u32, diff --git a/examples/rust/build.sh b/examples/rust/build.sh index e6d3b0d..744f9d0 100755 --- a/examples/rust/build.sh +++ b/examples/rust/build.sh @@ -6,7 +6,7 @@ exclude_wat=("tinywasm") out_dir="./target/wasm32-unknown-unknown/wasm" dest_dir="out" -features="+reference-types,+bulk-memory,+mutable-globals" +features="+reference-types,+bulk-memory,+mutable-globals,+multivalue" # ensure out dir exists mkdir -p "$dest_dir" From 11271a201633d3b07adacd07e407ac8d07e5fce3 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Thu, 9 May 2024 20:09:05 +0200 Subject: [PATCH 06/15] chore: update dependencies + test spec Signed-off-by: Henry Gressmann --- Cargo.lock | 138 ++++++++++++++---------- crates/parser/Cargo.toml | 2 +- crates/parser/src/conversion.rs | 27 ++++- crates/tinywasm/Cargo.toml | 2 +- crates/tinywasm/tests/generated/mvp.csv | 2 +- crates/wasm-testsuite/data | 2 +- 6 files changed, 108 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 27486ec..5ba99d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,9 +72,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "argh" @@ -95,7 +95,7 @@ dependencies = [ "argh_shared", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -127,9 +127,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" @@ -292,9 +292,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.96" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" [[package]] name = "cfg-if" @@ -679,7 +679,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -690,7 +690,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -846,7 +846,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -1012,9 +1012,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -1356,9 +1356,9 @@ checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -1422,9 +1422,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pathfinder_geometry" @@ -1557,9 +1557,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] @@ -1757,7 +1757,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.60", + "syn 2.0.61", "walkdir", ] @@ -1774,9 +1774,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc_version" @@ -1789,9 +1789,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -1824,21 +1824,21 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "self_cell" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.199" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" dependencies = [ "serde_derive", ] @@ -1856,20 +1856,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.199" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -1961,9 +1961,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.60" +version = "2.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" dependencies = [ "proc-macro2", "quote", @@ -1993,22 +1993,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -2060,7 +2060,7 @@ dependencies = [ "tinywasm-parser", "tinywasm-types", "wasm-testsuite", - "wast", + "wast 207.0.0", ] [[package]] @@ -2072,7 +2072,7 @@ dependencies = [ "log", "pretty_env_logger", "tinywasm", - "wast", + "wast 206.0.0", ] [[package]] @@ -2081,7 +2081,7 @@ version = "0.6.0" dependencies = [ "log", "tinywasm-types", - "wasmparser 0.206.0", + "wasmparser 0.207.0", ] [[package]] @@ -2122,7 +2122,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] [[package]] @@ -2261,7 +2261,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", "wasm-bindgen-shared", ] @@ -2306,7 +2306,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2326,6 +2326,15 @@ dependencies = [ "leb128", ] +[[package]] +name = "wasm-encoder" +version = "0.207.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d996306fb3aeaee0d9157adbe2f670df0236caf19f6728b221e92d0f27b3fe17" +dependencies = [ + "leb128", +] + [[package]] name = "wasm-testsuite" version = "0.3.0" @@ -2527,9 +2536,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.206.0" +version = "0.207.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39192edb55d55b41963db40fd49b0b542156f04447b5b512744a91d38567bdbc" +checksum = "e19bb9f8ab07616da582ef8adb24c54f1424c7ec876720b7da9db8ec0626c92c" dependencies = [ "ahash 0.8.11", "bitflags 2.5.0", @@ -2557,16 +2566,29 @@ dependencies = [ "leb128", "memchr", "unicode-width", - "wasm-encoder", + "wasm-encoder 0.206.0", +] + +[[package]] +name = "wast" +version = "207.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e40be9fd494bfa501309487d2dc0b3f229be6842464ecbdc54eac2679c84c93" +dependencies = [ + "bumpalo", + "leb128", + "memchr", + "unicode-width", + "wasm-encoder 0.207.0", ] [[package]] name = "wat" -version = "1.206.0" +version = "1.207.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da4c6f2606276c6e991aebf441b2fc92c517807393f039992a3e0ad873efe4ad" +checksum = "8eb2b15e2d5f300f5e1209e7dc237f2549edbd4203655b6c6cab5cf180561ee7" dependencies = [ - "wast", + "wast 207.0.0", ] [[package]] @@ -2773,20 +2795,20 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.61", ] diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 7d726d4..73f430b 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -8,7 +8,7 @@ authors.workspace=true repository.workspace=true [dependencies] -wasmparser={version="0.206", default-features=false} +wasmparser={version="0.207", default-features=false, features=["validate"]} log={version="0.4", optional=true} tinywasm-types={version="0.6.0", path="../types", default-features=false} diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index ccdc308..e94986d 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -80,8 +80,16 @@ pub(crate) fn convert_module_import(import: wasmparser::Import<'_>) -> Result ImportKind::Function(ty), wasmparser::TypeRef::Table(ty) => ImportKind::Table(TableType { element_type: convert_reftype(&ty.element_type), - size_initial: ty.initial, - size_max: ty.maximum, + size_initial: ty.initial.try_into().map_err(|_| { + crate::ParseError::UnsupportedOperator(format!("Table size initial is too large: {}", ty.initial)) + })?, + size_max: if let Some(max) = ty.maximum { + Some(max.try_into().map_err(|_| { + crate::ParseError::UnsupportedOperator(format!("Table size max is too large: {}", max)) + })?) + } else { + None + }, }), wasmparser::TypeRef::Memory(ty) => ImportKind::Memory(convert_module_memory(ty)?), wasmparser::TypeRef::Global(ty) => { @@ -123,7 +131,20 @@ pub(crate) fn convert_module_tables<'a, T: IntoIterator) -> Result { let ty = convert_reftype(&table.ty.element_type); - Ok(TableType { element_type: ty, size_initial: table.ty.initial, size_max: table.ty.maximum }) + + let size_initial = table.ty.initial.try_into().map_err(|_| { + crate::ParseError::UnsupportedOperator(format!("Table size initial is too large: {}", table.ty.initial)) + })?; + let size_max = if let Some(max) = table.ty.maximum { + Some( + max.try_into() + .map_err(|_| crate::ParseError::UnsupportedOperator(format!("Table size max is too large: {}", max)))?, + ) + } else { + None + }; + + Ok(TableType { element_type: ty, size_initial: size_initial, size_max }) } pub(crate) fn convert_module_globals<'a, T: IntoIterator>>>( diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index f601ef5..5f23389 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -20,7 +20,7 @@ libm={version="0.2", default-features=false} [dev-dependencies] wasm-testsuite={path="../wasm-testsuite"} -wast={version="206.0"} +wast={version="207.0"} owo-colors={version="4.0"} eyre={version="0.6"} serde_json={version="1.0"} diff --git a/crates/tinywasm/tests/generated/mvp.csv b/crates/tinywasm/tests/generated/mvp.csv index 9830c15..10c2dbb 100644 --- a/crates/tinywasm/tests/generated/mvp.csv +++ b/crates/tinywasm/tests/generated/mvp.csv @@ -6,4 +6,4 @@ 0.4.0,20254,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":183,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.4.1,20257,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.5.0,20272,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] -0.6.0,20272,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.6.0,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/wasm-testsuite/data b/crates/wasm-testsuite/data index 16a839d..9df2c8a 160000 --- a/crates/wasm-testsuite/data +++ b/crates/wasm-testsuite/data @@ -1 +1 @@ -Subproject commit 16a839d5601c283541a84572b47637f035b51437 +Subproject commit 9df2c8a23c4d2f889c2c1a62e5fb9b744579efc5 From 53bb44f45cfda750250e0835425307e3a1d763bc Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Thu, 9 May 2024 22:36:14 +0200 Subject: [PATCH 07/15] feat: implement I32StoreLocal & I32LocalGetConstAdd Signed-off-by: Henry Gressmann --- BENCHMARKS.md | 2 +- crates/parser/src/visit.rs | 56 ++++++++++++++----- .../tinywasm/src/runtime/interpreter/mod.rs | 15 +++++ crates/types/src/instructions.rs | 6 +- examples/rust/build.sh | 4 +- 5 files changed, 63 insertions(+), 20 deletions(-) diff --git a/BENCHMARKS.md b/BENCHMARKS.md index c34e16c..746c585 100644 --- a/BENCHMARKS.md +++ b/BENCHMARKS.md @@ -36,7 +36,7 @@ All runtimes are compiled with the following settings: | ------------ | -------- | ---------- | --------- | -------------------- | | `fib` | \*\* | ` 43.60µs` | `48.27µs` | ` 44.99µs` | | `fib-rec` | `0.27ms` | ` 21.13ms` | ` 4.63ms` | ` 0.47ms` | -| `argon2id` | `0.53ms` | ` 99.16ms` | `45.00ms` | ` 4.59ms` | +| `argon2id` | `0.53ms` | ` 86.16ms` | `45.00ms` | ` 4.59ms` | | `selfhosted` | `0.05ms` | ` 1.84ms` | ` 6.51ms` | `446.48ms` | _\* Uses tinywasm's internal module format instead of `wasm`. It takes ~5.7ms to parse and validate `tinywasm.wasm`._ diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 80dc789..48eba30 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -162,7 +162,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { visit_i64_load16_u, I64Load16U, visit_i64_load32_s, I64Load32S, visit_i64_load32_u, I64Load32U, - visit_i32_store, I32Store, + // visit_i32_store, I32Store, visit_i64_store, I64Store, visit_f32_store, F32Store, visit_f64_store, F64Store, @@ -321,6 +321,37 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { visit_i64_trunc_sat_f64_u, Instruction::I64TruncSatF64U } + fn visit_i32_store(&mut self, memarg: wasmparser::MemArg) -> Self::Output { + let arg = convert_memarg(memarg); + let i32store = Instruction::I32Store { offset: arg.offset, mem_addr: arg.mem_addr }; + + if self.instructions.len() < 3 { + return self.visit(i32store); + } + + #[cold] + fn cold() {} + + if arg.mem_addr > 0xFF || arg.offset > 0xFFFF_FFFF { + cold(); + return self.visit(i32store); + } + + match self.instructions[self.instructions.len() - 2..] { + [Instruction::LocalGet(a), Instruction::I32Const(b)] => { + self.instructions.pop(); + self.instructions.pop(); + self.visit(Instruction::I32StoreLocal { + local: a, + consti32: b, + offset: arg.offset as u32, + mem_addr: arg.mem_addr as u8, + }) + } + _ => self.visit(i32store), + } + } + fn visit_local_get(&mut self, idx: u32) -> Self::Output { if let Some(instruction) = self.instructions.last_mut() { match instruction { @@ -369,19 +400,18 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { } fn visit_i32_add(&mut self) -> Self::Output { - self.visit(Instruction::I32Add) - // if self.instructions.len() < 2 { - // return self.visit(Instruction::I32Add); - // } + if self.instructions.len() < 2 { + return self.visit(Instruction::I32Add); + } - // match self.instructions[self.instructions.len() - 2..] { - // // [Instruction::LocalGet(a), Instruction::I32Const(b)] => { - // // self.instructions.pop(); - // // self.instructions.pop(); - // // self.visit(Instruction::I32LocalGetConstAdd(a, b)) - // // } - // _ => self.visit(Instruction::I32Add), - // } + match self.instructions[self.instructions.len() - 2..] { + [Instruction::LocalGet(a), Instruction::I32Const(b)] => { + self.instructions.pop(); + self.instructions.pop(); + self.visit(Instruction::I32LocalGetConstAdd(a, b)) + } + _ => self.visit(Instruction::I32Add), + } } fn visit_block(&mut self, blockty: wasmparser::BlockType) -> Self::Output { diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index 2f0328b..6ff7be1 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -689,6 +689,21 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M let res = val ^ mask; stack.values.push(res.rotate_left(*rotate_by as u32).into()); } + + I32LocalGetConstAdd(local, val) => { + let local: i32 = cf.get_local(*local as usize).into(); + stack.values.push((local + *val).into()); + } + + I32StoreLocal { local, consti32, offset, mem_addr } => { + let (mem_addr, offset) = (*mem_addr as u32, *offset as u32); + let mem = store.get_mem(module.resolve_mem_addr(mem_addr) as usize)?; + let val = consti32; + let val = val.to_le_bytes(); + let addr: u64 = cf.get_local(*local as usize).into(); + mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?; + } + i => { cold(); log::error!("unimplemented instruction: {:?}", i); diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index 402cc9a..fc6fba2 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -84,16 +84,14 @@ pub enum Instruction { // Custom Instructions BrLabel(LabelAddr), - // Not implemented yet // LocalGet + I32Const + I32Add // One of the most common patterns in the Rust compiler output - // I32LocalGetConstAdd(LocalAddr, i32), + I32LocalGetConstAdd(LocalAddr, i32), - // Not implemented yet // LocalGet + I32Const + I32Store => I32LocalGetConstStore + I32Const // Also common, helps us skip the stack entirely. // Has to be followed by an I32Const instruction - // I32StoreLocal { local: LocalAddr, offset: i32, mem_addr: MemAddr }, + I32StoreLocal { local: LocalAddr, consti32: i32, offset: u32, mem_addr: u8 }, // I64Xor + I64Const + I64RotL // Commonly used by a few crypto libraries diff --git a/examples/rust/build.sh b/examples/rust/build.sh index 744f9d0..5028741 100755 --- a/examples/rust/build.sh +++ b/examples/rust/build.sh @@ -6,7 +6,7 @@ exclude_wat=("tinywasm") out_dir="./target/wasm32-unknown-unknown/wasm" dest_dir="out" -features="+reference-types,+bulk-memory,+mutable-globals,+multivalue" +features="+reference-types,+bulk-memory,+mutable-globals" # ensure out dir exists mkdir -p "$dest_dir" @@ -15,7 +15,7 @@ for bin in "${bins[@]}"; do RUSTFLAGS="-C target-feature=$features -C panic=abort" cargo build --target wasm32-unknown-unknown --package rust-wasm-examples --profile=wasm --bin "$bin" cp "$out_dir/$bin.wasm" "$dest_dir/" - wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wasm" -Oz --enable-bulk-memory --enable-multivalue --enable-reference-types --enable-mutable-globals + wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wasm" -Oz --enable-bulk-memory --enable-reference-types --enable-mutable-globals if [[ ! " ${exclude_wat[@]} " =~ " $bin " ]]; then wasm2wat "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wat" From 9f4e3c1c17569689afa80376c5f708f3b8d37f73 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Fri, 10 May 2024 00:13:07 +0200 Subject: [PATCH 08/15] docs: update changelog Signed-off-by: Henry Gressmann --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c51b74..4c918af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.6.1] - 2024-05-10 + +**All Commits**: https://github.com/explodingcamera/tinywasm/compare/v0.6.0...v0.6.1 + +### Changed + +- Switched back to the original `wasmparser` crate, which recently added support for `no_std` +- Performance improvements +- Updated dependencies + ## [0.6.0] - 2024-03-27 **All Commits**: https://github.com/explodingcamera/tinywasm/compare/v0.5.0...v0.6.0 From 2ac04cd653898786caca198726e6b9938185b76a Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Fri, 10 May 2024 00:13:43 +0200 Subject: [PATCH 09/15] Release 0.6.1 tinywasm@0.6.1 tinywasm-cli@0.6.1 tinywasm-parser@0.6.1 tinywasm-types@0.6.1 wasm-testsuite@0.4.0 Generated by cargo-workspaces --- Cargo.lock | 10 +++++----- Cargo.toml | 2 +- crates/wasm-testsuite/Cargo.toml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ba99d4..14fddce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2048,7 +2048,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tinywasm" -version = "0.6.0" +version = "0.6.1" dependencies = [ "eyre", "libm", @@ -2065,7 +2065,7 @@ dependencies = [ [[package]] name = "tinywasm-cli" -version = "0.6.0" +version = "0.6.1" dependencies = [ "argh", "color-eyre", @@ -2077,7 +2077,7 @@ dependencies = [ [[package]] name = "tinywasm-parser" -version = "0.6.0" +version = "0.6.1" dependencies = [ "log", "tinywasm-types", @@ -2096,7 +2096,7 @@ dependencies = [ [[package]] name = "tinywasm-types" -version = "0.6.0" +version = "0.6.1" dependencies = [ "bytecheck 0.7.0", "log", @@ -2337,7 +2337,7 @@ dependencies = [ [[package]] name = "wasm-testsuite" -version = "0.3.0" +version = "0.4.0" dependencies = [ "rust-embed", ] diff --git a/Cargo.toml b/Cargo.toml index 8972894..6cac50f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ panic="abort" inherits="release" [workspace.package] -version="0.6.0" +version="0.6.1" edition="2021" license="MIT OR Apache-2.0" authors=["Henry Gressmann "] diff --git a/crates/wasm-testsuite/Cargo.toml b/crates/wasm-testsuite/Cargo.toml index 3e12db5..5a59ecd 100644 --- a/crates/wasm-testsuite/Cargo.toml +++ b/crates/wasm-testsuite/Cargo.toml @@ -1,6 +1,6 @@ [package] name="wasm-testsuite" -version="0.3.0" +version="0.4.0" description="Mirror of the WebAssembly core testsuite for use in testing WebAssembly implementations" license="Apache-2.0" readme="README.md" From 868aa006b7f1eabffd4aec3a03555012148a7df1 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Fri, 10 May 2024 18:08:00 +0200 Subject: [PATCH 10/15] chore: slight perf improvements Signed-off-by: Henry Gressmann --- BENCHMARKS.md | 18 +- benchmarks/benches/argon2id.rs | 8 +- benchmarks/benches/fibonacci.rs | 11 +- benchmarks/benches/selfhosted.rs | 11 +- benchmarks/benches/util/mod.rs | 22 +-- crates/parser/src/visit.rs | 2 +- crates/tinywasm/src/func.rs | 2 +- crates/tinywasm/src/imports.rs | 15 +- crates/tinywasm/src/instance.rs | 31 ++- crates/tinywasm/src/lib.rs | 16 +- .../src/runtime/interpreter/macros.rs | 27 ++- .../tinywasm/src/runtime/interpreter/mod.rs | 179 +++++++----------- crates/tinywasm/src/runtime/stack.rs | 4 +- .../tinywasm/src/runtime/stack/block_stack.rs | 10 +- .../tinywasm/src/runtime/stack/call_stack.rs | 15 +- .../tinywasm/src/runtime/stack/value_stack.rs | 12 +- crates/tinywasm/src/runtime/value.rs | 53 ++---- crates/tinywasm/src/store/data.rs | 10 +- crates/tinywasm/src/store/mod.rs | 40 ++-- crates/tinywasm/src/store/table.rs | 11 +- crates/tinywasm/tests/generated/mvp.csv | 1 + crates/tinywasm/tests/testsuite/run.rs | 2 +- crates/types/src/instructions.rs | 8 +- examples/rust/analyze.py | 6 +- 24 files changed, 200 insertions(+), 314 deletions(-) diff --git a/BENCHMARKS.md b/BENCHMARKS.md index 746c585..6433be3 100644 --- a/BENCHMARKS.md +++ b/BENCHMARKS.md @@ -26,22 +26,18 @@ All runtimes are compiled with the following settings: ## Versions -- `tinywasm`: `0.4.1` +- `tinywasm`: `0.6.2` - `wasmi`: `0.31.2` -- `wasmer`: `4.2.5` +- `wasmer`: `4.2.8` ## Results -| Benchmark | Native | TinyWasm\* | Wasmi | Wasmer (Single Pass) | +| Benchmark | Native | TinyWasm | Wasmi | Wasmer (Single Pass) | | ------------ | -------- | ---------- | --------- | -------------------- | -| `fib` | \*\* | ` 43.60µs` | `48.27µs` | ` 44.99µs` | -| `fib-rec` | `0.27ms` | ` 21.13ms` | ` 4.63ms` | ` 0.47ms` | -| `argon2id` | `0.53ms` | ` 86.16ms` | `45.00ms` | ` 4.59ms` | -| `selfhosted` | `0.05ms` | ` 1.84ms` | ` 6.51ms` | `446.48ms` | - -_\* Uses tinywasm's internal module format instead of `wasm`. It takes ~5.7ms to parse and validate `tinywasm.wasm`._ - -_\*\* essentially instant as it gets computed at compile time._ +| `fib` | `0ms` | ` 19.09µs` | `18.53µs` | ` 48.09µs` | +| `fib-rec` | `0.27ms` | ` 22.22ms` | ` 4.96ms` | ` 0.47ms` | +| `argon2id` | `0.53ms` | ` 86.42ms` | `46.36ms` | ` 4.82ms` | +| `selfhosted` | `0.05ms` | ` 7.26ms` | ` 6.51ms` | `446.48ms` | ### Fib diff --git a/benchmarks/benches/argon2id.rs b/benchmarks/benches/argon2id.rs index 3046dee..0cf5af4 100644 --- a/benchmarks/benches/argon2id.rs +++ b/benchmarks/benches/argon2id.rs @@ -1,9 +1,8 @@ mod util; use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use util::wasm_to_twasm; -fn run_tinywasm(twasm: &[u8], params: (i32, i32, i32), name: &str) { - let (mut store, instance) = util::tinywasm(twasm); +fn run_tinywasm(wasm: &[u8], params: (i32, i32, i32), name: &str) { + let (mut store, instance) = util::tinywasm(wasm); let argon2 = instance.exported_func::<(i32, i32, i32), i32>(&store, name).expect("exported_func"); argon2.call(&mut store, params).expect("call"); } @@ -38,7 +37,6 @@ fn run_native(params: (i32, i32, i32)) { const ARGON2ID: &[u8] = include_bytes!("../../examples/rust/out/argon2id.wasm"); fn criterion_benchmark(c: &mut Criterion) { - let twasm = wasm_to_twasm(ARGON2ID); let params = (1000, 2, 1); let mut group = c.benchmark_group("argon2id"); @@ -46,7 +44,7 @@ fn criterion_benchmark(c: &mut Criterion) { group.sample_size(10); group.bench_function("native", |b| b.iter(|| run_native(black_box(params)))); - group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm, black_box(params), "argon2id"))); + group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(ARGON2ID, black_box(params), "argon2id"))); group.bench_function("wasmi", |b| b.iter(|| run_wasmi(ARGON2ID, black_box(params), "argon2id"))); group.bench_function("wasmer", |b| b.iter(|| run_wasmer(ARGON2ID, black_box(params), "argon2id"))); } diff --git a/benchmarks/benches/fibonacci.rs b/benchmarks/benches/fibonacci.rs index b391285..15c09ac 100644 --- a/benchmarks/benches/fibonacci.rs +++ b/benchmarks/benches/fibonacci.rs @@ -1,9 +1,8 @@ mod util; use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use util::wasm_to_twasm; -fn run_tinywasm(twasm: &[u8], iterations: i32, name: &str) { - let (mut store, instance) = util::tinywasm(twasm); +fn run_tinywasm(wasm: &[u8], iterations: i32, name: &str) { + let (mut store, instance) = util::tinywasm(wasm); let fib = instance.exported_func::(&store, name).expect("exported_func"); fib.call(&mut store, iterations).expect("call"); } @@ -47,12 +46,10 @@ fn run_native_recursive(n: i32) -> i32 { const FIBONACCI: &[u8] = include_bytes!("../../examples/rust/out/fibonacci.wasm"); fn criterion_benchmark(c: &mut Criterion) { - let twasm = wasm_to_twasm(FIBONACCI); - { let mut group = c.benchmark_group("fibonacci"); group.bench_function("native", |b| b.iter(|| run_native(black_box(60)))); - group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm, black_box(60), "fibonacci"))); + group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(FIBONACCI, black_box(60), "fibonacci"))); group.bench_function("wasmi", |b| b.iter(|| run_wasmi(FIBONACCI, black_box(60), "fibonacci"))); group.bench_function("wasmer", |b| b.iter(|| run_wasmer(FIBONACCI, black_box(60), "fibonacci"))); } @@ -61,7 +58,7 @@ fn criterion_benchmark(c: &mut Criterion) { let mut group = c.benchmark_group("fibonacci-recursive"); group.measurement_time(std::time::Duration::from_secs(5)); group.bench_function("native", |b| b.iter(|| run_native_recursive(black_box(26)))); - group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm, black_box(26), "fibonacci_recursive"))); + group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(FIBONACCI, black_box(26), "fibonacci_recursive"))); group.bench_function("wasmi", |b| b.iter(|| run_wasmi(FIBONACCI, black_box(26), "fibonacci_recursive"))); group.bench_function("wasmer", |b| b.iter(|| run_wasmer(FIBONACCI, black_box(26), "fibonacci_recursive"))); } diff --git a/benchmarks/benches/selfhosted.rs b/benchmarks/benches/selfhosted.rs index 02d44ac..21ea79f 100644 --- a/benchmarks/benches/selfhosted.rs +++ b/benchmarks/benches/selfhosted.rs @@ -1,5 +1,4 @@ mod util; -use crate::util::twasm_to_module; use criterion::{criterion_group, criterion_main, Criterion}; fn run_native() { @@ -15,7 +14,7 @@ fn run_native() { fn run_tinywasm(twasm: &[u8]) { use tinywasm::*; - let module = twasm_to_module(twasm); + let module = Module::parse_bytes(twasm).expect("Module::parse_bytes"); let mut store = Store::default(); let mut imports = Imports::default(); imports.define("env", "printi32", Extern::typed_func(|_: FuncContext<'_>, _: i32| Ok(()))).expect("define"); @@ -54,15 +53,9 @@ fn run_wasmer(wasm: &[u8]) { const TINYWASM: &[u8] = include_bytes!("../../examples/rust/out/tinywasm.wasm"); fn criterion_benchmark(c: &mut Criterion) { { - let mut group = c.benchmark_group("selfhosted-parse"); - group.bench_function("tinywasm", |b| b.iter(|| util::parse_wasm(TINYWASM))); - } - - { - let twasm = util::wasm_to_twasm(TINYWASM); let mut group = c.benchmark_group("selfhosted"); group.bench_function("native", |b| b.iter(run_native)); - group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(&twasm))); + group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(TINYWASM))); group.bench_function("wasmi", |b| b.iter(|| run_wasmi(TINYWASM))); group.bench_function("wasmer", |b| b.iter(|| run_wasmer(TINYWASM))); } diff --git a/benchmarks/benches/util/mod.rs b/benchmarks/benches/util/mod.rs index f75ce66..2961046 100644 --- a/benchmarks/benches/util/mod.rs +++ b/benchmarks/benches/util/mod.rs @@ -1,26 +1,8 @@ #![allow(dead_code)] -use tinywasm::{parser::Parser, types::TinyWasmModule}; - -pub fn parse_wasm(wasm: &[u8]) -> TinyWasmModule { - let parser = Parser::new(); - parser.parse_module_bytes(wasm).expect("parse_module_bytes") -} - -pub fn wasm_to_twasm(wasm: &[u8]) -> Vec { - let parser = Parser::new(); - let res = parser.parse_module_bytes(wasm).expect("parse_module_bytes"); - res.serialize_twasm().to_vec() -} - -#[inline] -pub fn twasm_to_module(twasm: &[u8]) -> tinywasm::Module { - unsafe { TinyWasmModule::from_twasm_unchecked(twasm) }.into() -} - -pub fn tinywasm(twasm: &[u8]) -> (tinywasm::Store, tinywasm::ModuleInstance) { +pub fn tinywasm(wasm: &[u8]) -> (tinywasm::Store, tinywasm::ModuleInstance) { use tinywasm::*; - let module = twasm_to_module(twasm); + let module = Module::parse_bytes(wasm).expect("Module::parse_bytes"); let mut store = Store::default(); let imports = Imports::default(); let instance = ModuleInstance::instantiate(&mut store, module, Some(imports)).expect("instantiate"); diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 48eba30..c3afee7 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -343,7 +343,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { self.instructions.pop(); self.visit(Instruction::I32StoreLocal { local: a, - consti32: b, + const_i32: b, offset: arg.offset as u32, mem_addr: arg.mem_addr as u8, }) diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs index d7f7ca1..95b7cc0 100644 --- a/crates/tinywasm/src/func.rs +++ b/crates/tinywasm/src/func.rs @@ -49,7 +49,7 @@ impl FuncHandle { return Err(Error::Other("Type mismatch".into())); } - let func_inst = store.get_func(self.addr as usize)?; + let func_inst = store.get_func(self.addr)?; let wasm_func = match &func_inst.func { Function::Host(host_func) => { let func = &host_func.clone().func; diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs index 67ac360..7c9e955 100644 --- a/crates/tinywasm/src/imports.rs +++ b/crates/tinywasm/src/imports.rs @@ -226,11 +226,8 @@ pub struct Imports { } pub(crate) enum ResolvedExtern { - // already in the store - Store(S), - - // needs to be added to the store, provided value - Extern(V), + Store(S), // already in the store + Extern(V), // needs to be added to the store, provided value } pub(crate) struct ResolvedImports { @@ -391,17 +388,17 @@ impl Imports { match (val, &import.kind) { (ExternVal::Global(global_addr), ImportKind::Global(ty)) => { - let global = store.get_global(global_addr as usize)?; + let global = store.get_global(global_addr)?; Self::compare_types(import, &global.borrow().ty, ty)?; imports.globals.push(global_addr); } (ExternVal::Table(table_addr), ImportKind::Table(ty)) => { - let table = store.get_table(table_addr as usize)?; + let table = store.get_table(table_addr)?; Self::compare_table_types(import, &table.borrow().kind, ty)?; imports.tables.push(table_addr); } (ExternVal::Memory(memory_addr), ImportKind::Memory(ty)) => { - let mem = store.get_mem(memory_addr as usize)?; + let mem = store.get_mem(memory_addr)?; let (size, kind) = { let mem = mem.borrow(); (mem.page_count(), mem.kind) @@ -410,7 +407,7 @@ impl Imports { imports.memories.push(memory_addr); } (ExternVal::Func(func_addr), ImportKind::Function(ty)) => { - let func = store.get_func(func_addr as usize)?; + let func = store.get_func(func_addr)?; let import_func_type = module .data .func_types diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs index 3fc4fe0..8a663c4 100644 --- a/crates/tinywasm/src/instance.rs +++ b/crates/tinywasm/src/instance.rs @@ -2,7 +2,7 @@ use alloc::{boxed::Box, format, rc::Rc, string::ToString}; use tinywasm_types::*; use crate::func::{FromWasmValueTuple, IntoWasmValueTuple}; -use crate::{log, Error, FuncHandle, FuncHandleTyped, Imports, MemoryRef, MemoryRefMut, Module, Result, Store}; +use crate::{Error, FuncHandle, FuncHandleTyped, Imports, MemoryRef, MemoryRefMut, Module, Result, Store}; /// An instanciated WebAssembly module /// @@ -61,13 +61,9 @@ impl ModuleInstance { // don't need to create a auxiliary frame etc. let idx = store.next_module_instance_idx(); - log::info!("Instantiating module at index {}", idx); - let imports = imports.unwrap_or_default(); - - let mut addrs = imports.link(store, &module, idx)?; + let mut addrs = imports.unwrap_or_default().link(store, &module, idx)?; let data = module.data; - // TODO: check if the compiler correctly optimizes this to prevent wasted allocations addrs.funcs.extend(store.init_funcs(data.funcs.into(), idx)?); addrs.tables.extend(store.init_tables(data.table_types.into(), idx)?); addrs.memories.extend(store.init_memories(data.memory_types.into(), idx)?); @@ -110,15 +106,14 @@ impl ModuleInstance { /// Get a export by name pub fn export_addr(&self, name: &str) -> Option { let exports = self.0.exports.iter().find(|e| e.name == name.into())?; - let kind = exports.kind.clone(); - let addr = match kind { + let addr = match exports.kind { ExternalKind::Func => self.0.func_addrs.get(exports.index as usize)?, ExternalKind::Table => self.0.table_addrs.get(exports.index as usize)?, ExternalKind::Memory => self.0.mem_addrs.get(exports.index as usize)?, ExternalKind::Global => self.0.global_addrs.get(exports.index as usize)?, }; - Some(ExternVal::new(kind, *addr)) + Some(ExternVal::new(exports.kind.clone(), *addr)) } #[inline] @@ -183,7 +178,7 @@ impl ModuleInstance { return Err(Error::Other(format!("Export is not a function: {}", name))); }; - let func_inst = store.get_func(func_addr as usize)?; + let func_inst = store.get_func(func_addr)?; let ty = func_inst.func.ty(); Ok(FuncHandle { addr: func_addr, module_addr: self.id(), name: Some(name.to_string()), ty: ty.clone() }) @@ -205,8 +200,8 @@ impl ModuleInstance { let ExternVal::Memory(mem_addr) = export else { return Err(Error::Other(format!("Export is not a memory: {}", name))); }; - let mem = self.memory(store, mem_addr)?; - Ok(mem) + + self.memory(store, mem_addr) } /// Get an exported memory by name @@ -215,21 +210,19 @@ impl ModuleInstance { let ExternVal::Memory(mem_addr) = export else { return Err(Error::Other(format!("Export is not a memory: {}", name))); }; - let mem = self.memory_mut(store, mem_addr)?; - Ok(mem) + + self.memory_mut(store, mem_addr) } /// Get a memory by address pub fn memory<'a>(&self, store: &'a mut Store, addr: MemAddr) -> Result> { - let addr = self.resolve_mem_addr(addr); - let mem = store.get_mem(addr as usize)?; + let mem = store.get_mem(self.resolve_mem_addr(addr))?; Ok(MemoryRef { instance: mem.borrow() }) } /// Get a memory by address (mutable) pub fn memory_mut<'a>(&self, store: &'a mut Store, addr: MemAddr) -> Result> { - let addr = self.resolve_mem_addr(addr); - let mem = store.get_mem(addr as usize)?; + let mem = store.get_mem(self.resolve_mem_addr(addr))?; Ok(MemoryRefMut { instance: mem.borrow_mut() }) } @@ -257,7 +250,7 @@ impl ModuleInstance { }; let func_addr = self.0.func_addrs.get(func_index as usize).expect("No func addr for start func, this is a bug"); - let func_inst = store.get_func(*func_addr as usize)?; + let func_inst = store.get_func(*func_addr)?; let ty = func_inst.func.ty(); Ok(Some(FuncHandle { module_addr: self.id(), addr: *func_addr, ty: ty.clone(), name: None })) diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs index e2d57fc..4a644fd 100644 --- a/crates/tinywasm/src/lib.rs +++ b/crates/tinywasm/src/lib.rs @@ -93,15 +93,13 @@ pub(crate) mod log { } mod error; -pub use { - error::*, - func::{FuncHandle, FuncHandleTyped}, - imports::*, - instance::ModuleInstance, - module::Module, - reference::*, - store::*, -}; +pub use error::*; +pub use func::{FuncHandle, FuncHandleTyped}; +pub use imports::*; +pub use instance::ModuleInstance; +pub use module::Module; +pub use reference::*; +pub use store::*; mod func; mod imports; diff --git a/crates/tinywasm/src/runtime/interpreter/macros.rs b/crates/tinywasm/src/runtime/interpreter/macros.rs index 30f34fc..b37dedd 100644 --- a/crates/tinywasm/src/runtime/interpreter/macros.rs +++ b/crates/tinywasm/src/runtime/interpreter/macros.rs @@ -30,27 +30,24 @@ macro_rules! mem_load { let (mem_addr, offset) = $arg; let mem_idx = $module.resolve_mem_addr(*mem_addr); - let mem = $store.get_mem(mem_idx as usize)?; + let mem = $store.get_mem(mem_idx)?; let mem_ref = mem.borrow_mut(); - let addr: u64 = $stack.values.pop()?.into(); - let addr = offset.checked_add(addr).ok_or_else(|| { + let memory_out_of_bounds = || { cold(); Error::Trap(crate::Trap::MemoryOutOfBounds { offset: *offset as usize, len: core::mem::size_of::<$load_type>(), max: mem_ref.max_pages(), }) - })?; + }; - let addr: usize = addr.try_into().ok().ok_or_else(|| { - cold(); - Error::Trap(crate::Trap::MemoryOutOfBounds { - offset: *offset as usize, - len: core::mem::size_of::<$load_type>(), - max: mem_ref.max_pages(), - }) - })?; + let addr: usize = offset + .checked_add($stack.values.pop()?.into()) + .ok_or_else(memory_out_of_bounds)? + .try_into() + .ok() + .ok_or_else(memory_out_of_bounds)?; const LEN: usize = core::mem::size_of::<$load_type>(); let val = mem_ref.load_as::(addr)?; @@ -66,10 +63,11 @@ macro_rules! mem_store { ($store_type:ty, $target_type:ty, $arg:expr, $stack:ident, $store:ident, $module:ident) => {{ let (mem_addr, offset) = $arg; - let mem = $store.get_mem($module.resolve_mem_addr(*mem_addr) as usize)?; + let mem = $store.get_mem($module.resolve_mem_addr(*mem_addr))?; let val: $store_type = $stack.values.pop()?.into(); let val = val.to_le_bytes(); let addr: u64 = $stack.values.pop()?.into(); + mem.borrow_mut().store((*offset + addr) as usize, val.len(), &val)?; }}; } @@ -163,8 +161,7 @@ macro_rules! arithmetic { /// Apply an arithmetic method to a single value on the stack macro_rules! arithmetic_single { ($op:ident, $ty:ty, $stack:ident) => {{ - let a: $ty = $stack.values.pop()?.into(); - $stack.values.push((a.$op() as $ty).into()); + arithmetic_single!($op, $ty, $ty, $stack) }}; ($op:ident, $from:ty, $to:ty, $stack:ident) => {{ diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index 6ff7be1..da37e80 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -22,42 +22,39 @@ use no_std_floats::NoStdFloatExt; impl InterpreterRuntime { // #[inline(always)] // a small 2-3% performance improvement in some cases pub(crate) fn exec(&self, store: &mut Store, stack: &mut Stack) -> Result<()> { - // The current call frame, gets updated inside of exec_one - let mut cf = stack.call_stack.pop()?; - - // The function to execute, gets updated from ExecResult::Call - let mut current_module = store.get_module_instance_raw(cf.func_instance.1); + let mut call_frame = stack.call_stack.pop()?; + let mut current_module = store.get_module_instance_raw(call_frame.func_instance.1); loop { - match exec_one(&mut cf, stack, store, ¤t_module) { + match exec_one(&mut call_frame, stack, store, ¤t_module) { + // return from the function + Ok(ExecResult::Return) => return Ok(()), + + // continue to the next instruction and increment the instruction pointer + Ok(ExecResult::Ok) => call_frame.instr_ptr += 1, + // Continue execution at the new top of the call stack Ok(ExecResult::Call) => { - let old = cf.block_ptr; - cf = stack.call_stack.pop()?; + let old = call_frame.block_ptr; + call_frame = stack.call_stack.pop()?; - if old > cf.block_ptr { + if old > call_frame.block_ptr { stack.blocks.truncate(old); } // keeping the pointer seperate from the call frame is about 2% faster // than storing it in the call frame - if cf.func_instance.1 != current_module.id() { - current_module.swap_with(cf.func_instance.1, store); + if call_frame.func_instance.1 != current_module.id() { + current_module.swap_with(call_frame.func_instance.1, store); } } - // return from the function - Ok(ExecResult::Return) => return Ok(()), - - // continue to the next instruction and increment the instruction pointer - Ok(ExecResult::Ok) => cf.instr_ptr += 1, - // trap the program Err(error) => { - cf.instr_ptr += 1; + call_frame.instr_ptr += 1; // push the call frame back onto the stack so that it can be resumed // if the trap can be handled - stack.call_stack.push(cf)?; + stack.call_stack.push(call_frame)?; return Err(error); } } @@ -89,7 +86,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M // unreasonable complexity. This *should* be optimized to a jump table. // See https://pliniker.github.io/post/dispatchers/ use tinywasm_types::Instruction::*; - match cf.current_instruction() { + match &instrs[cf.instr_ptr as usize] { Nop => { /* do nothing */ } Unreachable => { cold(); @@ -113,8 +110,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M Call(v) => { // prepare the call frame - let func_idx = module.resolve_func_addr(*v); - let func_inst = store.get_func(func_idx as usize)?.clone(); + let func_inst = store.get_func(module.resolve_func_addr(*v))?.clone(); let wasm_func = match &func_inst.func { crate::Function::Wasm(wasm_func) => wasm_func.clone(), @@ -140,17 +136,17 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M } CallIndirect(type_addr, table_addr) => { - let table = store.get_table(module.resolve_table_addr(*table_addr) as usize)?; + let table = store.get_table(module.resolve_table_addr(*table_addr))?; let table_idx = stack.values.pop_t::()?; // verify that the table is of the right type, this should be validated by the parser already let func_ref = { let table = table.borrow(); assert!(table.kind.element_type == ValType::RefFunc, "table is not of type funcref"); - table.get(table_idx as usize)?.addr().ok_or(Trap::UninitializedElement { index: table_idx as usize })? + table.get(table_idx)?.addr().ok_or(Trap::UninitializedElement { index: table_idx as usize })? }; - let func_inst = store.get_func(func_ref as usize)?.clone(); + let func_inst = store.get_func(func_ref)?.clone(); let call_ty = module.func_ty(*type_addr); let wasm_func = match func_inst.func { @@ -315,22 +311,21 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M stack.values.truncate_keep(block.stack_ptr, block.results as u32); } - LocalGet(local_index) => stack.values.push(cf.get_local(*local_index as usize)), - LocalSet(local_index) => cf.set_local(*local_index as usize, stack.values.pop()?), + LocalGet(local_index) => stack.values.push(cf.get_local(*local_index)), + LocalSet(local_index) => cf.set_local(*local_index, stack.values.pop()?), LocalTee(local_index) => cf.set_local( - *local_index as usize, + *local_index, *stack.values.last().expect("localtee: stack is empty. this should have been validated by the parser"), ), GlobalGet(global_index) => { - let idx = module.resolve_global_addr(*global_index); - let global = store.get_global_val(idx as usize)?; + let global = store.get_global_val(module.resolve_global_addr(*global_index))?; stack.values.push(global); } GlobalSet(global_index) => { let idx = module.resolve_global_addr(*global_index); - store.set_global_val(idx as usize, stack.values.pop()?)?; + store.set_global_val(idx, stack.values.pop()?)?; } I32Const(val) => stack.values.push((*val).into()), @@ -344,7 +339,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M } let mem_idx = module.resolve_mem_addr(*addr); - let mem = store.get_mem(mem_idx as usize)?; + let mem = store.get_mem(mem_idx)?; stack.values.push((mem.borrow().page_count() as i32).into()); } @@ -353,16 +348,11 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M return Err(Error::UnsupportedFeature("memory.grow with byte != 0".to_string())); } - let mem_idx = module.resolve_mem_addr(*addr); - let mem = store.get_mem(mem_idx as usize)?; - - let (res, prev_size) = { - let mut mem = mem.borrow_mut(); - let prev_size = mem.page_count() as i32; - (mem.grow(stack.values.pop_t::()?), prev_size) - }; + let mem = store.get_mem(module.resolve_mem_addr(*addr))?; + let mut mem = mem.borrow_mut(); + let prev_size = mem.page_count() as i32; - match res { + match mem.grow(stack.values.pop_t::()?) { Some(_) => stack.values.push(prev_size.into()), None => stack.values.push((-1).into()), } @@ -374,7 +364,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M let src: i32 = stack.values.pop()?.into(); let dst: i32 = stack.values.pop()?.into(); - let mem = store.get_mem(module.resolve_mem_addr(*from) as usize)?; + let mem = store.get_mem(module.resolve_mem_addr(*from))?; let mut mem = mem.borrow_mut(); if from == to { @@ -382,7 +372,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M mem.copy_within(dst as usize, src as usize, size as usize)?; } else { // copy between two memories - let mem2 = store.get_mem(module.resolve_mem_addr(*to) as usize)?; + let mem2 = store.get_mem(module.resolve_mem_addr(*to))?; let mut mem2 = mem2.borrow_mut(); mem2.copy_from_slice(dst as usize, mem.load(src as usize, size as usize)?)?; } @@ -393,9 +383,8 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M let val: i32 = stack.values.pop()?.into(); let dst: i32 = stack.values.pop()?.into(); - let mem = store.get_mem(module.resolve_mem_addr(*addr) as usize)?; - let mut mem = mem.borrow_mut(); - mem.fill(dst as usize, size as usize, val as u8)?; + let mem = store.get_mem(module.resolve_mem_addr(*addr))?; + mem.borrow_mut().fill(dst as usize, size as usize, val as u8)?; } MemoryInit(data_index, mem_index) => { @@ -403,7 +392,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M let offset = stack.values.pop_t::()? as usize; let dst = stack.values.pop_t::()? as usize; - let data = match &store.get_data(module.resolve_data_addr(*data_index) as usize)?.data { + let data = match &store.get_data(module.resolve_data_addr(*data_index))?.data { Some(data) => data, None => return Err(Trap::MemoryOutOfBounds { offset: 0, len: 0, max: 0 }.into()), }; @@ -412,18 +401,11 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M return Err(Trap::MemoryOutOfBounds { offset, len: size, max: data.len() }.into()); } - let mem = store.get_mem(module.resolve_mem_addr(*mem_index) as usize)?; - let mut mem = mem.borrow_mut(); - - // mem.store checks bounds - mem.store(dst, size, &data[offset..(offset + size)])?; + let mem = store.get_mem(module.resolve_mem_addr(*mem_index))?; + mem.borrow_mut().store(dst, size, &data[offset..(offset + size)])?; // mem.store checks bounds } - DataDrop(data_index) => { - let data_idx = module.resolve_data_addr(*data_index); - let data = store.get_data_mut(data_idx as usize)?; - data.drop(); - } + DataDrop(data_index) => store.get_data_mut(module.resolve_data_addr(*data_index))?.drop(), I32Store { mem_addr, offset } => mem_store!(i32, (mem_addr, offset), stack, store, module), I64Store { mem_addr, offset } => mem_store!(i64, (mem_addr, offset), stack, store, module), @@ -600,32 +582,28 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M TableGet(table_index) => { let table_idx = module.resolve_table_addr(*table_index); - let table = store.get_table(table_idx as usize)?; - let idx = stack.values.pop_t::()? as usize; + let table = store.get_table(table_idx)?; + let idx = stack.values.pop_t::()?; let v = table.borrow().get_wasm_val(idx)?; stack.values.push(v.into()); } TableSet(table_index) => { let table_idx = module.resolve_table_addr(*table_index); - let table = store.get_table(table_idx as usize)?; + let table = store.get_table(table_idx)?; let val = stack.values.pop_t::()?; - let idx = stack.values.pop_t::()? as usize; + let idx = stack.values.pop_t::()?; table.borrow_mut().set(idx, val)?; } TableSize(table_index) => { - let table_idx = module.resolve_table_addr(*table_index); - let table = store.get_table(table_idx as usize)?; + let table = store.get_table(module.resolve_table_addr(*table_index))?; stack.values.push(table.borrow().size().into()); } TableInit(table_index, elem_index) => { - let table_idx = module.resolve_table_addr(*table_index); - let table = store.get_table(table_idx as usize)?; - - let elem_idx = module.resolve_elem_addr(*elem_index); - let elem = store.get_elem(elem_idx as usize)?; + let table = store.get_table(module.resolve_table_addr(*table_index))?; + let elem = store.get_elem(module.resolve_elem_addr(*elem_index))?; if let ElementKind::Passive = elem.kind { return Err(Trap::TableOutOfBounds { offset: 0, len: 0, max: 0 }.into()); @@ -648,62 +626,41 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M I64TruncSatF64U => arithmetic_single!(trunc, f64, u64, stack), // custom instructions - LocalGet2(a, b) => { - stack.values.extend_from_slice(&[cf.get_local(*a as usize), cf.get_local(*b as usize)]); - } - LocalGet3(a, b, c) => { - stack.values.extend_from_slice(&[ - cf.get_local(*a as usize), - cf.get_local(*b as usize), - cf.get_local(*c as usize), - ]); - } - // LocalGet4(a, b, c, d) => { - // stack.values.extend_from_slice(&[ - // cf.get_local(*a as usize), - // cf.get_local(*b as usize), - // cf.get_local(*c as usize), - // cf.get_local(*d as usize), - // ]); - // } + LocalGet2(a, b) => stack.values.extend_from_slice(&[cf.get_local(*a), cf.get_local(*b)]), + LocalGet3(a, b, c) => stack.values.extend_from_slice(&[cf.get_local(*a), cf.get_local(*b), cf.get_local(*c)]), + LocalTeeGet(a, b) => { - #[inline] - fn local_tee_get(cf: &mut CallFrame, stack: &mut Stack, a: u32, b: u32) -> Result<()> { - let last = *stack - .values - .last() - .expect("localtee: stack is empty. this should have been validated by the parser"); - cf.set_local(a as usize, last); - stack.values.push(cf.get_local(b as usize)); - Ok(()) + #[inline(always)] + fn local_tee_get(cf: &mut CallFrame, stack: &mut Stack, a: u32, b: u32) { + let last = match stack.values.last() { + Ok(v) => v, + Err(_) => unreachable!("localtee: stack is empty. this should have been validated by the parser"), + }; + + cf.set_local(a, *last); + stack.values.push(cf.get_local(b)); } - local_tee_get(cf, stack, *a, *b)?; - } - LocalGetSet(a, b) => { - let a = cf.get_local(*a as usize); - cf.set_local(*b as usize, a); + + local_tee_get(cf, stack, *a, *b); } + LocalGetSet(a, b) => cf.set_local(*b, cf.get_local(*a)), I64XorConstRotl(rotate_by) => { - let val = stack.values.pop_t::()?; - let mask = stack.values.pop_t::()?; + let val: i64 = stack.values.pop()?.into(); + let mask: i64 = stack.values.pop()?.into(); let res = val ^ mask; stack.values.push(res.rotate_left(*rotate_by as u32).into()); } - I32LocalGetConstAdd(local, val) => { - let local: i32 = cf.get_local(*local as usize).into(); + let local: i32 = cf.get_local(*local).into(); stack.values.push((local + *val).into()); } - - I32StoreLocal { local, consti32, offset, mem_addr } => { + I32StoreLocal { local, const_i32: consti32, offset, mem_addr } => { let (mem_addr, offset) = (*mem_addr as u32, *offset as u32); - let mem = store.get_mem(module.resolve_mem_addr(mem_addr) as usize)?; - let val = consti32; - let val = val.to_le_bytes(); - let addr: u64 = cf.get_local(*local as usize).into(); + let mem = store.get_mem(module.resolve_mem_addr(mem_addr))?; + let val = consti32.to_le_bytes(); + let addr: u64 = cf.get_local(*local).into(); mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?; } - i => { cold(); log::error!("unimplemented instruction: {:?}", i); diff --git a/crates/tinywasm/src/runtime/stack.rs b/crates/tinywasm/src/runtime/stack.rs index 3db3c4b..a64b234 100644 --- a/crates/tinywasm/src/runtime/stack.rs +++ b/crates/tinywasm/src/runtime/stack.rs @@ -2,7 +2,7 @@ mod block_stack; mod call_stack; mod value_stack; -use self::{call_stack::CallStack, value_stack::ValueStack}; +pub(crate) use self::{call_stack::CallStack, value_stack::ValueStack}; pub(crate) use block_stack::{BlockFrame, BlockStack, BlockType}; pub(crate) use call_stack::CallFrame; @@ -16,6 +16,6 @@ pub struct Stack { impl Stack { pub(crate) fn new(call_frame: CallFrame) -> Self { - Self { values: ValueStack::default(), blocks: BlockStack::default(), call_stack: CallStack::new(call_frame) } + Self { values: ValueStack::default(), blocks: BlockStack::new(), call_stack: CallStack::new(call_frame) } } } diff --git a/crates/tinywasm/src/runtime/stack/block_stack.rs b/crates/tinywasm/src/runtime/stack/block_stack.rs index 719dc00..2b38cb9 100644 --- a/crates/tinywasm/src/runtime/stack/block_stack.rs +++ b/crates/tinywasm/src/runtime/stack/block_stack.rs @@ -2,10 +2,16 @@ use crate::{unlikely, Error, ModuleInstance, Result}; use alloc::vec::Vec; use tinywasm_types::BlockArgs; -#[derive(Debug, Clone, Default)] -pub(crate) struct BlockStack(Vec); // TODO: maybe Box<[LabelFrame]> by analyzing the label count when parsing the module? +#[derive(Debug, Clone)] +pub(crate) struct BlockStack(Vec); impl BlockStack { + pub(crate) fn new() -> Self { + let mut vec = Vec::new(); + vec.reserve(128); // gives a slight performance over with_capacity + Self(vec) + } + #[inline] pub(crate) fn len(&self) -> usize { self.0.len() diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs index c242b74..d436657 100644 --- a/crates/tinywasm/src/runtime/stack/call_stack.rs +++ b/crates/tinywasm/src/runtime/stack/call_stack.rs @@ -1,5 +1,5 @@ use alloc::{boxed::Box, rc::Rc, vec::Vec}; -use tinywasm_types::{Instruction, ModuleInstanceAddr, WasmFunction}; +use tinywasm_types::{Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction}; use crate::runtime::{BlockType, RawWasmValue}; use crate::unlikely; @@ -136,22 +136,17 @@ impl CallFrame { } #[inline] - pub(crate) fn set_local(&mut self, local_index: usize, value: RawWasmValue) { - self.locals[local_index] = value; + pub(crate) fn set_local(&mut self, local_index: LocalAddr, value: RawWasmValue) { + self.locals[local_index as usize] = value; } #[inline] - pub(crate) fn get_local(&self, local_index: usize) -> RawWasmValue { - self.locals[local_index] + pub(crate) fn get_local(&self, local_index: LocalAddr) -> RawWasmValue { + self.locals[local_index as usize] } #[inline(always)] pub(crate) fn instructions(&self) -> &[Instruction] { &self.func_instance.0.instructions } - - #[inline(always)] - pub(crate) fn current_instruction(&self) -> &Instruction { - &self.func_instance.0.instructions[self.instr_ptr as usize] - } } diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs index 2fa03e9..aa00a64 100644 --- a/crates/tinywasm/src/runtime/stack/value_stack.rs +++ b/crates/tinywasm/src/runtime/stack/value_stack.rs @@ -4,8 +4,7 @@ use crate::{cold, runtime::RawWasmValue, unlikely, Error, Result}; use alloc::vec::Vec; use tinywasm_types::{ValType, WasmValue}; -pub(crate) const MIN_VALUE_STACK_SIZE: usize = 1024; -// pub(crate) const MAX_VALUE_STACK_SIZE: usize = 1024 * 1024; +pub(crate) const MIN_VALUE_STACK_SIZE: usize = 1024 * 128; #[derive(Debug)] pub(crate) struct ValueStack { @@ -14,7 +13,9 @@ pub(crate) struct ValueStack { impl Default for ValueStack { fn default() -> Self { - Self { stack: Vec::with_capacity(MIN_VALUE_STACK_SIZE) } + let mut vec = Vec::new(); + vec.reserve(MIN_VALUE_STACK_SIZE); // gives a slight performance over with_capacity + Self { stack: vec } } } @@ -85,7 +86,7 @@ impl ValueStack { match self.stack.pop() { Some(v) => Ok(v.into()), None => { - cold(); + cold(); // 20+ performance improvement most of the time Err(Error::ValueStackUnderflow) } } @@ -104,8 +105,7 @@ impl ValueStack { #[inline] pub(crate) fn pop_params(&mut self, types: &[ValType]) -> Result> { - let res = self.pop_n_rev(types.len())?.zip(types.iter()).map(|(v, ty)| v.attach_type(*ty)).collect(); - Ok(res) + Ok(self.pop_n_rev(types.len())?.zip(types.iter()).map(|(v, ty)| v.attach_type(*ty)).collect()) } #[inline] diff --git a/crates/tinywasm/src/runtime/value.rs b/crates/tinywasm/src/runtime/value.rs index 2381657..55aa9fe 100644 --- a/crates/tinywasm/src/runtime/value.rs +++ b/crates/tinywasm/src/runtime/value.rs @@ -7,7 +7,6 @@ use tinywasm_types::{ValType, WasmValue}; /// /// See [`WasmValue`] for the public representation. #[derive(Clone, Copy, Default, PartialEq, Eq)] -// pub struct RawWasmValue([u8; 16]); pub struct RawWasmValue([u8; 8]); impl Debug for RawWasmValue { @@ -29,23 +28,14 @@ impl RawWasmValue { ValType::I64 => WasmValue::I64(self.into()), ValType::F32 => WasmValue::F32(f32::from_bits(self.into())), ValType::F64 => WasmValue::F64(f64::from_bits(self.into())), - // ValType::V128 => WasmValue::V128(self.into()), - ValType::RefExtern => { - let val: i64 = self.into(); - if val < 0 { - WasmValue::RefNull(ValType::RefExtern) - } else { - WasmValue::RefExtern(val as u32) - } - } - ValType::RefFunc => { - let val: i64 = self.into(); - if val < 0 { - WasmValue::RefNull(ValType::RefFunc) - } else { - WasmValue::RefFunc(val as u32) - } - } + ValType::RefExtern => match i64::from(self) { + v if v < 0 => WasmValue::RefNull(ValType::RefExtern), + addr => WasmValue::RefExtern(addr as u32), + }, + ValType::RefFunc => match i64::from(self) { + v if v < 0 => WasmValue::RefNull(ValType::RefFunc), + addr => WasmValue::RefFunc(addr as u32), + }, } } } @@ -58,7 +48,6 @@ impl From for RawWasmValue { WasmValue::I64(i) => Self::from(i), WasmValue::F32(i) => Self::from(i), WasmValue::F64(i) => Self::from(i), - // WasmValue::V128(i) => Self::from(i), WasmValue::RefExtern(v) => Self::from(v as i64), WasmValue::RefFunc(v) => Self::from(v as i64), WasmValue::RefNull(_) => Self::from(-1i64), @@ -88,24 +77,18 @@ macro_rules! impl_from_raw_wasm_value { }; } -type RawValue = u64; -type RawValueRep = [u8; 8]; - // This all looks like a lot of extra steps, but the compiler will optimize it all away. -impl_from_raw_wasm_value!(i32, |x| x as RawValue, |x: RawValueRep| i32::from_ne_bytes(x[0..4].try_into().unwrap())); -impl_from_raw_wasm_value!(i64, |x| x as RawValue, |x: RawValueRep| i64::from_ne_bytes(x[0..8].try_into().unwrap())); -impl_from_raw_wasm_value!(f32, |x| f32::to_bits(x) as RawValue, |x: RawValueRep| f32::from_bits(u32::from_ne_bytes( +impl_from_raw_wasm_value!(i32, |x| x as u64, |x: [u8; 8]| i32::from_ne_bytes(x[0..4].try_into().unwrap())); +impl_from_raw_wasm_value!(i64, |x| x as u64, |x: [u8; 8]| i64::from_ne_bytes(x[0..8].try_into().unwrap())); +impl_from_raw_wasm_value!(u8, |x| x as u64, |x: [u8; 8]| u8::from_ne_bytes(x[0..1].try_into().unwrap())); +impl_from_raw_wasm_value!(u16, |x| x as u64, |x: [u8; 8]| u16::from_ne_bytes(x[0..2].try_into().unwrap())); +impl_from_raw_wasm_value!(u32, |x| x as u64, |x: [u8; 8]| u32::from_ne_bytes(x[0..4].try_into().unwrap())); +impl_from_raw_wasm_value!(u64, |x| x as u64, |x: [u8; 8]| u64::from_ne_bytes(x[0..8].try_into().unwrap())); +impl_from_raw_wasm_value!(i8, |x| x as u64, |x: [u8; 8]| i8::from_ne_bytes(x[0..1].try_into().unwrap())); +impl_from_raw_wasm_value!(i16, |x| x as u64, |x: [u8; 8]| i16::from_ne_bytes(x[0..2].try_into().unwrap())); +impl_from_raw_wasm_value!(f32, |x| f32::to_bits(x) as u64, |x: [u8; 8]| f32::from_bits(u32::from_ne_bytes( x[0..4].try_into().unwrap() ))); -impl_from_raw_wasm_value!(f64, |x| f64::to_bits(x) as RawValue, |x: RawValueRep| f64::from_bits(u64::from_ne_bytes( +impl_from_raw_wasm_value!(f64, |x| f64::to_bits(x) as u64, |x: [u8; 8]| f64::from_bits(u64::from_ne_bytes( x[0..8].try_into().unwrap() ))); - -impl_from_raw_wasm_value!(u8, |x| x as RawValue, |x: RawValueRep| u8::from_ne_bytes(x[0..1].try_into().unwrap())); -impl_from_raw_wasm_value!(u16, |x| x as RawValue, |x: RawValueRep| u16::from_ne_bytes(x[0..2].try_into().unwrap())); -impl_from_raw_wasm_value!(u32, |x| x as RawValue, |x: RawValueRep| u32::from_ne_bytes(x[0..4].try_into().unwrap())); -impl_from_raw_wasm_value!(u64, |x| x as RawValue, |x: RawValueRep| u64::from_ne_bytes(x[0..8].try_into().unwrap())); -// impl_from_raw_wasm_value!(u128, |x| x, |x: RawValueRep| RawValue::from_ne_bytes(x)); - -impl_from_raw_wasm_value!(i8, |x| x as RawValue, |x: RawValueRep| i8::from_ne_bytes(x[0..1].try_into().unwrap())); -impl_from_raw_wasm_value!(i16, |x| x as RawValue, |x: RawValueRep| i16::from_ne_bytes(x[0..2].try_into().unwrap())); diff --git a/crates/tinywasm/src/store/data.rs b/crates/tinywasm/src/store/data.rs index efbb858..935e761 100644 --- a/crates/tinywasm/src/store/data.rs +++ b/crates/tinywasm/src/store/data.rs @@ -15,13 +15,7 @@ impl DataInstance { Self { data, _owner: owner } } - pub(crate) fn drop(&mut self) -> Option<()> { - match self.data { - None => None, - Some(_) => { - let _ = self.data.take(); - Some(()) - } - } + pub(crate) fn drop(&mut self) { + self.data.is_some().then(|| self.data.take()); } } diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs index 1cdcff3..fddf3f4 100644 --- a/crates/tinywasm/src/store/mod.rs +++ b/crates/tinywasm/src/store/mod.rs @@ -123,56 +123,60 @@ impl Store { /// Get the function at the actual index in the store #[inline] - pub(crate) fn get_func(&self, addr: usize) -> Result<&FunctionInstance> { - self.data.funcs.get(addr).ok_or_else(|| Self::not_found_error("function")) + pub(crate) fn get_func(&self, addr: FuncAddr) -> Result<&FunctionInstance> { + self.data.funcs.get(addr as usize).ok_or_else(|| Self::not_found_error("function")) } /// Get the memory at the actual index in the store #[inline] - pub(crate) fn get_mem(&self, addr: usize) -> Result<&Rc>> { - self.data.memories.get(addr).ok_or_else(|| Self::not_found_error("memory")) + pub(crate) fn get_mem(&self, addr: MemAddr) -> Result<&Rc>> { + self.data.memories.get(addr as usize).ok_or_else(|| Self::not_found_error("memory")) } /// Get the table at the actual index in the store #[inline] - pub(crate) fn get_table(&self, addr: usize) -> Result<&Rc>> { - self.data.tables.get(addr).ok_or_else(|| Self::not_found_error("table")) + pub(crate) fn get_table(&self, addr: TableAddr) -> Result<&Rc>> { + self.data.tables.get(addr as usize).ok_or_else(|| Self::not_found_error("table")) } /// Get the data at the actual index in the store #[inline] - pub(crate) fn get_data(&self, addr: usize) -> Result<&DataInstance> { - self.data.datas.get(addr).ok_or_else(|| Self::not_found_error("data")) + pub(crate) fn get_data(&self, addr: DataAddr) -> Result<&DataInstance> { + self.data.datas.get(addr as usize).ok_or_else(|| Self::not_found_error("data")) } /// Get the data at the actual index in the store #[inline] - pub(crate) fn get_data_mut(&mut self, addr: usize) -> Result<&mut DataInstance> { - self.data.datas.get_mut(addr).ok_or_else(|| Self::not_found_error("data")) + pub(crate) fn get_data_mut(&mut self, addr: DataAddr) -> Result<&mut DataInstance> { + self.data.datas.get_mut(addr as usize).ok_or_else(|| Self::not_found_error("data")) } /// Get the element at the actual index in the store #[inline] - pub(crate) fn get_elem(&self, addr: usize) -> Result<&ElementInstance> { - self.data.elements.get(addr).ok_or_else(|| Self::not_found_error("element")) + pub(crate) fn get_elem(&self, addr: ElemAddr) -> Result<&ElementInstance> { + self.data.elements.get(addr as usize).ok_or_else(|| Self::not_found_error("element")) } /// Get the global at the actual index in the store #[inline] - pub(crate) fn get_global(&self, addr: usize) -> Result<&Rc>> { - self.data.globals.get(addr).ok_or_else(|| Self::not_found_error("global")) + pub(crate) fn get_global(&self, addr: GlobalAddr) -> Result<&Rc>> { + self.data.globals.get(addr as usize).ok_or_else(|| Self::not_found_error("global")) } /// Get the global at the actual index in the store #[inline] - pub fn get_global_val(&self, addr: usize) -> Result { - self.data.globals.get(addr).ok_or_else(|| Self::not_found_error("global")).map(|global| global.borrow().value) + pub fn get_global_val(&self, addr: MemAddr) -> Result { + self.data + .globals + .get(addr as usize) + .ok_or_else(|| Self::not_found_error("global")) + .map(|global| global.borrow().value) } /// Set the global at the actual index in the store #[inline] - pub(crate) fn set_global_val(&mut self, addr: usize, value: RawWasmValue) -> Result<()> { - let global = self.data.globals.get(addr).ok_or_else(|| Self::not_found_error("global")); + pub(crate) fn set_global_val(&mut self, addr: MemAddr, value: RawWasmValue) -> Result<()> { + let global = self.data.globals.get(addr as usize).ok_or_else(|| Self::not_found_error("global")); global.map(|global| global.borrow_mut().value = value) } } diff --git a/crates/tinywasm/src/store/table.rs b/crates/tinywasm/src/store/table.rs index 52c35f6..a094a14 100644 --- a/crates/tinywasm/src/store/table.rs +++ b/crates/tinywasm/src/store/table.rs @@ -20,7 +20,7 @@ impl TableInstance { Self { elements: vec![TableElement::Uninitialized; kind.size_initial as usize], kind, _owner: owner } } - pub(crate) fn get_wasm_val(&self, addr: usize) -> Result { + pub(crate) fn get_wasm_val(&self, addr: TableAddr) -> Result { let val = self.get(addr)?.addr(); Ok(match self.kind.element_type { @@ -30,12 +30,13 @@ impl TableInstance { }) } - pub(crate) fn get(&self, addr: usize) -> Result<&TableElement> { - self.elements.get(addr).ok_or_else(|| Error::Trap(Trap::UndefinedElement { index: addr })) + pub(crate) fn get(&self, addr: TableAddr) -> Result<&TableElement> { + self.elements.get(addr as usize).ok_or_else(|| Error::Trap(Trap::UndefinedElement { index: addr as usize })) } - pub(crate) fn set(&mut self, table_idx: usize, value: Addr) -> Result<()> { - self.grow_to_fit(table_idx + 1).map(|_| self.elements[table_idx] = TableElement::Initialized(value)) + pub(crate) fn set(&mut self, table_idx: TableAddr, value: Addr) -> Result<()> { + self.grow_to_fit(table_idx as usize + 1) + .map(|_| self.elements[table_idx as usize] = TableElement::Initialized(value)) } pub(crate) fn grow_to_fit(&mut self, new_size: usize) -> Result<()> { diff --git a/crates/tinywasm/tests/generated/mvp.csv b/crates/tinywasm/tests/generated/mvp.csv index 10c2dbb..6cf7fea 100644 --- a/crates/tinywasm/tests/generated/mvp.csv +++ b/crates/tinywasm/tests/generated/mvp.csv @@ -7,3 +7,4 @@ 0.4.1,20257,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.5.0,20272,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.6.0,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.6.1,20278,0,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/tinywasm/tests/testsuite/run.rs b/crates/tinywasm/tests/testsuite/run.rs index aed23bd..1de633f 100644 --- a/crates/tinywasm/tests/testsuite/run.rs +++ b/crates/tinywasm/tests/testsuite/run.rs @@ -408,7 +408,7 @@ impl TestSuite { let module_global = match match module.export_addr(global) { Some(ExternVal::Global(addr)) => { - store.get_global_val(addr as usize).map_err(|_| eyre!("failed to get global")) + store.get_global_val(addr).map_err(|_| eyre!("failed to get global")) } _ => Err(eyre!("no module to get global from")), } { diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index fc6fba2..96e8810 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -91,7 +91,7 @@ pub enum Instruction { // LocalGet + I32Const + I32Store => I32LocalGetConstStore + I32Const // Also common, helps us skip the stack entirely. // Has to be followed by an I32Const instruction - I32StoreLocal { local: LocalAddr, consti32: i32, offset: u32, mem_addr: u8 }, + I32StoreLocal { local: LocalAddr, const_i32: i32, offset: u32, mem_addr: u8 }, // I64Xor + I64Const + I64RotL // Commonly used by a few crypto libraries @@ -103,12 +103,6 @@ pub enum Instruction { LocalGet3(LocalAddr, LocalAddr, LocalAddr), LocalGetSet(LocalAddr, LocalAddr), - // Not implemented yet - // I32AddConst(i32), - // I32SubConst(i32), - // I64AddConst(i64), - // I64SubConst(i64), - // Control Instructions // See Unreachable, diff --git a/examples/rust/analyze.py b/examples/rust/analyze.py index a450a1a..a134a00 100644 --- a/examples/rust/analyze.py +++ b/examples/rust/analyze.py @@ -13,17 +13,17 @@ file_path = sys.argv[1] # Regex to match WASM operators, adjust as necessary -operator_pattern = re.compile(r'\b[a-z0-9_]+\.[a-z0-9_]+\b') +operator_pattern = re.compile(r"\b[a-z0-9_]+\.[a-z0-9_]+\b") # Read the file -with open(file_path, 'r') as file: +with open(file_path, "r") as file: content = file.read() # Find all operators operators = operator_pattern.findall(content) # Generate sequences of three consecutive operators -sequences = [' '.join(operators[i:i+seq_len]) for i in range(len(operators) - 2)] +sequences = [" ".join(operators[i : i + seq_len]) for i in range(len(operators) - 2)] # Count occurrences of each sequence sequence_counts = Counter(sequences) From b2b39468325b9ed7043fed48a15a77b83b13d63e Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Sat, 11 May 2024 21:07:41 +0200 Subject: [PATCH 11/15] chore: simplify code Signed-off-by: Henry Gressmann --- crates/parser/src/conversion.rs | 52 ++-- crates/parser/src/visit.rs | 58 ++--- crates/tinywasm/src/imports.rs | 2 +- .../tinywasm/src/runtime/interpreter/mod.rs | 146 +++++------ .../tinywasm/src/runtime/stack/block_stack.rs | 6 +- .../tinywasm/src/runtime/stack/call_stack.rs | 23 +- .../tinywasm/src/runtime/stack/value_stack.rs | 6 +- crates/tinywasm/tests/generated/2.0.csv | 1 + crates/types/src/instructions.rs | 232 +++++------------- 9 files changed, 176 insertions(+), 350 deletions(-) diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index e94986d..4e4434b 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -83,12 +83,11 @@ pub(crate) fn convert_module_import(import: wasmparser::Import<'_>) -> Result Some(max.try_into().map_err(|_| { crate::ParseError::UnsupportedOperator(format!("Table size max is too large: {}", max)) - })?) - } else { - None + })?), + None => None, }, }), wasmparser::TypeRef::Memory(ty) => ImportKind::Memory(convert_module_memory(ty)?), @@ -105,10 +104,7 @@ pub(crate) fn convert_module_import(import: wasmparser::Import<'_>) -> Result>>( memory_types: T, ) -> Result> { - let memory_type = - memory_types.into_iter().map(|memory| convert_module_memory(memory?)).collect::>>()?; - - Ok(memory_type) + memory_types.into_iter().map(|memory| convert_module_memory(memory?)).collect::>>() } pub(crate) fn convert_module_memory(memory: wasmparser::MemoryType) -> Result { @@ -125,26 +121,23 @@ pub(crate) fn convert_module_memory(memory: wasmparser::MemoryType) -> Result>>>( table_types: T, ) -> Result> { - let table_type = table_types.into_iter().map(|table| convert_module_table(table?)).collect::>>()?; - Ok(table_type) + table_types.into_iter().map(|table| convert_module_table(table?)).collect::>>() } pub(crate) fn convert_module_table(table: wasmparser::Table<'_>) -> Result { - let ty = convert_reftype(&table.ty.element_type); - let size_initial = table.ty.initial.try_into().map_err(|_| { crate::ParseError::UnsupportedOperator(format!("Table size initial is too large: {}", table.ty.initial)) })?; - let size_max = if let Some(max) = table.ty.maximum { - Some( + + let size_max = match table.ty.maximum { + Some(max) => Some( max.try_into() .map_err(|_| crate::ParseError::UnsupportedOperator(format!("Table size max is too large: {}", max)))?, - ) - } else { - None + ), + None => None, }; - Ok(TableType { element_type: ty, size_initial: size_initial, size_max }) + Ok(TableType { element_type: convert_reftype(&table.ty.element_type), size_initial: size_initial, size_max }) } pub(crate) fn convert_module_globals<'a, T: IntoIterator>>>( @@ -208,12 +201,8 @@ pub(crate) fn convert_module_type(ty: wasmparser::RecGroup) -> Result )); } let ty = types.next().unwrap().unwrap_func(); - - let params = - ty.params().iter().map(|p| Ok(convert_valtype(p))).collect::>>()?.into_boxed_slice(); - - let results = - ty.results().iter().map(|p| Ok(convert_valtype(p))).collect::>>()?.into_boxed_slice(); + let params = ty.params().iter().map(convert_valtype).collect::>().into_boxed_slice(); + let results = ty.results().iter().map(convert_valtype).collect::>().into_boxed_slice(); Ok(FuncType { params, results }) } @@ -235,14 +224,13 @@ pub(crate) fn convert_reftype(reftype: &wasmparser::RefType) -> ValType { } pub(crate) fn convert_valtype(valtype: &wasmparser::ValType) -> ValType { - use wasmparser::ValType::*; match valtype { - I32 => ValType::I32, - I64 => ValType::I64, - F32 => ValType::F32, - F64 => ValType::F64, - Ref(r) => convert_reftype(r), - V128 => unimplemented!("128-bit values are not supported yet"), + wasmparser::ValType::I32 => ValType::I32, + wasmparser::ValType::I64 => ValType::I64, + wasmparser::ValType::F32 => ValType::F32, + wasmparser::ValType::F64 => ValType::F64, + wasmparser::ValType::Ref(r) => convert_reftype(r), + wasmparser::ValType::V128 => unimplemented!("128-bit values are not supported yet"), } } diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index c3afee7..8b9e15d 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -3,7 +3,7 @@ use crate::{conversion::convert_blocktype, Result}; use crate::conversion::{convert_heaptype, convert_memarg, convert_valtype}; use alloc::string::ToString; use alloc::{boxed::Box, format, vec::Vec}; -use tinywasm_types::{BlockArgsPacked, Instruction}; +use tinywasm_types::Instruction; use wasmparser::{FuncValidator, FunctionBody, VisitOperator, WasmModuleResources}; struct ValidateThenVisit<'a, T, U>(T, &'a mut U); @@ -65,16 +65,14 @@ macro_rules! define_primitive_operands { ($($name:ident, $instr:expr, $ty:ty),*) => { $( fn $name(&mut self, arg: $ty) -> Self::Output { - self.instructions.push($instr(arg)); - Ok(()) + Ok(self.instructions.push($instr(arg))) } )* }; ($($name:ident, $instr:expr, $ty:ty, $ty2:ty),*) => { $( fn $name(&mut self, arg: $ty, arg2: $ty) -> Self::Output { - self.instructions.push($instr(arg, arg2)); - Ok(()) + Ok(self.instructions.push($instr(arg, arg2))) } )* }; @@ -112,8 +110,7 @@ impl FunctionBuilder { #[inline] fn visit(&mut self, op: Instruction) -> Result<()> { - self.instructions.push(op); - Ok(()) + Ok(self.instructions.push(op)) } } @@ -162,7 +159,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { visit_i64_load16_u, I64Load16U, visit_i64_load32_s, I64Load32S, visit_i64_load32_u, I64Load32U, - // visit_i32_store, I32Store, + // visit_i32_store, I32Store, custom implementation visit_i64_store, I64Store, visit_f32_store, F32Store, visit_f64_store, F64Store, @@ -325,15 +322,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { let arg = convert_memarg(memarg); let i32store = Instruction::I32Store { offset: arg.offset, mem_addr: arg.mem_addr }; - if self.instructions.len() < 3 { - return self.visit(i32store); - } - - #[cold] - fn cold() {} - - if arg.mem_addr > 0xFF || arg.offset > 0xFFFF_FFFF { - cold(); + if self.instructions.len() < 3 || arg.mem_addr > 0xFF || arg.offset > 0xFFFF_FFFF { return self.visit(i32store); } @@ -353,31 +342,22 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { } fn visit_local_get(&mut self, idx: u32) -> Self::Output { - if let Some(instruction) = self.instructions.last_mut() { - match instruction { - Instruction::LocalGet(a) => *instruction = Instruction::LocalGet2(*a, idx), - Instruction::LocalGet2(a, b) => *instruction = Instruction::LocalGet3(*a, *b, idx), - Instruction::LocalTee(a) => *instruction = Instruction::LocalTeeGet(*a, idx), - _ => return self.visit(Instruction::LocalGet(idx)), - }; - Ok(()) - } else { - self.visit(Instruction::LocalGet(idx)) - } + let Some(instruction) = self.instructions.last_mut() else { + return self.visit(Instruction::LocalGet(idx)); + }; + + match instruction { + Instruction::LocalGet(a) => *instruction = Instruction::LocalGet2(*a, idx), + Instruction::LocalGet2(a, b) => *instruction = Instruction::LocalGet3(*a, *b, idx), + Instruction::LocalTee(a) => *instruction = Instruction::LocalTeeGet(*a, idx), + _ => return self.visit(Instruction::LocalGet(idx)), + }; + + Ok(()) } fn visit_local_set(&mut self, idx: u32) -> Self::Output { self.visit(Instruction::LocalSet(idx)) - // if let Some(instruction) = self.instructions.last_mut() { - // match instruction { - // // Needs more testing, seems to make performance worse - // // Instruction::LocalGet(a) => *instruction = Instruction::LocalGetSet(*a, idx), - // _ => return self.visit(Instruction::LocalSet(idx)), - // }; - // // Ok(()) - // } else { - // self.visit(Instruction::LocalSet(idx)) - // } } fn visit_local_tee(&mut self, idx: u32) -> Self::Output { @@ -426,7 +406,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { fn visit_if(&mut self, ty: wasmparser::BlockType) -> Self::Output { self.label_ptrs.push(self.instructions.len()); - self.visit(Instruction::If(BlockArgsPacked::new(convert_blocktype(ty)), 0, 0)) + self.visit(Instruction::If(convert_blocktype(ty).into(), 0, 0)) } fn visit_else(&mut self) -> Self::Output { diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs index 7c9e955..c4bae3b 100644 --- a/crates/tinywasm/src/imports.rs +++ b/crates/tinywasm/src/imports.rs @@ -15,7 +15,7 @@ pub enum Function { /// A host function Host(Rc), - /// A function defined in WebAssembly + /// A pointer to a WebAssembly function Wasm(Rc), } diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index da37e80..5e1500f 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -1,11 +1,11 @@ use alloc::format; -use alloc::{string::ToString, vec::Vec}; +use alloc::string::ToString; use core::ops::{BitAnd, BitOr, BitXor, Neg}; use tinywasm_types::{ElementKind, ValType}; use super::{InterpreterRuntime, Stack}; use crate::runtime::{BlockFrame, BlockType, CallFrame}; -use crate::{cold, log, unlikely}; +use crate::{cold, unlikely}; use crate::{Error, FuncContext, ModuleInstance, Result, Store, Trap}; mod macros; @@ -23,13 +23,10 @@ impl InterpreterRuntime { // #[inline(always)] // a small 2-3% performance improvement in some cases pub(crate) fn exec(&self, store: &mut Store, stack: &mut Stack) -> Result<()> { let mut call_frame = stack.call_stack.pop()?; - let mut current_module = store.get_module_instance_raw(call_frame.func_instance.1); + let mut current_module = store.get_module_instance_raw(call_frame.module_addr); loop { match exec_one(&mut call_frame, stack, store, ¤t_module) { - // return from the function - Ok(ExecResult::Return) => return Ok(()), - // continue to the next instruction and increment the instruction pointer Ok(ExecResult::Ok) => call_frame.instr_ptr += 1, @@ -44,18 +41,25 @@ impl InterpreterRuntime { // keeping the pointer seperate from the call frame is about 2% faster // than storing it in the call frame - if call_frame.func_instance.1 != current_module.id() { - current_module.swap_with(call_frame.func_instance.1, store); + if call_frame.module_addr != current_module.id() { + current_module.swap_with(call_frame.module_addr, store); } } + // return from the function + Ok(ExecResult::Return) => { + cold(); + return Ok(()); + } + // trap the program - Err(error) => { + Err(e) => { + cold(); call_frame.instr_ptr += 1; // push the call frame back onto the stack so that it can be resumed // if the trap can be handled stack.call_stack.push(call_frame)?; - return Err(error); + return Err(e); } } } @@ -75,28 +79,17 @@ enum ExecResult { // this can be a 30%+ performance difference in some cases #[inline(always)] fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &ModuleInstance) -> Result { - let instrs = &cf.func_instance.0.instructions; - - if unlikely(cf.instr_ptr as usize >= instrs.len() || instrs.is_empty()) { - log::error!("instr_ptr out of bounds: {} >= {}", cf.instr_ptr, instrs.len()); - return Err(Error::Other(format!("instr_ptr out of bounds: {} >= {}", cf.instr_ptr, instrs.len()))); - } + let instrs = &cf.func_instance.instructions; // A match statement is probably the fastest way to do this without // unreasonable complexity. This *should* be optimized to a jump table. // See https://pliniker.github.io/post/dispatchers/ use tinywasm_types::Instruction::*; - match &instrs[cf.instr_ptr as usize] { + match instrs.get(cf.instr_ptr as usize).expect("instr_ptr out of bounds, this should never happen") { Nop => { /* do nothing */ } - Unreachable => { - cold(); - return Err(crate::Trap::Unreachable.into()); - } + Unreachable => return Err(crate::Trap::Unreachable.into()), Drop => stack.values.pop().map(|_| ())?, - - Select( - _valtype, // due to validation, we know that the type of the values on the stack are correct - ) => { + Select(_valtype) => { // due to validation, we know that the type of the values on the stack let cond: i32 = stack.values.pop()?.into(); let val2 = stack.values.pop()?; @@ -110,24 +103,32 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M Call(v) => { // prepare the call frame - let func_inst = store.get_func(module.resolve_func_addr(*v))?.clone(); - + let func_inst = store.get_func(module.resolve_func_addr(*v))?; let wasm_func = match &func_inst.func { - crate::Function::Wasm(wasm_func) => wasm_func.clone(), + crate::Function::Wasm(wasm_func) => wasm_func, crate::Function::Host(host_func) => { - let func = &host_func.func; + let func = &host_func.clone(); let params = stack.values.pop_params(&host_func.ty.params)?; - let res = (func)(FuncContext { store, module_addr: module.id() }, ¶ms)?; + let res = (func.func)(FuncContext { store, module_addr: module.id() }, ¶ms)?; stack.values.extend_from_typed(&res); return Ok(ExecResult::Ok); } }; let params = stack.values.pop_n_rev(wasm_func.ty.params.len())?; - let call_frame = CallFrame::new(wasm_func, func_inst.owner, params, stack.blocks.len() as u32); + let call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, stack.blocks.len() as u32); // push the call frame cf.instr_ptr += 1; // skip the call instruction + + // this is sometimes faster, and seems more efficient, but sometimes it's also a lot slower + // stack.call_stack.push(core::mem::replace(cf, call_frame))?; + // if cf.module_addr != module.id() { + // module.swap_with(cf.module_addr, store); + // } + // cf.instr_ptr -= 1; + // return Ok(ExecResult::Ok); + stack.call_stack.push(cf.clone())?; stack.call_stack.push(call_frame)?; @@ -150,10 +151,9 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M let call_ty = module.func_ty(*type_addr); let wasm_func = match func_inst.func { - crate::Function::Wasm(ref f) => f.clone(), + crate::Function::Wasm(ref f) => f, crate::Function::Host(host_func) => { if unlikely(host_func.ty != *call_ty) { - log::error!("indirect call type mismatch: {:?} != {:?}", host_func.ty, call_ty); return Err(Trap::IndirectCallTypeMismatch { actual: host_func.ty.clone(), expected: call_ty.clone(), @@ -170,16 +170,14 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M }; if unlikely(wasm_func.ty != *call_ty) { - log::error!("indirect call type mismatch: {:?} != {:?}", wasm_func.ty, call_ty); return Err( Trap::IndirectCallTypeMismatch { actual: wasm_func.ty.clone(), expected: call_ty.clone() }.into() ); } let params = stack.values.pop_n_rev(wasm_func.ty.params.len())?; - let call_frame = CallFrame::new(wasm_func, func_inst.owner, params, stack.blocks.len() as u32); + let call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, stack.blocks.len() as u32); - // push the call frame cf.instr_ptr += 1; // skip the call instruction stack.call_stack.push(cf.clone())?; stack.call_stack.push(call_frame)?; @@ -197,7 +195,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M cf.instr_ptr + *end_offset, stack.values.len() as u32, BlockType::If, - &args.unpack(), + &(*args).into(), module, ), &mut stack.values, @@ -207,20 +205,21 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M } // falsy value is on the top of the stack - if *else_offset != 0 { - let label = BlockFrame::new( - cf.instr_ptr + *else_offset, - cf.instr_ptr + *end_offset, - stack.values.len() as u32, - BlockType::Else, - &args.unpack(), - module, - ); - cf.instr_ptr += *else_offset; - cf.enter_block(label, &mut stack.values, &mut stack.blocks); - } else { + if *else_offset == 0 { cf.instr_ptr += *end_offset; + return Ok(ExecResult::Ok); } + + let label = BlockFrame::new( + cf.instr_ptr + *else_offset, + cf.instr_ptr + *end_offset, + stack.values.len() as u32, + BlockType::Else, + &(*args).into(), + module, + ); + cf.instr_ptr += *else_offset; + cf.enter_block(label, &mut stack.values, &mut stack.blocks); } Loop(args, end_offset) => { @@ -254,30 +253,18 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M } BrTable(default, len) => { - let start = cf.instr_ptr + 1; - let end = cf.instr_ptr + 1 + *len; - let instr = cf.instructions()[start as usize..end as usize] - .iter() - .map(|i| match i { - BrLabel(l) => Ok(*l), - _ => { - cold(); - panic!("Expected BrLabel, this should have been validated by the parser") - } - }) - .collect::>>()?; - - if unlikely(instr.len() != *len as usize) { - panic!( - "Expected {} BrLabel instructions, got {}, this should have been validated by the parser", - len, - instr.len() - ); + let start = (cf.instr_ptr + 1) as usize; + let end = start + *len as usize; + if end > cf.instructions().len() { + return Err(Error::Other(format!("br_table out of bounds: {} >= {}", end, cf.instructions().len()))); } let idx = stack.values.pop_t::()? as usize; - let to = instr.get(idx).unwrap_or(default); - break_to!(cf, stack, to); + match cf.instructions()[start..end].get(idx) { + None => break_to!(cf, stack, default), + Some(BrLabel(to)) => break_to!(cf, stack, to), + _ => return Err(Error::Other("br_table with invalid label".to_string())), + } } Br(v) => break_to!(cf, stack, v), @@ -294,29 +281,20 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M // We're essentially using else as a EndBlockFrame instruction for if blocks Else(end_offset) => { - let block = - stack.blocks.pop().expect("else: no label to end, this should have been validated by the parser"); - + let block = stack.blocks.pop()?; stack.values.truncate_keep(block.stack_ptr, block.results as u32); cf.instr_ptr += *end_offset; } // remove the label from the label stack EndBlockFrame => { - let block = stack - .blocks - .pop() - .expect("end blockframe: no label to end, this should have been validated by the parser"); - + let block = stack.blocks.pop()?; stack.values.truncate_keep(block.stack_ptr, block.results as u32); } LocalGet(local_index) => stack.values.push(cf.get_local(*local_index)), LocalSet(local_index) => cf.set_local(*local_index, stack.values.pop()?), - LocalTee(local_index) => cf.set_local( - *local_index, - *stack.values.last().expect("localtee: stack is empty. this should have been validated by the parser"), - ), + LocalTee(local_index) => cf.set_local(*local_index, *stack.values.last()?), GlobalGet(global_index) => { let global = store.get_global_val(module.resolve_global_addr(*global_index))?; @@ -628,7 +606,6 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M // custom instructions LocalGet2(a, b) => stack.values.extend_from_slice(&[cf.get_local(*a), cf.get_local(*b)]), LocalGet3(a, b, c) => stack.values.extend_from_slice(&[cf.get_local(*a), cf.get_local(*b), cf.get_local(*c)]), - LocalTeeGet(a, b) => { #[inline(always)] fn local_tee_get(cf: &mut CallFrame, stack: &mut Stack, a: u32, b: u32) { @@ -663,8 +640,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M } i => { cold(); - log::error!("unimplemented instruction: {:?}", i); - return Err(Error::UnsupportedFeature(alloc::format!("unimplemented instruction: {:?}", i))); + return Err(Error::UnsupportedFeature(format!("unimplemented instruction: {:?}", i))); } }; diff --git a/crates/tinywasm/src/runtime/stack/block_stack.rs b/crates/tinywasm/src/runtime/stack/block_stack.rs index 2b38cb9..a7b8ece 100644 --- a/crates/tinywasm/src/runtime/stack/block_stack.rs +++ b/crates/tinywasm/src/runtime/stack/block_stack.rs @@ -8,7 +8,7 @@ pub(crate) struct BlockStack(Vec); impl BlockStack { pub(crate) fn new() -> Self { let mut vec = Vec::new(); - vec.reserve(128); // gives a slight performance over with_capacity + vec.reserve(128); Self(vec) } @@ -17,7 +17,7 @@ impl BlockStack { self.0.len() } - #[inline] + #[inline(always)] pub(crate) fn push(&mut self, block: BlockFrame) { self.0.push(block); } @@ -63,7 +63,7 @@ pub(crate) struct BlockFrame { } impl BlockFrame { - #[inline] + #[inline(always)] pub(crate) fn new( instr_ptr: u32, end_instr_ptr: u32, diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs index d436657..060d530 100644 --- a/crates/tinywasm/src/runtime/stack/call_stack.rs +++ b/crates/tinywasm/src/runtime/stack/call_stack.rs @@ -7,8 +7,7 @@ use crate::{Error, Result, Trap}; use super::BlockFrame; -const CALL_STACK_SIZE: usize = 128; -const CALL_STACK_MAX_SIZE: usize = 1024; +const CALL_STACK_SIZE: usize = 1024; #[derive(Debug)] pub(crate) struct CallStack { @@ -18,7 +17,10 @@ pub(crate) struct CallStack { impl CallStack { #[inline] pub(crate) fn new(initial_frame: CallFrame) -> Self { - let mut stack = Self { stack: Vec::with_capacity(CALL_STACK_SIZE) }; + let mut stack = Vec::new(); + stack.reserve_exact(CALL_STACK_SIZE); + + let mut stack = Self { stack: stack }; stack.push(initial_frame).unwrap(); stack } @@ -38,7 +40,7 @@ impl CallStack { #[inline] pub(crate) fn push(&mut self, call_frame: CallFrame) -> Result<()> { - if unlikely(self.stack.len() >= CALL_STACK_MAX_SIZE) { + if unlikely(self.stack.len() >= CALL_STACK_SIZE) { return Err(Trap::CallStackOverflow.into()); } self.stack.push(call_frame); @@ -50,7 +52,8 @@ impl CallStack { pub(crate) struct CallFrame { pub(crate) instr_ptr: u32, pub(crate) block_ptr: u32, - pub(crate) func_instance: (Rc, ModuleInstanceAddr), + pub(crate) func_instance: Rc, + pub(crate) module_addr: ModuleInstanceAddr, pub(crate) locals: Box<[RawWasmValue]>, } @@ -124,15 +127,15 @@ impl CallFrame { block_ptr: u32, ) -> Self { let locals = { - let local_types = &wasm_func_inst.locals; - let total_size = local_types.len() + params.len(); - let mut locals = Vec::with_capacity(total_size); + let total_size = wasm_func_inst.locals.len() + params.len(); + let mut locals = Vec::new(); + locals.reserve_exact(total_size); locals.extend(params); locals.resize_with(total_size, RawWasmValue::default); locals.into_boxed_slice() }; - Self { instr_ptr: 0, func_instance: (wasm_func_inst, owner), locals, block_ptr } + Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, locals, block_ptr } } #[inline] @@ -147,6 +150,6 @@ impl CallFrame { #[inline(always)] pub(crate) fn instructions(&self) -> &[Instruction] { - &self.func_instance.0.instructions + &self.func_instance.instructions } } diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs index aa00a64..354898e 100644 --- a/crates/tinywasm/src/runtime/stack/value_stack.rs +++ b/crates/tinywasm/src/runtime/stack/value_stack.rs @@ -126,12 +126,10 @@ impl ValueStack { #[inline] pub(crate) fn pop_n_rev(&mut self, n: usize) -> Result> { - let len = self.stack.len(); - if unlikely(len < n) { + if unlikely(self.stack.len() < n) { return Err(Error::ValueStackUnderflow); } - let res = self.stack.drain((len - n)..); - Ok(res) + Ok(self.stack.drain((self.stack.len() - n)..)) } } diff --git a/crates/tinywasm/tests/generated/2.0.csv b/crates/tinywasm/tests/generated/2.0.csv index c97b58e..11dd840 100644 --- a/crates/tinywasm/tests/generated/2.0.csv +++ b/crates/tinywasm/tests/generated/2.0.csv @@ -2,3 +2,4 @@ 0.4.0,27549,334,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":183,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":720,"failed":60},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.4.1,27551,335,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":719,"failed":61},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] 0.5.0,27551,335,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":156,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":99,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":163,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":719,"failed":61},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.6.1,27572,335,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":162,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":112,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":118,"failed":0},{"name":"br_table.wast","passed":174,"failed":0},{"name":"bulk.wast","passed":75,"failed":42},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":170,"failed":0},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":61,"failed":0},{"name":"elem.wast","passed":98,"failed":0},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":96,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":900,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":441,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":172,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":110,"failed":0},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":186,"failed":0},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":132,"failed":0},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":97,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":79,"failed":0},{"name":"memory_copy.wast","passed":4450,"failed":0},{"name":"memory_fill.wast","passed":100,"failed":0},{"name":"memory_grow.wast","passed":96,"failed":0},{"name":"memory_init.wast","passed":240,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"ref_func.wast","passed":9,"failed":8},{"name":"ref_is_null.wast","passed":4,"failed":12},{"name":"ref_null.wast","passed":1,"failed":2},{"name":"return.wast","passed":84,"failed":0},{"name":"select.wast","passed":148,"failed":0},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table-sub.wast","passed":2,"failed":0},{"name":"table.wast","passed":19,"failed":0},{"name":"table_copy.wast","passed":1613,"failed":115},{"name":"table_fill.wast","passed":23,"failed":22},{"name":"table_get.wast","passed":10,"failed":6},{"name":"table_grow.wast","passed":21,"failed":29},{"name":"table_init.wast","passed":719,"failed":61},{"name":"table_set.wast","passed":19,"failed":7},{"name":"table_size.wast","passed":8,"failed":31},{"name":"token.wast","passed":58,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":118,"failed":0},{"name":"unreached-valid.wast","passed":7,"failed":0},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index 96e8810..ee624bd 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -15,8 +15,9 @@ pub enum BlockArgs { /// This is needed to keep the size of the Instruction enum small. /// Sadly, using #[repr(u8)] on BlockArgs itself is not possible because of the FuncType variant. pub struct BlockArgsPacked([u8; 5]); // Modifying this directly can cause runtime errors, but no UB -impl BlockArgsPacked { - pub fn new(args: BlockArgs) -> Self { + +impl From for BlockArgsPacked { + fn from(args: BlockArgs) -> Self { let mut packed = [0; 5]; match args { BlockArgs::Empty => packed[0] = 0, @@ -31,11 +32,14 @@ impl BlockArgsPacked { } Self(packed) } - pub fn unpack(&self) -> BlockArgs { - match self.0[0] { +} + +impl From for BlockArgs { + fn from(packed: BlockArgsPacked) -> Self { + match packed.0[0] { 0 => BlockArgs::Empty, - 1 => BlockArgs::Type(ValType::from_byte(self.0[1]).unwrap()), - 2 => BlockArgs::FuncType(u32::from_le_bytes(self.0[1..].try_into().unwrap())), + 1 => BlockArgs::Type(ValType::from_byte(packed.0[1]).unwrap()), + 2 => BlockArgs::FuncType(u32::from_le_bytes(packed.0[1..].try_into().unwrap())), _ => unreachable!(), } } @@ -80,30 +84,27 @@ pub enum ConstInstruction { #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))] // should be kept as small as possible (16 bytes max) +#[rustfmt::skip] pub enum Instruction { - // Custom Instructions + // > Custom Instructions BrLabel(LabelAddr), - // LocalGet + I32Const + I32Add // One of the most common patterns in the Rust compiler output I32LocalGetConstAdd(LocalAddr, i32), - // LocalGet + I32Const + I32Store => I32LocalGetConstStore + I32Const // Also common, helps us skip the stack entirely. // Has to be followed by an I32Const instruction I32StoreLocal { local: LocalAddr, const_i32: i32, offset: u32, mem_addr: u8 }, - // I64Xor + I64Const + I64RotL // Commonly used by a few crypto libraries I64XorConstRotl(i64), - // LocalTee + LocalGet LocalTeeGet(LocalAddr, LocalAddr), LocalGet2(LocalAddr, LocalAddr), LocalGet3(LocalAddr, LocalAddr, LocalAddr), LocalGetSet(LocalAddr, LocalAddr), - // Control Instructions + // > Control Instructions // See Unreachable, Nop, @@ -119,12 +120,12 @@ pub enum Instruction { Call(FuncAddr), CallIndirect(TypeAddr, TableAddr), - // Parametric Instructions + // > Parametric Instructions // See Drop, Select(Option), - // Variable Instructions + // > Variable Instructions // See LocalGet(LocalAddr), LocalSet(LocalAddr), @@ -132,7 +133,7 @@ pub enum Instruction { GlobalGet(GlobalAddr), GlobalSet(GlobalAddr), - // Memory Instructions + // > Memory Instructions I32Load { offset: u64, mem_addr: MemAddr }, I64Load { offset: u64, mem_addr: MemAddr }, F32Load { offset: u64, mem_addr: MemAddr }, @@ -159,157 +160,43 @@ pub enum Instruction { MemorySize(MemAddr, u8), MemoryGrow(MemAddr, u8), - // Constants + // > Constants I32Const(i32), I64Const(i64), F32Const(f32), F64Const(f64), - // Reference Types + // > Reference Types RefNull(ValType), RefFunc(FuncAddr), RefIsNull, - // Numeric Instructions + // > Numeric Instructions // See - I32Eqz, - I32Eq, - I32Ne, - I32LtS, - I32LtU, - I32GtS, - I32GtU, - I32LeS, - I32LeU, - I32GeS, - I32GeU, - I64Eqz, - I64Eq, - I64Ne, - I64LtS, - I64LtU, - I64GtS, - I64GtU, - I64LeS, - I64LeU, - I64GeS, - I64GeU, - F32Eq, - F32Ne, - F32Lt, - F32Gt, - F32Le, - F32Ge, - F64Eq, - F64Ne, - F64Lt, - F64Gt, - F64Le, - F64Ge, - I32Clz, - I32Ctz, - I32Popcnt, - I32Add, - I32Sub, - I32Mul, - I32DivS, - I32DivU, - I32RemS, - I32RemU, - I32And, - I32Or, - I32Xor, - I32Shl, - I32ShrS, - I32ShrU, - I32Rotl, - I32Rotr, - I64Clz, - I64Ctz, - I64Popcnt, - I64Add, - I64Sub, - I64Mul, - I64DivS, - I64DivU, - I64RemS, - I64RemU, - I64And, - I64Or, - I64Xor, - I64Shl, - I64ShrS, - I64ShrU, - I64Rotl, - I64Rotr, - F32Abs, - F32Neg, - F32Ceil, - F32Floor, - F32Trunc, - F32Nearest, - F32Sqrt, - F32Add, - F32Sub, - F32Mul, - F32Div, - F32Min, - F32Max, - F32Copysign, - F64Abs, - F64Neg, - F64Ceil, - F64Floor, - F64Trunc, - F64Nearest, - F64Sqrt, - F64Add, - F64Sub, - F64Mul, - F64Div, - F64Min, - F64Max, - F64Copysign, - I32WrapI64, - I32TruncF32S, - I32TruncF32U, - I32TruncF64S, - I32TruncF64U, - I32Extend8S, - I32Extend16S, - I64Extend8S, - I64Extend16S, - I64Extend32S, - I64ExtendI32S, - I64ExtendI32U, - I64TruncF32S, - I64TruncF32U, - I64TruncF64S, - I64TruncF64U, - F32ConvertI32S, - F32ConvertI32U, - F32ConvertI64S, - F32ConvertI64U, - F32DemoteF64, - F64ConvertI32S, - F64ConvertI32U, - F64ConvertI64S, - F64ConvertI64U, - F64PromoteF32, - I32ReinterpretF32, - I64ReinterpretF64, - F32ReinterpretI32, - F64ReinterpretI64, - I32TruncSatF32S, - I32TruncSatF32U, - I32TruncSatF64S, - I32TruncSatF64U, - I64TruncSatF32S, - I64TruncSatF32U, - I64TruncSatF64S, - I64TruncSatF64U, - - // Table Instructions + I32Eqz, I32Eq, I32Ne, I32LtS, I32LtU, I32GtS, I32GtU, I32LeS, I32LeU, I32GeS, I32GeU, + I64Eqz, I64Eq, I64Ne, I64LtS, I64LtU, I64GtS, I64GtU, I64LeS, I64LeU, I64GeS, I64GeU, + // Comparisons + F32Eq, F32Ne, F32Lt, F32Gt, F32Le, F32Ge, + F64Eq, F64Ne, F64Lt, F64Gt, F64Le, F64Ge, + I32Clz, I32Ctz, I32Popcnt, I32Add, I32Sub, I32Mul, I32DivS, I32DivU, I32RemS, I32RemU, + I64Clz, I64Ctz, I64Popcnt, I64Add, I64Sub, I64Mul, I64DivS, I64DivU, I64RemS, I64RemU, + // Bitwise + I32And, I32Or, I32Xor, I32Shl, I32ShrS, I32ShrU, I32Rotl, I32Rotr, + I64And, I64Or, I64Xor, I64Shl, I64ShrS, I64ShrU, I64Rotl, I64Rotr, + // Floating Point + F32Abs, F32Neg, F32Ceil, F32Floor, F32Trunc, F32Nearest, F32Sqrt, F32Add, F32Sub, F32Mul, F32Div, F32Min, F32Max, F32Copysign, + F64Abs, F64Neg, F64Ceil, F64Floor, F64Trunc, F64Nearest, F64Sqrt, F64Add, F64Sub, F64Mul, F64Div, F64Min, F64Max, F64Copysign, + I32WrapI64, I32TruncF32S, I32TruncF32U, I32TruncF64S, I32TruncF64U, I32Extend8S, I32Extend16S, + I64Extend8S, I64Extend16S, I64Extend32S, I64ExtendI32S, I64ExtendI32U, I64TruncF32S, I64TruncF32U, I64TruncF64S, I64TruncF64U, + F32ConvertI32S, F32ConvertI32U, F32ConvertI64S, F32ConvertI64U, F32DemoteF64, + F64ConvertI32S, F64ConvertI32U, F64ConvertI64S, F64ConvertI64U, F64PromoteF32, + // Reinterpretations (noops at runtime) + I32ReinterpretF32, I64ReinterpretF64, F32ReinterpretI32, F64ReinterpretI64, + // Saturating Float-to-Int Conversions + I32TruncSatF32S, I32TruncSatF32U, I32TruncSatF64S, I32TruncSatF64U, + I64TruncSatF32S, I64TruncSatF32U, I64TruncSatF64S, I64TruncSatF64U, + + // > Table Instructions TableInit(TableAddr, ElemAddr), TableGet(TableAddr), TableSet(TableAddr), @@ -318,7 +205,7 @@ pub enum Instruction { TableSize(TableAddr), TableFill(TableAddr), - // Bulk Memory Instructions + // > Bulk Memory Instructions MemoryInit(MemAddr, DataAddr), MemoryCopy(MemAddr, MemAddr), MemoryFill(MemAddr), @@ -331,44 +218,37 @@ mod test_blockargs_packed { #[test] fn test_empty() { - let args = BlockArgs::Empty; - let packed = BlockArgsPacked::new(args); - assert_eq!(packed.unpack(), BlockArgs::Empty); + let packed: BlockArgsPacked = BlockArgs::Empty.into(); + assert_eq!(BlockArgs::from(packed), BlockArgs::Empty); } #[test] fn test_val_type_i32() { - let args = BlockArgs::Type(ValType::I32); - let packed = BlockArgsPacked::new(args); - assert_eq!(packed.unpack(), BlockArgs::Type(ValType::I32)); + let packed: BlockArgsPacked = BlockArgs::Type(ValType::I32).into(); + assert_eq!(BlockArgs::from(packed), BlockArgs::Type(ValType::I32)); } #[test] fn test_val_type_i64() { - let args = BlockArgs::Type(ValType::I64); - let packed = BlockArgsPacked::new(args); - assert_eq!(packed.unpack(), BlockArgs::Type(ValType::I64)); + let packed: BlockArgsPacked = BlockArgs::Type(ValType::I64).into(); + assert_eq!(BlockArgs::from(packed), BlockArgs::Type(ValType::I64)); } #[test] fn test_val_type_f32() { - let args = BlockArgs::Type(ValType::F32); - let packed = BlockArgsPacked::new(args); - assert_eq!(packed.unpack(), BlockArgs::Type(ValType::F32)); + let packed: BlockArgsPacked = BlockArgs::Type(ValType::F32).into(); + assert_eq!(BlockArgs::from(packed), BlockArgs::Type(ValType::F32)); } #[test] fn test_val_type_f64() { - let args = BlockArgs::Type(ValType::F64); - let packed = BlockArgsPacked::new(args); - assert_eq!(packed.unpack(), BlockArgs::Type(ValType::F64)); + let packed: BlockArgsPacked = BlockArgs::Type(ValType::F64).into(); + assert_eq!(BlockArgs::from(packed), BlockArgs::Type(ValType::F64)); } #[test] fn test_func_type() { - let func_type = 123; // Use an arbitrary u32 value - let args = BlockArgs::FuncType(func_type); - let packed = BlockArgsPacked::new(args); - assert_eq!(packed.unpack(), BlockArgs::FuncType(func_type)); + let packed: BlockArgsPacked = BlockArgs::FuncType(0x12345678).into(); + assert_eq!(BlockArgs::from(packed), BlockArgs::FuncType(0x12345678)); } } From e771c6df456f6c6655a7850defffdbb5cc574461 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Sun, 12 May 2024 20:20:21 +0200 Subject: [PATCH 12/15] chore: clippy fixes and more tests Signed-off-by: Henry Gressmann --- crates/parser/src/conversion.rs | 2 +- crates/parser/src/visit.rs | 3 +- crates/tinywasm/src/lib.rs | 1 + .../tinywasm/src/runtime/interpreter/mod.rs | 27 ++++++------ .../tinywasm/src/runtime/stack/call_stack.rs | 2 +- .../tinywasm/src/runtime/stack/value_stack.rs | 44 +++++++++++++------ crates/tinywasm/src/runtime/value.rs | 28 +++++++++++- 7 files changed, 75 insertions(+), 32 deletions(-) diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index 4e4434b..31056a3 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -137,7 +137,7 @@ pub(crate) fn convert_module_table(table: wasmparser::Table<'_>) -> Result None, }; - Ok(TableType { element_type: convert_reftype(&table.ty.element_type), size_initial: size_initial, size_max }) + Ok(TableType { element_type: convert_reftype(&table.ty.element_type), size_initial, size_max }) } pub(crate) fn convert_module_globals<'a, T: IntoIterator>>>( diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 8b9e15d..df6fc7a 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -110,7 +110,8 @@ impl FunctionBuilder { #[inline] fn visit(&mut self, op: Instruction) -> Result<()> { - Ok(self.instructions.push(op)) + self.instructions.push(op); + Ok(()) } } diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs index 4a644fd..0bc17d6 100644 --- a/crates/tinywasm/src/lib.rs +++ b/crates/tinywasm/src/lib.rs @@ -3,6 +3,7 @@ no_crate_inject, attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_assignments, unused_variables)) ))] +#![allow(unexpected_cfgs, clippy::reserve_after_initialization)] #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms, unreachable_pub)] #![cfg_attr(nightly, feature(error_in_core))] #![cfg_attr(not(feature = "unsafe"), deny(unsafe_code))] diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index 5e1500f..404e4fe 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -138,7 +138,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M CallIndirect(type_addr, table_addr) => { let table = store.get_table(module.resolve_table_addr(*table_addr))?; - let table_idx = stack.values.pop_t::()?; + let table_idx: u32 = stack.values.pop()?.into(); // verify that the table is of the right type, this should be validated by the parser already let func_ref = { @@ -188,7 +188,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M If(args, else_offset, end_offset) => { // truthy value is on the top of the stack, so enter the then block - if stack.values.pop_t::()? != 0 { + if i32::from(stack.values.pop()?) != 0 { cf.enter_block( BlockFrame::new( cf.instr_ptr, @@ -259,8 +259,8 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M return Err(Error::Other(format!("br_table out of bounds: {} >= {}", end, cf.instructions().len()))); } - let idx = stack.values.pop_t::()? as usize; - match cf.instructions()[start..end].get(idx) { + let idx: i32 = stack.values.pop()?.into(); + match cf.instructions()[start..end].get(idx as usize) { None => break_to!(cf, stack, default), Some(BrLabel(to)) => break_to!(cf, stack, to), _ => return Err(Error::Other("br_table with invalid label".to_string())), @@ -269,7 +269,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M Br(v) => break_to!(cf, stack, v), BrIf(v) => { - if stack.values.pop_t::()? != 0 { + if i32::from(stack.values.pop()?) != 0 { break_to!(cf, stack, v); } } @@ -329,8 +329,9 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M let mem = store.get_mem(module.resolve_mem_addr(*addr))?; let mut mem = mem.borrow_mut(); let prev_size = mem.page_count() as i32; + let pages_delta: i32 = stack.values.pop()?.into(); - match mem.grow(stack.values.pop_t::()?) { + match mem.grow(pages_delta) { Some(_) => stack.values.push(prev_size.into()), None => stack.values.push((-1).into()), } @@ -366,9 +367,9 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M } MemoryInit(data_index, mem_index) => { - let size = stack.values.pop_t::()? as usize; - let offset = stack.values.pop_t::()? as usize; - let dst = stack.values.pop_t::()? as usize; + let size = i32::from(stack.values.pop()?) as usize; + let offset = i32::from(stack.values.pop()?) as usize; + let dst = i32::from(stack.values.pop()?) as usize; let data = match &store.get_data(module.resolve_data_addr(*data_index))?.data { Some(data) => data, @@ -561,7 +562,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M TableGet(table_index) => { let table_idx = module.resolve_table_addr(*table_index); let table = store.get_table(table_idx)?; - let idx = stack.values.pop_t::()?; + let idx: u32 = stack.values.pop()?.into(); let v = table.borrow().get_wasm_val(idx)?; stack.values.push(v.into()); } @@ -569,8 +570,8 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M TableSet(table_index) => { let table_idx = module.resolve_table_addr(*table_index); let table = store.get_table(table_idx)?; - let val = stack.values.pop_t::()?; - let idx = stack.values.pop_t::()?; + let val = stack.values.pop()?.into(); + let idx = stack.values.pop()?.into(); table.borrow_mut().set(idx, val)?; } @@ -632,7 +633,7 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M stack.values.push((local + *val).into()); } I32StoreLocal { local, const_i32: consti32, offset, mem_addr } => { - let (mem_addr, offset) = (*mem_addr as u32, *offset as u32); + let (mem_addr, offset) = (*mem_addr as u32, *offset); let mem = store.get_mem(module.resolve_mem_addr(mem_addr))?; let val = consti32.to_le_bytes(); let addr: u64 = cf.get_local(*local).into(); diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs index 060d530..8002385 100644 --- a/crates/tinywasm/src/runtime/stack/call_stack.rs +++ b/crates/tinywasm/src/runtime/stack/call_stack.rs @@ -20,7 +20,7 @@ impl CallStack { let mut stack = Vec::new(); stack.reserve_exact(CALL_STACK_SIZE); - let mut stack = Self { stack: stack }; + let mut stack = Self { stack }; stack.push(initial_frame).unwrap(); stack } diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs index 354898e..8a3f3fa 100644 --- a/crates/tinywasm/src/runtime/stack/value_stack.rs +++ b/crates/tinywasm/src/runtime/stack/value_stack.rs @@ -81,17 +81,6 @@ impl ValueStack { } } - #[inline] - pub(crate) fn pop_t>(&mut self) -> Result { - match self.stack.pop() { - Some(v) => Ok(v.into()), - None => { - cold(); // 20+ performance improvement most of the time - Err(Error::ValueStackUnderflow) - } - } - } - #[inline] pub(crate) fn pop(&mut self) -> Result { match self.stack.pop() { @@ -144,11 +133,38 @@ mod tests { stack.push(2.into()); stack.push(3.into()); assert_eq!(stack.len(), 3); - assert_eq!(stack.pop_t::().unwrap(), 3); + assert_eq!(i32::from(stack.pop().unwrap()), 3); assert_eq!(stack.len(), 2); - assert_eq!(stack.pop_t::().unwrap(), 2); + assert_eq!(i32::from(stack.pop().unwrap()), 2); assert_eq!(stack.len(), 1); - assert_eq!(stack.pop_t::().unwrap(), 1); + assert_eq!(i32::from(stack.pop().unwrap()), 1); assert_eq!(stack.len(), 0); } + + #[test] + fn test_truncate_keep() { + macro_rules! test_macro { + ($( $n:expr, $end_keep:expr, $expected:expr ),*) => { + $( + let mut stack = ValueStack::default(); + stack.push(1.into()); + stack.push(2.into()); + stack.push(3.into()); + stack.push(4.into()); + stack.push(5.into()); + stack.truncate_keep($n, $end_keep); + assert_eq!(stack.len(), $expected); + )* + }; + } + + test_macro! { + 0, 0, 0, + 1, 0, 1, + 0, 1, 1, + 1, 1, 2, + 2, 1, 3, + 2, 2, 4 + } + } } diff --git a/crates/tinywasm/src/runtime/value.rs b/crates/tinywasm/src/runtime/value.rs index 55aa9fe..2865308 100644 --- a/crates/tinywasm/src/runtime/value.rs +++ b/crates/tinywasm/src/runtime/value.rs @@ -83,12 +83,36 @@ impl_from_raw_wasm_value!(i64, |x| x as u64, |x: [u8; 8]| i64::from_ne_bytes(x[0 impl_from_raw_wasm_value!(u8, |x| x as u64, |x: [u8; 8]| u8::from_ne_bytes(x[0..1].try_into().unwrap())); impl_from_raw_wasm_value!(u16, |x| x as u64, |x: [u8; 8]| u16::from_ne_bytes(x[0..2].try_into().unwrap())); impl_from_raw_wasm_value!(u32, |x| x as u64, |x: [u8; 8]| u32::from_ne_bytes(x[0..4].try_into().unwrap())); -impl_from_raw_wasm_value!(u64, |x| x as u64, |x: [u8; 8]| u64::from_ne_bytes(x[0..8].try_into().unwrap())); +impl_from_raw_wasm_value!(u64, |x| x, |x: [u8; 8]| u64::from_ne_bytes(x[0..8].try_into().unwrap())); impl_from_raw_wasm_value!(i8, |x| x as u64, |x: [u8; 8]| i8::from_ne_bytes(x[0..1].try_into().unwrap())); impl_from_raw_wasm_value!(i16, |x| x as u64, |x: [u8; 8]| i16::from_ne_bytes(x[0..2].try_into().unwrap())); impl_from_raw_wasm_value!(f32, |x| f32::to_bits(x) as u64, |x: [u8; 8]| f32::from_bits(u32::from_ne_bytes( x[0..4].try_into().unwrap() ))); -impl_from_raw_wasm_value!(f64, |x| f64::to_bits(x) as u64, |x: [u8; 8]| f64::from_bits(u64::from_ne_bytes( +impl_from_raw_wasm_value!(f64, f64::to_bits, |x: [u8; 8]| f64::from_bits(u64::from_ne_bytes( x[0..8].try_into().unwrap() ))); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_raw_wasm_value() { + macro_rules! test_macro { + ($( $ty:ty => $val:expr ),*) => { + $( + let raw: RawWasmValue = $val.into(); + let val: $ty = raw.into(); + assert_eq!(val, $val); + )* + }; + } + + test_macro! { + i32 => 0, i64 => 0, u8 => 0, u16 => 0, u32 => 0, u64 => 0, i8 => 0, i16 => 0, f32 => 0.0, f64 => 0.0, + i32 => i32::MIN, i64 => i64::MIN, u8 => u8::MIN, u16 => u16::MIN, u32 => u32::MIN, u64 => u64::MIN, i8 => i8::MIN, i16 => i16::MIN, f32 => f32::MIN, f64 => f64::MIN, + i32 => i32::MAX, i64 => i64::MAX, u8 => u8::MAX, u16 => u16::MAX, u32 => u32::MAX, u64 => u64::MAX, i8 => i8::MAX, i16 => i16::MAX, f32 => f32::MAX, f64 => f64::MAX + } + } +} From d9cdd0b53c870bf7d9d69b854b8da2692d152871 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Wed, 15 May 2024 13:38:13 +0200 Subject: [PATCH 13/15] feat: v0.7.0 (#13) * Remove all unsafe code * Refactor interpreter loop * Optimize Call-frames * Remove unnecessary reference counter data from store --------- Signed-off-by: Henry Gressmann --- .cargo/config.toml | 5 + BENCHMARKS.md | 9 +- CHANGELOG.md | 11 + Cargo.lock | 635 ++++++++- Cargo.toml | 4 +- README.md | 10 +- benchmarks/Cargo.toml | 6 +- benchmarks/benches/selfhosted.rs | 9 +- crates/cli/Cargo.toml | 2 +- crates/parser/src/conversion.rs | 33 +- crates/parser/src/module.rs | 9 +- crates/parser/src/visit.rs | 62 +- crates/tinywasm/Cargo.toml | 2 +- crates/tinywasm/src/imports.rs | 2 +- crates/tinywasm/src/instance.rs | 26 +- crates/tinywasm/src/lib.rs | 4 +- crates/tinywasm/src/reference.rs | 5 +- .../src/runtime/interpreter/macros.rs | 195 ++- .../tinywasm/src/runtime/interpreter/mod.rs | 1238 +++++++++-------- .../tinywasm/src/runtime/stack/block_stack.rs | 56 +- .../tinywasm/src/runtime/stack/call_stack.rs | 58 +- .../tinywasm/src/runtime/stack/value_stack.rs | 60 +- crates/tinywasm/src/runtime/value.rs | 4 +- crates/tinywasm/src/store/global.rs | 10 +- crates/tinywasm/src/store/memory.rs | 49 +- crates/tinywasm/src/store/mod.rs | 61 +- crates/types/Cargo.toml | 3 +- crates/types/src/archive.rs | 22 - crates/types/src/instructions.rs | 1 + crates/types/src/lib.rs | 5 +- examples/rust/Cargo.toml | 2 +- examples/rust/analyze.py | 9 +- examples/rust/build.sh | 2 +- 33 files changed, 1615 insertions(+), 994 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index df52e1c..be912c8 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -7,3 +7,8 @@ test-wast="test --package tinywasm --test test-wast -- --enable " test-wast-release="test --package tinywasm --test test-wast --release -- --enable " generate-charts="run --package scripts --bin generate-charts --release" benchmark="bench -p benchmarks --bench" + +# # enable for linux perf +# [target.x86_64-unknown-linux-gnu] +# linker="/usr/bin/clang" +# rustflags=["-Clink-arg=-fuse-ld=lld", "-Clink-arg=-Wl,--no-rosegment"] diff --git a/BENCHMARKS.md b/BENCHMARKS.md index 6433be3..1358f70 100644 --- a/BENCHMARKS.md +++ b/BENCHMARKS.md @@ -1,7 +1,7 @@ # Benchmark results All benchmarks are run on a Ryzen 7 5800X with 32GB of RAM on Linux 6.6. -WebAssembly files are optimized using [wasm-opt](https://github.com/WebAssembly/binaryen), +WebAssembly files are optimized using [wasm-opt](https://github.com/WebAssembly/binaryen) (with the `--O3` flag) and the benchmark code is available in the `crates/benchmarks` folder. These are mainly preliminary benchmarks, and I will be rewriting the benchmarks to be more accurate and to test more features in the future. @@ -20,7 +20,6 @@ All WebAssembly files are compiled with the following settings: All runtimes are compiled with the following settings: -- `unsafe` features are enabled. - `opt-level` is set to 3, `lto` is set to `thin`, `codegen-units` is set to 1. - No CPU-specific optimizations are used as AVX2 can reduce performance by more than 50% on some CPUs. @@ -34,9 +33,9 @@ All runtimes are compiled with the following settings: | Benchmark | Native | TinyWasm | Wasmi | Wasmer (Single Pass) | | ------------ | -------- | ---------- | --------- | -------------------- | -| `fib` | `0ms` | ` 19.09µs` | `18.53µs` | ` 48.09µs` | -| `fib-rec` | `0.27ms` | ` 22.22ms` | ` 4.96ms` | ` 0.47ms` | -| `argon2id` | `0.53ms` | ` 86.42ms` | `46.36ms` | ` 4.82ms` | +| `fib` | `0ms` | ` 18.70µs` | `18.53µs` | ` 48.09µs` | +| `fib-rec` | `0.27ms` | ` 16.02ms` | ` 4.96ms` | ` 0.47ms` | +| `argon2id` | `0.53ms` | ` 80.54ms` | `46.36ms` | ` 4.82ms` | | `selfhosted` | `0.05ms` | ` 7.26ms` | ` 6.51ms` | `446.48ms` | ### Fib diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c918af..f6539a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.7.0] - 2024-05-15 + +**All Commits**: https://github.com/explodingcamera/tinywasm/compare/v0.6.0...v0.7.0 + +### Changed + +- Remove all unsafe code +- Refactor interpreter loop +- Optimize Call-frames +- Remove unnecessary reference counter data from store + ## [0.6.1] - 2024-05-10 **All Commits**: https://github.com/explodingcamera/tinywasm/compare/v0.6.0...v0.6.1 diff --git a/Cargo.lock b/Cargo.lock index 14fddce..3f38395 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,12 +70,61 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + [[package]] name = "anstyle" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" + [[package]] name = "argh" version = "0.1.12" @@ -146,6 +195,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64ct" version = "1.6.0" @@ -283,6 +338,18 @@ name = "bytes" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +dependencies = [ + "serde", +] + +[[package]] +name = "bytesize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" +dependencies = [ + "serde", +] [[package]] name = "cast" @@ -340,33 +407,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", - "half", + "half 2.4.1", ] [[package]] name = "clap" -version = "4.5.4" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" dependencies = [ "clap_builder", + "clap_derive", ] [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" dependencies = [ + "anstream", "anstyle", "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.61", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "color-eyre" @@ -401,6 +483,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + [[package]] name = "const-cstr" version = "0.3.0" @@ -659,14 +747,38 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + [[package]] name = "darling" version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.8", + "darling_macro 0.20.8", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", ] [[package]] @@ -682,13 +794,24 @@ dependencies = [ "syn 2.0.61", ] +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + [[package]] name = "darling_macro" version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ - "darling_core", + "darling_core 0.20.8", "quote", "syn 2.0.61", ] @@ -717,6 +840,37 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + [[package]] name = "digest" version = "0.10.7" @@ -758,6 +912,15 @@ dependencies = [ "libloading", ] +[[package]] +name = "document-features" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" +dependencies = [ + "litrs", +] + [[package]] name = "downcast-rs" version = "1.2.1" @@ -776,6 +939,12 @@ dependencies = [ "wio", ] +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "dynasm" version = "1.2.3" @@ -843,7 +1012,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" dependencies = [ - "darling", + "darling 0.20.8", "proc-macro2", "quote", "syn 2.0.61", @@ -868,6 +1037,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "eyre" version = "0.6.12" @@ -884,6 +1063,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + [[package]] name = "fdeflate" version = "0.3.4" @@ -893,6 +1078,18 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", +] + [[package]] name = "flate2" version = "1.0.30" @@ -1017,8 +1214,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -1061,6 +1260,12 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "half" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" + [[package]] name = "half" version = "2.4.1" @@ -1089,12 +1294,24 @@ dependencies = [ "ahash 0.8.11", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "humantime" version = "2.1.0" @@ -1168,6 +1385,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] @@ -1178,6 +1396,7 @@ checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.5", + "serde", ] [[package]] @@ -1197,6 +1416,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itertools" version = "0.10.5" @@ -1271,6 +1496,18 @@ dependencies = [ "libc", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "lock_api" version = "0.4.12" @@ -1331,9 +1568,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] @@ -1404,7 +1641,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.1", "smallvec", "windows-targets", ] @@ -1625,6 +1862,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.1" @@ -1787,6 +2033,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "ryu" version = "1.0.18" @@ -1802,6 +2061,31 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schemars" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6e7ed6919cb46507fb01ff1654309219f62b4d603822501b0b80d42f6f21ef" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "schemars_derive" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185f2b7aa7e02d418e453790dde16890256bbd2bcd04b7dc5348811052b53f49" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.61", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1833,6 +2117,9 @@ name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] [[package]] name = "serde" @@ -1854,6 +2141,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half 1.8.3", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.201" @@ -1865,6 +2162,17 @@ dependencies = [ "syn 2.0.61", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "serde_json" version = "1.0.117" @@ -1876,6 +2184,28 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.2.6", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha2" version = "0.10.8" @@ -1942,6 +2272,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "subtle" version = "2.5.0" @@ -1976,12 +2312,35 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tar" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "target-lexicon" version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + [[package]] name = "termcolor" version = "1.4.1" @@ -2072,7 +2431,7 @@ dependencies = [ "log", "pretty_env_logger", "tinywasm", - "wast 206.0.0", + "wast 207.0.0", ] [[package]] @@ -2103,6 +2462,65 @@ dependencies = [ "rkyv", ] +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.15", +] + +[[package]] +name = "toml" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.12", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.2.6", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +dependencies = [ + "indexmap 2.2.6", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.8", +] + [[package]] name = "tracing" version = "0.1.40" @@ -2195,6 +2613,12 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "url" version = "2.5.0" @@ -2204,8 +2628,15 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "uuid" version = "1.8.0" @@ -2265,29 +2696,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-downcast" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dac026d43bcca6e7ce1c0956ba68f59edf6403e8e930a5d891be72c31a44340" -dependencies = [ - "js-sys", - "once_cell", - "wasm-bindgen", - "wasm-bindgen-downcast-macros", -] - -[[package]] -name = "wasm-bindgen-downcast-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5020cfa87c7cecefef118055d44e3c1fc122c7ec25701d528ee458a0b45f38f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.92" @@ -2319,9 +2727,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-encoder" -version = "0.206.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d759312e1137f199096d80a70be685899cd7d3d09c572836bb2e9b69b4dc3b1e" +checksum = "1ba64e81215916eaeb48fee292f29401d69235d62d8b8fd92a7b2844ec5ae5f7" dependencies = [ "leb128", ] @@ -2344,9 +2752,9 @@ dependencies = [ [[package]] name = "wasmer" -version = "4.2.2" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e626f958755a90a6552b9528f59b58a62ae288e6c17fcf40e99495bc33c60f0" +checksum = "6d6beae0c56cd5c26fe29aa613c6637bde6747a782ec3e3ed362c2dda615e701" dependencies = [ "bytes", "cfg-if", @@ -2360,8 +2768,8 @@ dependencies = [ "shared-buffer", "target-lexicon", "thiserror", + "tracing", "wasm-bindgen", - "wasm-bindgen-downcast", "wasmer-compiler", "wasmer-compiler-cranelift", "wasmer-compiler-singlepass", @@ -2374,9 +2782,9 @@ dependencies = [ [[package]] name = "wasmer-compiler" -version = "4.2.2" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848e1922694cf97f4df680a0534c9d72c836378b5eb2313c1708fe1a75b40044" +checksum = "df65b299475df71947607b24528e5a34e0fc42ad84350c242e591cbf74a6bc37" dependencies = [ "backtrace", "bytes", @@ -2395,15 +2803,16 @@ dependencies = [ "thiserror", "wasmer-types", "wasmer-vm", - "wasmparser 0.95.0", + "wasmparser 0.121.2", "winapi", + "xxhash-rust", ] [[package]] name = "wasmer-compiler-cranelift" -version = "4.2.2" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d96bce6fad15a954edcfc2749b59e47ea7de524b6ef3df392035636491a40b4" +checksum = "42867bde8e7bda9419c9b08a20eb58ed8e493fea5ba3cb920f602df826cb7795" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -2420,9 +2829,9 @@ dependencies = [ [[package]] name = "wasmer-compiler-singlepass" -version = "4.2.2" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebaa865b40ffb3351b03dab9fe9930a5248c25daebd55b464b79b862d9b55ccd" +checksum = "8ffcce77a325738b1b64e1ec7e141b62b0706ecd7cfbf70227aedc9a8c9c1bd6" dependencies = [ "byteorder", "dynasm", @@ -2437,11 +2846,33 @@ dependencies = [ "wasmer-types", ] +[[package]] +name = "wasmer-config" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a0f70c177b1c5062cfe0f5308c3317751796fef9403c22a0cd7b4cacd4ccd8" +dependencies = [ + "anyhow", + "bytesize", + "derive_builder", + "hex", + "indexmap 2.2.6", + "schemars", + "semver", + "serde", + "serde_cbor", + "serde_json", + "serde_yaml", + "thiserror", + "toml 0.8.12", + "url", +] + [[package]] name = "wasmer-derive" -version = "4.2.2" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f08f80d166a9279671b7af7a09409c28ede2e0b4e3acabbf0e3cb22c8038ba7" +checksum = "231826965de8fe7bfba02b3b8adac3304ca8b7fea92dc6129e8330e020aa6b45" dependencies = [ "proc-macro-error", "proc-macro2", @@ -2451,25 +2882,30 @@ dependencies = [ [[package]] name = "wasmer-types" -version = "4.2.2" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae2c892882f0b416783fb4310e5697f5c30587f6f9555f9d4f2be85ab39d5d3d" +checksum = "9782e1a5a28ae2c5165cdfc1aa5ce2aa89b20f745ae3f3a3974f6500849cc31a" dependencies = [ "bytecheck 0.6.12", "enum-iterator", "enumset", + "getrandom", + "hex", "indexmap 1.9.3", "more-asserts", "rkyv", + "sha2", "target-lexicon", "thiserror", + "webc", + "xxhash-rust", ] [[package]] name = "wasmer-vm" -version = "4.2.2" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c0a9a57b627fb39e5a491058d4365f099bc9b140031c000fded24a3306d9480" +checksum = "9f143d07733ac0832f42c7acb1b0abf22f00e38505eb605951f06af382970f80" dependencies = [ "backtrace", "cc", @@ -2526,12 +2962,13 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.95.0" +version = "0.121.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ea896273ea99b15132414be1da01ab0d8836415083298ecaffbe308eaac87a" +checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" dependencies = [ - "indexmap 1.9.3", - "url", + "bitflags 2.5.0", + "indexmap 2.2.6", + "semver", ] [[package]] @@ -2558,15 +2995,14 @@ dependencies = [ [[package]] name = "wast" -version = "206.0.0" +version = "64.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68586953ee4960b1f5d84ebf26df3b628b17e6173bc088e0acfbce431469795a" +checksum = "a259b226fd6910225aa7baeba82f9d9933b6d00f2ce1b49b80fa4214328237cc" dependencies = [ - "bumpalo", "leb128", "memchr", "unicode-width", - "wasm-encoder 0.206.0", + "wasm-encoder 0.32.0", ] [[package]] @@ -2584,11 +3020,11 @@ dependencies = [ [[package]] name = "wat" -version = "1.207.0" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb2b15e2d5f300f5e1209e7dc237f2549edbd4203655b6c6cab5cf180561ee7" +checksum = "53253d920ab413fca1c7dc2161d601c79b4fdf631d0ba51dd4343bf9b556c3f6" dependencies = [ - "wast 207.0.0", + "wast 64.0.0", ] [[package]] @@ -2601,6 +3037,36 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webc" +version = "6.0.0-alpha8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbf53893f8df356f1305446c1bc59c4082cb592f39ffcae0a2f10bd8ed100bb9" +dependencies = [ + "anyhow", + "base64", + "bytes", + "cfg-if", + "clap", + "document-features", + "flate2", + "indexmap 1.9.3", + "libc", + "once_cell", + "semver", + "serde", + "serde_cbor", + "serde_json", + "sha2", + "shared-buffer", + "tar", + "tempfile", + "thiserror", + "toml 0.7.8", + "url", + "wasmer-config", +] + [[package]] name = "weezl" version = "0.1.8" @@ -2763,6 +3229,24 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +dependencies = [ + "memchr", +] + [[package]] name = "wio" version = "0.2.2" @@ -2781,6 +3265,23 @@ dependencies = [ "tap", ] +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + +[[package]] +name = "xxhash-rust" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927da81e25be1e1a2901d59b81b37dd2efd1fc9c9345a55007f09bf5a2d3ee03" + [[package]] name = "yeslogic-fontconfig-sys" version = "3.2.0" diff --git a/Cargo.toml b/Cargo.toml index 6cac50f..37dd86c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,8 +28,8 @@ test=false [dev-dependencies] color-eyre="0.6" -tinywasm={path="crates/tinywasm", features=["unsafe"]} -wat={version="1.206"} +tinywasm={path="crates/tinywasm"} +wat={version="1"} pretty_env_logger="0.5" [profile.bench] diff --git a/README.md b/README.md index 38000f4..bf36393 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

TinyWasm

- A tiny WebAssembly Runtime written in Rust + A tiny WebAssembly Runtime written in safe Rust
@@ -12,9 +12,9 @@ ## Why TinyWasm? -- **Tiny**: TinyWasm is designed to be as small as possible without significantly compromising performance or functionality (< 6000 lines of code). -- **Portable**: TinyWasm runs on any platform that Rust can target, including other WebAssembly Runtimes, with minimal external dependencies. -- **Lightweight**: TinyWasm is easy to integrate and has a low call overhead, making it suitable for scripting and embedding. +- **Tiny**: TinyWasm is designed to be as small as possible without significantly compromising performance or functionality (< 4000 LLOC). +- **Portable**: TinyWasm runs on any platform that Rust can target, including `no_std`, with minimal external dependencies. +- **Safe**: No unsafe code is used in the runtime (`rkyv` which uses unsafe code can be used for serialization, but it is optional). ## Status @@ -65,8 +65,6 @@ $ tinywasm-cli --help Enables the `tinywasm-parser` crate. This is enabled by default. - **`archive`**\ Enables pre-parsing of archives. This is enabled by default. -- **`unsafe`**\ - Uses `unsafe` code to improve performance, particularly in Memory access. With all these features disabled, TinyWasm only depends on `core`, `alloc` ,and `libm` and can be used in `no_std` environments. Since `libm` is not as performant as the compiler's math intrinsics, it is recommended to use the `std` feature if possible (at least [for now](https://github.com/rust-lang/rfcs/issues/2505)), especially on wasm32 targets. diff --git a/benchmarks/Cargo.toml b/benchmarks/Cargo.toml index f2cfe69..e137a92 100644 --- a/benchmarks/Cargo.toml +++ b/benchmarks/Cargo.toml @@ -5,10 +5,10 @@ edition.workspace=true [dependencies] criterion={version="0.5", features=["html_reports"]} -tinywasm={path="../crates/tinywasm", features=["unsafe"]} -wat={version="1.206"} +tinywasm={path="../crates/tinywasm"} +wat={version="1"} wasmi={version="0.31", features=["std"]} -wasmer={version="4.2", features=["cranelift", "singlepass"]} +wasmer={version="4.3", features=["cranelift", "singlepass"]} argon2={version="0.5"} [[bench]] diff --git a/benchmarks/benches/selfhosted.rs b/benchmarks/benches/selfhosted.rs index 21ea79f..4241eea 100644 --- a/benchmarks/benches/selfhosted.rs +++ b/benchmarks/benches/selfhosted.rs @@ -1,5 +1,5 @@ mod util; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; fn run_native() { use tinywasm::*; @@ -52,6 +52,13 @@ fn run_wasmer(wasm: &[u8]) { const TINYWASM: &[u8] = include_bytes!("../../examples/rust/out/tinywasm.wasm"); fn criterion_benchmark(c: &mut Criterion) { + { + let mut group = c.benchmark_group("selfhosted-parse"); + group.bench_function("tinywasm", |b| { + b.iter(|| tinywasm::Module::parse_bytes(black_box(TINYWASM)).expect("parse")) + }); + } + { let mut group = c.benchmark_group("selfhosted"); group.bench_function("native", |b| b.iter(run_native)); diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index ab0324f..3c4657d 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -19,7 +19,7 @@ argh="0.1" color-eyre={version="0.6", default-features=false} log="0.4" pretty_env_logger="0.5" -wast={version="206.0", optional=true} +wast={version="207.0", optional=true} [features] default=["wat"] diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index 31056a3..001d7cc 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -7,8 +7,7 @@ use wasmparser::{FuncValidator, OperatorsReader, ValidatorResources}; pub(crate) fn convert_module_elements<'a, T: IntoIterator>>>( elements: T, ) -> Result> { - let elements = elements.into_iter().map(|element| convert_module_element(element?)).collect::>>()?; - Ok(elements) + elements.into_iter().map(|element| convert_module_element(element?)).collect::>>() } pub(crate) fn convert_module_element(element: wasmparser::Element<'_>) -> Result { @@ -47,8 +46,7 @@ pub(crate) fn convert_module_element(element: wasmparser::Element<'_>) -> Result pub(crate) fn convert_module_data_sections<'a, T: IntoIterator>>>( data_sections: T, ) -> Result> { - let data_sections = data_sections.into_iter().map(|data| convert_module_data(data?)).collect::>>()?; - Ok(data_sections) + data_sections.into_iter().map(|data| convert_module_data(data?)).collect::>>() } pub(crate) fn convert_module_data(data: wasmparser::Data<'_>) -> Result { @@ -68,8 +66,7 @@ pub(crate) fn convert_module_data(data: wasmparser::Data<'_>) -> Result>>>( imports: T, ) -> Result> { - let imports = imports.into_iter().map(|import| convert_module_import(import?)).collect::>>()?; - Ok(imports) + imports.into_iter().map(|import| convert_module_import(import?)).collect::>>() } pub(crate) fn convert_module_import(import: wasmparser::Import<'_>) -> Result { @@ -140,8 +137,8 @@ pub(crate) fn convert_module_table(table: wasmparser::Table<'_>) -> Result
>>>( - globals: T, +pub(crate) fn convert_module_globals( + globals: wasmparser::SectionLimited<'_, wasmparser::Global<'_>>, ) -> Result> { let globals = globals .into_iter() @@ -149,7 +146,6 @@ pub(crate) fn convert_module_globals<'a, T: IntoIterator>>()?; @@ -172,7 +168,7 @@ pub(crate) fn convert_module_export(export: wasmparser::Export<'_>) -> Result, - mut validator: FuncValidator, + validator: &mut FuncValidator, ) -> Result { let locals_reader = func.get_locals_reader()?; let count = locals_reader.get_count(); @@ -187,7 +183,7 @@ pub(crate) fn convert_module_code( } } - let body = process_operators(Some(&mut validator), &func)?; + let body = process_operators(Some(validator), func)?; let locals = locals.into_boxed_slice(); Ok((body, locals)) } @@ -245,18 +241,15 @@ pub(crate) fn process_const_operators(ops: OperatorsReader<'_>) -> Result= 2); assert!(matches!(ops[ops.len() - 1], wasmparser::Operator::End)); - process_const_operator(ops[ops.len() - 2].clone()) -} -pub(crate) fn process_const_operator(op: wasmparser::Operator<'_>) -> Result { - match op { - wasmparser::Operator::RefNull { hty } => Ok(ConstInstruction::RefNull(convert_heaptype(hty))), - wasmparser::Operator::RefFunc { function_index } => Ok(ConstInstruction::RefFunc(function_index)), - wasmparser::Operator::I32Const { value } => Ok(ConstInstruction::I32Const(value)), - wasmparser::Operator::I64Const { value } => Ok(ConstInstruction::I64Const(value)), + match &ops[ops.len() - 2] { + wasmparser::Operator::RefNull { hty } => Ok(ConstInstruction::RefNull(convert_heaptype(*hty))), + wasmparser::Operator::RefFunc { function_index } => Ok(ConstInstruction::RefFunc(*function_index)), + wasmparser::Operator::I32Const { value } => Ok(ConstInstruction::I32Const(*value)), + wasmparser::Operator::I64Const { value } => Ok(ConstInstruction::I64Const(*value)), wasmparser::Operator::F32Const { value } => Ok(ConstInstruction::F32Const(f32::from_bits(value.bits()))), wasmparser::Operator::F64Const { value } => Ok(ConstInstruction::F64Const(f64::from_bits(value.bits()))), - wasmparser::Operator::GlobalGet { global_index } => Ok(ConstInstruction::GlobalGet(global_index)), + wasmparser::Operator::GlobalGet { global_index } => Ok(ConstInstruction::GlobalGet(*global_index)), op => Err(crate::ParseError::UnsupportedOperator(format!("Unsupported const instruction: {:?}", op))), } } diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs index 8414c17..1cd5ed5 100644 --- a/crates/parser/src/module.rs +++ b/crates/parser/src/module.rs @@ -2,12 +2,14 @@ use crate::log::debug; use crate::{conversion, ParseError, Result}; use alloc::{boxed::Box, format, vec::Vec}; use tinywasm_types::{Data, Element, Export, FuncType, Global, Import, Instruction, MemoryType, TableType, ValType}; -use wasmparser::{Payload, Validator}; +use wasmparser::{FuncValidatorAllocations, Payload, Validator}; pub(crate) type Code = (Box<[Instruction]>, Box<[ValType]>); #[derive(Default)] pub(crate) struct ModuleReader { + func_validator_allocations: Option, + pub(crate) version: Option, pub(crate) start_func: Option, pub(crate) func_types: Vec, @@ -129,8 +131,9 @@ impl ModuleReader { CodeSectionEntry(function) => { debug!("Found code section entry"); let v = validator.code_section_entry(&function)?; - let func_validator = v.into_validator(Default::default()); - self.code.push(conversion::convert_module_code(function, func_validator)?); + let mut func_validator = v.into_validator(self.func_validator_allocations.take().unwrap_or_default()); + self.code.push(conversion::convert_module_code(function, &mut func_validator)?); + self.func_validator_allocations = Some(func_validator.into_allocations()); } ImportSection(reader) => { if !self.imports.is_empty() { diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index df6fc7a..332380c 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -29,12 +29,11 @@ where pub(crate) fn process_operators( validator: Option<&mut FuncValidator>, - body: &FunctionBody<'_>, + body: FunctionBody<'_>, ) -> Result> { let mut reader = body.get_operators_reader()?; let remaining = reader.get_binary_reader().bytes_remaining(); let mut builder = FunctionBuilder::new(remaining); - if let Some(validator) = validator { while !reader.eof() { let validate = validator.visitor(reader.original_position()); @@ -53,6 +52,7 @@ pub(crate) fn process_operators( macro_rules! define_operands { ($($name:ident, $instr:expr),*) => { $( + #[inline(always)] fn $name(&mut self) -> Self::Output { self.instructions.push($instr); Ok(()) @@ -64,15 +64,19 @@ macro_rules! define_operands { macro_rules! define_primitive_operands { ($($name:ident, $instr:expr, $ty:ty),*) => { $( + #[inline(always)] fn $name(&mut self, arg: $ty) -> Self::Output { - Ok(self.instructions.push($instr(arg))) + self.instructions.push($instr(arg)); + Ok(()) } )* }; ($($name:ident, $instr:expr, $ty:ty, $ty2:ty),*) => { $( + #[inline(always)] fn $name(&mut self, arg: $ty, arg2: $ty) -> Self::Output { - Ok(self.instructions.push($instr(arg, arg2))) + self.instructions.push($instr(arg, arg2)); + Ok(()) } )* }; @@ -81,6 +85,7 @@ macro_rules! define_primitive_operands { macro_rules! define_mem_operands { ($($name:ident, $instr:ident),*) => { $( + #[inline(always)] fn $name(&mut self, mem_arg: wasmparser::MemArg) -> Self::Output { let arg = convert_memarg(mem_arg); self.instructions.push(Instruction::$instr { @@ -100,7 +105,7 @@ pub(crate) struct FunctionBuilder { impl FunctionBuilder { pub(crate) fn new(instr_capacity: usize) -> Self { - Self { instructions: Vec::with_capacity(instr_capacity), label_ptrs: Vec::with_capacity(256) } + Self { instructions: Vec::with_capacity(instr_capacity / 4), label_ptrs: Vec::with_capacity(256) } } #[cold] @@ -108,7 +113,7 @@ impl FunctionBuilder { Err(crate::ParseError::UnsupportedOperator(format!("Unsupported instruction: {:?}", name))) } - #[inline] + #[inline(always)] fn visit(&mut self, op: Instruction) -> Result<()> { self.instructions.push(op); Ok(()) @@ -126,6 +131,7 @@ macro_rules! impl_visit_operator { (@@saturating_float_to_int $($rest:tt)* ) => {}; (@@bulk_memory $($rest:tt)* ) => {}; (@@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident) => { + #[cold] fn $visit(&mut self $($(,$arg: $argty)*)?) -> Result<()>{ self.unsupported(stringify!($visit)) } @@ -319,6 +325,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { visit_i64_trunc_sat_f64_u, Instruction::I64TruncSatF64U } + #[inline(always)] fn visit_i32_store(&mut self, memarg: wasmparser::MemArg) -> Self::Output { let arg = convert_memarg(memarg); let i32store = Instruction::I32Store { offset: arg.offset, mem_addr: arg.mem_addr }; @@ -342,6 +349,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { } } + #[inline(always)] fn visit_local_get(&mut self, idx: u32) -> Self::Output { let Some(instruction) = self.instructions.last_mut() else { return self.visit(Instruction::LocalGet(idx)); @@ -357,14 +365,17 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { Ok(()) } + #[inline(always)] fn visit_local_set(&mut self, idx: u32) -> Self::Output { self.visit(Instruction::LocalSet(idx)) } + #[inline(always)] fn visit_local_tee(&mut self, idx: u32) -> Self::Output { self.visit(Instruction::LocalTee(idx)) } + #[inline(always)] fn visit_i64_rotl(&mut self) -> Self::Output { if self.instructions.len() < 2 { return self.visit(Instruction::I64Rotl); @@ -380,6 +391,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { } } + #[inline(always)] fn visit_i32_add(&mut self) -> Self::Output { if self.instructions.len() < 2 { return self.visit(Instruction::I32Add); @@ -395,35 +407,39 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { } } + #[inline(always)] fn visit_block(&mut self, blockty: wasmparser::BlockType) -> Self::Output { self.label_ptrs.push(self.instructions.len()); self.visit(Instruction::Block(convert_blocktype(blockty), 0)) } + #[inline(always)] fn visit_loop(&mut self, ty: wasmparser::BlockType) -> Self::Output { self.label_ptrs.push(self.instructions.len()); self.visit(Instruction::Loop(convert_blocktype(ty), 0)) } + #[inline(always)] fn visit_if(&mut self, ty: wasmparser::BlockType) -> Self::Output { self.label_ptrs.push(self.instructions.len()); self.visit(Instruction::If(convert_blocktype(ty).into(), 0, 0)) } + #[inline(always)] fn visit_else(&mut self) -> Self::Output { self.label_ptrs.push(self.instructions.len()); self.visit(Instruction::Else(0)) } + #[inline(always)] fn visit_end(&mut self) -> Self::Output { let Some(label_pointer) = self.label_ptrs.pop() else { return self.visit(Instruction::Return); }; let current_instr_ptr = self.instructions.len(); - - match self.instructions[label_pointer] { - Instruction::Else(ref mut else_instr_end_offset) => { + match self.instructions.get_mut(label_pointer) { + Some(Instruction::Else(else_instr_end_offset)) => { *else_instr_end_offset = (current_instr_ptr - label_pointer) .try_into() .expect("else_instr_end_offset is too large, tinywasm does not support if blocks that large"); @@ -439,7 +455,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { let if_label_pointer = self.label_ptrs.pop().ok_or_else(error)?; let if_instruction = &mut self.instructions[if_label_pointer]; - let Instruction::If(_, ref mut else_offset, ref mut end_offset) = if_instruction else { + let Instruction::If(_, else_offset, end_offset) = if_instruction else { return Err(error()); }; @@ -451,23 +467,22 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { .try_into() .expect("else_instr_end_offset is too large, tinywasm does not support blocks that large"); } - Instruction::Block(_, ref mut end_offset) - | Instruction::Loop(_, ref mut end_offset) - | Instruction::If(_, _, ref mut end_offset) => { + Some(Instruction::Block(_, end_offset)) + | Some(Instruction::Loop(_, end_offset)) + | Some(Instruction::If(_, _, end_offset)) => { *end_offset = (current_instr_ptr - label_pointer) .try_into() .expect("else_instr_end_offset is too large, tinywasm does not support blocks that large"); } _ => { - return Err(crate::ParseError::UnsupportedOperator( - "Expected to end a block, but the last label was not a block".to_string(), - )) + unreachable!("Expected to end a block, but the last label was not a block") } }; self.visit(Instruction::EndBlockFrame) } + #[inline(always)] fn visit_br_table(&mut self, targets: wasmparser::BrTable<'_>) -> Self::Output { let def = targets.default(); let instrs = targets @@ -476,32 +491,36 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { .collect::, wasmparser::BinaryReaderError>>() .expect("BrTable targets are invalid, this should have been caught by the validator"); - self.instructions - .extend(IntoIterator::into_iter([Instruction::BrTable(def, instrs.len() as u32)]).chain(instrs)); - + self.instructions.extend(([Instruction::BrTable(def, instrs.len() as u32)].into_iter()).chain(instrs)); Ok(()) } + #[inline(always)] fn visit_call(&mut self, idx: u32) -> Self::Output { self.visit(Instruction::Call(idx)) } + #[inline(always)] fn visit_call_indirect(&mut self, ty: u32, table: u32, _table_byte: u8) -> Self::Output { self.visit(Instruction::CallIndirect(ty, table)) } + #[inline(always)] fn visit_memory_size(&mut self, mem: u32, mem_byte: u8) -> Self::Output { self.visit(Instruction::MemorySize(mem, mem_byte)) } + #[inline(always)] fn visit_memory_grow(&mut self, mem: u32, mem_byte: u8) -> Self::Output { self.visit(Instruction::MemoryGrow(mem, mem_byte)) } + #[inline(always)] fn visit_f32_const(&mut self, val: wasmparser::Ieee32) -> Self::Output { self.visit(Instruction::F32Const(f32::from_bits(val.bits()))) } + #[inline(always)] fn visit_f64_const(&mut self, val: wasmparser::Ieee64) -> Self::Output { self.visit(Instruction::F64Const(f64::from_bits(val.bits()))) } @@ -518,24 +537,29 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder { visit_data_drop, Instruction::DataDrop, u32 } + #[inline(always)] fn visit_elem_drop(&mut self, _elem_index: u32) -> Self::Output { self.unsupported("elem_drop") } + #[inline(always)] fn visit_table_copy(&mut self, dst_table: u32, src_table: u32) -> Self::Output { self.visit(Instruction::TableCopy { from: src_table, to: dst_table }) } // Reference Types + #[inline(always)] fn visit_ref_null(&mut self, ty: wasmparser::HeapType) -> Self::Output { self.visit(Instruction::RefNull(convert_heaptype(ty))) } + #[inline(always)] fn visit_ref_is_null(&mut self) -> Self::Output { self.visit(Instruction::RefIsNull) } + #[inline(always)] fn visit_typed_select(&mut self, ty: wasmparser::ValType) -> Self::Output { self.visit(Instruction::Select(Some(convert_valtype(&ty)))) } diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 5f23389..ffd8ac9 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -32,8 +32,8 @@ default=["std", "parser", "logging", "archive"] logging=["_log", "tinywasm-parser?/logging", "tinywasm-types/logging"] std=["tinywasm-parser?/std", "tinywasm-types/std"] parser=["tinywasm-parser"] -unsafe=["tinywasm-types/unsafe"] archive=["tinywasm-types/archive"] +nightly=[] [[test]] name="test-mvp" diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs index c4bae3b..f24ed73 100644 --- a/crates/tinywasm/src/imports.rs +++ b/crates/tinywasm/src/imports.rs @@ -389,7 +389,7 @@ impl Imports { match (val, &import.kind) { (ExternVal::Global(global_addr), ImportKind::Global(ty)) => { let global = store.get_global(global_addr)?; - Self::compare_types(import, &global.borrow().ty, ty)?; + Self::compare_types(import, &global.ty, ty)?; imports.globals.push(global_addr); } (ExternVal::Table(table_addr), ImportKind::Table(ty)) => { diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs index 8a663c4..8402302 100644 --- a/crates/tinywasm/src/instance.rs +++ b/crates/tinywasm/src/instance.rs @@ -90,7 +90,7 @@ impl ModuleInstance { }; let instance = ModuleInstance::new(instance); - store.add_instance(instance.clone())?; + store.add_instance(instance.clone()); if let Some(trap) = elem_trapped { return Err(trap.into()); @@ -113,7 +113,7 @@ impl ModuleInstance { ExternalKind::Global => self.0.global_addrs.get(exports.index as usize)?, }; - Some(ExternVal::new(exports.kind.clone(), *addr)) + Some(ExternVal::new(exports.kind, *addr)) } #[inline] @@ -132,37 +132,37 @@ impl ModuleInstance { } // resolve a function address to the global store address - #[inline] + #[inline(always)] pub(crate) fn resolve_func_addr(&self, addr: FuncAddr) -> FuncAddr { - *self.0.func_addrs.get(addr as usize).expect("No func addr for func, this is a bug") + self.0.func_addrs[addr as usize] } // resolve a table address to the global store address - #[inline] + #[inline(always)] pub(crate) fn resolve_table_addr(&self, addr: TableAddr) -> TableAddr { - *self.0.table_addrs.get(addr as usize).expect("No table addr for table, this is a bug") + self.0.table_addrs[addr as usize] } // resolve a memory address to the global store address - #[inline] + #[inline(always)] pub(crate) fn resolve_mem_addr(&self, addr: MemAddr) -> MemAddr { - *self.0.mem_addrs.get(addr as usize).expect("No mem addr for mem, this is a bug") + self.0.mem_addrs[addr as usize] } // resolve a data address to the global store address - #[inline] + #[inline(always)] pub(crate) fn resolve_data_addr(&self, addr: DataAddr) -> MemAddr { - *self.0.data_addrs.get(addr as usize).expect("No data addr for data, this is a bug") + self.0.data_addrs[addr as usize] } // resolve a memory address to the global store address - #[inline] + #[inline(always)] pub(crate) fn resolve_elem_addr(&self, addr: ElemAddr) -> ElemAddr { - *self.0.elem_addrs.get(addr as usize).expect("No elem addr for elem, this is a bug") + self.0.elem_addrs[addr as usize] } // resolve a global address to the global store address - #[inline] + #[inline(always)] pub(crate) fn resolve_global_addr(&self, addr: GlobalAddr) -> GlobalAddr { self.0.global_addrs[addr as usize] } diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs index 0bc17d6..2e9fece 100644 --- a/crates/tinywasm/src/lib.rs +++ b/crates/tinywasm/src/lib.rs @@ -6,7 +6,7 @@ #![allow(unexpected_cfgs, clippy::reserve_after_initialization)] #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms, unreachable_pub)] #![cfg_attr(nightly, feature(error_in_core))] -#![cfg_attr(not(feature = "unsafe"), deny(unsafe_code))] +#![forbid(unsafe_code)] //! A tiny WebAssembly Runtime written in Rust //! @@ -23,8 +23,6 @@ //! Enables the `tinywasm-parser` crate. This is enabled by default. //!- **`archive`**\ //! Enables pre-parsing of archives. This is enabled by default. -//!- **`unsafe`**\ -//! Uses `unsafe` code to improve performance, particularly in Memory access //! //! With all these features disabled, TinyWasm only depends on `core`, `alloc` and `libm`. //! By disabling `std`, you can use TinyWasm in `no_std` environments. This requires diff --git a/crates/tinywasm/src/reference.rs b/crates/tinywasm/src/reference.rs index 6713a42..f3acc49 100644 --- a/crates/tinywasm/src/reference.rs +++ b/crates/tinywasm/src/reference.rs @@ -2,7 +2,6 @@ use core::cell::{Ref, RefCell, RefMut}; use core::ffi::CStr; use alloc::ffi::CString; -use alloc::rc::Rc; use alloc::string::{String, ToString}; use alloc::vec::Vec; @@ -142,9 +141,9 @@ impl MemoryStringExt for MemoryRef<'_> {} impl MemoryStringExt for MemoryRefMut<'_> {} /// A reference to a global instance -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct GlobalRef { - pub(crate) instance: Rc>, + pub(crate) instance: RefCell, } impl GlobalRef { diff --git a/crates/tinywasm/src/runtime/interpreter/macros.rs b/crates/tinywasm/src/runtime/interpreter/macros.rs index b37dedd..8a092c0 100644 --- a/crates/tinywasm/src/runtime/interpreter/macros.rs +++ b/crates/tinywasm/src/runtime/interpreter/macros.rs @@ -10,12 +10,13 @@ // This is a bit hard to see from the spec, but it's vaild to use breaks to return // from a function, so we need to check if the label stack is empty macro_rules! break_to { - ($cf:ident, $stack:ident, $break_to_relative:ident) => {{ + ($cf:ident, $stack:ident, $module:ident, $store:ident, $break_to_relative:ident) => {{ if $cf.break_to(*$break_to_relative, &mut $stack.values, &mut $stack.blocks).is_none() { - match $stack.call_stack.is_empty() { - true => return Ok(ExecResult::Return), - false => return Ok(ExecResult::Call), + if $stack.call_stack.is_empty() { + return Ok(()); } + + call!($cf, $stack, $module, $store) } }}; } @@ -27,31 +28,35 @@ macro_rules! mem_load { }}; ($load_type:ty, $target_type:ty, $arg:expr, $stack:ident, $store:ident, $module:ident) => {{ - let (mem_addr, offset) = $arg; + #[inline(always)] + fn mem_load_inner( + store: &Store, + module: &crate::ModuleInstance, + stack: &mut crate::runtime::Stack, + mem_addr: tinywasm_types::MemAddr, + offset: u64, + ) -> Result<()> { + let mem = store.get_mem(module.resolve_mem_addr(mem_addr))?; + let addr: usize = match offset.checked_add(stack.values.pop()?.into()).map(|a| a.try_into()) { + Some(Ok(a)) => a, + _ => { + cold(); + return Err(Error::Trap(crate::Trap::MemoryOutOfBounds { + offset: offset as usize, + len: core::mem::size_of::<$load_type>(), + max: mem.borrow().max_pages(), + })); + } + }; + + const LEN: usize = core::mem::size_of::<$load_type>(); + let val = mem.borrow().load_as::(addr)?; + stack.values.push((val as $target_type).into()); + Ok(()) + } - let mem_idx = $module.resolve_mem_addr(*mem_addr); - let mem = $store.get_mem(mem_idx)?; - let mem_ref = mem.borrow_mut(); - - let memory_out_of_bounds = || { - cold(); - Error::Trap(crate::Trap::MemoryOutOfBounds { - offset: *offset as usize, - len: core::mem::size_of::<$load_type>(), - max: mem_ref.max_pages(), - }) - }; - - let addr: usize = offset - .checked_add($stack.values.pop()?.into()) - .ok_or_else(memory_out_of_bounds)? - .try_into() - .ok() - .ok_or_else(memory_out_of_bounds)?; - - const LEN: usize = core::mem::size_of::<$load_type>(); - let val = mem_ref.load_as::(addr)?; - $stack.values.push((val as $target_type).into()); + let (mem_addr, offset) = $arg; + mem_load_inner($store, &$module, $stack, *mem_addr, *offset)?; }}; } @@ -62,13 +67,24 @@ macro_rules! mem_store { }}; ($store_type:ty, $target_type:ty, $arg:expr, $stack:ident, $store:ident, $module:ident) => {{ - let (mem_addr, offset) = $arg; - let mem = $store.get_mem($module.resolve_mem_addr(*mem_addr))?; - let val: $store_type = $stack.values.pop()?.into(); - let val = val.to_le_bytes(); - let addr: u64 = $stack.values.pop()?.into(); + #[inline(always)] + fn mem_store_inner( + store: &Store, + module: &crate::ModuleInstance, + stack: &mut crate::runtime::Stack, + mem_addr: tinywasm_types::MemAddr, + offset: u64, + ) -> Result<()> { + let mem = store.get_mem(module.resolve_mem_addr(mem_addr))?; + let val: $store_type = stack.values.pop()?.into(); + let val = val.to_le_bytes(); + let addr: u64 = stack.values.pop()?.into(); + mem.borrow_mut().store((offset + addr) as usize, val.len(), &val)?; + Ok(()) + } - mem.borrow_mut().store((*offset + addr) as usize, val.len(), &val)?; + let (mem_addr, offset) = $arg; + mem_store_inner($store, &$module, $stack, *mem_addr, *offset)?; }}; } @@ -77,8 +93,8 @@ macro_rules! mem_store { /// for a specific conversion, which are then used in the actual conversion. /// Rust sadly doesn't have wrapping casts for floats yet, maybe never. /// Alternatively, https://crates.io/crates/az could be used for this but -/// it's not worth the dependency. -#[rustfmt::skip] +/// it's not worth the dependency. +#[rustfmt::skip] macro_rules! float_min_max { (f32, i32) => {(-2147483904.0_f32, 2147483648.0_f32)}; (f64, i32) => {(-2147483649.0_f64, 2147483648.0_f64)}; @@ -94,20 +110,17 @@ macro_rules! float_min_max { /// Convert a value on the stack macro_rules! conv { - ($from:ty, $to:ty, $stack:ident) => {{ - $stack.values.replace_top(|v| { - let a: $from = v.into(); - (a as $to).into() - }); - }}; + ($from:ty, $to:ty, $stack:ident) => { + $stack.values.replace_top(|v| (<$from>::from(v) as $to).into())? + }; } /// Convert a value on the stack with error checking macro_rules! checked_conv_float { // Direct conversion with error checking (two types) - ($from:tt, $to:tt, $stack:ident) => {{ + ($from:tt, $to:tt, $stack:ident) => { checked_conv_float!($from, $to, $to, $stack) - }}; + }; // Conversion with an intermediate unsigned type and error checking (three types) ($from:tt, $intermediate:tt, $to:tt, $stack:ident) => {{ let (min, max) = float_min_max!($from, $intermediate); @@ -127,67 +140,96 @@ macro_rules! checked_conv_float { /// Compare two values on the stack macro_rules! comp { - ($op:tt, $to:ty, $stack:ident) => {{ - let b: $to = $stack.values.pop()?.into(); - let a: $to = $stack.values.pop()?.into(); - $stack.values.push(((a $op b) as i32).into()); - }}; + ($op:tt, $to:ty, $stack:ident) => { + $stack.values.calculate(|a, b| { + ((<$to>::from(a) $op <$to>::from(b)) as i32).into() + })? + }; } /// Compare a value on the stack to zero macro_rules! comp_zero { - ($op:tt, $ty:ty, $stack:ident) => {{ - let a: $ty = $stack.values.pop()?.into(); - $stack.values.push(((a $op 0) as i32).into()); - }}; + ($op:tt, $ty:ty, $stack:ident) => { + $stack.values.replace_top(|v| { + ((<$ty>::from(v) $op 0) as i32).into() + })? + }; } /// Apply an arithmetic method to two values on the stack macro_rules! arithmetic { - ($op:ident, $to:ty, $stack:ident) => {{ - let b: $to = $stack.values.pop()?.into(); - let a: $to = $stack.values.pop()?.into(); - $stack.values.push((a.$op(b) as $to).into()); - }}; + ($op:ident, $to:ty, $stack:ident) => { + $stack.values.calculate(|a, b| { + (<$to>::from(a).$op(<$to>::from(b)) as $to).into() + })? + }; // also allow operators such as +, - - ($op:tt, $ty:ty, $stack:ident) => {{ - let b: $ty = $stack.values.pop()?.into(); - let a: $ty = $stack.values.pop()?.into(); - $stack.values.push((a $op b).into()); - }}; + ($op:tt, $ty:ty, $stack:ident) => { + $stack.values.calculate(|a, b| { + ((<$ty>::from(a) $op <$ty>::from(b)) as $ty).into() + })? + }; } /// Apply an arithmetic method to a single value on the stack macro_rules! arithmetic_single { - ($op:ident, $ty:ty, $stack:ident) => {{ + ($op:ident, $ty:ty, $stack:ident) => { arithmetic_single!($op, $ty, $ty, $stack) - }}; + }; - ($op:ident, $from:ty, $to:ty, $stack:ident) => {{ - let a: $from = $stack.values.pop()?.into(); - $stack.values.push((a.$op() as $to).into()); - }}; + ($op:ident, $from:ty, $to:ty, $stack:ident) => { + $stack.values.replace_top(|v| (<$from>::from(v).$op() as $to).into())? + }; } /// Apply an arithmetic operation to two values on the stack with error checking macro_rules! checked_int_arithmetic { - ($op:ident, $to:ty, $stack:ident) => {{ - let b: $to = $stack.values.pop()?.into(); - let a: $to = $stack.values.pop()?.into(); + ($op:ident, $to:ty, $stack:ident) => { + $stack.values.calculate_trap(|a, b| { + let a: $to = a.into(); + let b: $to = b.into(); + + if unlikely(b == 0) { + return Err(Error::Trap(crate::Trap::DivisionByZero)); + } + + let result = a.$op(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow))?; + Ok((result).into()) + })? + }; +} + +macro_rules! call { + ($cf:expr, $stack:expr, $module:expr, $store:expr) => {{ + let old = $cf.block_ptr; + $cf = $stack.call_stack.pop()?; + + if old > $cf.block_ptr { + $stack.blocks.truncate(old); + } - if unlikely(b == 0) { - return Err(Error::Trap(crate::Trap::DivisionByZero)); + if $cf.module_addr != $module.id() { + $module.swap_with($cf.module_addr, $store); } - let result = a.$op(b).ok_or_else(|| Error::Trap(crate::Trap::IntegerOverflow))?; - $stack.values.push((result).into()); + continue; }}; } +macro_rules! skip { + ($code:expr) => { + match $code { + Ok(_) => continue, + Err(e) => return Err(e), + } + }; +} + pub(super) use arithmetic; pub(super) use arithmetic_single; pub(super) use break_to; +pub(super) use call; pub(super) use checked_conv_float; pub(super) use checked_int_arithmetic; pub(super) use comp; @@ -196,3 +238,4 @@ pub(super) use conv; pub(super) use float_min_max; pub(super) use mem_load; pub(super) use mem_store; +pub(super) use skip; diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs index 404e4fe..d01faeb 100644 --- a/crates/tinywasm/src/runtime/interpreter/mod.rs +++ b/crates/tinywasm/src/runtime/interpreter/mod.rs @@ -1,12 +1,12 @@ use alloc::format; use alloc::string::ToString; use core::ops::{BitAnd, BitOr, BitXor, Neg}; -use tinywasm_types::{ElementKind, ValType}; +use tinywasm_types::{BlockArgs, ElementKind, ValType}; -use super::{InterpreterRuntime, Stack}; +use super::{InterpreterRuntime, RawWasmValue, Stack}; use crate::runtime::{BlockFrame, BlockType, CallFrame}; -use crate::{cold, unlikely}; -use crate::{Error, FuncContext, ModuleInstance, Result, Store, Trap}; +use crate::{cold, unlikely, ModuleInstance}; +use crate::{Error, FuncContext, Result, Store, Trap}; mod macros; mod traits; @@ -20,630 +20,756 @@ mod no_std_floats; use no_std_floats::NoStdFloatExt; impl InterpreterRuntime { - // #[inline(always)] // a small 2-3% performance improvement in some cases pub(crate) fn exec(&self, store: &mut Store, stack: &mut Stack) -> Result<()> { - let mut call_frame = stack.call_stack.pop()?; - let mut current_module = store.get_module_instance_raw(call_frame.module_addr); + let mut cf = stack.call_stack.pop()?; + let mut module = store.get_module_instance_raw(cf.module_addr); loop { - match exec_one(&mut call_frame, stack, store, ¤t_module) { - // continue to the next instruction and increment the instruction pointer - Ok(ExecResult::Ok) => call_frame.instr_ptr += 1, - - // Continue execution at the new top of the call stack - Ok(ExecResult::Call) => { - let old = call_frame.block_ptr; - call_frame = stack.call_stack.pop()?; - - if old > call_frame.block_ptr { - stack.blocks.truncate(old); + use tinywasm_types::Instruction::*; + match cf.fetch_instr() { + Nop => cold(), + Unreachable => self.exec_unreachable()?, + Drop => stack.values.pop().map(|_| ())?, + Select(_valtype) => self.exec_select(stack)?, + + Call(v) => skip!(self.exec_call(*v, store, stack, &mut cf, &mut module)), + CallIndirect(ty, table) => { + skip!(self.exec_call_indirect(*ty, *table, store, stack, &mut cf, &mut module)) + } + If(args, el, end) => skip!(self.exec_if((*args).into(), *el, *end, stack, &mut cf, &mut module)), + Loop(args, end) => self.enter_block(stack, cf.instr_ptr, *end, BlockType::Loop, args, &module), + Block(args, end) => self.enter_block(stack, cf.instr_ptr, *end, BlockType::Block, args, &module), + + Br(v) => break_to!(cf, stack, module, store, v), + BrIf(v) => { + if i32::from(stack.values.pop()?) != 0 { + break_to!(cf, stack, module, store, v); + } + } + BrTable(default, len) => { + let start = cf.instr_ptr + 1; + let end = start + *len as usize; + if end > cf.instructions().len() { + return Err(Error::Other(format!( + "br_table out of bounds: {} >= {}", + end, + cf.instructions().len() + ))); } - // keeping the pointer seperate from the call frame is about 2% faster - // than storing it in the call frame - if call_frame.module_addr != current_module.id() { - current_module.swap_with(call_frame.module_addr, store); + let idx: i32 = stack.values.pop()?.into(); + match cf.instructions()[start..end].get(idx as usize) { + None => break_to!(cf, stack, module, store, default), + Some(BrLabel(to)) => break_to!(cf, stack, module, store, to), + _ => return Err(Error::Other("br_table with invalid label".to_string())), } } - // return from the function - Ok(ExecResult::Return) => { - cold(); - return Ok(()); + Return => match stack.call_stack.is_empty() { + true => return Ok(()), + false => call!(cf, stack, module, store), + }, + + // We're essentially using else as a EndBlockFrame instruction for if blocks + Else(end_offset) => self.exec_else(stack, *end_offset, &mut cf)?, + + // remove the label from the label stack + EndBlockFrame => self.exec_end_block(stack)?, + + LocalGet(local_index) => self.exec_local_get(*local_index, stack, &cf), + LocalSet(local_index) => self.exec_local_set(*local_index, stack, &mut cf)?, + LocalTee(local_index) => self.exec_local_tee(*local_index, stack, &mut cf)?, + + GlobalGet(global_index) => self.exec_global_get(*global_index, stack, store, &module)?, + GlobalSet(global_index) => self.exec_global_set(*global_index, stack, store, &module)?, + + I32Const(val) => self.exec_const(*val, stack), + I64Const(val) => self.exec_const(*val, stack), + F32Const(val) => self.exec_const(*val, stack), + F64Const(val) => self.exec_const(*val, stack), + + MemorySize(addr, byte) => self.exec_memory_size(*addr, *byte, stack, store, &module)?, + MemoryGrow(addr, byte) => self.exec_memory_grow(*addr, *byte, stack, store, &module)?, + + // Bulk memory operations + MemoryCopy(from, to) => self.exec_memory_copy(*from, *to, stack, store, &module)?, + MemoryFill(addr) => self.exec_memory_fill(*addr, stack, store, &module)?, + MemoryInit(data_idx, mem_idx) => self.exec_memory_init(*data_idx, *mem_idx, stack, store, &module)?, + DataDrop(data_index) => store.get_data_mut(module.resolve_data_addr(*data_index))?.drop(), + + I32Store { mem_addr, offset } => mem_store!(i32, (mem_addr, offset), stack, store, module), + I64Store { mem_addr, offset } => mem_store!(i64, (mem_addr, offset), stack, store, module), + F32Store { mem_addr, offset } => mem_store!(f32, (mem_addr, offset), stack, store, module), + F64Store { mem_addr, offset } => mem_store!(f64, (mem_addr, offset), stack, store, module), + I32Store8 { mem_addr, offset } => mem_store!(i8, i32, (mem_addr, offset), stack, store, module), + I32Store16 { mem_addr, offset } => mem_store!(i16, i32, (mem_addr, offset), stack, store, module), + I64Store8 { mem_addr, offset } => mem_store!(i8, i64, (mem_addr, offset), stack, store, module), + I64Store16 { mem_addr, offset } => mem_store!(i16, i64, (mem_addr, offset), stack, store, module), + I64Store32 { mem_addr, offset } => mem_store!(i32, i64, (mem_addr, offset), stack, store, module), + + I32Load { mem_addr, offset } => mem_load!(i32, (mem_addr, offset), stack, store, module), + I64Load { mem_addr, offset } => mem_load!(i64, (mem_addr, offset), stack, store, module), + F32Load { mem_addr, offset } => mem_load!(f32, (mem_addr, offset), stack, store, module), + F64Load { mem_addr, offset } => mem_load!(f64, (mem_addr, offset), stack, store, module), + I32Load8S { mem_addr, offset } => mem_load!(i8, i32, (mem_addr, offset), stack, store, module), + I32Load8U { mem_addr, offset } => mem_load!(u8, i32, (mem_addr, offset), stack, store, module), + I32Load16S { mem_addr, offset } => mem_load!(i16, i32, (mem_addr, offset), stack, store, module), + I32Load16U { mem_addr, offset } => mem_load!(u16, i32, (mem_addr, offset), stack, store, module), + I64Load8S { mem_addr, offset } => mem_load!(i8, i64, (mem_addr, offset), stack, store, module), + I64Load8U { mem_addr, offset } => mem_load!(u8, i64, (mem_addr, offset), stack, store, module), + I64Load16S { mem_addr, offset } => mem_load!(i16, i64, (mem_addr, offset), stack, store, module), + I64Load16U { mem_addr, offset } => mem_load!(u16, i64, (mem_addr, offset), stack, store, module), + I64Load32S { mem_addr, offset } => mem_load!(i32, i64, (mem_addr, offset), stack, store, module), + I64Load32U { mem_addr, offset } => mem_load!(u32, i64, (mem_addr, offset), stack, store, module), + + I64Eqz => comp_zero!(==, i64, stack), + I32Eqz => comp_zero!(==, i32, stack), + + I32Eq => comp!(==, i32, stack), + I64Eq => comp!(==, i64, stack), + F32Eq => comp!(==, f32, stack), + F64Eq => comp!(==, f64, stack), + + I32Ne => comp!(!=, i32, stack), + I64Ne => comp!(!=, i64, stack), + F32Ne => comp!(!=, f32, stack), + F64Ne => comp!(!=, f64, stack), + + I32LtS => comp!(<, i32, stack), + I64LtS => comp!(<, i64, stack), + I32LtU => comp!(<, u32, stack), + I64LtU => comp!(<, u64, stack), + F32Lt => comp!(<, f32, stack), + F64Lt => comp!(<, f64, stack), + + I32LeS => comp!(<=, i32, stack), + I64LeS => comp!(<=, i64, stack), + I32LeU => comp!(<=, u32, stack), + I64LeU => comp!(<=, u64, stack), + F32Le => comp!(<=, f32, stack), + F64Le => comp!(<=, f64, stack), + + I32GeS => comp!(>=, i32, stack), + I64GeS => comp!(>=, i64, stack), + I32GeU => comp!(>=, u32, stack), + I64GeU => comp!(>=, u64, stack), + F32Ge => comp!(>=, f32, stack), + F64Ge => comp!(>=, f64, stack), + + I32GtS => comp!(>, i32, stack), + I64GtS => comp!(>, i64, stack), + I32GtU => comp!(>, u32, stack), + I64GtU => comp!(>, u64, stack), + F32Gt => comp!(>, f32, stack), + F64Gt => comp!(>, f64, stack), + + I64Add => arithmetic!(wrapping_add, i64, stack), + I32Add => arithmetic!(wrapping_add, i32, stack), + F32Add => arithmetic!(+, f32, stack), + F64Add => arithmetic!(+, f64, stack), + + I32Sub => arithmetic!(wrapping_sub, i32, stack), + I64Sub => arithmetic!(wrapping_sub, i64, stack), + F32Sub => arithmetic!(-, f32, stack), + F64Sub => arithmetic!(-, f64, stack), + + F32Div => arithmetic!(/, f32, stack), + F64Div => arithmetic!(/, f64, stack), + + I32Mul => arithmetic!(wrapping_mul, i32, stack), + I64Mul => arithmetic!(wrapping_mul, i64, stack), + F32Mul => arithmetic!(*, f32, stack), + F64Mul => arithmetic!(*, f64, stack), + + // these can trap + I32DivS => checked_int_arithmetic!(checked_div, i32, stack), + I64DivS => checked_int_arithmetic!(checked_div, i64, stack), + I32DivU => checked_int_arithmetic!(checked_div, u32, stack), + I64DivU => checked_int_arithmetic!(checked_div, u64, stack), + + I32RemS => checked_int_arithmetic!(checked_wrapping_rem, i32, stack), + I64RemS => checked_int_arithmetic!(checked_wrapping_rem, i64, stack), + I32RemU => checked_int_arithmetic!(checked_wrapping_rem, u32, stack), + I64RemU => checked_int_arithmetic!(checked_wrapping_rem, u64, stack), + + I32And => arithmetic!(bitand, i32, stack), + I64And => arithmetic!(bitand, i64, stack), + I32Or => arithmetic!(bitor, i32, stack), + I64Or => arithmetic!(bitor, i64, stack), + I32Xor => arithmetic!(bitxor, i32, stack), + I64Xor => arithmetic!(bitxor, i64, stack), + I32Shl => arithmetic!(wasm_shl, i32, stack), + I64Shl => arithmetic!(wasm_shl, i64, stack), + I32ShrS => arithmetic!(wasm_shr, i32, stack), + I64ShrS => arithmetic!(wasm_shr, i64, stack), + I32ShrU => arithmetic!(wasm_shr, u32, stack), + I64ShrU => arithmetic!(wasm_shr, u64, stack), + I32Rotl => arithmetic!(wasm_rotl, i32, stack), + I64Rotl => arithmetic!(wasm_rotl, i64, stack), + I32Rotr => arithmetic!(wasm_rotr, i32, stack), + I64Rotr => arithmetic!(wasm_rotr, i64, stack), + + I32Clz => arithmetic_single!(leading_zeros, i32, stack), + I64Clz => arithmetic_single!(leading_zeros, i64, stack), + I32Ctz => arithmetic_single!(trailing_zeros, i32, stack), + I64Ctz => arithmetic_single!(trailing_zeros, i64, stack), + I32Popcnt => arithmetic_single!(count_ones, i32, stack), + I64Popcnt => arithmetic_single!(count_ones, i64, stack), + + F32ConvertI32S => conv!(i32, f32, stack), + F32ConvertI64S => conv!(i64, f32, stack), + F64ConvertI32S => conv!(i32, f64, stack), + F64ConvertI64S => conv!(i64, f64, stack), + F32ConvertI32U => conv!(u32, f32, stack), + F32ConvertI64U => conv!(u64, f32, stack), + F64ConvertI32U => conv!(u32, f64, stack), + F64ConvertI64U => conv!(u64, f64, stack), + I32Extend8S => conv!(i8, i32, stack), + I32Extend16S => conv!(i16, i32, stack), + I64Extend8S => conv!(i8, i64, stack), + I64Extend16S => conv!(i16, i64, stack), + I64Extend32S => conv!(i32, i64, stack), + I64ExtendI32U => conv!(u32, i64, stack), + I64ExtendI32S => conv!(i32, i64, stack), + I32WrapI64 => conv!(i64, i32, stack), + + F32DemoteF64 => conv!(f64, f32, stack), + F64PromoteF32 => conv!(f32, f64, stack), + + F32Abs => arithmetic_single!(abs, f32, stack), + F64Abs => arithmetic_single!(abs, f64, stack), + F32Neg => arithmetic_single!(neg, f32, stack), + F64Neg => arithmetic_single!(neg, f64, stack), + F32Ceil => arithmetic_single!(ceil, f32, stack), + F64Ceil => arithmetic_single!(ceil, f64, stack), + F32Floor => arithmetic_single!(floor, f32, stack), + F64Floor => arithmetic_single!(floor, f64, stack), + F32Trunc => arithmetic_single!(trunc, f32, stack), + F64Trunc => arithmetic_single!(trunc, f64, stack), + F32Nearest => arithmetic_single!(tw_nearest, f32, stack), + F64Nearest => arithmetic_single!(tw_nearest, f64, stack), + F32Sqrt => arithmetic_single!(sqrt, f32, stack), + F64Sqrt => arithmetic_single!(sqrt, f64, stack), + F32Min => arithmetic!(tw_minimum, f32, stack), + F64Min => arithmetic!(tw_minimum, f64, stack), + F32Max => arithmetic!(tw_maximum, f32, stack), + F64Max => arithmetic!(tw_maximum, f64, stack), + F32Copysign => arithmetic!(copysign, f32, stack), + F64Copysign => arithmetic!(copysign, f64, stack), + + // no-op instructions since types are erased at runtime + I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {} + + // unsigned versions of these are a bit broken atm + I32TruncF32S => checked_conv_float!(f32, i32, stack), + I32TruncF64S => checked_conv_float!(f64, i32, stack), + I32TruncF32U => checked_conv_float!(f32, u32, i32, stack), + I32TruncF64U => checked_conv_float!(f64, u32, i32, stack), + I64TruncF32S => checked_conv_float!(f32, i64, stack), + I64TruncF64S => checked_conv_float!(f64, i64, stack), + I64TruncF32U => checked_conv_float!(f32, u64, i64, stack), + I64TruncF64U => checked_conv_float!(f64, u64, i64, stack), + + TableGet(table_idx) => self.exec_table_get(*table_idx, stack, store, &module)?, + TableSet(table_idx) => self.exec_table_set(*table_idx, stack, store, &module)?, + TableSize(table_idx) => self.exec_table_size(*table_idx, stack, store, &module)?, + TableInit(table_idx, elem_idx) => self.exec_table_init(*elem_idx, *table_idx, store, &module)?, + + I32TruncSatF32S => arithmetic_single!(trunc, f32, i32, stack), + I32TruncSatF32U => arithmetic_single!(trunc, f32, u32, stack), + I32TruncSatF64S => arithmetic_single!(trunc, f64, i32, stack), + I32TruncSatF64U => arithmetic_single!(trunc, f64, u32, stack), + I64TruncSatF32S => arithmetic_single!(trunc, f32, i64, stack), + I64TruncSatF32U => arithmetic_single!(trunc, f32, u64, stack), + I64TruncSatF64S => arithmetic_single!(trunc, f64, i64, stack), + I64TruncSatF64U => arithmetic_single!(trunc, f64, u64, stack), + + // custom instructions + LocalGet2(a, b) => self.exec_local_get2(*a, *b, stack, &cf), + LocalGet3(a, b, c) => self.exec_local_get3(*a, *b, *c, stack, &cf), + LocalTeeGet(a, b) => self.exec_local_tee_get(*a, *b, stack, &mut cf), + LocalGetSet(a, b) => self.exec_local_get_set(*a, *b, &mut cf), + I64XorConstRotl(rotate_by) => self.exec_i64_xor_const_rotl(*rotate_by, stack)?, + I32LocalGetConstAdd(local, val) => self.exec_i32_local_get_const_add(*local, *val, stack, &cf), + I32StoreLocal { local, const_i32: consti32, offset, mem_addr } => { + self.exec_i32_store_local(*local, *consti32, *offset, *mem_addr, &cf, store, &module)? } - - // trap the program - Err(e) => { + i => { cold(); - call_frame.instr_ptr += 1; - // push the call frame back onto the stack so that it can be resumed - // if the trap can be handled - stack.call_stack.push(call_frame)?; - return Err(e); + return Err(Error::UnsupportedFeature(format!("unimplemented instruction: {:?}", i))); } - } - } - } -} - -enum ExecResult { - Ok, - Return, - Call, -} + }; -/// Run a single step of the interpreter -/// A seperate function is used so later, we can more easily implement -/// a step-by-step debugger (using generators once they're stable?) -// we want this be always part of the loop, rust just doesn't inline it as its too big -// this can be a 30%+ performance difference in some cases -#[inline(always)] -fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &ModuleInstance) -> Result { - let instrs = &cf.func_instance.instructions; - - // A match statement is probably the fastest way to do this without - // unreasonable complexity. This *should* be optimized to a jump table. - // See https://pliniker.github.io/post/dispatchers/ - use tinywasm_types::Instruction::*; - match instrs.get(cf.instr_ptr as usize).expect("instr_ptr out of bounds, this should never happen") { - Nop => { /* do nothing */ } - Unreachable => return Err(crate::Trap::Unreachable.into()), - Drop => stack.values.pop().map(|_| ())?, - Select(_valtype) => { - // due to validation, we know that the type of the values on the stack - let cond: i32 = stack.values.pop()?.into(); - let val2 = stack.values.pop()?; - - // if cond != 0, we already have the right value on the stack - if cond == 0 { - let _ = stack.values.pop()?; - stack.values.push(val2); - } + cf.instr_ptr += 1; } + } - Call(v) => { - // prepare the call frame - let func_inst = store.get_func(module.resolve_func_addr(*v))?; - let wasm_func = match &func_inst.func { - crate::Function::Wasm(wasm_func) => wasm_func, - crate::Function::Host(host_func) => { - let func = &host_func.clone(); - let params = stack.values.pop_params(&host_func.ty.params)?; - let res = (func.func)(FuncContext { store, module_addr: module.id() }, ¶ms)?; - stack.values.extend_from_typed(&res); - return Ok(ExecResult::Ok); - } - }; + #[inline(always)] + fn exec_end_block(&self, stack: &mut Stack) -> Result<()> { + let block = stack.blocks.pop()?; + stack.values.truncate_keep(block.stack_ptr, block.results as u32); + Ok(()) + } - let params = stack.values.pop_n_rev(wasm_func.ty.params.len())?; - let call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, stack.blocks.len() as u32); + #[inline(always)] + fn exec_else(&self, stack: &mut Stack, end_offset: u32, cf: &mut CallFrame) -> Result<()> { + let block = stack.blocks.pop()?; + stack.values.truncate_keep(block.stack_ptr, block.results as u32); + cf.instr_ptr += end_offset as usize; + Ok(()) + } - // push the call frame - cf.instr_ptr += 1; // skip the call instruction + #[inline(always)] + #[cold] + fn exec_unreachable(&self) -> Result<()> { + Err(Error::Trap(Trap::Unreachable)) + } - // this is sometimes faster, and seems more efficient, but sometimes it's also a lot slower - // stack.call_stack.push(core::mem::replace(cf, call_frame))?; - // if cf.module_addr != module.id() { - // module.swap_with(cf.module_addr, store); - // } - // cf.instr_ptr -= 1; - // return Ok(ExecResult::Ok); + #[inline(always)] + fn exec_const(&self, val: impl Into, stack: &mut Stack) { + stack.values.push(val.into()); + } - stack.call_stack.push(cf.clone())?; - stack.call_stack.push(call_frame)?; + #[inline(always)] + fn exec_i32_store_local( + &self, + local: u32, + const_i32: i32, + offset: u32, + mem_addr: u8, + cf: &CallFrame, + store: &Store, + module: &ModuleInstance, + ) -> Result<()> { + let mem_addr = module.resolve_mem_addr(mem_addr as u32); + let mem = store.get_mem(mem_addr)?; + let val = const_i32.to_le_bytes(); + let addr: u64 = cf.get_local(local).into(); + mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?; + Ok(()) + } - // call the function - return Ok(ExecResult::Call); - } + #[inline(always)] + fn exec_i32_local_get_const_add(&self, local: u32, val: i32, stack: &mut Stack, cf: &CallFrame) { + let local: i32 = cf.get_local(local).into(); + stack.values.push((local + val).into()); + } - CallIndirect(type_addr, table_addr) => { - let table = store.get_table(module.resolve_table_addr(*table_addr))?; - let table_idx: u32 = stack.values.pop()?.into(); + #[inline(always)] + fn exec_i64_xor_const_rotl(&self, rotate_by: i64, stack: &mut Stack) -> Result<()> { + let val: i64 = stack.values.pop()?.into(); + let res = stack.values.last_mut()?; + let mask: i64 = (*res).into(); + *res = (val ^ mask).rotate_left(rotate_by as u32).into(); + Ok(()) + } - // verify that the table is of the right type, this should be validated by the parser already - let func_ref = { - let table = table.borrow(); - assert!(table.kind.element_type == ValType::RefFunc, "table is not of type funcref"); - table.get(table_idx)?.addr().ok_or(Trap::UninitializedElement { index: table_idx as usize })? - }; + #[inline(always)] + fn exec_local_get(&self, local_index: u32, stack: &mut Stack, cf: &CallFrame) { + stack.values.push(cf.get_local(local_index)); + } - let func_inst = store.get_func(func_ref)?.clone(); - let call_ty = module.func_ty(*type_addr); - - let wasm_func = match func_inst.func { - crate::Function::Wasm(ref f) => f, - crate::Function::Host(host_func) => { - if unlikely(host_func.ty != *call_ty) { - return Err(Trap::IndirectCallTypeMismatch { - actual: host_func.ty.clone(), - expected: call_ty.clone(), - } - .into()); - } + #[inline(always)] + fn exec_local_get2(&self, a: u32, b: u32, stack: &mut Stack, cf: &CallFrame) { + stack.values.push(cf.get_local(a)); + stack.values.push(cf.get_local(b)); + } - let host_func = host_func.clone(); - let params = stack.values.pop_params(&host_func.ty.params)?; - let res = (host_func.func)(FuncContext { store, module_addr: module.id() }, ¶ms)?; - stack.values.extend_from_typed(&res); - return Ok(ExecResult::Ok); - } - }; + #[inline(always)] + fn exec_local_get3(&self, a: u32, b: u32, c: u32, stack: &mut Stack, cf: &CallFrame) { + stack.values.push(cf.get_local(a)); + stack.values.push(cf.get_local(b)); + stack.values.push(cf.get_local(c)); + } - if unlikely(wasm_func.ty != *call_ty) { - return Err( - Trap::IndirectCallTypeMismatch { actual: wasm_func.ty.clone(), expected: call_ty.clone() }.into() - ); - } + #[inline(always)] + fn exec_local_get_set(&self, a: u32, b: u32, cf: &mut CallFrame) { + cf.set_local(b, cf.get_local(a)) + } - let params = stack.values.pop_n_rev(wasm_func.ty.params.len())?; - let call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, stack.blocks.len() as u32); + #[inline(always)] + fn exec_local_set(&self, local_index: u32, stack: &mut Stack, cf: &mut CallFrame) -> Result<()> { + cf.set_local(local_index, stack.values.pop()?); + Ok(()) + } - cf.instr_ptr += 1; // skip the call instruction - stack.call_stack.push(cf.clone())?; - stack.call_stack.push(call_frame)?; + #[inline(always)] + fn exec_local_tee(&self, local_index: u32, stack: &mut Stack, cf: &mut CallFrame) -> Result<()> { + cf.set_local(local_index, *stack.values.last()?); + Ok(()) + } - // call the function - return Ok(ExecResult::Call); - } + #[inline(always)] + fn exec_local_tee_get(&self, a: u32, b: u32, stack: &mut Stack, cf: &mut CallFrame) { + let last = + stack.values.last().expect("localtee: stack is empty. this should have been validated by the parser"); + cf.set_local(a, *last); + stack.values.push(match a == b { + true => *last, + false => cf.get_local(b), + }); + } - If(args, else_offset, end_offset) => { - // truthy value is on the top of the stack, so enter the then block - if i32::from(stack.values.pop()?) != 0 { - cf.enter_block( - BlockFrame::new( - cf.instr_ptr, - cf.instr_ptr + *end_offset, - stack.values.len() as u32, - BlockType::If, - &(*args).into(), - module, - ), - &mut stack.values, - &mut stack.blocks, - ); - return Ok(ExecResult::Ok); - } + #[inline(always)] + fn exec_global_get( + &self, + global_index: u32, + stack: &mut Stack, + store: &Store, + module: &ModuleInstance, + ) -> Result<()> { + let global = store.get_global_val(module.resolve_global_addr(global_index))?; + stack.values.push(global); + Ok(()) + } - // falsy value is on the top of the stack - if *else_offset == 0 { - cf.instr_ptr += *end_offset; - return Ok(ExecResult::Ok); - } + #[inline(always)] + fn exec_global_set( + &self, + global_index: u32, + stack: &mut Stack, + store: &mut Store, + module: &ModuleInstance, + ) -> Result<()> { + let idx = module.resolve_global_addr(global_index); + store.set_global_val(idx, stack.values.pop()?)?; + Ok(()) + } - let label = BlockFrame::new( - cf.instr_ptr + *else_offset, - cf.instr_ptr + *end_offset, - stack.values.len() as u32, - BlockType::Else, - &(*args).into(), - module, - ); - cf.instr_ptr += *else_offset; - cf.enter_block(label, &mut stack.values, &mut stack.blocks); - } + #[inline(always)] + fn exec_table_get( + &self, + table_index: u32, + stack: &mut Stack, + store: &Store, + module: &ModuleInstance, + ) -> Result<()> { + let table_idx = module.resolve_table_addr(table_index); + let table = store.get_table(table_idx)?; + let idx: u32 = stack.values.pop()?.into(); + let v = table.borrow().get_wasm_val(idx)?; + stack.values.push(v.into()); + Ok(()) + } - Loop(args, end_offset) => { - cf.enter_block( - BlockFrame::new( - cf.instr_ptr, - cf.instr_ptr + *end_offset, - stack.values.len() as u32, - BlockType::Loop, - args, - module, - ), - &mut stack.values, - &mut stack.blocks, - ); - } + #[inline(always)] + fn exec_table_set( + &self, + table_index: u32, + stack: &mut Stack, + store: &Store, + module: &ModuleInstance, + ) -> Result<()> { + let table_idx = module.resolve_table_addr(table_index); + let table = store.get_table(table_idx)?; + let val = stack.values.pop()?.into(); + let idx = stack.values.pop()?.into(); + table.borrow_mut().set(idx, val)?; + Ok(()) + } - Block(args, end_offset) => { - cf.enter_block( - BlockFrame::new( - cf.instr_ptr, - cf.instr_ptr + *end_offset, - stack.values.len() as u32, - BlockType::Block, - args, - module, - ), - &mut stack.values, - &mut stack.blocks, - ); - } + #[inline(always)] + fn exec_table_size( + &self, + table_index: u32, + stack: &mut Stack, + store: &Store, + module: &ModuleInstance, + ) -> Result<()> { + let table_idx = module.resolve_table_addr(table_index); + let table = store.get_table(table_idx)?; + stack.values.push(table.borrow().size().into()); + Ok(()) + } - BrTable(default, len) => { - let start = (cf.instr_ptr + 1) as usize; - let end = start + *len as usize; - if end > cf.instructions().len() { - return Err(Error::Other(format!("br_table out of bounds: {} >= {}", end, cf.instructions().len()))); - } + #[inline(always)] + fn exec_table_init(&self, elem_index: u32, table_index: u32, store: &Store, module: &ModuleInstance) -> Result<()> { + let table_idx = module.resolve_table_addr(table_index); + let table = store.get_table(table_idx)?; + let elem = store.get_elem(module.resolve_elem_addr(elem_index))?; - let idx: i32 = stack.values.pop()?.into(); - match cf.instructions()[start..end].get(idx as usize) { - None => break_to!(cf, stack, default), - Some(BrLabel(to)) => break_to!(cf, stack, to), - _ => return Err(Error::Other("br_table with invalid label".to_string())), - } + if let ElementKind::Passive = elem.kind { + return Err(Trap::TableOutOfBounds { offset: 0, len: 0, max: 0 }.into()); } - Br(v) => break_to!(cf, stack, v), - BrIf(v) => { - if i32::from(stack.values.pop()?) != 0 { - break_to!(cf, stack, v); - } - } + let Some(items) = elem.items.as_ref() else { + return Err(Trap::TableOutOfBounds { offset: 0, len: 0, max: 0 }.into()); + }; - Return => match stack.call_stack.is_empty() { - true => return Ok(ExecResult::Return), - false => return Ok(ExecResult::Call), - }, + table.borrow_mut().init(module.func_addrs(), 0, items)?; + Ok(()) + } - // We're essentially using else as a EndBlockFrame instruction for if blocks - Else(end_offset) => { - let block = stack.blocks.pop()?; - stack.values.truncate_keep(block.stack_ptr, block.results as u32); - cf.instr_ptr += *end_offset; + #[inline(always)] + fn exec_select(&self, stack: &mut Stack) -> Result<()> { + let cond: i32 = stack.values.pop()?.into(); + let val2 = stack.values.pop()?; + // if cond != 0, we already have the right value on the stack + if cond == 0 { + *stack.values.last_mut()? = val2; } + Ok(()) + } - // remove the label from the label stack - EndBlockFrame => { - let block = stack.blocks.pop()?; - stack.values.truncate_keep(block.stack_ptr, block.results as u32); + #[inline(always)] + fn exec_memory_size( + &self, + addr: u32, + byte: u8, + stack: &mut Stack, + store: &Store, + module: &ModuleInstance, + ) -> Result<()> { + if unlikely(byte != 0) { + return Err(Error::UnsupportedFeature("memory.size with byte != 0".to_string())); } - LocalGet(local_index) => stack.values.push(cf.get_local(*local_index)), - LocalSet(local_index) => cf.set_local(*local_index, stack.values.pop()?), - LocalTee(local_index) => cf.set_local(*local_index, *stack.values.last()?), - - GlobalGet(global_index) => { - let global = store.get_global_val(module.resolve_global_addr(*global_index))?; - stack.values.push(global); - } + let mem_idx = module.resolve_mem_addr(addr); + let mem = store.get_mem(mem_idx)?; + stack.values.push((mem.borrow().page_count() as i32).into()); + Ok(()) + } - GlobalSet(global_index) => { - let idx = module.resolve_global_addr(*global_index); - store.set_global_val(idx, stack.values.pop()?)?; + #[inline(always)] + fn exec_memory_grow( + &self, + addr: u32, + byte: u8, + stack: &mut Stack, + store: &Store, + module: &ModuleInstance, + ) -> Result<()> { + if unlikely(byte != 0) { + return Err(Error::UnsupportedFeature("memory.grow with byte != 0".to_string())); } - I32Const(val) => stack.values.push((*val).into()), - I64Const(val) => stack.values.push((*val).into()), - F32Const(val) => stack.values.push((*val).into()), - F64Const(val) => stack.values.push((*val).into()), + let mut mem = store.get_mem(module.resolve_mem_addr(addr))?.borrow_mut(); + let prev_size = mem.page_count() as i32; + let pages_delta = stack.values.last_mut()?; + *pages_delta = match mem.grow(i32::from(*pages_delta)) { + Some(_) => prev_size.into(), + None => (-1).into(), + }; - MemorySize(addr, byte) => { - if unlikely(*byte != 0) { - return Err(Error::UnsupportedFeature("memory.size with byte != 0".to_string())); - } + Ok(()) + } - let mem_idx = module.resolve_mem_addr(*addr); - let mem = store.get_mem(mem_idx)?; - stack.values.push((mem.borrow().page_count() as i32).into()); + #[inline(always)] + fn exec_memory_copy( + &self, + from: u32, + to: u32, + stack: &mut Stack, + store: &Store, + module: &ModuleInstance, + ) -> Result<()> { + let size: i32 = stack.values.pop()?.into(); + let src: i32 = stack.values.pop()?.into(); + let dst: i32 = stack.values.pop()?.into(); + + if from == to { + let mut mem_from = store.get_mem(module.resolve_mem_addr(from))?.borrow_mut(); + // copy within the same memory + mem_from.copy_within(dst as usize, src as usize, size as usize)?; + } else { + // copy between two memories + let mem_from = store.get_mem(module.resolve_mem_addr(from))?.borrow(); + let mut mem_to = store.get_mem(module.resolve_mem_addr(to))?.borrow_mut(); + mem_to.copy_from_slice(dst as usize, mem_from.load(src as usize, size as usize)?)?; } + Ok(()) + } - MemoryGrow(addr, byte) => { - if unlikely(*byte != 0) { - return Err(Error::UnsupportedFeature("memory.grow with byte != 0".to_string())); - } + #[inline(always)] + fn exec_memory_fill(&self, addr: u32, stack: &mut Stack, store: &Store, module: &ModuleInstance) -> Result<()> { + let size: i32 = stack.values.pop()?.into(); + let val: i32 = stack.values.pop()?.into(); + let dst: i32 = stack.values.pop()?.into(); - let mem = store.get_mem(module.resolve_mem_addr(*addr))?; - let mut mem = mem.borrow_mut(); - let prev_size = mem.page_count() as i32; - let pages_delta: i32 = stack.values.pop()?.into(); + let mem = store.get_mem(module.resolve_mem_addr(addr))?; + mem.borrow_mut().fill(dst as usize, size as usize, val as u8)?; + Ok(()) + } - match mem.grow(pages_delta) { - Some(_) => stack.values.push(prev_size.into()), - None => stack.values.push((-1).into()), - } + #[inline(always)] + fn exec_memory_init( + &self, + data_index: u32, + mem_index: u32, + stack: &mut Stack, + store: &Store, + module: &ModuleInstance, + ) -> Result<()> { + let size = i32::from(stack.values.pop()?) as usize; + let offset = i32::from(stack.values.pop()?) as usize; + let dst = i32::from(stack.values.pop()?) as usize; + + let data = match &store.get_data(module.resolve_data_addr(data_index))?.data { + Some(data) => data, + None => return Err(Trap::MemoryOutOfBounds { offset: 0, len: 0, max: 0 }.into()), + }; + + if unlikely(offset + size > data.len()) { + return Err(Trap::MemoryOutOfBounds { offset, len: size, max: data.len() }.into()); } - // Bulk memory operations - MemoryCopy(from, to) => { - let size: i32 = stack.values.pop()?.into(); - let src: i32 = stack.values.pop()?.into(); - let dst: i32 = stack.values.pop()?.into(); - - let mem = store.get_mem(module.resolve_mem_addr(*from))?; - let mut mem = mem.borrow_mut(); - - if from == to { - // copy within the same memory - mem.copy_within(dst as usize, src as usize, size as usize)?; - } else { - // copy between two memories - let mem2 = store.get_mem(module.resolve_mem_addr(*to))?; - let mut mem2 = mem2.borrow_mut(); - mem2.copy_from_slice(dst as usize, mem.load(src as usize, size as usize)?)?; + let mem = store.get_mem(module.resolve_mem_addr(mem_index))?; + mem.borrow_mut().store(dst, size, &data[offset..(offset + size)])?; + Ok(()) + } + + #[inline(always)] + fn exec_call( + &self, + v: u32, + store: &mut Store, + stack: &mut Stack, + cf: &mut CallFrame, + module: &mut ModuleInstance, + ) -> Result<()> { + let func_inst = store.get_func(module.resolve_func_addr(v))?; + let wasm_func = match &func_inst.func { + crate::Function::Wasm(wasm_func) => wasm_func, + crate::Function::Host(host_func) => { + let func = &host_func.clone(); + let params = stack.values.pop_params(&host_func.ty.params)?; + let res = (func.func)(FuncContext { store, module_addr: module.id() }, ¶ms)?; + stack.values.extend_from_typed(&res); + cf.instr_ptr += 1; + return Ok(()); } - } + }; - MemoryFill(addr) => { - let size: i32 = stack.values.pop()?.into(); - let val: i32 = stack.values.pop()?.into(); - let dst: i32 = stack.values.pop()?.into(); + let params = stack.values.pop_n_rev(wasm_func.ty.params.len())?; + let new_call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, stack.blocks.len() as u32); - let mem = store.get_mem(module.resolve_mem_addr(*addr))?; - mem.borrow_mut().fill(dst as usize, size as usize, val as u8)?; + cf.instr_ptr += 1; // skip the call instruction + stack.call_stack.push(core::mem::replace(cf, new_call_frame))?; + if cf.module_addr != module.id() { + module.swap_with(cf.module_addr, store); } + Ok(()) + } - MemoryInit(data_index, mem_index) => { - let size = i32::from(stack.values.pop()?) as usize; - let offset = i32::from(stack.values.pop()?) as usize; - let dst = i32::from(stack.values.pop()?) as usize; + #[inline(always)] + fn exec_call_indirect( + &self, + type_addr: u32, + table_addr: u32, + store: &mut Store, + stack: &mut Stack, + cf: &mut CallFrame, + module: &mut ModuleInstance, + ) -> Result<()> { + let table = store.get_table(module.resolve_table_addr(table_addr))?; + let table_idx: u32 = stack.values.pop()?.into(); + + // verify that the table is of the right type, this should be validated by the parser already + let func_ref = { + let table = table.borrow(); + assert!(table.kind.element_type == ValType::RefFunc, "table is not of type funcref"); + table.get(table_idx)?.addr().ok_or(Trap::UninitializedElement { index: table_idx as usize })? + }; + + let func_inst = store.get_func(func_ref)?.clone(); + let call_ty = module.func_ty(type_addr); + + let wasm_func = match func_inst.func { + crate::Function::Wasm(ref f) => f, + crate::Function::Host(host_func) => { + if unlikely(host_func.ty != *call_ty) { + return Err(Trap::IndirectCallTypeMismatch { + actual: host_func.ty.clone(), + expected: call_ty.clone(), + } + .into()); + } - let data = match &store.get_data(module.resolve_data_addr(*data_index))?.data { - Some(data) => data, - None => return Err(Trap::MemoryOutOfBounds { offset: 0, len: 0, max: 0 }.into()), - }; + let host_func = host_func.clone(); + let params = stack.values.pop_params(&host_func.ty.params)?; + let res = (host_func.func)(FuncContext { store, module_addr: module.id() }, ¶ms)?; + stack.values.extend_from_typed(&res); - if unlikely(offset + size > data.len()) { - return Err(Trap::MemoryOutOfBounds { offset, len: size, max: data.len() }.into()); + cf.instr_ptr += 1; + return Ok(()); } + }; - let mem = store.get_mem(module.resolve_mem_addr(*mem_index))?; - mem.borrow_mut().store(dst, size, &data[offset..(offset + size)])?; // mem.store checks bounds + if unlikely(wasm_func.ty != *call_ty) { + return Err( + Trap::IndirectCallTypeMismatch { actual: wasm_func.ty.clone(), expected: call_ty.clone() }.into() + ); } - DataDrop(data_index) => store.get_data_mut(module.resolve_data_addr(*data_index))?.drop(), - - I32Store { mem_addr, offset } => mem_store!(i32, (mem_addr, offset), stack, store, module), - I64Store { mem_addr, offset } => mem_store!(i64, (mem_addr, offset), stack, store, module), - F32Store { mem_addr, offset } => mem_store!(f32, (mem_addr, offset), stack, store, module), - F64Store { mem_addr, offset } => mem_store!(f64, (mem_addr, offset), stack, store, module), - I32Store8 { mem_addr, offset } => mem_store!(i8, i32, (mem_addr, offset), stack, store, module), - I32Store16 { mem_addr, offset } => mem_store!(i16, i32, (mem_addr, offset), stack, store, module), - I64Store8 { mem_addr, offset } => mem_store!(i8, i64, (mem_addr, offset), stack, store, module), - I64Store16 { mem_addr, offset } => mem_store!(i16, i64, (mem_addr, offset), stack, store, module), - I64Store32 { mem_addr, offset } => mem_store!(i32, i64, (mem_addr, offset), stack, store, module), - - I32Load { mem_addr, offset } => mem_load!(i32, (mem_addr, offset), stack, store, module), - I64Load { mem_addr, offset } => mem_load!(i64, (mem_addr, offset), stack, store, module), - F32Load { mem_addr, offset } => mem_load!(f32, (mem_addr, offset), stack, store, module), - F64Load { mem_addr, offset } => mem_load!(f64, (mem_addr, offset), stack, store, module), - I32Load8S { mem_addr, offset } => mem_load!(i8, i32, (mem_addr, offset), stack, store, module), - I32Load8U { mem_addr, offset } => mem_load!(u8, i32, (mem_addr, offset), stack, store, module), - I32Load16S { mem_addr, offset } => mem_load!(i16, i32, (mem_addr, offset), stack, store, module), - I32Load16U { mem_addr, offset } => mem_load!(u16, i32, (mem_addr, offset), stack, store, module), - I64Load8S { mem_addr, offset } => mem_load!(i8, i64, (mem_addr, offset), stack, store, module), - I64Load8U { mem_addr, offset } => mem_load!(u8, i64, (mem_addr, offset), stack, store, module), - I64Load16S { mem_addr, offset } => mem_load!(i16, i64, (mem_addr, offset), stack, store, module), - I64Load16U { mem_addr, offset } => mem_load!(u16, i64, (mem_addr, offset), stack, store, module), - I64Load32S { mem_addr, offset } => mem_load!(i32, i64, (mem_addr, offset), stack, store, module), - I64Load32U { mem_addr, offset } => mem_load!(u32, i64, (mem_addr, offset), stack, store, module), - - I64Eqz => comp_zero!(==, i64, stack), - I32Eqz => comp_zero!(==, i32, stack), - - I32Eq => comp!(==, i32, stack), - I64Eq => comp!(==, i64, stack), - F32Eq => comp!(==, f32, stack), - F64Eq => comp!(==, f64, stack), - - I32Ne => comp!(!=, i32, stack), - I64Ne => comp!(!=, i64, stack), - F32Ne => comp!(!=, f32, stack), - F64Ne => comp!(!=, f64, stack), - - I32LtS => comp!(<, i32, stack), - I64LtS => comp!(<, i64, stack), - I32LtU => comp!(<, u32, stack), - I64LtU => comp!(<, u64, stack), - F32Lt => comp!(<, f32, stack), - F64Lt => comp!(<, f64, stack), - - I32LeS => comp!(<=, i32, stack), - I64LeS => comp!(<=, i64, stack), - I32LeU => comp!(<=, u32, stack), - I64LeU => comp!(<=, u64, stack), - F32Le => comp!(<=, f32, stack), - F64Le => comp!(<=, f64, stack), - - I32GeS => comp!(>=, i32, stack), - I64GeS => comp!(>=, i64, stack), - I32GeU => comp!(>=, u32, stack), - I64GeU => comp!(>=, u64, stack), - F32Ge => comp!(>=, f32, stack), - F64Ge => comp!(>=, f64, stack), - - I32GtS => comp!(>, i32, stack), - I64GtS => comp!(>, i64, stack), - I32GtU => comp!(>, u32, stack), - I64GtU => comp!(>, u64, stack), - F32Gt => comp!(>, f32, stack), - F64Gt => comp!(>, f64, stack), - - I64Add => arithmetic!(wrapping_add, i64, stack), - I32Add => arithmetic!(wrapping_add, i32, stack), - F32Add => arithmetic!(+, f32, stack), - F64Add => arithmetic!(+, f64, stack), - - I32Sub => arithmetic!(wrapping_sub, i32, stack), - I64Sub => arithmetic!(wrapping_sub, i64, stack), - F32Sub => arithmetic!(-, f32, stack), - F64Sub => arithmetic!(-, f64, stack), - - F32Div => arithmetic!(/, f32, stack), - F64Div => arithmetic!(/, f64, stack), - - I32Mul => arithmetic!(wrapping_mul, i32, stack), - I64Mul => arithmetic!(wrapping_mul, i64, stack), - F32Mul => arithmetic!(*, f32, stack), - F64Mul => arithmetic!(*, f64, stack), - - // these can trap - I32DivS => checked_int_arithmetic!(checked_div, i32, stack), - I64DivS => checked_int_arithmetic!(checked_div, i64, stack), - I32DivU => checked_int_arithmetic!(checked_div, u32, stack), - I64DivU => checked_int_arithmetic!(checked_div, u64, stack), - - I32RemS => checked_int_arithmetic!(checked_wrapping_rem, i32, stack), - I64RemS => checked_int_arithmetic!(checked_wrapping_rem, i64, stack), - I32RemU => checked_int_arithmetic!(checked_wrapping_rem, u32, stack), - I64RemU => checked_int_arithmetic!(checked_wrapping_rem, u64, stack), - - I32And => arithmetic!(bitand, i32, stack), - I64And => arithmetic!(bitand, i64, stack), - I32Or => arithmetic!(bitor, i32, stack), - I64Or => arithmetic!(bitor, i64, stack), - I32Xor => arithmetic!(bitxor, i32, stack), - I64Xor => arithmetic!(bitxor, i64, stack), - I32Shl => arithmetic!(wasm_shl, i32, stack), - I64Shl => arithmetic!(wasm_shl, i64, stack), - I32ShrS => arithmetic!(wasm_shr, i32, stack), - I64ShrS => arithmetic!(wasm_shr, i64, stack), - I32ShrU => arithmetic!(wasm_shr, u32, stack), - I64ShrU => arithmetic!(wasm_shr, u64, stack), - I32Rotl => arithmetic!(wasm_rotl, i32, stack), - I64Rotl => arithmetic!(wasm_rotl, i64, stack), - I32Rotr => arithmetic!(wasm_rotr, i32, stack), - I64Rotr => arithmetic!(wasm_rotr, i64, stack), - - I32Clz => arithmetic_single!(leading_zeros, i32, stack), - I64Clz => arithmetic_single!(leading_zeros, i64, stack), - I32Ctz => arithmetic_single!(trailing_zeros, i32, stack), - I64Ctz => arithmetic_single!(trailing_zeros, i64, stack), - I32Popcnt => arithmetic_single!(count_ones, i32, stack), - I64Popcnt => arithmetic_single!(count_ones, i64, stack), - - F32ConvertI32S => conv!(i32, f32, stack), - F32ConvertI64S => conv!(i64, f32, stack), - F64ConvertI32S => conv!(i32, f64, stack), - F64ConvertI64S => conv!(i64, f64, stack), - F32ConvertI32U => conv!(u32, f32, stack), - F32ConvertI64U => conv!(u64, f32, stack), - F64ConvertI32U => conv!(u32, f64, stack), - F64ConvertI64U => conv!(u64, f64, stack), - I32Extend8S => conv!(i8, i32, stack), - I32Extend16S => conv!(i16, i32, stack), - I64Extend8S => conv!(i8, i64, stack), - I64Extend16S => conv!(i16, i64, stack), - I64Extend32S => conv!(i32, i64, stack), - I64ExtendI32U => conv!(u32, i64, stack), - I64ExtendI32S => conv!(i32, i64, stack), - I32WrapI64 => conv!(i64, i32, stack), - - F32DemoteF64 => conv!(f64, f32, stack), - F64PromoteF32 => conv!(f32, f64, stack), - - F32Abs => arithmetic_single!(abs, f32, stack), - F64Abs => arithmetic_single!(abs, f64, stack), - F32Neg => arithmetic_single!(neg, f32, stack), - F64Neg => arithmetic_single!(neg, f64, stack), - F32Ceil => arithmetic_single!(ceil, f32, stack), - F64Ceil => arithmetic_single!(ceil, f64, stack), - F32Floor => arithmetic_single!(floor, f32, stack), - F64Floor => arithmetic_single!(floor, f64, stack), - F32Trunc => arithmetic_single!(trunc, f32, stack), - F64Trunc => arithmetic_single!(trunc, f64, stack), - F32Nearest => arithmetic_single!(tw_nearest, f32, stack), - F64Nearest => arithmetic_single!(tw_nearest, f64, stack), - F32Sqrt => arithmetic_single!(sqrt, f32, stack), - F64Sqrt => arithmetic_single!(sqrt, f64, stack), - F32Min => arithmetic!(tw_minimum, f32, stack), - F64Min => arithmetic!(tw_minimum, f64, stack), - F32Max => arithmetic!(tw_maximum, f32, stack), - F64Max => arithmetic!(tw_maximum, f64, stack), - F32Copysign => arithmetic!(copysign, f32, stack), - F64Copysign => arithmetic!(copysign, f64, stack), - - // no-op instructions since types are erased at runtime - I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {} - - // unsigned versions of these are a bit broken atm - I32TruncF32S => checked_conv_float!(f32, i32, stack), - I32TruncF64S => checked_conv_float!(f64, i32, stack), - I32TruncF32U => checked_conv_float!(f32, u32, i32, stack), - I32TruncF64U => checked_conv_float!(f64, u32, i32, stack), - I64TruncF32S => checked_conv_float!(f32, i64, stack), - I64TruncF64S => checked_conv_float!(f64, i64, stack), - I64TruncF32U => checked_conv_float!(f32, u64, i64, stack), - I64TruncF64U => checked_conv_float!(f64, u64, i64, stack), - - TableGet(table_index) => { - let table_idx = module.resolve_table_addr(*table_index); - let table = store.get_table(table_idx)?; - let idx: u32 = stack.values.pop()?.into(); - let v = table.borrow().get_wasm_val(idx)?; - stack.values.push(v.into()); - } + let params = stack.values.pop_n_rev(wasm_func.ty.params.len())?; + let new_call_frame = CallFrame::new(wasm_func.clone(), func_inst.owner, params, stack.blocks.len() as u32); - TableSet(table_index) => { - let table_idx = module.resolve_table_addr(*table_index); - let table = store.get_table(table_idx)?; - let val = stack.values.pop()?.into(); - let idx = stack.values.pop()?.into(); - table.borrow_mut().set(idx, val)?; + cf.instr_ptr += 1; // skip the call instruction + stack.call_stack.push(core::mem::replace(cf, new_call_frame))?; + if cf.module_addr != module.id() { + module.swap_with(cf.module_addr, store); } + Ok(()) + } - TableSize(table_index) => { - let table = store.get_table(module.resolve_table_addr(*table_index))?; - stack.values.push(table.borrow().size().into()); + #[inline(always)] + fn exec_if( + &self, + args: BlockArgs, + else_offset: u32, + end_offset: u32, + stack: &mut Stack, + cf: &mut CallFrame, + module: &mut ModuleInstance, + ) -> Result<()> { + // truthy value is on the top of the stack, so enter the then block + if i32::from(stack.values.pop()?) != 0 { + self.enter_block(stack, cf.instr_ptr, end_offset, BlockType::If, &args, module); + cf.instr_ptr += 1; + return Ok(()); } - TableInit(table_index, elem_index) => { - let table = store.get_table(module.resolve_table_addr(*table_index))?; - let elem = store.get_elem(module.resolve_elem_addr(*elem_index))?; + // falsy value is on the top of the stack + if else_offset == 0 { + cf.instr_ptr += end_offset as usize + 1; + return Ok(()); + } - if let ElementKind::Passive = elem.kind { - return Err(Trap::TableOutOfBounds { offset: 0, len: 0, max: 0 }.into()); - } + let old = cf.instr_ptr; + cf.instr_ptr += else_offset as usize; - let Some(items) = elem.items.as_ref() else { - return Err(Trap::TableOutOfBounds { offset: 0, len: 0, max: 0 }.into()); - }; + self.enter_block(stack, old + else_offset as usize, end_offset - else_offset, BlockType::Else, &args, module); - table.borrow_mut().init(module.func_addrs(), 0, items)?; - } + cf.instr_ptr += 1; + Ok(()) + } - I32TruncSatF32S => arithmetic_single!(trunc, f32, i32, stack), - I32TruncSatF32U => arithmetic_single!(trunc, f32, u32, stack), - I32TruncSatF64S => arithmetic_single!(trunc, f64, i32, stack), - I32TruncSatF64U => arithmetic_single!(trunc, f64, u32, stack), - I64TruncSatF32S => arithmetic_single!(trunc, f32, i64, stack), - I64TruncSatF32U => arithmetic_single!(trunc, f32, u64, stack), - I64TruncSatF64S => arithmetic_single!(trunc, f64, i64, stack), - I64TruncSatF64U => arithmetic_single!(trunc, f64, u64, stack), - - // custom instructions - LocalGet2(a, b) => stack.values.extend_from_slice(&[cf.get_local(*a), cf.get_local(*b)]), - LocalGet3(a, b, c) => stack.values.extend_from_slice(&[cf.get_local(*a), cf.get_local(*b), cf.get_local(*c)]), - LocalTeeGet(a, b) => { - #[inline(always)] - fn local_tee_get(cf: &mut CallFrame, stack: &mut Stack, a: u32, b: u32) { - let last = match stack.values.last() { - Ok(v) => v, - Err(_) => unreachable!("localtee: stack is empty. this should have been validated by the parser"), - }; - - cf.set_local(a, *last); - stack.values.push(cf.get_local(b)); + #[inline(always)] + fn enter_block( + &self, + stack: &mut super::Stack, + instr_ptr: usize, + end_instr_offset: u32, + ty: BlockType, + args: &BlockArgs, + module: &ModuleInstance, + ) { + let (params, results) = match args { + BlockArgs::Empty => (0, 0), + BlockArgs::Type(_) => (0, 1), + BlockArgs::FuncType(t) => { + let ty = module.func_ty(*t); + (ty.params.len() as u8, ty.results.len() as u8) } - - local_tee_get(cf, stack, *a, *b); - } - LocalGetSet(a, b) => cf.set_local(*b, cf.get_local(*a)), - I64XorConstRotl(rotate_by) => { - let val: i64 = stack.values.pop()?.into(); - let mask: i64 = stack.values.pop()?.into(); - let res = val ^ mask; - stack.values.push(res.rotate_left(*rotate_by as u32).into()); - } - I32LocalGetConstAdd(local, val) => { - let local: i32 = cf.get_local(*local).into(); - stack.values.push((local + *val).into()); - } - I32StoreLocal { local, const_i32: consti32, offset, mem_addr } => { - let (mem_addr, offset) = (*mem_addr as u32, *offset); - let mem = store.get_mem(module.resolve_mem_addr(mem_addr))?; - let val = consti32.to_le_bytes(); - let addr: u64 = cf.get_local(*local).into(); - mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?; - } - i => { - cold(); - return Err(Error::UnsupportedFeature(format!("unimplemented instruction: {:?}", i))); - } - }; - - Ok(ExecResult::Ok) + }; + + stack.blocks.push(BlockFrame { + instr_ptr, + end_instr_offset, + stack_ptr: stack.values.len() as u32 - params as u32, + results, + params, + ty, + }); + } } diff --git a/crates/tinywasm/src/runtime/stack/block_stack.rs b/crates/tinywasm/src/runtime/stack/block_stack.rs index a7b8ece..9a823fd 100644 --- a/crates/tinywasm/src/runtime/stack/block_stack.rs +++ b/crates/tinywasm/src/runtime/stack/block_stack.rs @@ -1,18 +1,15 @@ -use crate::{unlikely, Error, ModuleInstance, Result}; +use crate::{cold, unlikely, Error, Result}; use alloc::vec::Vec; -use tinywasm_types::BlockArgs; #[derive(Debug, Clone)] pub(crate) struct BlockStack(Vec); impl BlockStack { pub(crate) fn new() -> Self { - let mut vec = Vec::new(); - vec.reserve(128); - Self(vec) + Self(Vec::with_capacity(128)) } - #[inline] + #[inline(always)] pub(crate) fn len(&self) -> usize { self.0.len() } @@ -35,55 +32,36 @@ impl BlockStack { Some(&self.0[self.0.len() - index as usize - 1]) } - #[inline] + #[inline(always)] pub(crate) fn pop(&mut self) -> Result { - self.0.pop().ok_or(Error::BlockStackUnderflow) + match self.0.pop() { + Some(frame) => Ok(frame), + None => { + cold(); + Err(Error::BlockStackUnderflow) + } + } } /// keep the top `len` blocks and discard the rest - #[inline] + #[inline(always)] pub(crate) fn truncate(&mut self, len: u32) { self.0.truncate(len as usize); } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub(crate) struct BlockFrame { - // position of the instruction pointer when the block was entered - pub(crate) instr_ptr: u32, - // position of the end instruction of the block - pub(crate) end_instr_ptr: u32, - - // position of the stack pointer when the block was entered - pub(crate) stack_ptr: u32, + pub(crate) instr_ptr: usize, // position of the instruction pointer when the block was entered + pub(crate) end_instr_offset: u32, // position of the end instruction of the block + pub(crate) stack_ptr: u32, // position of the stack pointer when the block was entered pub(crate) results: u8, pub(crate) params: u8, pub(crate) ty: BlockType, } -impl BlockFrame { - #[inline(always)] - pub(crate) fn new( - instr_ptr: u32, - end_instr_ptr: u32, - stack_ptr: u32, - ty: BlockType, - args: &BlockArgs, - module: &ModuleInstance, - ) -> Self { - let (params, results) = match args { - BlockArgs::Empty => (0, 0), - BlockArgs::Type(_) => (0, 1), - BlockArgs::FuncType(t) => { - let ty = module.func_ty(*t); - (ty.params.len() as u8, ty.results.len() as u8) - } - }; - - Self { instr_ptr, end_instr_ptr, stack_ptr, results, params, ty } - } -} +impl BlockFrame {} #[derive(Debug, Copy, Clone)] #[allow(dead_code)] diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs index 8002385..5dc754f 100644 --- a/crates/tinywasm/src/runtime/stack/call_stack.rs +++ b/crates/tinywasm/src/runtime/stack/call_stack.rs @@ -1,11 +1,8 @@ -use alloc::{boxed::Box, rc::Rc, vec::Vec}; -use tinywasm_types::{Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction}; - use crate::runtime::{BlockType, RawWasmValue}; -use crate::unlikely; +use crate::{cold, unlikely}; use crate::{Error, Result, Trap}; - -use super::BlockFrame; +use alloc::{boxed::Box, rc::Rc, vec::Vec}; +use tinywasm_types::{Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction}; const CALL_STACK_SIZE: usize = 1024; @@ -19,10 +16,8 @@ impl CallStack { pub(crate) fn new(initial_frame: CallFrame) -> Self { let mut stack = Vec::new(); stack.reserve_exact(CALL_STACK_SIZE); - - let mut stack = Self { stack }; - stack.push(initial_frame).unwrap(); - stack + stack.push(initial_frame); + Self { stack } } #[inline] @@ -30,17 +25,20 @@ impl CallStack { self.stack.is_empty() } - #[inline] + #[inline(always)] pub(crate) fn pop(&mut self) -> Result { match self.stack.pop() { Some(frame) => Ok(frame), - None => Err(Error::CallStackUnderflow), + None => { + cold(); + Err(Error::CallStackUnderflow) + } } } - #[inline] + #[inline(always)] pub(crate) fn push(&mut self, call_frame: CallFrame) -> Result<()> { - if unlikely(self.stack.len() >= CALL_STACK_SIZE) { + if unlikely(self.stack.len() >= self.stack.capacity()) { return Err(Trap::CallStackOverflow.into()); } self.stack.push(call_frame); @@ -50,7 +48,7 @@ impl CallStack { #[derive(Debug, Clone)] pub(crate) struct CallFrame { - pub(crate) instr_ptr: u32, + pub(crate) instr_ptr: usize, pub(crate) block_ptr: u32, pub(crate) func_instance: Rc, pub(crate) module_addr: ModuleInstanceAddr, @@ -58,20 +56,15 @@ pub(crate) struct CallFrame { } impl CallFrame { - /// Push a new label to the label stack and ensure the stack has the correct values - pub(crate) fn enter_block( - &mut self, - block_frame: BlockFrame, - values: &mut super::ValueStack, - blocks: &mut super::BlockStack, - ) { - if block_frame.params > 0 { - let start = (block_frame.stack_ptr - block_frame.params as u32) as usize; - let end = block_frame.stack_ptr as usize; - values.extend_from_within(start..end); + #[inline(always)] + pub(crate) fn fetch_instr(&self) -> &Instruction { + match self.func_instance.instructions.get(self.instr_ptr) { + Some(instr) => instr, + None => { + cold(); + panic!("Instruction pointer out of bounds"); + } } - - blocks.push(block_frame); } /// Break to a block at the given index (relative to the current frame) @@ -108,7 +101,7 @@ impl CallFrame { values.break_to(break_to.stack_ptr, break_to.results); // (the inst_ptr will be incremented by 1 before the next instruction is executed) - self.instr_ptr = break_to.end_instr_ptr; + self.instr_ptr = break_to.instr_ptr + break_to.end_instr_offset as usize; // we also want to trim the label stack, including the block blocks.truncate(blocks.len() as u32 - (break_to_relative + 1)); @@ -118,8 +111,7 @@ impl CallFrame { Some(()) } - // TODO: perf: a lot of time is spent here - #[inline(always)] // about 10% faster with this + #[inline(always)] pub(crate) fn new( wasm_func_inst: Rc, owner: ModuleInstanceAddr, @@ -138,12 +130,12 @@ impl CallFrame { Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, locals, block_ptr } } - #[inline] + #[inline(always)] pub(crate) fn set_local(&mut self, local_index: LocalAddr, value: RawWasmValue) { self.locals[local_index as usize] = value; } - #[inline] + #[inline(always)] pub(crate) fn get_local(&self, local_index: LocalAddr) -> RawWasmValue { self.locals[local_index as usize] } diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs index 8a3f3fa..1573a5d 100644 --- a/crates/tinywasm/src/runtime/stack/value_stack.rs +++ b/crates/tinywasm/src/runtime/stack/value_stack.rs @@ -1,5 +1,3 @@ -use core::ops::Range; - use crate::{cold, runtime::RawWasmValue, unlikely, Error, Result}; use alloc::vec::Vec; use tinywasm_types::{ValType, WasmValue}; @@ -13,43 +11,48 @@ pub(crate) struct ValueStack { impl Default for ValueStack { fn default() -> Self { - let mut vec = Vec::new(); - vec.reserve(MIN_VALUE_STACK_SIZE); // gives a slight performance over with_capacity - Self { stack: vec } + Self { stack: Vec::with_capacity(MIN_VALUE_STACK_SIZE) } } } impl ValueStack { - #[inline] - pub(crate) fn extend_from_within(&mut self, range: Range) { - self.stack.extend_from_within(range); - } - #[inline] pub(crate) fn extend_from_typed(&mut self, values: &[WasmValue]) { self.stack.extend(values.iter().map(|v| RawWasmValue::from(*v))); } - #[inline] - pub(crate) fn extend_from_slice(&mut self, values: &[RawWasmValue]) { - self.stack.extend_from_slice(values); + #[inline(always)] + pub(crate) fn replace_top(&mut self, func: fn(RawWasmValue) -> RawWasmValue) -> Result<()> { + let v = self.last_mut()?; + *v = func(*v); + Ok(()) } - #[inline] - pub(crate) fn replace_top(&mut self, func: impl FnOnce(RawWasmValue) -> RawWasmValue) { - let len = self.stack.len(); - if unlikely(len == 0) { - return; - } - let top = self.stack[len - 1]; - self.stack[len - 1] = func(top); + #[inline(always)] + pub(crate) fn calculate(&mut self, func: fn(RawWasmValue, RawWasmValue) -> RawWasmValue) -> Result<()> { + let v2 = self.pop()?; + let v1 = self.last_mut()?; + *v1 = func(*v1, v2); + Ok(()) } - #[inline] + #[inline(always)] + pub(crate) fn calculate_trap( + &mut self, + func: fn(RawWasmValue, RawWasmValue) -> Result, + ) -> Result<()> { + let v2 = self.pop()?; + let v1 = self.last_mut()?; + *v1 = func(*v1, v2)?; + Ok(()) + } + + #[inline(always)] pub(crate) fn len(&self) -> usize { self.stack.len() } + #[inline] pub(crate) fn truncate_keep(&mut self, n: u32, end_keep: u32) { let total_to_keep = n + end_keep; let len = self.stack.len() as u32; @@ -70,6 +73,17 @@ impl ValueStack { self.stack.push(value); } + #[inline] + pub(crate) fn last_mut(&mut self) -> Result<&mut RawWasmValue> { + match self.stack.last_mut() { + Some(v) => Ok(v), + None => { + cold(); + Err(Error::ValueStackUnderflow) + } + } + } + #[inline] pub(crate) fn last(&self) -> Result<&RawWasmValue> { match self.stack.last() { @@ -81,7 +95,7 @@ impl ValueStack { } } - #[inline] + #[inline(always)] pub(crate) fn pop(&mut self) -> Result { match self.stack.pop() { Some(v) => Ok(v), diff --git a/crates/tinywasm/src/runtime/value.rs b/crates/tinywasm/src/runtime/value.rs index 2865308..e5769bf 100644 --- a/crates/tinywasm/src/runtime/value.rs +++ b/crates/tinywasm/src/runtime/value.rs @@ -86,9 +86,9 @@ impl_from_raw_wasm_value!(u32, |x| x as u64, |x: [u8; 8]| u32::from_ne_bytes(x[0 impl_from_raw_wasm_value!(u64, |x| x, |x: [u8; 8]| u64::from_ne_bytes(x[0..8].try_into().unwrap())); impl_from_raw_wasm_value!(i8, |x| x as u64, |x: [u8; 8]| i8::from_ne_bytes(x[0..1].try_into().unwrap())); impl_from_raw_wasm_value!(i16, |x| x as u64, |x: [u8; 8]| i16::from_ne_bytes(x[0..2].try_into().unwrap())); -impl_from_raw_wasm_value!(f32, |x| f32::to_bits(x) as u64, |x: [u8; 8]| f32::from_bits(u32::from_ne_bytes( +impl_from_raw_wasm_value!(f32, |x| f32::to_bits(x) as u64, |x: [u8; 8]| f32::from_ne_bytes( x[0..4].try_into().unwrap() -))); +)); impl_from_raw_wasm_value!(f64, f64::to_bits, |x: [u8; 8]| f64::from_bits(u64::from_ne_bytes( x[0..8].try_into().unwrap() ))); diff --git a/crates/tinywasm/src/store/global.rs b/crates/tinywasm/src/store/global.rs index cbba1a2..6cc778c 100644 --- a/crates/tinywasm/src/store/global.rs +++ b/crates/tinywasm/src/store/global.rs @@ -1,3 +1,5 @@ +use core::cell::Cell; + use alloc::{format, string::ToString}; use tinywasm_types::*; @@ -8,19 +10,19 @@ use crate::{runtime::RawWasmValue, unlikely, Error, Result}; /// See #[derive(Debug)] pub(crate) struct GlobalInstance { - pub(crate) value: RawWasmValue, + pub(crate) value: Cell, pub(crate) ty: GlobalType, pub(crate) _owner: ModuleInstanceAddr, // index into store.module_instances } impl GlobalInstance { pub(crate) fn new(ty: GlobalType, value: RawWasmValue, owner: ModuleInstanceAddr) -> Self { - Self { ty, value, _owner: owner } + Self { ty, value: value.into(), _owner: owner } } #[inline] pub(crate) fn get(&self) -> WasmValue { - self.value.attach_type(self.ty.ty) + self.value.get().attach_type(self.ty.ty) } pub(crate) fn set(&mut self, val: WasmValue) -> Result<()> { @@ -36,7 +38,7 @@ impl GlobalInstance { return Err(Error::Other("global is immutable".to_string())); } - self.value = val.into(); + self.value.set(val.into()); Ok(()) } } diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs index 00bcc97..5ef4366 100644 --- a/crates/tinywasm/src/store/memory.rs +++ b/crates/tinywasm/src/store/memory.rs @@ -32,6 +32,7 @@ impl MemoryInstance { } } + #[inline(never)] #[cold] fn trap_oob(&self, addr: usize, len: usize) -> Error { Error::Trap(crate::Trap::MemoryOutOfBounds { offset: addr, len, max: self.data.len() }) @@ -46,20 +47,7 @@ impl MemoryInstance { return Err(self.trap_oob(addr, data.len())); } - // WebAssembly doesn't require alignment for stores - #[cfg(not(feature = "unsafe"))] self.data[addr..end].copy_from_slice(data); - - #[cfg(feature = "unsafe")] - // SAFETY: we checked that `end` is in bounds above, this is the same as `copy_from_slice` - // src must is for reads of count * size_of::() bytes. - // dst must is for writes of count * size_of::() bytes. - // Both src and dst are properly aligned. - // The region of memory beginning at src does not overlap with the region of memory beginning at dst with the same size. - unsafe { - core::ptr::copy_nonoverlapping(data.as_ptr(), self.data[addr..end].as_mut_ptr(), len); - } - Ok(()) } @@ -88,14 +76,10 @@ impl MemoryInstance { if end > self.data.len() { return Err(self.trap_oob(addr, SIZE)); } - - #[cfg(not(feature = "unsafe"))] - let val = T::from_le_bytes(self.data[addr..end].try_into().expect("slice size mismatch")); - - #[cfg(feature = "unsafe")] - // SAFETY: we checked that `end` is in bounds above. All types that implement `Into` are valid - // to load from unaligned addresses. - let val = unsafe { core::ptr::read_unaligned(self.data[addr..end].as_ptr() as *const T) }; + let val = T::from_le_bytes(match self.data[addr..end].try_into() { + Ok(bytes) => bytes, + Err(_) => unreachable!("checked bounds above"), + }); Ok(val) } @@ -168,37 +152,20 @@ impl MemoryInstance { } } -#[allow(unsafe_code)] /// A trait for types that can be loaded from memory -/// -/// # Safety -/// Only implemented for primitive types, unsafe to not allow it for other types. -/// Only actually unsafe to implement if the `unsafe` feature is enabled since there might be -/// UB for loading things things like packed structs -pub(crate) unsafe trait MemLoadable: Sized + Copy { +pub(crate) trait MemLoadable: Sized + Copy { /// Load a value from memory - #[allow(unused)] fn from_le_bytes(bytes: [u8; T]) -> Self; - /// Load a value from memory - #[allow(unused)] - fn from_be_bytes(bytes: [u8; T]) -> Self; } macro_rules! impl_mem_loadable_for_primitive { ($($type:ty, $size:expr),*) => { $( - #[allow(unused)] - #[allow(unsafe_code)] - unsafe impl MemLoadable<$size> for $type { - #[inline] + impl MemLoadable<$size> for $type { + #[inline(always)] fn from_le_bytes(bytes: [u8; $size]) -> Self { <$type>::from_le_bytes(bytes) } - - #[inline] - fn from_be_bytes(bytes: [u8; $size]) -> Self { - <$type>::from_be_bytes(bytes) - } } )* } diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs index fddf3f4..8c6e698 100644 --- a/crates/tinywasm/src/store/mod.rs +++ b/crates/tinywasm/src/store/mod.rs @@ -1,4 +1,4 @@ -use alloc::{boxed::Box, format, rc::Rc, string::ToString, vec::Vec}; +use alloc::{boxed::Box, format, string::ToString, vec::Vec}; use core::cell::RefCell; use core::sync::atomic::{AtomicUsize, Ordering}; use tinywasm_types::*; @@ -31,7 +31,6 @@ static STORE_ID: AtomicUsize = AtomicUsize::new(0); pub struct Store { id: usize, module_instances: Vec, - module_instance_count: usize, pub(crate) data: StoreData, pub(crate) runtime: Runtime, @@ -74,14 +73,7 @@ impl PartialEq for Store { impl Default for Store { fn default() -> Self { let id = STORE_ID.fetch_add(1, Ordering::Relaxed); - - Self { - id, - module_instances: Vec::new(), - module_instance_count: 0, - data: StoreData::default(), - runtime: Runtime::Default, - } + Self { id, module_instances: Vec::new(), data: StoreData::default(), runtime: Runtime::Default } } } @@ -92,9 +84,9 @@ impl Default for Store { /// See pub(crate) struct StoreData { pub(crate) funcs: Vec, - pub(crate) tables: Vec>>, - pub(crate) memories: Vec>>, - pub(crate) globals: Vec>>, + pub(crate) tables: Vec>, + pub(crate) memories: Vec>, + pub(crate) globals: Vec, pub(crate) elements: Vec, pub(crate) datas: Vec, } @@ -106,14 +98,12 @@ impl Store { } pub(crate) fn next_module_instance_idx(&self) -> ModuleInstanceAddr { - self.module_instance_count as ModuleInstanceAddr + self.module_instances.len() as ModuleInstanceAddr } - pub(crate) fn add_instance(&mut self, instance: ModuleInstance) -> Result<()> { - assert!(instance.id() == self.module_instance_count as ModuleInstanceAddr); + pub(crate) fn add_instance(&mut self, instance: ModuleInstance) { + assert!(instance.id() == self.module_instances.len() as ModuleInstanceAddr); self.module_instances.push(instance); - self.module_instance_count += 1; - Ok(()) } #[cold] @@ -129,13 +119,13 @@ impl Store { /// Get the memory at the actual index in the store #[inline] - pub(crate) fn get_mem(&self, addr: MemAddr) -> Result<&Rc>> { + pub(crate) fn get_mem(&self, addr: MemAddr) -> Result<&RefCell> { self.data.memories.get(addr as usize).ok_or_else(|| Self::not_found_error("memory")) } /// Get the table at the actual index in the store #[inline] - pub(crate) fn get_table(&self, addr: TableAddr) -> Result<&Rc>> { + pub(crate) fn get_table(&self, addr: TableAddr) -> Result<&RefCell> { self.data.tables.get(addr as usize).ok_or_else(|| Self::not_found_error("table")) } @@ -159,7 +149,7 @@ impl Store { /// Get the global at the actual index in the store #[inline] - pub(crate) fn get_global(&self, addr: GlobalAddr) -> Result<&Rc>> { + pub(crate) fn get_global(&self, addr: GlobalAddr) -> Result<&GlobalInstance> { self.data.globals.get(addr as usize).ok_or_else(|| Self::not_found_error("global")) } @@ -170,14 +160,14 @@ impl Store { .globals .get(addr as usize) .ok_or_else(|| Self::not_found_error("global")) - .map(|global| global.borrow().value) + .map(|global| global.value.get()) } /// Set the global at the actual index in the store #[inline] pub(crate) fn set_global_val(&mut self, addr: MemAddr, value: RawWasmValue) -> Result<()> { let global = self.data.globals.get(addr as usize).ok_or_else(|| Self::not_found_error("global")); - global.map(|global| global.borrow_mut().value = value) + global.map(|global| global.value.set(value)) } } @@ -199,7 +189,7 @@ impl Store { let table_count = self.data.tables.len(); let mut table_addrs = Vec::with_capacity(table_count); for (i, table) in tables.into_iter().enumerate() { - self.data.tables.push(Rc::new(RefCell::new(TableInstance::new(table, idx)))); + self.data.tables.push(RefCell::new(TableInstance::new(table, idx))); table_addrs.push((i + table_count) as TableAddr); } Ok(table_addrs) @@ -213,7 +203,7 @@ impl Store { if let MemoryArch::I64 = mem.arch { return Err(Error::UnsupportedFeature("64-bit memories".to_string())); } - self.data.memories.push(Rc::new(RefCell::new(MemoryInstance::new(mem, idx)))); + self.data.memories.push(RefCell::new(MemoryInstance::new(mem, idx))); mem_addrs.push((i + mem_count) as MemAddr); } Ok(mem_addrs) @@ -232,11 +222,11 @@ impl Store { let mut global_addrs = imported_globals; for (i, global) in new_globals.iter().enumerate() { - self.data.globals.push(Rc::new(RefCell::new(GlobalInstance::new( + self.data.globals.push(GlobalInstance::new( global.ty, self.eval_const(&global.init, &global_addrs, func_addrs)?, idx, - )))); + )); global_addrs.push((i + global_count) as Addr); } @@ -255,8 +245,7 @@ impl Store { let addr = globals.get(*addr as usize).copied().ok_or_else(|| { Error::Other(format!("global {} not found. This should have been caught by the validator", addr)) })?; - let global = self.data.globals[addr as usize].clone(); - let val = i64::from(global.borrow().value); + let val: i64 = self.data.globals[addr as usize].value.get().into(); // check if the global is actually a null reference match val < 0 { @@ -374,12 +363,12 @@ impl Store { } pub(crate) fn add_global(&mut self, ty: GlobalType, value: RawWasmValue, idx: ModuleInstanceAddr) -> Result { - self.data.globals.push(Rc::new(RefCell::new(GlobalInstance::new(ty, value, idx)))); + self.data.globals.push(GlobalInstance::new(ty, value, idx)); Ok(self.data.globals.len() as Addr - 1) } pub(crate) fn add_table(&mut self, table: TableType, idx: ModuleInstanceAddr) -> Result { - self.data.tables.push(Rc::new(RefCell::new(TableInstance::new(table, idx)))); + self.data.tables.push(RefCell::new(TableInstance::new(table, idx))); Ok(self.data.tables.len() as TableAddr - 1) } @@ -387,7 +376,7 @@ impl Store { if let MemoryArch::I64 = mem.arch { return Err(Error::UnsupportedFeature("64-bit memories".to_string())); } - self.data.memories.push(Rc::new(RefCell::new(MemoryInstance::new(mem, idx)))); + self.data.memories.push(RefCell::new(MemoryInstance::new(mem, idx))); Ok(self.data.memories.len() as MemAddr - 1) } @@ -401,10 +390,7 @@ impl Store { use tinywasm_types::ConstInstruction::*; let val = match const_instr { I32Const(i) => *i, - GlobalGet(addr) => { - let global = self.data.globals[*addr as usize].borrow(); - i32::from(global.value) - } + GlobalGet(addr) => i32::from(self.data.globals[*addr as usize].value.get()), _ => return Err(Error::Other("expected i32".to_string())), }; Ok(val) @@ -430,8 +416,7 @@ impl Store { let global = self.data.globals.get(*addr as usize).expect("global not found. This should be unreachable"); - - global.borrow().value + global.value.get() } RefNull(t) => RawWasmValue::from(t.default_value()), RefFunc(idx) => RawWasmValue::from(*module_func_addrs.get(*idx as usize).ok_or_else(|| { diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml index 76e5679..33271d5 100644 --- a/crates/types/Cargo.toml +++ b/crates/types/Cargo.toml @@ -13,8 +13,7 @@ rkyv={version="0.7", optional=true, default-features=false, features=["size_32", bytecheck={version="0.7", optional=true} [features] -default=["std", "logging", "archive", "unsafe"] +default=["std", "logging", "archive"] std=["rkyv?/std"] archive=["dep:rkyv", "dep:bytecheck"] logging=["dep:log"] -unsafe=[] diff --git a/crates/types/src/archive.rs b/crates/types/src/archive.rs index 9bf095b..52146e7 100644 --- a/crates/types/src/archive.rs +++ b/crates/types/src/archive.rs @@ -65,18 +65,6 @@ impl TinyWasmModule { Ok(root.deserialize(&mut rkyv::Infallible).unwrap()) } - #[cfg(feature = "unsafe")] - #[allow(unsafe_code)] - /// Creates a TinyWasmModule from a slice of bytes. - /// - /// # Safety - /// This function is only safe to call if the bytes have been created by - /// a trusted source. Otherwise, it may cause undefined behavior. - pub unsafe fn from_twasm_unchecked(wasm: &[u8]) -> Self { - let len = validate_magic(wasm).unwrap(); - rkyv::archived_root::(&wasm[len..]).deserialize(&mut rkyv::Infallible).unwrap() - } - /// Serializes the TinyWasmModule into a vector of bytes. /// AlignedVec can be deferenced as a slice of bytes and /// implements io::Write when the `std` feature is enabled. @@ -101,14 +89,4 @@ mod tests { let wasm2 = TinyWasmModule::from_twasm(&twasm).unwrap(); assert_eq!(wasm, wasm2); } - - #[cfg(feature = "unsafe")] - #[test] - fn test_serialize_unchecked() { - let wasm = TinyWasmModule::default(); - let twasm = wasm.serialize_twasm(); - #[allow(unsafe_code)] - let wasm2 = unsafe { TinyWasmModule::from_twasm_unchecked(&twasm) }; - assert_eq!(wasm, wasm2); - } } diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index ee624bd..6290bb4 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -85,6 +85,7 @@ pub enum ConstInstruction { #[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))] // should be kept as small as possible (16 bytes max) #[rustfmt::skip] +#[non_exhaustive] pub enum Instruction { // > Custom Instructions BrLabel(LabelAddr), diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index c5c8071..5e38bfc 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -4,8 +4,7 @@ ))] #![warn(missing_debug_implementations, rust_2018_idioms, unreachable_pub)] #![no_std] -#![cfg_attr(not(feature = "unsafe"), forbid(unsafe_code))] -#![cfg_attr(feature = "unsafe", deny(unused_unsafe))] +#![forbid(unsafe_code)] //! Types used by [`tinywasm`](https://docs.rs/tinywasm) and [`tinywasm_parser`](https://docs.rs/tinywasm_parser). @@ -95,7 +94,7 @@ pub struct TinyWasmModule { /// A WebAssembly External Kind. /// /// See -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), archive(check_bytes))] pub enum ExternalKind { /// A WebAssembly Function. diff --git a/examples/rust/Cargo.toml b/examples/rust/Cargo.toml index f3f475e..f88fde4 100644 --- a/examples/rust/Cargo.toml +++ b/examples/rust/Cargo.toml @@ -10,7 +10,7 @@ forced-target="wasm32-unknown-unknown" edition="2021" [dependencies] -tinywasm={path="../../crates/tinywasm", features=["parser", "std", "unsafe"]} +tinywasm={path="../../crates/tinywasm", features=["parser", "std", "nightly"]} argon2={version="0.5"} [[bin]] diff --git a/examples/rust/analyze.py b/examples/rust/analyze.py index a134a00..a813c1c 100644 --- a/examples/rust/analyze.py +++ b/examples/rust/analyze.py @@ -2,15 +2,14 @@ import sys from collections import Counter -seq_len = 5 - # Check if a file path was provided -if len(sys.argv) < 2: - print("Usage: python script.py path/to/yourfile.wat") +if len(sys.argv) < 3: + print("Usage: python script.py sequence_length path/to/yourfile.wat") sys.exit(1) # The first command line argument is the file path -file_path = sys.argv[1] +seq_len = int(sys.argv[1]) +file_path = sys.argv[2] # Regex to match WASM operators, adjust as necessary operator_pattern = re.compile(r"\b[a-z0-9_]+\.[a-z0-9_]+\b") diff --git a/examples/rust/build.sh b/examples/rust/build.sh index 5028741..9c1f77d 100755 --- a/examples/rust/build.sh +++ b/examples/rust/build.sh @@ -15,7 +15,7 @@ for bin in "${bins[@]}"; do RUSTFLAGS="-C target-feature=$features -C panic=abort" cargo build --target wasm32-unknown-unknown --package rust-wasm-examples --profile=wasm --bin "$bin" cp "$out_dir/$bin.wasm" "$dest_dir/" - wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wasm" -Oz --enable-bulk-memory --enable-reference-types --enable-mutable-globals + wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wasm" -O3 --enable-bulk-memory --enable-reference-types --enable-mutable-globals if [[ ! " ${exclude_wat[@]} " =~ " $bin " ]]; then wasm2wat "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wat" From 41d0ff6c2cd731f62492f1841bb8887991df17b4 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Wed, 15 May 2024 13:47:18 +0200 Subject: [PATCH 14/15] chore: update benchmarks Signed-off-by: Henry Gressmann --- BENCHMARKS.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/BENCHMARKS.md b/BENCHMARKS.md index 1358f70..50df853 100644 --- a/BENCHMARKS.md +++ b/BENCHMARKS.md @@ -22,21 +22,27 @@ All runtimes are compiled with the following settings: - `opt-level` is set to 3, `lto` is set to `thin`, `codegen-units` is set to 1. - No CPU-specific optimizations are used as AVX2 can reduce performance by more than 50% on some CPUs. +- Default runtime settings are used ## Versions -- `tinywasm`: `0.6.2` +- `tinywasm`: `0.7.0` - `wasmi`: `0.31.2` -- `wasmer`: `4.2.8` +- `wasmer`: `4.3.0` ## Results +> Results include the time it takes to parse/compile the WebAssembly file and execute the function. + | Benchmark | Native | TinyWasm | Wasmi | Wasmer (Single Pass) | | ------------ | -------- | ---------- | --------- | -------------------- | -| `fib` | `0ms` | ` 18.70µs` | `18.53µs` | ` 48.09µs` | -| `fib-rec` | `0.27ms` | ` 16.02ms` | ` 4.96ms` | ` 0.47ms` | -| `argon2id` | `0.53ms` | ` 80.54ms` | `46.36ms` | ` 4.82ms` | -| `selfhosted` | `0.05ms` | ` 7.26ms` | ` 6.51ms` | `446.48ms` | +| `fib` | `6.33µs` | ` 19.18µs` | `18.26µs` | ` 51.20µs` | +| `fib-rec` | `0.27ms` | ` 16.09ms` | ` 5.08ms` | ` 0.47ms` | +| `argon2id` | `0.50ms` | ` 89.52ms` | `45.31ms` | ` 4.74ms` | +| `selfhosted` | `0.05ms` | ` 7.93ms` | ` 7.54ms` | `512.45ms` | + +> Note that parsing is still pretty slow, especially for the `selfhosted` benchmark, taking up `~6ms` for TinyWasm. +> This can be improved by using the `archive` feature, which pre-parses the WebAssembly file into tinywasm's custom bytecode format. ### Fib From eb6f7c72789177ce1ce9c9aa0d5e7468507ff18d Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Wed, 15 May 2024 13:47:31 +0200 Subject: [PATCH 15/15] Release 0.7.0 tinywasm@0.7.0 tinywasm-cli@0.7.0 tinywasm-parser@0.7.0 tinywasm-types@0.7.0 Generated by cargo-workspaces --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- crates/cli/Cargo.toml | 2 +- crates/parser/Cargo.toml | 2 +- crates/tinywasm/Cargo.toml | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3f38395..0703613 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2407,7 +2407,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tinywasm" -version = "0.6.1" +version = "0.7.0" dependencies = [ "eyre", "libm", @@ -2424,7 +2424,7 @@ dependencies = [ [[package]] name = "tinywasm-cli" -version = "0.6.1" +version = "0.7.0" dependencies = [ "argh", "color-eyre", @@ -2436,7 +2436,7 @@ dependencies = [ [[package]] name = "tinywasm-parser" -version = "0.6.1" +version = "0.7.0" dependencies = [ "log", "tinywasm-types", @@ -2455,7 +2455,7 @@ dependencies = [ [[package]] name = "tinywasm-types" -version = "0.6.1" +version = "0.7.0" dependencies = [ "bytecheck 0.7.0", "log", diff --git a/Cargo.toml b/Cargo.toml index 37dd86c..58ded7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ panic="abort" inherits="release" [workspace.package] -version="0.6.1" +version="0.7.0" edition="2021" license="MIT OR Apache-2.0" authors=["Henry Gressmann "] diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 3c4657d..4aa9cd0 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -14,7 +14,7 @@ path="src/bin.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tinywasm={version="0.6.0", path="../tinywasm", features=["std", "parser"]} +tinywasm={version="0.7.0", path="../tinywasm", features=["std", "parser"]} argh="0.1" color-eyre={version="0.6", default-features=false} log="0.4" diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 73f430b..206a9ed 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -10,7 +10,7 @@ repository.workspace=true [dependencies] wasmparser={version="0.207", default-features=false, features=["validate"]} log={version="0.4", optional=true} -tinywasm-types={version="0.6.0", path="../types", default-features=false} +tinywasm-types={version="0.7.0", path="../types", default-features=false} [features] default=["std", "logging"] diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index ffd8ac9..ca6b723 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -14,8 +14,8 @@ path="src/lib.rs" [dependencies] _log={version="0.4", optional=true, package="log"} -tinywasm-parser={version="0.6.0", path="../parser", default-features=false, optional=true} -tinywasm-types={version="0.6.0", path="../types", default-features=false} +tinywasm-parser={version="0.7.0", path="../parser", default-features=false, optional=true} +tinywasm-types={version="0.7.0", path="../types", default-features=false} libm={version="0.2", default-features=false} [dev-dependencies] pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy