It has been a long time since the last article about Wasmi in May 2024. Since then, a lot has happened on the Wasmi project, both technically and non-technically, which culminated in the release of Wasmi 1.0, only eight years after its initial version. 1

Wasmi is an efficient and versatile WebAssembly (Wasm) interpreter with a focus on embedded environments. It is an excellent choice for IoT devices, plugin systems, cloud hosts, as smart contract execution engine and even for your lightweight game console.

Before going into all the details, a huge thank you to the Stellar Development Foundation (SDF) which sponsors development of the Wasmi project since October 2024. Without their sponsorship, the Wasmi project wouldn’t be where it is today.

What does 1.0 mean?

Over the course of the last major versions, a ton of deprecations and fine tuning of Wasmi’s API has been implemented, all in preparation for the 1.0 release. With this release, all those deprecated APIs are going to be removed. The 1.0 release marks an important promise of API stability for Wasmi users.

Wasmi 1.0 represents years of careful evolution: new WebAssembly features, cleaner internals, better performance, and stronger security. This release positions Wasmi as a robust choice for anyone needing a lightweight, highly compatible, versatile, and efficient Wasm interpreter.

New Wasm Proposals

Since May 2024, a lot of Wasm proposals have been implemented in Wasmi.

  • ✅ The Wasm multi-memory proposal allows users to define multiple linear memories within a single Wasm module. With this, users can isolate and protect different memories with different purposes from each other.
  • ✅ The Wasm memory64 proposal allows users to define 64-bit Wasm modules, thus being able to execute Wasm binaries that require more than just 4GB of memory.
  • ✅ The Wasm custom-page-sizes proposal allows defining linear memories with page sizes of 1 byte. By default, linear memories have page sizes of 64KB, thus this allows executing Wasm on tiny embedded devices with less than 64KB of memory.
  • ✅ The Wasm simd proposal defines over 200 new 128-bit SIMD operators. This allows users to optimize certain compute-intensive workloads. Honestly, a questionable use-case for an interpreter to say the least, which is why Wasmi’s simd support comes opt-in so users don’t have to take the bloat. To add insult to injury, it was made sure that simd operators in Wasmi actually use SIMD machine instructions. 2
  • ✅ The Wasm relaxed-simd proposal defines some non-deterministic extension operators on top of the Wasm simd proposal which can be more efficient in some cases.
  • ✅ The Wasm wide-arithmetic proposal defines 128-bit arithmetic operators for add, sub, and mul. These operators allow optimizing certain use-cases such as big-integer arithmetic.

With these additions, Wasmi supports all of Wasm 2.0 and even quite a few proposals from Wasm 3.0. 3

Engine Optimizations

Countless execution engine improvements, new optimizations, refinements on Wasmi’s internal bytecode, code clean-ups, and refactorings have significantly improved Wasmi’s translation and especially execution performance, all while lowering its memory footprint and supporting new features.

Note, though, that performance was not the primary focus since the last blog post, and Wasmi is still using the same interpreter architecture that was introduced in May 2024.

Benchmarks

All the benchmarks shown below were conducted on an Apple M2 Pro using rustc 1.91.1 via the Wasmi benchmarks at this revision.

The Coremark benchmark also shows a clear positive progression. 4

Safety & Security Improvements

Given Wasmi’s origins as an execution engine for smart contracts on the blockchain and its focus on constrained devices and embedded systems, deterministic execution, safety, and security have always been of central importance.

Security Audit

The Stellar Development Foundation sponsored an extensive security audit for Wasmi conducted by Runtime Verification.

Over the course of several months, a whole team of security professionals inspected the Wasmi codebase, analysed its architecture, and wrote down their assessment in the document linked above. During that process, they were able to find some issues and concerns, which were quickly fixed.

Fuzzing Infrastructure

