WebAssembly interpreters are having a moment. Two of the fastest ones around, Wasm3 and Makepad's Stitch, share a DNA of threaded code, accumulator registers, and tail calls. Wasmi 2.0, released September 1, 2026, took that DNA and built a new engine around it. After eight months of work, the Rust interpreter that powers Typst, Zellij, and Stellar's Soroban smart contracts runs about 2.2x faster than its 1.0 predecessor, and it now keeps pace with the fastest portable interpreters on the market.1
Most of the release notes are about execution speed: the ~2.2x figure is the geometric mean across the wasmi-benchmarks suite on an Apple M2 Pro.1 The number matters less than how it was reached. This release is a from-scratch rewrite of the interpreter core, and the announcement post from maintainer Robin Freyler reads like a mini-course in interpreter engineering.
What changed under the hood
The Wasmi 1.0 executor was a classic stack machine: a loop with a large match on opcodes, operands shuffled through stack slots encoded in the instruction stream. Wasmi 2.0 replaces that with four dispatch strategies, the fastest of which is direct-threaded code: function pointers embedded directly in the internal IR, with a tail call from one instruction handler to the next.2
To make that work, the new engine needed three things:
- Accumulator registers. IR instructions now write results into three implicit registers,
ireg,freg32, andfreg64, instead of named stack slots. Ani64.addshrinks from decoding slots, loading, computing, and storing to a singleaddoniregwith an immediate. The compiledaarch64handler is four instructions.3 - A redesigned instance layout. Wasmi 1.0's
InstanceEntityscattered instance objects across separate heap allocations, so evenglobal.getneeded a chain of dependent loads. The new layout puts all handles in one contiguous, dynamically sized buffer, with offsets baked into the module's IR. Instance access is one pointer offset away, matching Wasm3 and Stitch despite Wasmi's module-shared bytecode rather than per-instance bytecode.4 - A lock-free
CodeMap. The old one wrapped aVec-style arena in a mutex, so every internal Wasm call took a lock. The new one stores function bodies in append-only buckets that never reallocate, with per-entry atomic state. That enables lazy compilation and zero-lookup calls, closing the gap to Wasm3 and Stitch on call-heavy workloads.5
There is also a fix that reads like a compiler bug hunt. Wasmi 2.0's i32.lt handler was hurt by DestinationPropagation, a MIR optimization Rust 1.92 enabled by default. The pass collapsed two dispatch paths into one, which confused the branch predictor. A small rewrite of the handler raised CoreMark scores from about 2800 to over 4200, a ~50% gain from a single fix and the most important "optimization" in the release.6
Everything else in the release
Fuel metering is now stable. Costs are tied to the input Wasm bytecode instead of Wasmi's internal IR, so they stay consistent across versions, using the same technique as Wasmtime, and they are configurable through Config::operator_cost and Config::fuel_cost.7
Binary size gets attention too. A new validate feature drops Wasm validation support, saving roughly 200 to 300 kB, and the default feature set gained auto-dispatch, which uses tail-call-based dispatch where the platform supports it and falls back to portable dispatch elsewhere.7
Enabling simd no longer costs anything on non-simd code. Cell width is fixed at 64 bits, and v128 values just use two adjacent cells, so enabling the feature no longer inflates memory usage or regresses plain code.7
The CLI was renamed from wasmi_cli to wasmi and now takes Wasmtime-style run and wast subcommands. There is also support for the Wasm deterministic profile behind a deterministic feature, and a config option to disallow a module's start function.7
Existing 1.x users should read the migration guide before upgrading. The breaking changes: Ref and RefType replace Val and ValType in the table APIs, table elements shrink to 32-bit references (2 to 4x less memory), ResourceLimiter callbacks now return a Result, and absolute fuel numbers differ from 1.x, so persisted fuel budgets need recalibration.8
Where it lands
The benchmark charts put Wasmi 2.0 in the same league as Wasm3, WAMR's fast interpreter, Wasmtime's Pulley, and Stitch, which is a crowded field.1 Wasmi's pitch was always portability first: a no_std-friendly interpreter for embedded and constrained environments with deterministic execution and a Wasmtime-like API. Version 2.0 mostly erases the old performance gap without giving that up.
The next major version is already scoped: Wasmi 3.0 aims to support all of WebAssembly 3.0, which means implementing the function-references, exception-handling, and gc proposals.9
One thing worth knowing about the project's future: Stellar Development Foundation's sponsorship, which let Freyler work on Wasmi full time for two years, ends in October 2026. He is looking for continued funding or a role that leaves room for Wasmi work, and his contact details are in the announcement post.
- https://wasmi-labs.github.io/blog/posts/wasmi-v2.0/
- https://wasmi-labs.github.io/blog/posts/wasmi-v2.0/#new-modes-of-instruction-dispatch
- https://wasmi-labs.github.io/blog/posts/wasmi-v2.0/#accumulator-registers
- https://wasmi-labs.github.io/blog/posts/wasmi-v2.0/#instance-object-access
- https://wasmi-labs.github.io/blog/posts/wasmi-v2.0/#lock-free-codemap
- https://wasmi-labs.github.io/blog/posts/wasmi-v2.0/#accidental-rust-deoptimization
- https://github.com/wasmi-labs/wasmi/releases/tag/v2.0.0
- https://raw.githubusercontent.com/wasmi-labs/wasmi/v2.0.0/docs/migration-v1-to-v2.md
- https://wasmi-labs.github.io/blog/posts/wasmi-v2.0/#whats-next