What Happened To WebAssembly

table of contents

On every WebAssembly discussion, inevitably a comment (often near the top) asks what happened.

It seems to have been advertised as a world-changing advancement. Was it just more sales? Was this another JVM applet scenario, doomed to fail?

I’d like to tackle this in a weird twist because I think these types of questions make some misconceptions that are important to clear up.

Of course, WebAssembly does See real-world uses. Let’s list some examples!

For many of these people, WebAssembly is either critical to their entire product or a key feature.

But I think this alone is not very convincing. We have yet to see major websites built entirely with a WebAssembly-based framework. We are not building our applications directly on WebAssembly for maximum portability. But why not?

To answer this, we need a good mental model of what WebAssembly is. This will help us qualify where it is most impactful and the limitations we are facing.

In a word, WebAssembly is a language.

A note on speed

This makes it a bit difficult to answer questions like “how fast is WebAssembly?” You don’t ask how fast algebraic notation is—that’s not a very sensible question.

In the context of something like JavaScript, the language is only as fast as the engine that runs it. There is no benchmark in JavaScript language, but you can benchmark JS engines like V8, SpiderMonkey, and JavaScriptCore. You can benchmark IO libraries of JS runtimes like bun, deno, and node.

What people really mean is “how useful are the constructs of this language for efficient mapping of modern hardware” and “what is the current landscape of systems that leverage these constructs”.

Through enough clever engineering, you can make any system fast enough with a few changes. If compiling your code directly into C doesn’t bother you, it is possible to achieve “almost native” speed in both JavaScript and WebAssembly.

That’s right, you can compile WebAssembly! You can also choose to interpret it directly—it will depend on your runtime, like every other system.

So let’s ask the real question of WebAssembly: how useful are the constructs of this language for efficient mapping of modern hardware? Turns out, quite useful!

an efficient mapping

WebAssembly is a fairly close approximation of an assembly language. Not too close, mind you. This is of a higher level than that. But it is enough to cleanly compile most assembly languages ​​without any significant speed trade-off.

And yes, you can write WebAssembly by hand! I’ve created a Rustlings-esque course called Watlings where you can write wats by hand to solve some basic exercises.

WAT is a very close approximation of WASM. it is About In 1:1 you can compile WAT to Wasm and then back to WAT, with barely any loss in information (you may lose variable names and some metadata). it looks like this:

;; import external i32, name it $global_num_import

(import "env" "global_num" (global $global_num_import i32))

;; A function that adds param $a to $global_num_import, returns i32