Wasmi has received its own fuzzing infrastructure consisting of 3 different fuzzing targets:

  • 🔧 translate: Continuously translates Wasm blobs and tries to find bugs in Wasmi’s translation engine.
  • 🏃 execute: Executes Wasm blobs with various inputs and tries to find bugs in Wasmi’s execution engine.
  • ⚖️ differential: Compares the execution of Wasmi with other Wasm runtimes and tries to find examples of mismatching semantics. 5

Especially the differential fuzzing target finds quite a lot of issues before they land in new releases. And conversely, on Wasmtime’s own fuzzing infrastructure, Wasmi acts as an oracle for its differential fuzzing.

OSS-Fuzz

On top of that, Wasmi has been added to Google’s OSS-Fuzz and is now continuously fuzzed. This has already found some intricate bugs and issues and is a valuable addition that helps keep Wasmi safe and secure.

Wast Testsuite

Wasmi now has its own external Wasmi testsuite alongside the official Wasm spec testsuite. This WebAssembly Script (Wast) based testsuite features Wasmi-specific test cases and is continuously extended to assert semantic behavior in even more cases. 6

Minified Dependency Graph

A minified graph of external dependencies usually implies a smaller attack surface. In May 2024, Wasmi still had 7 external dependencies. Wasmi 1.0 reduced this to just 2:

  • spin: Low-level primitives for locks and mutexes for no_std environments which Wasmi supports. Note that this is a trivial dependency when compiling Wasmi with the std feature enabled.
  • wasmparser: A Bytecode Alliance maintained highly efficient Wasm parser and validator.

There are plans for an internal wasmi_parse crate to replace the external wasmparser crate. 7

Cargo Timing Reports

Below you can see the cargo timing reports for: cargo build -p wasmi --no-default-features 8

Wasmi 0.32Wasmi 1.0

New Features

Wasmi and its feature set are constantly evolving. In this section, the most notable new features since the last post in May 2024 are listed.

C-API Bindings

Support for the “official” WebAssembly C-API has been added to Wasmi via wasmi_c_api_impl crate. With this, any library or language that can interface with C code can now also use Wasmi. Visit C-API README to learn more about using Wasmi from C.

There are also plans for Python bindings for Wasmi via the popular PyO3 library. If that’s something you would love to see, please join the discussion.

Refueled Resumable Calls

As with many other Wasm runtimes, Wasmi has fuel metering built-in. This solves the problem of ensuring that executions halt eventually. Executions are provided a quantity of fuel and yield back to the host when they run out of it before returning.

💡 Wouldn’t it be great if the host could then decide to resume the execution later?

This is exactly what is possible with Wasmi today, and it comes in very handy when using Wasmi as an execution engine to schedule concurrent Wasm jobs, similar to how operating systems do. 9

Usability Improvements

Wasmi has received more usability improvements than could fit on a single list.

Some of the most relevant are:

  • 🔋: WAT is now supported in Module::new and Module::new_unchecked if its wat crate feature is enabled. 10
  • 🪞: Wasmtime API mirror has been further improved. The ultimate goal is for Wasmi to be a drop-in replacement for most users.
  • ⚡: The Instance::new API has been added, which is more low-level and efficient than the Linker API in some cases.
  • 📚: An extensive Usage Guide has been written to provide Wasmi users with the most important knowledge to get the most out of their Wasmi installment.
  • 🌳: Via hash-collections and prefer-btree-collections, users can decide if Wasmi uses hash-tables or btree-tables. Why is this important? In some no_std environments, it is not generally safe to use hash-tables, since they require random initialization, which environments such as wasm32 cannot provide. 11
  • 🔓: Users can compile Wasm modules within called host functions, which previously caused a deadlock.

Looking Ahead

The look ahead is even more exciting than the look behind!

The Next-Gen Engine

Wasmi 2.0 will shift its focus again onto performance. Work on Wasmi 2.0 has already been well underway, and preliminary benchmarks look great. 12

It will feature different modes of interpreter dispatch with various advantages represented by 2 new crate features:

