Home / Software y Cloud / WebAssembly decoded: the binary that compiles once and runs everywhere

WebAssembly decoded: the binary that compiles once and runs everywhere

Ilustración de WebAssembly

When you open a page that runs WebAssembly (or Wasm), the browser is not executing JavaScript that somehow works magic: it is running a binary compiled beforehand, on another machine, inside a virtual machine designed to be fast, portable and isolated. It is the current way to bring to the web what used to demand a native application.

Published as a W3C standard in 2019, WebAssembly grew out of asm.js, the JavaScript subset Mozilla designed to let C and C++ code run in the browser. The idea is simple at its root: you write in Rust, C, C++ or Go; a compiler — usually LLVM — turns it into a compact binary bytecode with a .wasm extension; and the browser executes it. Your code is never turned back into text: it travels already compiled.

A stack virtual machine, not the hardware

Unlike JavaScript, which is interpreted and optimized incrementally, WebAssembly is designed to be a compiler target. Its execution model is a stack machine: each operation pops values off a stack and leaves the result on top. That format resembles a CPU’s register architecture, which lets the JIT (just-in-time) engine translate it into native instructions almost directly: hence it runs at 60 to 90 % of native speed and delivers deterministic execution times, without the latency spikes of JavaScript’s interleaved garbage collector.

The instruction set is deliberately small: the numeric types i32, i64, f32 and f64, plus arithmetic, logic, memory and control-flow operations. No objects, no inheritance, no string by default. That austerity is an advantage: with so few types and no dynamic dispatch table, the engine can emit highly efficient machine code and, crucially, code that is inferable in a provably safe way.

Linear memory: the frontier with the outside world

The heart of Wasm’s memory model is linear memory: a single contiguous byte buffer, divided into 64 KiB pages, which the VM code can grow on demand via the memory.grow instruction. Addresses move across that flat space as plain integers, with no real system pointers. Communication with the outside world happens through imports and exports: the code exports functions and memory for the host (the browser, Node.js or an edge runtime) to call, and imports functions and memory the host lends it.

That design is what guarantees isolation (sandboxing): the virtual machine only touches the memory region the host grants it; reading outside it triggers a trap and aborts the module. There is no way for a malicious binary to reach the whole browser process, which is exactly the security promise that untrusted code downloaded from the Internet demands.

WASI: Wasm leaves the browser

For years Wasm was tied to the browser. The WASI (WebAssembly System Interface) standard unbinds it: it defines a portable operating-system API —input/output, clock, environments, sockets— that any runtime implements safely. With WASI, a module compiled once runs at the edge (Cloudflare Workers, Fastly Compute), on servers without a traditional OS, or embedded in applications. And because it stays isolated and stable, it is used as a plugin format: version differences or language gaps in host applications stop mattering when the contract is a Wasm binary.

It is not a panacea of “write once, run everywhere”: binaries are typically ~1–2 MB, round-trips with the host across the memory boundary carry a cost, and debugging is less comfortable than in a managed language. But when you need predictable performance, real portability and a strong sandbox in a single artifact, there is no longer any need to reinvent the wheel.

Where it is heading

WebAssembly keeps growing with extension proposals that add exactly what it once lacked: reference types and shared-everything functions for real threads and concurrency with atomics, and the long-awaited garbage collection (GC) that will also let managed languages such as Java or C# compile without shipping their runtime. The Wasm component model effort, meanwhile, aims to package complex modules into units that are reusable and interoperable across languages. In just a few years, the browser and the edge have gained a serious way to run arbitrary code with the guarantees the web has always demanded: speed, portability and isolation.