(func $add_to_global_num (param $a i32) (result i32)

;; The last stack value is the return value

(i32.add (local.get $a) (global.get $global_num_import))

;; export local function, name it add_to_global

(export "add_to_global" (func $add_to_global_num))

Try reading the code. It will feel both familiar and foreign.

We have functions and S-expressions. We have import and export. But we also have such instructions i32.add And implicit stack returns.

Wasm is a bytecode which is probably best compared to JVMIS (ie JVM bytecode). Their goals and constraints are similar, but the scenarios and guarantees are different.

Compared with JVM bytecode, Wasm has a much smaller API and stronger security guarantees. It has less say over your memory management strategy and more limits on what your program can do without the permission of its host environment.

It can crunch the numbers, but its memory and all imports must be explicitly provided for. In this way, it is very different from real assembly language (or, more widely used language).

We will consider this later.

You can compile multiple languages ​​into Wasm.

Notable among them are Rust, C, Zig, Go, Kotlin, Java and C#. Runtimes for commonly interpreted languages ​​are compiled into WebAssembly, such as Python, PHP, and Ruby. There are also several languages ​​that compile entirely on WebAssembly, such as AssemblyScript, Grain, and Moonbit.

For many of these, not needing a garbage-collector is important. For others, it would be helpful to include one. Wasm allows for both (the GC option is very recent).

Your browser includes a Wasm “engine”, making it a doubly attractive compilation target. This means that without much setup, your phone and laptop can already run Wasm programs.

Just as the JVM can have multiple implementations of its runner, there are several implementations that run independently of your browser such as wastime, wasmage, and wasmer.

$ Wasmer run cowsay "I am cow"

These languages ​​can output a single artifact without being too specific to your computer’s hardware. You only need a wasm runner to execute it (note more JVM analogies).

Right now, Wasm is looking really similar to JVM. The main differences seem to be around memory management strategies and how many platforms support it.

The security story is what really troubles us.

WebAssembly maintains a minimal attack surface by treating all external interactions as explicit, host-defined imports. We went to this first. Its “default-by-default” architecture, small instruction set, hidden control-flow stack (i.e. no raw pointers), and linear memory form a combination very strong Security story.

This is so you can ensure process-like isolation within the same process. Cloudflare takes advantage of this aspect within V8 to run untrusted code very efficiently by using V8 isolates. This means significant efficiency gains without significant safety trade-offs.

Wasm programs can start up to 100 times faster if you can avoid starting a separate process. Firmyon, a company in the Wasm hosting sector, advertises sub-millisecond spinup times.

In these cases, performance is a direct result of enabling security guarantees.

In other cases, the security feature may unlock support.

Flash is a multimedia platform that was primarily used for animations and games, until it was removed from (mainly) all major browsers in January 2021 due to security concerns. Ruffle has revived Flash experiences on sites like Newgrounds by acting as an interpreter and VM for ActionScript.

Cloudflare allows running Python code with the same security guarantees as your JS code using PyDroid, which is a Wasm build of CPython.

Figma runs untrusted user plugins in your browser by running them in a QuickJS engine that is compiled into Wasm.

Elsewhere, security allows extreme embeddability.

We have learned about the ways in which you can run Wasm programs. A Wasm runner can be quite light. Rather than forcing library authors into a specific language (usually Lua or JavaScript), Wasm’s support itself opens the door to a much broader set of options.

Tools like Zellige, Envoy, and Lapse support Wasm for their plugin ecosystem.

In environments where the JavaScript engine is already in use, this means access to programs that you would not otherwise be able to run.

It includes image processing, OCR, physics engine, rendering engine, media toolkit, database and parser, among many others.

In most of these cases, the use of Wasm will be transparent to you. The library you installed must simply be using it somewhere in its dependency tree.

The codebases of Godot and Figma are written in C++, but are often compiled to (or in combination with) WebAssembly and prepared for the browser.

It seems that the most common use of Wasm is to bridge language gaps. It appears that groups of tools are more common in some ecosystems. Squash would be a more limited application if it could only choose image compression libraries from npm.

Browsers run WebAssembly with almost the same pipeline that runs JavaScript. This appears to impose a strict limit on the performance of Wasm applications, but they will often be more or less performant due to their architecture or domain.

More efficient programs can be produced by using languages ​​with richer type systems and more sophisticated optimizing compilers. The JIT model of engines like the V8 may prevent optimization if the cost of optimization exceeds the benefit from running the optimized code. You can more easily avoid megamorphic functions by avoiding JavaScript.

However, there is a cost to crossing the host-program boundary, especially if memory is cloned. Zaplib’s postmortem is interesting to read here. Moving the codebase incrementally to Wasm could incur significant costs in crossing the border, negating any benefits in the short term.

A smaller API surface also means binary bloat as system APIs are more often re-built than imported. There are standards like WASI that aim to help here. Still, there is no native string type (yet).

Zig seems to produce the smallest wasm binaries among the mainstream languages.

The practical performance of Wasm in native contexts (i.e. outside the JS engine) appears to be affected by several reasons. Any type of threading and IO incurs some cost. Memory usage is large. The onset of cold is slow.

Still, the performance trade-off may not be significant enough to make a difference. For most uses, I’d bet it’s “fast enough”. If you’re in a performance-sensitive context, the benefits of Wasm are probably not as relevant.

Obviously things are happening.

There are a lot of things worth watching on the Wasam IO YouTube channel.

In fact, standards and language development in WASM have given rise to significant controversy internally. There is a great desire for progress, but standardization means that decisions are hard to reverse. For many people, things are moving too fast and in the wrong direction.

There is the “more official” W3C working group and then the “less official” Bytecode Alliance which works much faster and focuses on tooling and language development directly outside Wasm (e.g. on WIT and the WebAssembly component model).

Wasm feature offerings are being rapidly advanced and adopted by a wide range of devices. This is remarkable progress for standardization, but also scary to watch if you fear major missteps.

So why do people think nothing happened?

I think most people are under the impression that this technological advancement would have had a more pronounced impact on their work. That they will knowingly access and use Wasm tools.

Many people think that Wasm is a way to replace JavaScript within the browser – which they may not need to include. .js Absolutely file. This is very unlikely.

However, you can use frameworks like Blazor and Leptos without being aware of or involved in the JS artifacts produced.

Mostly, Wasm tools have been adopted and used by library authors, not application developers. The inner parts are opaque. This is probably fine.

Separately, I think the philosophy of deliberately obscuring teaching material around Wasm doesn’t help the community. It’s a battle I’ve lost many times.

For now, maybe check out Watlings. I will definitely expand on this at some point.



<a href

Leave a Comment