summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cargo/config.toml8
-rw-r--r--BENCHMARKS.md2
-rw-r--r--Cargo.lock421
-rw-r--r--Cargo.toml2
-rw-r--r--benchmarks/benches/argon2id.rs2
-rw-r--r--benchmarks/benches/fibonacci.rs6
-rw-r--r--benchmarks/benches/selfhosted.rs18
-rw-r--r--crates/parser/src/visit.rs64
-rw-r--r--crates/tinywasm/Cargo.toml2
-rw-r--r--crates/tinywasm/src/boxvec.rs12
-rw-r--r--crates/tinywasm/src/instance.rs33
-rw-r--r--crates/tinywasm/src/runtime/interpreter/macros.rs41
-rw-r--r--crates/tinywasm/src/runtime/interpreter/mod.rs148
-rw-r--r--crates/tinywasm/src/runtime/raw.rs19
-rw-r--r--crates/tinywasm/src/runtime/stack/call_stack.rs39
-rw-r--r--crates/tinywasm/src/runtime/stack/value_stack.rs37
-rw-r--r--crates/tinywasm/src/store/memory.rs45
-rw-r--r--crates/tinywasm/src/store/mod.rs20
-rw-r--r--crates/types/src/instructions.rs12
-rwxr-xr-xexamples/rust/build.sh2
-rw-r--r--scripts/Cargo.toml2
-rw-r--r--scripts/src/bin/generate-charts/progress.rs1
22 files changed, 276 insertions, 660 deletions
diff --git a/.cargo/config.toml b/.cargo/config.toml
index be912c8..2470377 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -8,7 +8,7 @@ test-wast-release="test --package tinywasm --test test-wast --release -- --enabl
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"]
+# 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 50df853..7b094d7 100644
--- a/BENCHMARKS.md
+++ b/BENCHMARKS.md
@@ -42,7 +42,7 @@ All runtimes are compiled with the following settings:
| `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.
+> This can be improved by using the `archive` feature, which pre-compiles the WebAssembly file into tinywasm's internal bytecode format.
### Fib
diff --git a/Cargo.lock b/Cargo.lock
index f87a015..10c945e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -50,21 +50,6 @@ dependencies = [
]
[[package]]
-name = "android-tzdata"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
-
-[[package]]
-name = "android_system_properties"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
-dependencies = [
- "libc",
-]
-
-[[package]]
name = "anes"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -322,12 +307,6 @@ dependencies = [
]
[[package]]
-name = "bytemuck"
-version = "1.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78834c15cb5d5efe3452d58b1e8ba890dd62d21907f867f383358198e56ebca5"
-
-[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -370,20 +349,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
-name = "chrono"
-version = "0.4.38"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
-dependencies = [
- "android-tzdata",
- "iana-time-zone",
- "js-sys",
- "num-traits",
- "wasm-bindgen",
- "windows-targets",
-]
-
-[[package]]
name = "ciborium"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -478,70 +443,12 @@ dependencies = [
]
[[package]]
-name = "color_quant"
-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 = "core-foundation"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
-name = "core-foundation-sys"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
-
-[[package]]
-name = "core-graphics"
-version = "0.23.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
-dependencies = [
- "bitflags 1.3.2",
- "core-foundation",
- "core-graphics-types",
- "foreign-types",
- "libc",
-]
-
-[[package]]
-name = "core-graphics-types"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
-dependencies = [
- "bitflags 1.3.2",
- "core-foundation",
- "libc",
-]
-
-[[package]]
-name = "core-text"
-version = "20.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5"
-dependencies = [
- "core-foundation",
- "core-graphics",
- "foreign-types",
- "libc",
-]
-
-[[package]]
name = "corosensei"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -742,16 +649,6 @@ dependencies = [
]
[[package]]
-name = "cstr"
-version = "0.2.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68523903c8ae5aacfa32a0d9ae60cadeb764e1da14ee0d26b1f3089f13a54636"
-dependencies = [
- "proc-macro2",
- "quote",
-]
-
-[[package]]
name = "darling"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -887,36 +784,6 @@ dependencies = [
]
[[package]]
-name = "dirs-next"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
-dependencies = [
- "cfg-if",
- "dirs-sys-next",
-]
-
-[[package]]
-name = "dirs-sys-next"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
-dependencies = [
- "libc",
- "redox_users",
- "winapi",
-]
-
-[[package]]
-name = "dlib"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
-dependencies = [
- "libloading",
-]
-
-[[package]]
name = "document-features"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -932,18 +799,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
[[package]]
-name = "dwrote"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b"
-dependencies = [
- "lazy_static",
- "libc",
- "winapi",
- "wio",
-]
-
-[[package]]
name = "dyn-clone"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1074,15 +929,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
[[package]]
-name = "fdeflate"
-version = "0.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645"
-dependencies = [
- "simd-adler32",
-]
-
-[[package]]
name = "filetime"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1105,70 +951,12 @@ dependencies = [
]
[[package]]
-name = "float-ord"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d"
-
-[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
-name = "font-kit"
-version = "0.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2845a73bbd781e691ab7c2a028c579727cd254942e8ced57ff73e0eafd60de87"
-dependencies = [
- "bitflags 2.5.0",
- "byteorder",
- "core-foundation",
- "core-graphics",
- "core-text",
- "dirs-next",
- "dwrote",
- "float-ord",
- "freetype-sys",
- "lazy_static",
- "libc",
- "log",
- "pathfinder_geometry",
- "pathfinder_simd",
- "walkdir",
- "winapi",
- "yeslogic-fontconfig-sys",
-]
-
-[[package]]
-name = "foreign-types"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
-dependencies = [
- "foreign-types-macros",
- "foreign-types-shared",
-]
-
-[[package]]
-name = "foreign-types-macros"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.66",
-]
-
-[[package]]
-name = "foreign-types-shared"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
-
-[[package]]
name = "form_urlencoded"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1178,17 +966,6 @@ dependencies = [
]
[[package]]
-name = "freetype-sys"
-version = "0.20.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e7edc5b9669349acfda99533e9e0bcf26a51862ab43b08ee7745c55d28eb134"
-dependencies = [
- "cc",
- "libc",
- "pkg-config",
-]
-
-[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1227,16 +1004,6 @@ dependencies = [
]
[[package]]
-name = "gif"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045"
-dependencies = [
- "color_quant",
- "weezl",
-]
-
-[[package]]
name = "gimli"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1325,29 +1092,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
-name = "iana-time-zone"
-version = "0.1.60"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
-dependencies = [
- "android_system_properties",
- "core-foundation-sys",
- "iana-time-zone-haiku",
- "js-sys",
- "wasm-bindgen",
- "windows-core",
-]
-
-[[package]]
-name = "iana-time-zone-haiku"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
-dependencies = [
- "cc",
-]
-
-[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1364,20 +1108,6 @@ dependencies = [
]
[[package]]
-name = "image"
-version = "0.24.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d"
-dependencies = [
- "bytemuck",
- "byteorder",
- "color_quant",
- "jpeg-decoder",
- "num-traits",
- "png",
-]
-
-[[package]]
name = "indenter"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1444,12 +1174,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
-name = "jpeg-decoder"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
-
-[[package]]
name = "js-sys"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1477,32 +1201,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
-name = "libloading"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
-dependencies = [
- "cfg-if",
- "windows-targets",
-]
-
-[[package]]
name = "libm"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]]
-name = "libredox"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
-dependencies = [
- "bitflags 2.5.0",
- "libc",
-]
-
-[[package]]
name = "linux-raw-sys"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1588,7 +1292,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae"
dependencies = [
"adler",
- "simd-adler32",
]
[[package]]
@@ -1687,25 +1390,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
-name = "pathfinder_geometry"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3"
-dependencies = [
- "log",
- "pathfinder_simd",
-]
-
-[[package]]
-name = "pathfinder_simd"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebf45976c56919841273f2a0fc684c28437e2f304e264557d9c72be5d5a718be"
-dependencies = [
- "rustc_version",
-]
-
-[[package]]
name = "percent-encoding"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1718,27 +1402,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
-name = "pkg-config"
-version = "0.3.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
-
-[[package]]
name = "plotters"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3"
dependencies = [
- "chrono",
- "font-kit",
- "image",
- "lazy_static",
"num-traits",
- "pathfinder_geometry",
"plotters-backend",
- "plotters-bitmap",
"plotters-svg",
- "ttf-parser",
"wasm-bindgen",
"web-sys",
]
@@ -1750,17 +1421,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7"
[[package]]
-name = "plotters-bitmap"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7e7f6fb8302456d7c264a94dada86f76d76e1a03e2294ee86ca7da92983b0a6"
-dependencies = [
- "gif",
- "image",
- "plotters-backend",
-]
-
-[[package]]
name = "plotters-svg"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1770,19 +1430,6 @@ dependencies = [
]
[[package]]
-name = "png"
-version = "0.17.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1"
-dependencies = [
- "bitflags 1.3.2",
- "crc32fast",
- "fdeflate",
- "flate2",
- "miniz_oxide",
-]
-
-[[package]]
name = "pretty_env_logger"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1905,17 +1552,6 @@ dependencies = [
]
[[package]]
-name = "redox_users"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
-dependencies = [
- "getrandom",
- "libredox",
- "thiserror",
-]
-
-[[package]]
name = "regalloc2"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2049,15 +1685,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
-name = "rustc_version"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
-dependencies = [
- "semver",
-]
-
-[[package]]
name = "rustix"
version = "0.38.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2261,12 +1888,6 @@ dependencies = [
]
[[package]]
-name = "simd-adler32"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
-
-[[package]]
name = "simdutf8"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2610,12 +2231,6 @@ dependencies = [
]
[[package]]
-name = "ttf-parser"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4"
-
-[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3112,12 +2727,6 @@ dependencies = [
]
[[package]]
-name = "weezl"
-version = "0.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
-
-[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3149,15 +2758,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
-name = "windows-core"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
-dependencies = [
- "windows-targets",
-]
-
-[[package]]
name = "windows-sys"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3292,15 +2892,6 @@ dependencies = [
]
[[package]]
-name = "wio"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5"
-dependencies = [
- "winapi",
-]
-
-[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3327,18 +2918,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927da81e25be1e1a2901d59b81b37dd2efd1fc9c9345a55007f09bf5a2d3ee03"
[[package]]
-name = "yeslogic-fontconfig-sys"
-version = "5.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffb6b23999a8b1a997bf47c7bb4d19ad4029c3327bb3386ebe0a5ff584b33c7a"
-dependencies = [
- "cstr",
- "dlib",
- "once_cell",
- "pkg-config",
-]
-
-[[package]]
name = "zerocopy"
version = "0.7.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 5d85fae..1b944a4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,7 @@ default-members=[".", "crates/tinywasm", "crates/types", "crates/parser"]
resolver="2"
[profile.wasm]
-opt-level="s"
+opt-level=3
lto="thin"
codegen-units=1
panic="abort"
diff --git a/benchmarks/benches/argon2id.rs b/benchmarks/benches/argon2id.rs
index e458983..76e1eee 100644
--- a/benchmarks/benches/argon2id.rs
+++ b/benchmarks/benches/argon2id.rs
@@ -35,7 +35,7 @@ fn run_native(params: (i32, i32, i32)) {
run_native(params.0, params.1, params.2)
}
-const ARGON2ID: &[u8] = include_bytes!("../../examples/rust/out/argon2id.wasm");
+static ARGON2ID: &[u8] = include_bytes!("../../examples/rust/out/argon2id.opt.wasm");
fn criterion_benchmark(c: &mut Criterion) {
let params = (1000, 2, 1);
diff --git a/benchmarks/benches/fibonacci.rs b/benchmarks/benches/fibonacci.rs
index 61b9a68..e610ab2 100644
--- a/benchmarks/benches/fibonacci.rs
+++ b/benchmarks/benches/fibonacci.rs
@@ -44,7 +44,7 @@ fn run_native_recursive(n: i32) -> i32 {
run_native_recursive(n - 1) + run_native_recursive(n - 2)
}
-const FIBONACCI: &[u8] = include_bytes!("../../examples/rust/out/fibonacci.wasm");
+static FIBONACCI: &[u8] = include_bytes!("../../examples/rust/out/fibonacci.opt.wasm");
fn criterion_benchmark(c: &mut Criterion) {
// {
// let mut group = c.benchmark_group("fibonacci");
@@ -58,7 +58,9 @@ 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(FIBONACCI, black_box(26), "fibonacci_recursive")));
+ group.bench_function("tinywasm", |b| {
+ b.iter(|| run_tinywasm(black_box(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 441923b..adac85a 100644
--- a/benchmarks/benches/selfhosted.rs
+++ b/benchmarks/benches/selfhosted.rs
@@ -50,21 +50,21 @@ fn run_wasmer(wasm: &[u8]) {
hello.call(&mut store, &[]).expect("call");
}
-const TINYWASM: &[u8] = include_bytes!("../../examples/rust/out/tinywasm.wasm");
+static TINYWASM: &[u8] = include_bytes!("../../examples/rust/out/tinywasm.opt.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 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");
+ 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(TINYWASM)));
- // group.bench_function("wasmi", |b| b.iter(|| run_wasmi(TINYWASM)));
- // group.bench_function("wasmer", |b| b.iter(|| run_wasmer(TINYWASM)));
+ group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(black_box(TINYWASM))));
+ // group.bench_function("wasmi", |b| b.iter(|| run_wasmi(black_box(TINYWASM))));
+ // group.bench_function("wasmer", |b| b.iter(|| run_wasmer(black_box(TINYWASM))));
}
}
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs
index bddd01d..c9176a4 100644
--- a/crates/parser/src/visit.rs
+++ b/crates/parser/src/visit.rs
@@ -126,9 +126,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
visit_global_set, Instruction::GlobalSet, u32,
visit_i32_const, Instruction::I32Const, i32,
visit_i64_const, Instruction::I64Const, i64,
- visit_call, Instruction::Call, u32,
- visit_local_set, Instruction::LocalSet, u32,
- visit_local_tee, Instruction::LocalTee, u32
+ visit_call, Instruction::Call, u32
}
define_primitive_operands! {
@@ -319,10 +317,19 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
}
match self.instructions[self.instructions.len() - 2..] {
+ [_, Instruction::LocalGet2(a, b)] => {
+ self.instructions.pop();
+ self.instructions.push(Instruction::I32StoreLocal {
+ local_a: a,
+ local_b: b,
+ offset: arg.offset as u32,
+ mem_addr: arg.mem_addr as u8,
+ })
+ }
[Instruction::LocalGet(a), Instruction::I32Const(b)] => {
self.instructions.pop();
self.instructions.pop();
- self.instructions.push(Instruction::I32StoreLocal {
+ self.instructions.push(Instruction::I32ConstStoreLocal {
local: a,
const_i32: b,
offset: arg.offset as u32,
@@ -334,10 +341,10 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
}
fn visit_local_get(&mut self, idx: u32) -> Self::Output {
- if self.instructions.is_empty() {
+ let Some(instruction) = self.instructions.last_mut() else {
return self.instructions.push(Instruction::LocalGet(idx));
- }
- let instruction = self.instructions.last_mut().unwrap();
+ };
+
match instruction {
Instruction::LocalGet(a) => *instruction = Instruction::LocalGet2(*a, idx),
Instruction::LocalGet2(a, b) => *instruction = Instruction::LocalGet3(*a, *b, idx),
@@ -346,32 +353,47 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
};
}
+ fn visit_local_set(&mut self, idx: u32) -> Self::Output {
+ let Some(instruction) = self.instructions.last_mut() else {
+ return self.instructions.push(Instruction::LocalSet(idx));
+ };
+ match instruction {
+ Instruction::LocalGet(a) => *instruction = Instruction::LocalGetSet(*a, idx),
+ _ => self.instructions.push(Instruction::LocalSet(idx)),
+ };
+ }
+
+ fn visit_local_tee(&mut self, idx: u32) -> Self::Output {
+ self.instructions.push(Instruction::LocalTee(idx))
+ }
+
fn visit_i64_rotl(&mut self) -> Self::Output {
- if self.instructions.len() < 2 {
+ let Some([Instruction::I64Xor, Instruction::I64Const(a)]) = self.instructions.last_chunk::<2>() else {
return self.instructions.push(Instruction::I64Rotl);
- }
-
- match self.instructions[self.instructions.len() - 2..] {
- [Instruction::I64Xor, Instruction::I64Const(a)] => {
- self.instructions.pop();
- self.instructions.pop();
- self.instructions.push(Instruction::I64XorConstRotl(a))
- }
- _ => self.instructions.push(Instruction::I64Rotl),
- }
+ };
+ let a = *a;
+ self.instructions.pop();
+ self.instructions.pop();
+ self.instructions.push(Instruction::I64XorConstRotl(a))
}
fn visit_i32_add(&mut self) -> Self::Output {
- if self.instructions.len() < 2 {
+ let Some(last) = self.instructions.last_chunk::<2>() else {
return self.instructions.push(Instruction::I32Add);
- }
+ };
- match self.instructions[self.instructions.len() - 2..] {
+ match *last {
[Instruction::LocalGet(a), Instruction::I32Const(b)] => {
self.instructions.pop();
self.instructions.pop();
self.instructions.push(Instruction::I32LocalGetConstAdd(a, b))
}
+ [Instruction::LocalGet2(a, b), Instruction::I32Const(c)] => {
+ self.instructions.pop();
+ self.instructions.pop();
+ self.instructions.push(Instruction::LocalGet(a));
+ self.instructions.push(Instruction::I32LocalGetConstAdd(b, c))
+ }
_ => self.instructions.push(Instruction::I32Add),
}
}
diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml
index 78c1b42..0d2c00e 100644
--- a/crates/tinywasm/Cargo.toml
+++ b/crates/tinywasm/Cargo.toml
@@ -28,7 +28,7 @@ serde={version="1.0", features=["derive"]}
pretty_env_logger="0.5"
[features]
-default=["std", "parser", "logging", "archive", "simd", "nightly"]
+default=["std", "parser", "logging", "archive"]
logging=["_log", "tinywasm-parser?/logging", "tinywasm-types/logging"]
std=["tinywasm-parser?/std", "tinywasm-types/std"]
parser=["tinywasm-parser"]
diff --git a/crates/tinywasm/src/boxvec.rs b/crates/tinywasm/src/boxvec.rs
index 17d3740..9c6732d 100644
--- a/crates/tinywasm/src/boxvec.rs
+++ b/crates/tinywasm/src/boxvec.rs
@@ -83,6 +83,18 @@ impl<T: Copy + Default> BoxVec<T> {
}
#[inline(always)]
+ pub(crate) fn extend(&mut self, iter: impl Iterator<Item = T>) {
+ let (lower, _) = iter.size_hint();
+ let upper = lower;
+ let new_end = self.end + upper;
+ assert!(new_end <= self.data.len(), "stack overflow");
+ for (i, value) in iter.enumerate() {
+ self.data[self.end + i] = value;
+ }
+ self.end = new_end;
+ }
+
+ #[inline(always)]
pub(crate) fn drain(&mut self, range: impl RangeBounds<usize>) -> Cow<'_, [T]> {
let start = match range.start_bound() {
core::ops::Bound::Included(&start) => start,
diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs
index abc2819..d9e038a 100644
--- a/crates/tinywasm/src/instance.rs
+++ b/crates/tinywasm/src/instance.rs
@@ -133,40 +133,45 @@ impl ModuleInstance {
&self.0.func_addrs
}
+ #[cold]
+ fn not_found_error(name: &str) -> Error {
+ Error::Other(format!("address for {} not found", name))
+ }
+
// resolve a function address to the global store address
#[inline(always)]
- pub(crate) fn resolve_func_addr(&self, addr: FuncAddr) -> FuncAddr {
- self.0.func_addrs[addr as usize]
+ pub(crate) fn resolve_func_addr(&self, addr: FuncAddr) -> Result<FuncAddr> {
+ self.0.func_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("function")).copied()
}
// resolve a table address to the global store address
#[inline(always)]
- pub(crate) fn resolve_table_addr(&self, addr: TableAddr) -> TableAddr {
- self.0.table_addrs[addr as usize]
+ pub(crate) fn resolve_table_addr(&self, addr: TableAddr) -> Result<TableAddr> {
+ self.0.table_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("table")).copied()
}
// resolve a memory address to the global store address
#[inline(always)]
- pub(crate) fn resolve_mem_addr(&self, addr: MemAddr) -> MemAddr {
- self.0.mem_addrs[addr as usize]
+ pub(crate) fn resolve_mem_addr(&self, addr: MemAddr) -> Result<MemAddr> {
+ self.0.mem_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("mem")).copied()
}
// resolve a data address to the global store address
#[inline(always)]
- pub(crate) fn resolve_data_addr(&self, addr: DataAddr) -> MemAddr {
- self.0.data_addrs[addr as usize]
+ pub(crate) fn resolve_data_addr(&self, addr: DataAddr) -> Result<DataAddr> {
+ self.0.data_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("data")).copied()
}
// resolve a memory address to the global store address
#[inline(always)]
- pub(crate) fn resolve_elem_addr(&self, addr: ElemAddr) -> ElemAddr {
- self.0.elem_addrs[addr as usize]
+ pub(crate) fn resolve_elem_addr(&self, addr: ElemAddr) -> Result<ElemAddr> {
+ self.0.elem_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("elem")).copied()
}
// resolve a global address to the global store address
#[inline(always)]
- pub(crate) fn resolve_global_addr(&self, addr: GlobalAddr) -> GlobalAddr {
- self.0.global_addrs[addr as usize]
+ pub(crate) fn resolve_global_addr(&self, addr: GlobalAddr) -> Result<GlobalAddr> {
+ self.0.global_addrs.get(addr as usize).ok_or_else(|| Self::not_found_error("global")).copied()
}
/// Get an exported function by name
@@ -218,13 +223,13 @@ impl ModuleInstance {
/// Get a memory by address
pub fn memory<'a>(&self, store: &'a mut Store, addr: MemAddr) -> Result<MemoryRef<'a>> {
- let mem = store.get_mem(self.resolve_mem_addr(addr))?;
+ 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<MemoryRefMut<'a>> {
- let mem = store.get_mem(self.resolve_mem_addr(addr))?;
+ let mem = store.get_mem(self.resolve_mem_addr(addr)?)?;
Ok(MemoryRefMut { instance: mem.borrow_mut() })
}
diff --git a/crates/tinywasm/src/runtime/interpreter/macros.rs b/crates/tinywasm/src/runtime/interpreter/macros.rs
index aca2252..b2042c2 100644
--- a/crates/tinywasm/src/runtime/interpreter/macros.rs
+++ b/crates/tinywasm/src/runtime/interpreter/macros.rs
@@ -1,20 +1,14 @@
-//! More generic macros for various instructions
-//!
-//! These macros are used to generate the actual instruction implementations.
-//! In some basic tests this generated better assembly than using generic functions, even when inlined.
-//! (Something to revisit in the future)
-
// Break to a block at the given index (relative to the current frame)
// If there is no block at the given index, return or call the parent function
//
// 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 {
- ($break_to_relative:expr, $self:expr) => {{
+ ($break_to_relative:expr, $self:expr) => {
if $self.cf.break_to($break_to_relative, &mut $self.stack.values, &mut $self.stack.blocks).is_none() {
return $self.exec_return();
}
- }};
+ };
}
/// Doing the actual conversion from float to int is a bit tricky, because
@@ -51,20 +45,19 @@ macro_rules! checked_conv_float {
checked_conv_float!($from, $to, $to, $self)
};
// Conversion with an intermediate unsigned type and error checking (three types)
- ($from:tt, $intermediate:tt, $to:tt, $self:expr) => {{
- let (min, max) = float_min_max!($from, $intermediate);
- let a: $from = $self.stack.values.pop()?.into();
-
- if unlikely(a.is_nan()) {
- return Err(Error::Trap(crate::Trap::InvalidConversionToInt));
- }
-
- if unlikely(a <= min || a >= max) {
- return Err(Error::Trap(crate::Trap::IntegerOverflow));
- }
-
- $self.stack.values.push((a as $intermediate as $to).into());
- }};
+ ($from:tt, $intermediate:tt, $to:tt, $self:expr) => {
+ $self.stack.values.replace_top_trap(|v| {
+ let (min, max) = float_min_max!($from, $intermediate);
+ let a: $from = v.into();
+ if unlikely(a.is_nan()) {
+ return Err(Error::Trap(crate::Trap::InvalidConversionToInt));
+ }
+ if unlikely(a <= min || a >= max) {
+ return Err(Error::Trap(crate::Trap::IntegerOverflow));
+ }
+ Ok((a as $intermediate as $to).into())
+ })?
+ };
}
/// Compare two values on the stack
@@ -79,9 +72,7 @@ macro_rules! comp {
/// Compare a value on the stack to zero
macro_rules! comp_zero {
($op:tt, $ty:ty, $self:expr) => {
- $self.stack.values.replace_top(|v| {
- ((<$ty>::from(v) $op 0) as i32).into()
- })?
+ $self.stack.values.replace_top(|v| ((<$ty>::from(v) $op 0) as i32).into())?
};
}
diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs
index 6163f1b..8902aad 100644
--- a/crates/tinywasm/src/runtime/interpreter/mod.rs
+++ b/crates/tinywasm/src/runtime/interpreter/mod.rs
@@ -2,11 +2,10 @@ use alloc::{format, rc::Rc, string::ToString};
use core::ops::{BitAnd, BitOr, BitXor, ControlFlow, Neg};
use tinywasm_types::{BlockArgs, ElementKind, Instruction, ModuleInstanceAddr, ValType, WasmFunction};
-use super::raw::ToMemBytes;
use super::stack::{BlockFrame, BlockType};
use super::{InterpreterRuntime, RawWasmValue, Stack};
use crate::runtime::CallFrame;
-use crate::{cold, unlikely, Error, FuncContext, MemLoadable, ModuleInstance, Result, Store, Trap};
+use crate::{cold, unlikely, Error, FuncContext, MemLoadable, MemStorable, ModuleInstance, Result, Store, Trap};
mod macros;
mod traits;
@@ -36,10 +35,11 @@ struct Executor<'store, 'stack> {
impl<'store, 'stack> Executor<'store, 'stack> {
pub(crate) fn new(store: &'store mut Store, stack: &'stack mut Stack) -> Result<Self> {
let current_frame = stack.call_stack.pop().ok_or_else(|| Error::CallStackUnderflow)?;
- let current_module = store.get_module_instance_raw(current_frame.module_addr);
+ let current_module = store.get_module_instance_raw(current_frame.module_addr());
Ok(Self { cf: current_frame, module: current_module, stack, store })
}
+ #[inline]
pub(crate) fn run_to_completion(&mut self) -> Result<()> {
loop {
match self.exec_next()? {
@@ -58,16 +58,17 @@ impl<'store, 'stack> Executor<'store, 'stack> {
Drop => self.exec_drop()?,
Select(_valtype) => self.exec_select()?,
- Call(v) => return self.exec_call_direct(*v),
- CallIndirect(ty, table) => return self.exec_call_indirect(*ty, *table),
+ Call(v) => self.exec_call_direct(*v)?,
+ CallIndirect(ty, table) => self.exec_call_indirect(*ty, *table)?,
- If(args, el, end) => return self.exec_if((*args).into(), *el, *end),
+ If(args, el, end) => self.exec_if((*args).into(), *el, *end)?,
Else(end_offset) => self.exec_else(*end_offset)?,
- Loop(args, end) => self.enter_block(self.cf.instr_ptr, *end, BlockType::Loop, *args),
- Block(args, end) => self.enter_block(self.cf.instr_ptr, *end, BlockType::Block, *args),
+ Loop(args, end) => self.enter_block(self.cf.instr_ptr(), *end, BlockType::Loop, *args),
+ Block(args, end) => self.enter_block(self.cf.instr_ptr(), *end, BlockType::Block, *args),
Br(v) => return self.exec_br(*v),
BrIf(v) => return self.exec_br_if(*v),
BrTable(default, len) => return self.exec_brtable(*default, *len),
+ BrLabel(_) => {}
Return => return self.exec_return(),
EndBlockFrame => self.exec_end_block()?,
@@ -292,13 +293,11 @@ impl<'store, 'stack> Executor<'store, 'stack> {
LocalGetSet(a, b) => self.exec_local_get_set(*a, *b),
I64XorConstRotl(rotate_by) => self.exec_i64_xor_const_rotl(*rotate_by)?,
I32LocalGetConstAdd(local, val) => self.exec_i32_local_get_const_add(*local, *val),
- I32StoreLocal { local, const_i32, offset, mem_addr } => {
- self.exec_i32_store_local(*local, *const_i32, *offset, *mem_addr)?
+ I32ConstStoreLocal { local, const_i32, offset, mem_addr } => {
+ self.exec_i32_const_store_local(*local, *const_i32, *offset, *mem_addr)?
}
-
- i => {
- cold();
- return Err(Error::UnsupportedFeature(format!("unimplemented instruction: {:?}", i)));
+ I32StoreLocal { local_a, local_b, offset, mem_addr } => {
+ self.exec_i32_store_local(*local_a, *local_b, *offset, *mem_addr)?
}
};
@@ -326,16 +325,17 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
Ok(())
}
- fn exec_call(&mut self, wasm_func: Rc<WasmFunction>, owner: ModuleInstanceAddr) -> Result<ControlFlow<()>> {
+ fn exec_call(&mut self, wasm_func: Rc<WasmFunction>, owner: ModuleInstanceAddr) -> Result<()> {
let params = self.stack.values.pop_n(wasm_func.ty.params.len())?;
let new_call_frame = CallFrame::new(wasm_func, owner, params, self.stack.blocks.len() as u32);
self.cf.instr_ptr += 1; // skip the call instruction
self.stack.call_stack.push(core::mem::replace(&mut self.cf, new_call_frame))?;
- self.module.swap_with(self.cf.module_addr, self.store);
- Ok(ControlFlow::Continue(()))
+ self.module.swap_with(self.cf.module_addr(), self.store);
+ self.cf.instr_ptr -= 1;
+ Ok(())
}
- fn exec_call_direct(&mut self, v: u32) -> Result<ControlFlow<()>> {
- let func_inst = self.store.get_func(self.module.resolve_func_addr(v))?;
+ fn exec_call_direct(&mut self, v: u32) -> Result<()> {
+ let func_inst = self.store.get_func(self.module.resolve_func_addr(v)?)?;
let wasm_func = match &func_inst.func {
crate::Function::Wasm(wasm_func) => wasm_func,
crate::Function::Host(host_func) => {
@@ -343,16 +343,15 @@ impl<'store, 'stack> Executor<'store, 'stack> {
let params = self.stack.values.pop_params(&host_func.ty.params)?;
let res = (func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, &params)?;
self.stack.values.extend_from_typed(&res);
- self.cf.instr_ptr += 1;
- return Ok(ControlFlow::Continue(()));
+ return Ok(());
}
};
self.exec_call(wasm_func.clone(), func_inst.owner)
}
- fn exec_call_indirect(&mut self, type_addr: u32, table_addr: u32) -> Result<ControlFlow<()>> {
+ fn exec_call_indirect(&mut self, type_addr: u32, table_addr: u32) -> Result<()> {
// verify that the table is of the right type, this should be validated by the parser already
let func_ref = {
- let table = self.store.get_table(self.module.resolve_table_addr(table_addr))?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_addr)?)?;
let table_idx: u32 = self.stack.values.pop()?.into();
let table = table.borrow();
assert!(table.kind.element_type == ValType::RefFunc, "table is not of type funcref");
@@ -379,8 +378,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
let params = self.stack.values.pop_params(&host_func.ty.params)?;
let res = (host_func.func)(FuncContext { store: self.store, module_addr: self.module.id() }, &params)?;
self.stack.values.extend_from_typed(&res);
- self.cf.instr_ptr += 1;
- return Ok(ControlFlow::Continue(()));
+ return Ok(());
}
};
@@ -392,29 +390,27 @@ impl<'store, 'stack> Executor<'store, 'stack> {
Err(Trap::IndirectCallTypeMismatch { actual: wasm_func.ty.clone(), expected: call_ty.clone() }.into())
}
- fn exec_if(&mut self, args: BlockArgs, else_offset: u32, end_offset: u32) -> Result<ControlFlow<()>> {
+ fn exec_if(&mut self, args: BlockArgs, else_offset: u32, end_offset: u32) -> Result<()> {
// truthy value is on the top of the stack, so enter the then block
if i32::from(self.stack.values.pop()?) != 0 {
- self.enter_block(self.cf.instr_ptr, end_offset, BlockType::If, args);
- self.cf.instr_ptr += 1;
- return Ok(ControlFlow::Continue(()));
+ self.enter_block(self.cf.instr_ptr(), end_offset, BlockType::If, args);
+ return Ok(());
}
// falsy value is on the top of the stack
if else_offset == 0 {
- self.cf.instr_ptr += end_offset as usize + 1;
- return Ok(ControlFlow::Continue(()));
+ *self.cf.instr_ptr_mut() += end_offset as usize;
+ return Ok(());
}
- let old = self.cf.instr_ptr;
- self.cf.instr_ptr += else_offset as usize;
+ let old = self.cf.instr_ptr();
+ *self.cf.instr_ptr_mut() += else_offset as usize;
self.enter_block(old + else_offset as usize, end_offset - else_offset, BlockType::Else, args);
- self.cf.instr_ptr += 1;
- Ok(ControlFlow::Continue(()))
+ Ok(())
}
fn exec_else(&mut self, end_offset: u32) -> Result<()> {
self.exec_end_block()?;
- self.cf.instr_ptr += end_offset as usize;
+ *self.cf.instr_ptr_mut() += end_offset as usize;
Ok(())
}
fn enter_block(&mut self, instr_ptr: usize, end_instr_offset: u32, ty: BlockType, args: BlockArgs) {
@@ -472,7 +468,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
fn exec_br(&mut self, to: u32) -> Result<ControlFlow<()>> {
break_to!(to, self);
- self.cf.instr_ptr += 1;
+ self.cf.incr_instr_ptr();
Ok(ControlFlow::Continue(()))
}
fn exec_br_if(&mut self, to: u32) -> Result<ControlFlow<()>> {
@@ -480,11 +476,11 @@ impl<'store, 'stack> Executor<'store, 'stack> {
if val != 0 {
break_to!(to, self);
}
- self.cf.instr_ptr += 1;
+ self.cf.incr_instr_ptr();
Ok(ControlFlow::Continue(()))
}
fn exec_brtable(&mut self, default: u32, len: u32) -> Result<ControlFlow<()>> {
- let start = self.cf.instr_ptr + 1;
+ let start = self.cf.instr_ptr() + 1;
let end = start + len as usize;
if end > self.cf.instructions().len() {
return Err(Error::Other(format!("br_table out of bounds: {} >= {}", end, self.cf.instructions().len())));
@@ -497,21 +493,21 @@ impl<'store, 'stack> Executor<'store, 'stack> {
_ => return Err(Error::Other("br_table with invalid label".to_string())),
}
- self.cf.instr_ptr += 1;
+ self.cf.incr_instr_ptr();
Ok(ControlFlow::Continue(()))
}
fn exec_return(&mut self) -> Result<ControlFlow<()>> {
- let old = self.cf.block_ptr;
+ let old = self.cf.block_ptr();
match self.stack.call_stack.pop() {
None => return Ok(ControlFlow::Break(())),
Some(cf) => self.cf = cf,
}
- if old > self.cf.block_ptr {
+ if old > self.cf.block_ptr() {
self.stack.blocks.truncate(old);
}
- self.module.swap_with(self.cf.module_addr, self.store);
+ self.module.swap_with(self.cf.module_addr(), self.store);
Ok(ControlFlow::Continue(()))
}
fn exec_end_block(&mut self) -> Result<()> {
@@ -532,11 +528,11 @@ impl<'store, 'stack> Executor<'store, 'stack> {
self.stack.values.last().map(|val| self.cf.set_local(local_index, *val))
}
fn exec_global_get(&mut self, global_index: u32) -> Result<()> {
- self.stack.values.push(self.store.get_global_val(self.module.resolve_global_addr(global_index))?);
+ self.stack.values.push(self.store.get_global_val(self.module.resolve_global_addr(global_index)?)?);
Ok(())
}
fn exec_global_set(&mut self, global_index: u32) -> Result<()> {
- self.store.set_global_val(self.module.resolve_global_addr(global_index), self.stack.values.pop()?)
+ self.store.set_global_val(self.module.resolve_global_addr(global_index)?, self.stack.values.pop()?)
}
fn exec_const(&mut self, val: impl Into<RawWasmValue>) {
@@ -551,7 +547,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
return Err(Error::UnsupportedFeature("memory.size with byte != 0".to_string()));
}
- let mem = self.store.get_mem(self.module.resolve_mem_addr(addr))?;
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(addr)?)?;
self.stack.values.push((mem.borrow().page_count() as i32).into());
Ok(())
}
@@ -560,7 +556,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
return Err(Error::UnsupportedFeature("memory.grow with byte != 0".to_string()));
}
- let mut mem = self.store.get_mem(self.module.resolve_mem_addr(addr))?.borrow_mut();
+ let mut mem = self.store.get_mem(self.module.resolve_mem_addr(addr)?)?.borrow_mut();
let prev_size = mem.page_count() as i32;
let pages_delta = self.stack.values.last_mut()?;
*pages_delta = match mem.grow(i32::from(*pages_delta)) {
@@ -577,13 +573,13 @@ impl<'store, 'stack> Executor<'store, 'stack> {
let dst: i32 = self.stack.values.pop()?.into();
if from == to {
- let mut mem_from = self.store.get_mem(self.module.resolve_mem_addr(from))?.borrow_mut();
+ let mut mem_from = self.store.get_mem(self.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 = self.store.get_mem(self.module.resolve_mem_addr(from))?.borrow();
- let mut mem_to = self.store.get_mem(self.module.resolve_mem_addr(to))?.borrow_mut();
+ let mem_from = self.store.get_mem(self.module.resolve_mem_addr(from)?)?.borrow();
+ let mut mem_to = self.store.get_mem(self.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(())
@@ -593,7 +589,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
let val: i32 = self.stack.values.pop()?.into();
let dst: i32 = self.stack.values.pop()?.into();
- let mem = self.store.get_mem(self.module.resolve_mem_addr(addr))?;
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(addr)?)?;
mem.borrow_mut().fill(dst as usize, size as usize, val as u8)?;
Ok(())
}
@@ -602,8 +598,8 @@ impl<'store, 'stack> Executor<'store, 'stack> {
let offset: i32 = self.stack.values.pop()?.into(); // s
let dst: i32 = self.stack.values.pop()?.into(); // d
- let data = self.store.get_data(self.module.resolve_data_addr(data_index))?;
- let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_index))?;
+ let data = self.store.get_data(self.module.resolve_data_addr(data_index)?)?;
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_index)?)?;
let data_len = data.data.as_ref().map(|d| d.len()).unwrap_or(0);
@@ -624,10 +620,10 @@ impl<'store, 'stack> Executor<'store, 'stack> {
Ok(())
}
fn exec_data_drop(&mut self, data_index: u32) -> Result<()> {
- self.store.get_data_mut(self.module.resolve_data_addr(data_index)).map(|d| d.drop())
+ self.store.get_data_mut(self.module.resolve_data_addr(data_index)?).map(|d| d.drop())
}
fn exec_elem_drop(&mut self, elem_index: u32) -> Result<()> {
- self.store.get_elem_mut(self.module.resolve_elem_addr(elem_index)).map(|e| e.drop())
+ self.store.get_elem_mut(self.module.resolve_elem_addr(elem_index)?).map(|e| e.drop())
}
fn exec_table_copy(&mut self, from: u32, to: u32) -> Result<()> {
let size: i32 = self.stack.values.pop()?.into();
@@ -635,13 +631,13 @@ impl<'store, 'stack> Executor<'store, 'stack> {
let dst: i32 = self.stack.values.pop()?.into();
if from == to {
- let mut table_from = self.store.get_table(self.module.resolve_table_addr(from))?.borrow_mut();
+ let mut table_from = self.store.get_table(self.module.resolve_table_addr(from)?)?.borrow_mut();
// copy within the same memory
table_from.copy_within(dst as usize, src as usize, size as usize)?;
} else {
// copy between two memories
- let table_from = self.store.get_table(self.module.resolve_table_addr(from))?.borrow();
- let mut table_to = self.store.get_table(self.module.resolve_table_addr(to))?.borrow_mut();
+ let table_from = self.store.get_table(self.module.resolve_table_addr(from)?)?.borrow();
+ let mut table_to = self.store.get_table(self.module.resolve_table_addr(to)?)?.borrow_mut();
table_to.copy_from_slice(dst as usize, table_from.load(src as usize, size as usize)?)?;
}
Ok(())
@@ -653,9 +649,10 @@ impl<'store, 'stack> Executor<'store, 'stack> {
mem_addr: tinywasm_types::MemAddr,
offset: u64,
) -> Result<()> {
- let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr))?;
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)?)?;
let val: u64 = self.stack.values.pop()?.into();
let Some(Ok(addr)) = offset.checked_add(val).map(|a| a.try_into()) else {
+ cold();
return Err(Error::Trap(crate::Trap::MemoryOutOfBounds {
offset: offset as usize,
len: LOAD_SIZE,
@@ -667,12 +664,12 @@ impl<'store, 'stack> Executor<'store, 'stack> {
self.stack.values.push(cast(val).into());
Ok(())
}
- fn exec_mem_store<T: From<RawWasmValue> + ToMemBytes<N>, const N: usize>(
+ fn exec_mem_store<T: From<RawWasmValue> + MemStorable<N>, const N: usize>(
&mut self,
mem_addr: tinywasm_types::MemAddr,
offset: u64,
) -> Result<()> {
- let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr))?;
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)?)?;
let val: T = self.stack.values.pop()?.into();
let val = val.to_mem_bytes();
let addr: u64 = self.stack.values.pop()?.into();
@@ -681,14 +678,14 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
fn exec_table_get(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index))?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?;
let idx: u32 = self.stack.values.pop()?.into();
let v = table.borrow().get_wasm_val(idx)?;
self.stack.values.push(v.into());
Ok(())
}
fn exec_table_set(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index))?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?;
let val = self.stack.values.pop()?.as_reference();
let idx = self.stack.values.pop()?.into();
table.borrow_mut().set(idx, val.into())?;
@@ -696,14 +693,14 @@ impl<'store, 'stack> Executor<'store, 'stack> {
Ok(())
}
fn exec_table_size(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index))?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?;
self.stack.values.push(table.borrow().size().into());
Ok(())
}
fn exec_table_init(&mut self, elem_index: u32, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index))?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?;
let table_len = table.borrow().size();
- let elem = self.store.get_elem(self.module.resolve_elem_addr(elem_index))?;
+ let elem = self.store.get_elem(self.module.resolve_elem_addr(elem_index)?)?;
let elem_len = elem.items.as_ref().map(|items| items.len()).unwrap_or(0);
let size: i32 = self.stack.values.pop()?.into(); // n
@@ -732,7 +729,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
// todo: this is just a placeholder, need to check the spec
fn exec_table_grow(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index))?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?;
let sz = table.borrow().size();
let n: i32 = self.stack.values.pop()?.into();
@@ -746,7 +743,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
Ok(())
}
fn exec_table_fill(&mut self, table_index: u32) -> Result<()> {
- let table = self.store.get_table(self.module.resolve_table_addr(table_index))?;
+ let table = self.store.get_table(self.module.resolve_table_addr(table_index)?)?;
let n: i32 = self.stack.values.pop()?.into();
let val = self.stack.values.pop()?.as_reference();
@@ -769,14 +766,21 @@ impl<'store, 'stack> Executor<'store, 'stack> {
}
// custom instructions
-
- fn exec_i32_store_local(&mut self, local: u32, const_i32: i32, offset: u32, mem_addr: u8) -> Result<()> {
- let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr as u32))?;
- let val = const_i32.to_le_bytes();
+ fn exec_i32_const_store_local(&mut self, local: u32, const_i32: i32, offset: u32, mem_addr: u8) -> Result<()> {
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr as u32)?)?;
+ let val = const_i32.to_mem_bytes();
let addr: u64 = self.cf.get_local(local).into();
mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?;
Ok(())
}
+ fn exec_i32_store_local(&mut self, local_a: u32, local_b: u32, offset: u32, mem_addr: u8) -> Result<()> {
+ let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr as u32)?)?;
+ let addr: u64 = self.cf.get_local(local_a).into();
+ let val: i32 = self.cf.get_local(local_b).into();
+ let val = val.to_mem_bytes();
+ mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?;
+ Ok(())
+ }
fn exec_i32_local_get_const_add(&mut self, local: u32, val: i32) {
let local: i32 = self.cf.get_local(local).into();
self.stack.values.push((local + val).into());
diff --git a/crates/tinywasm/src/runtime/raw.rs b/crates/tinywasm/src/runtime/raw.rs
index 877dcb1..a186fd7 100644
--- a/crates/tinywasm/src/runtime/raw.rs
+++ b/crates/tinywasm/src/runtime/raw.rs
@@ -15,25 +15,6 @@ impl Debug for RawWasmValue {
}
}
-pub(crate) trait ToMemBytes<const N: usize> {
- fn to_mem_bytes(self) -> [u8; N];
-}
-
-macro_rules! impl_to_mem_bytes {
- ($( $ty:ty, $n:expr ),*) => {
- $(
- impl ToMemBytes<$n> for $ty {
- #[inline]
- fn to_mem_bytes(self) -> [u8; $n] {
- self.to_ne_bytes()
- }
- }
- )*
- };
-}
-
-impl_to_mem_bytes! {u8, 1, u16, 2, u32, 4, u64, 8, i8, 1, i16, 2, i32, 4, i64, 8, f32, 4, f64, 8}
-
impl RawWasmValue {
#[inline]
/// Attach a type to the raw value (does not support simd values)
diff --git a/crates/tinywasm/src/runtime/stack/call_stack.rs b/crates/tinywasm/src/runtime/stack/call_stack.rs
index 14077a8..30957be 100644
--- a/crates/tinywasm/src/runtime/stack/call_stack.rs
+++ b/crates/tinywasm/src/runtime/stack/call_stack.rs
@@ -3,10 +3,11 @@ use crate::runtime::RawWasmValue;
use crate::unlikely;
use crate::{Result, Trap};
-use alloc::{boxed::Box, rc::Rc, vec::Vec};
+use alloc::boxed::Box;
+use alloc::{rc::Rc, vec, vec::Vec};
use tinywasm_types::{Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction};
-const CALL_STACK_SIZE: usize = 1024;
+pub(crate) const MAX_CALL_STACK_SIZE: usize = 1024;
#[derive(Debug)]
pub(crate) struct CallStack {
@@ -16,10 +17,7 @@ pub(crate) struct CallStack {
impl CallStack {
#[inline]
pub(crate) fn new(initial_frame: CallFrame) -> Self {
- let mut stack = Vec::new();
- stack.reserve_exact(CALL_STACK_SIZE);
- stack.push(initial_frame);
- Self { stack }
+ Self { stack: vec![initial_frame] }
}
#[inline(always)]
@@ -29,7 +27,7 @@ impl CallStack {
#[inline(always)]
pub(crate) fn push(&mut self, call_frame: CallFrame) -> Result<()> {
- if unlikely((self.stack.len() + 1) >= CALL_STACK_SIZE) {
+ if unlikely((self.stack.len() + 1) >= MAX_CALL_STACK_SIZE) {
return Err(Trap::CallStackOverflow.into());
}
self.stack.push(call_frame);
@@ -48,6 +46,31 @@ pub(crate) struct CallFrame {
impl CallFrame {
#[inline(always)]
+ pub(crate) fn instr_ptr(&self) -> usize {
+ self.instr_ptr
+ }
+
+ #[inline(always)]
+ pub(crate) fn instr_ptr_mut(&mut self) -> &mut usize {
+ &mut self.instr_ptr
+ }
+
+ #[inline(always)]
+ pub(crate) fn incr_instr_ptr(&mut self) {
+ self.instr_ptr += 1;
+ }
+
+ #[inline(always)]
+ pub(crate) fn module_addr(&self) -> ModuleInstanceAddr {
+ self.module_addr
+ }
+
+ #[inline(always)]
+ pub(crate) fn block_ptr(&self) -> u32 {
+ self.block_ptr
+ }
+
+ #[inline(always)]
pub(crate) fn fetch_instr(&self) -> &Instruction {
match self.func_instance.instructions.get(self.instr_ptr) {
Some(instr) => instr,
@@ -115,7 +138,7 @@ impl CallFrame {
locals.into_boxed_slice()
};
- Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, locals, block_ptr }
+ Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, block_ptr, locals }
}
#[inline(always)]
diff --git a/crates/tinywasm/src/runtime/stack/value_stack.rs b/crates/tinywasm/src/runtime/stack/value_stack.rs
index db05364..159e366 100644
--- a/crates/tinywasm/src/runtime/stack/value_stack.rs
+++ b/crates/tinywasm/src/runtime/stack/value_stack.rs
@@ -4,14 +4,10 @@ use tinywasm_types::{ValType, WasmValue};
use super::BlockFrame;
-pub(crate) const MIN_VALUE_STACK_SIZE: usize = 1024 * 128;
-// pub(crate) const MAX_VALUE_STACK_SIZE: usize = u32::MAX / 32 as usize;
+pub(crate) const VALUE_STACK_SIZE: usize = 1024 * 128;
#[cfg(feature = "simd")]
-pub(crate) const MIN_SIMD_VALUE_STACK_SIZE: usize = 1024 * 32;
-
-// #[cfg(feature = "simd")]
-// pub(crate) const MAX_SIMD_VALUE_STACK_SIZE: usize = u16::MAX as usize;
+pub(crate) const SIMD_VALUE_STACK_SIZE: usize = 1024 * 32;
#[cfg(feature = "simd")]
use crate::runtime::raw_simd::RawSimdWasmValue;
@@ -27,10 +23,10 @@ pub(crate) struct ValueStack {
impl Default for ValueStack {
fn default() -> Self {
Self {
- stack: BoxVec::with_capacity(MIN_VALUE_STACK_SIZE),
+ stack: BoxVec::with_capacity(VALUE_STACK_SIZE),
#[cfg(feature = "simd")]
- simd_stack: BoxVec::with_capacity(MIN_SIMD_VALUE_STACK_SIZE),
+ simd_stack: BoxVec::with_capacity(SIMD_VALUE_STACK_SIZE),
}
}
}
@@ -58,20 +54,17 @@ impl ValueStack {
}
#[inline(always)]
- pub(crate) fn calculate(&mut self, func: fn(RawWasmValue, RawWasmValue) -> RawWasmValue) -> Result<()> {
- if self.stack.end < 2 {
- cold(); // cold in here instead of the stack makes a huge performance difference
- return Err(Error::ValueStackUnderflow);
- }
-
- assert!(
- self.stack.end >= 2 && self.stack.end <= self.stack.data.len(),
- "invalid stack state (should be impossible)"
- );
- self.stack.data[self.stack.end - 2] =
- func(self.stack.data[self.stack.end - 2], self.stack.data[self.stack.end - 1]);
+ pub(crate) fn replace_top_trap(&mut self, func: fn(RawWasmValue) -> Result<RawWasmValue>) -> Result<()> {
+ let v = self.last_mut()?;
+ *v = func(*v)?;
+ Ok(())
+ }
- self.stack.end -= 1;
+ #[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(())
}
@@ -154,7 +147,7 @@ impl ValueStack {
#[inline]
pub(crate) fn pop_params(&mut self, types: &[ValType]) -> Result<Vec<WasmValue>> {
#[cfg(not(feature = "simd"))]
- return Ok(self.pop_n_rev(types.len())?.zip(types.iter()).map(|(v, ty)| v.attach_type(*ty)).collect());
+ return Ok(self.pop_n(types.len())?.iter().zip(types.iter()).map(|(v, ty)| v.attach_type(*ty)).collect());
#[cfg(feature = "simd")]
{
diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs
index e480577..9d6cdaf 100644
--- a/crates/tinywasm/src/store/memory.rs
+++ b/crates/tinywasm/src/store/memory.rs
@@ -81,12 +81,11 @@ impl MemoryInstance {
if end > self.data.len() {
return Err(self.trap_oob(addr, SIZE));
}
- let val = T::from_le_bytes(match self.data[addr..end].try_into() {
+
+ Ok(T::from_le_bytes(match self.data[addr..end].try_into() {
Ok(bytes) => bytes,
Err(_) => unreachable!("checked bounds above"),
- });
-
- Ok(val)
+ }))
}
#[inline]
@@ -99,8 +98,7 @@ impl MemoryInstance {
if end > self.data.len() {
return Err(self.trap_oob(addr, len));
}
-
- self.data[addr..end].fill(val);
+ self.data[addr..end].fill_with(|| val);
Ok(())
}
@@ -132,15 +130,13 @@ impl MemoryInstance {
Ok(())
}
+ #[inline]
pub(crate) fn grow(&mut self, pages_delta: i32) -> Option<i32> {
let current_pages = self.page_count();
let new_pages = current_pages as i64 + pages_delta as i64;
+ debug_assert!(new_pages <= i32::MAX as i64, "page count should never be greater than i32::MAX");
- if new_pages < 0 || new_pages > MAX_PAGES as i64 {
- return None;
- }
-
- if new_pages as usize > self.max_pages() {
+ if new_pages < 0 || new_pages > MAX_PAGES as i64 || new_pages as usize > self.max_pages() {
return None;
}
@@ -150,20 +146,26 @@ impl MemoryInstance {
}
// Zero initialize the new pages
- self.data.resize(new_size, 0);
+ self.data.reserve_exact(new_size);
+ self.data.resize_with(new_size, Default::default);
self.page_count = new_pages as usize;
- debug_assert!(current_pages <= i32::MAX as usize, "page count should never be greater than i32::MAX");
Some(current_pages as i32)
}
}
+/// A trait for types that can be stored in memory
+pub(crate) trait MemStorable<const N: usize> {
+ /// Store a value in memory
+ fn to_mem_bytes(self) -> [u8; N];
+}
+
/// A trait for types that can be loaded from memory
-pub(crate) trait MemLoadable<const T: usize>: Sized + Copy {
+pub(crate) trait MemLoadable<const N: usize>: Sized + Copy {
/// Load a value from memory
- fn from_le_bytes(bytes: [u8; T]) -> Self;
+ fn from_le_bytes(bytes: [u8; N]) -> Self;
}
-macro_rules! impl_mem_loadable_for_primitive {
+macro_rules! impl_mem_traits {
($($type:ty, $size:expr),*) => {
$(
impl MemLoadable<$size> for $type {
@@ -172,13 +174,18 @@ macro_rules! impl_mem_loadable_for_primitive {
<$type>::from_le_bytes(bytes)
}
}
+
+ impl MemStorable<$size> for $type {
+ #[inline(always)]
+ fn to_mem_bytes(self) -> [u8; $size] {
+ self.to_ne_bytes()
+ }
+ }
)*
}
}
-impl_mem_loadable_for_primitive!(
- u8, 1, i8, 1, u16, 2, i16, 2, u32, 4, i32, 4, f32, 4, u64, 8, i64, 8, f64, 8, u128, 16, i128, 16
-);
+impl_mem_traits!(u8, 1, i8, 1, u16, 2, i16, 2, u32, 4, i32, 4, f32, 4, u64, 8, i64, 8, f64, 8, u128, 16, i128, 16);
#[cfg(test)]
mod memory_instance_tests {
diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs
index 6617988..f72dcab 100644
--- a/crates/tinywasm/src/store/mod.rs
+++ b/crates/tinywasm/src/store/mod.rs
@@ -112,55 +112,55 @@ impl Store {
}
/// Get the function at the actual index in the store
- #[inline]
+ #[inline(always)]
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]
+ #[inline(always)]
pub(crate) fn get_mem(&self, addr: MemAddr) -> Result<&RefCell<MemoryInstance>> {
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]
+ #[inline(always)]
pub(crate) fn get_table(&self, addr: TableAddr) -> Result<&RefCell<TableInstance>> {
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]
+ #[inline(always)]
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]
+ #[inline(always)]
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]
+ #[inline(always)]
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 element at the actual index in the store
- #[inline]
+ #[inline(always)]
pub(crate) fn get_elem_mut(&mut self, addr: ElemAddr) -> Result<&mut ElementInstance> {
self.data.elements.get_mut(addr as usize).ok_or_else(|| Self::not_found_error("element"))
}
/// Get the global at the actual index in the store
- #[inline]
+ #[inline(always)]
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"))
}
/// Get the global at the actual index in the store
- #[inline]
+ #[inline(always)]
pub fn get_global_val(&self, addr: MemAddr) -> Result<RawWasmValue> {
self.data
.globals
@@ -170,7 +170,7 @@ impl Store {
}
/// Set the global at the actual index in the store
- #[inline]
+ #[inline(always)]
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.value.set(value))
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index bb1f96c..f9f861e 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -85,18 +85,16 @@ 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),
// 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
+ // LocalGet + I32Const + I32Store
+ I32ConstStoreLocal { local: LocalAddr, const_i32: i32, offset: u32, mem_addr: u8 },
+ // LocalGet + LocalGet + I32Store
+ I32StoreLocal { local_a: LocalAddr, local_b: LocalAddr, offset: u32, mem_addr: u8 },
+ // I64Xor + I64Const + I64RotL
// Commonly used by a few crypto libraries
I64XorConstRotl(i64),
// LocalTee + LocalGet
diff --git a/examples/rust/build.sh b/examples/rust/build.sh
index 9c1f77d..fcfd01c 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" -O3 --enable-bulk-memory --enable-reference-types --enable-mutable-globals
+ wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.opt.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"
diff --git a/scripts/Cargo.toml b/scripts/Cargo.toml
index 5217729..a1baadf 100644
--- a/scripts/Cargo.toml
+++ b/scripts/Cargo.toml
@@ -4,5 +4,5 @@ publish=false
edition.workspace=true
[dependencies]
-plotters={version="0.3"}
+plotters={version="0.3", default-features=false, features=["histogram", "svg_backend"]}
eyre={version="0.6"}
diff --git a/scripts/src/bin/generate-charts/progress.rs b/scripts/src/bin/generate-charts/progress.rs
index 1ecc09c..3cc3c26 100644
--- a/scripts/src/bin/generate-charts/progress.rs
+++ b/scripts/src/bin/generate-charts/progress.rs
@@ -72,6 +72,5 @@ pub fn create_progress_chart(name: &str, csv_path: &Path, output_path: &Path) ->
)?;
root_area.present()?;
-
Ok(())
}