portable-dispatchportable-dispatch
indirect-dispatchDirect threaded instruction dispatch. This is the fastest option at the expense of portability and memory consumption. Similar to Stitch or Wasm3.Portable call-based instruction dispatch within a loop.
indirect-dispatchIndirect threaded instruction dispatch. Slightly slower than its direct counterpart, but has a slightly better memory footprint.Simple but efficient loop-match based instruction dispatch similar to how Wasmi 1.0 dispatch works.

Ideally, it will make use of both become keyword, and #[loop_match] attribute, once those features are stabilized. 13

This is just the pinnacle of what is about to come with Wasmi 2.0, and a blog post is more than likely to appear once it is ready for prime time.

Full Wasm 3.0 Support

Wasmi already implements many of the Wasm 3.0 proposals, and even more:

However, the following Wasm 3.0 proposals are still missing:

Supporting these three missing Wasm proposals and thus making Wasmi WebAssembly 3.0 compatible will be a high priority once the next-gen execution engine, described above, has been implemented.

Try It Out!

Try out and use Wasmi today in various ways:

Special Thanks

  • Again, a huge thank you to Stellar Development Foundation (SDF) for their generous sponsoring and support of the Wasmi project and its development. All this work would not have been possible without the SDF.
  • I would like to express my gratitude to Parity Technologies for allowing me to turn Wasmi into a stand-alone FOSS project.
  • Next, I would like to thank E.J.P. Bruel, author of Stitch, an exceptionally well-engineered high-performance Wasm interpreter. We have kind of become Wasm interpreter sparring partners, and I am very grateful for the exchange. His work on Stitch has inspired several of the techniques planned for Wasmi 2.0.
  • Finally, I am thankful for the regular chats with Graydon Hoare, his steady support for the Wasmi project, and his deep knowledge of programming languages, compilers, and related technical topics, which continue to inspire me.

  1. The author of this article is not a native english speaker. All mistakes contained in the article are his. In case of severe issues feel free to open a pull request↩︎

  2. I verified this using cargo show-asm on a Macbook M2 Pro ARM machine at least for many of the simd operators. ↩︎

  3. The full list of Wasmi support Wasm proposals can be found here↩︎

  4. Note that the Coremark score of Wasmi v0.32 is significantly worse than in the last blog post. The reason for this is likely the different Rust compiler version. It is not uncommon for new compiler versions to drastically change performance metrics, especially if the underlying LLVM version changes. ↩︎

  5. Currently we differentially fuzz against an older, much simpler version of Wasmi itself as well as the mature and battletested Wasmtime Wasm runtime. ↩︎

  6. Before that, Wasmi’s tests were tightly integrated with its translation engine. This necessitated updates to them whenever Wasmi’s translation engine was changed. While those tightly integrated tests helped with early development, it is needless to say, that this process wasn’t sustainable. ↩︎

  7. The wasmparser crate itself is of high quality and has served Wasmi well so far. However, over time it accumulated a ton of other stakeholders with various different requirements and Wasmi got a bit isolated with its focus on high-performance parsing and validation. ↩︎

  8. Wasmi v0.32 requires ~6s to compile whereas Wasmi 1.0 reduces this to ~4.7s. The preliminary Wasmi 2.0 behaves similarly to Wasmi 1.0:  ↩︎

  9. An example use case of how refueled resumable functions are used is shown in Wasmi’s own testsuite where tests are given just enough fuel to continue execution and are refueled iteratively. ↩︎

  10. Note that Wasmi’s wat crate feature is enabled by default. ↩︎

  11. That’s why Rust’s standard library does not provide HashMap in its alloc crate. Note that the hashbrown crate has no_std support but kinda cheats as its random initialization is not applicable to some systems and thus a potential attack vector for safety critical no_std systems. ↩︎

  12. For the curious, here is a link to the PR that implements Wasmi 2.0 in a preliminary state. ↩︎

  13. For #[loop_match] there are ideas floating around to improve codegen quality of interpreters by trying to push LLVM into a better direction for a computed-goto like dispatch. It is unclear whether this will be implemented and included into the #[loop_match] design. ↩︎