February 22, 2022

How to Think About WebAssembly (Amid the Hype)

Matt Butcher Matt Butcher

webassembly javascript ebpf risc v flash docker

How to Think About WebAssembly (Amid the Hype)

WebAssembly (also called Wasm) is certainly the subject of much hype right now. But what is it? Is it the JavaScript Killer? Is it a new programming language for the web? Is it (as we like to say) the next wave of cloud compute? We’ve heard it called many things: a better eBPF, the alternative to RISC V, a competitor to Java (or Flash), a performance booster for browsers, a replacement for Docker.

Thinking About WebAssembly

All those things are, to some degree, sensible ways of looking at WebAssembly. However, it might help to take a bird’s eye view of the technology and understand its essential properties. And from there, these other assessments will begin to make sense. Once we’ve covered the essential characteristics of WebAssembly, we’ll circle back to Fermyon’s stance that WebAssembly is the enabling technology behind the next wave of cloud compute.

So What Exactly Is WebAssembly?

The simplest way to think of WebAssembly is as a standardized bytecode format for executing programs.

Some programs run with only the assistance of the operating system. We are used to compiling “systems languages” like C, C++, Go, and Rust into a binary executable format that be executed directly on the operating system.

Some programs are written using scripting languages, and source code is read and executed in rapid succession. JavaScript, Python, Ruby, PHP, and Perl all fall into this category.

Finally, some programs are compiled to a bytecode format, but then require a special program (a runtime or virtual machine) to run them. Java and C# (and all .NET languages) are the most common examples. Java, for example, is executed with the JVM (Java Virtual Machine) while .NET languages are executed by the CLR (Common Language Runtime).

WebAssembly is a bytecode format that any WebAssembly-capable runtime can execute.

Is that all? In a sense, yes. But it is the particular characteristics of WebAssembly that make it such a compelling entry into what might appear to be an already crowded field. To understand that, we need to take a quick look at its history.

WebAssembly Was About the Web

WebAssembly Was About the Web

In the previous section, we defined WebAssembly (perhaps unsatisfactorily) as “a bytecode format that any WebAssembly-capable runtime can execute.” But where are these WebAssembly runtimes?

The original intention was that the runtime would be embedded into every major web browser.

With this accomplished, popular browsers would be able to execute not just JavaScript text documents, but also compiled binaries. Performance was one reason. But also, many different languages could be compiled into WebAssembly. As Luke Wagner wrote in his introductory post:

WebAssembly… defines a portable, size- and load-time-efficient format and execution model specifically designed to serve as a compilation target for the Web. [Emphasis added]

The idea was that compilers would be able to read source code in a variety of languages, C, C++, Rust, Go, Ruby… whatever. And then these compilers would emit Wasm bytecode. When a web browser fetched a WebAssembly file from a remote server, it would then execute the bytecode as a program.

With a story like this, it is clear why people asked if WebAssembly was a JavaScript killer or the next wave of Java Applets or Flash media. In a somewhat inexplicable twist of fate, though, WebAssembly did not immediately take off as a browser technology.

But it just so happened that WebAssembly’s design features made it attractive beyond the browser.

WebAssembly Is Now About More Than the Web

Wasm has cropped up in a variety of interesting places lately. This is peculiar, in that the name itself seems to wave people off of the fact that WebAssembly could be used for something other than the web. But the reason can be found in WebAssembly’s key features–features dictated by a browser environment.

What are some of the key features that a browser-based runtime might require? Here are a few:

  • Strong security: You don’t want to trust arbitrary code that came from somewhere on the Internet.
  • Small binary sizes: Bandwidth is a constant limitation, so files must be no larger than a few megabytes, and preferably only a few kilobytes.
  • Fast loading and running: We go to tremendous lengths to make our websites load fast and remain responsive. And it’s no wonder why. A bored user isn’t going to stick around.
  • Support for many operating systems and architectures: In the age of smart phones, tablets, iMacs, and XBoxes, we can’t require our users to be running Windows on an Intel processor, or only support visitors on macOS with an M1.
  • Interoperability with the browser: It’s not enough to build a binary format that runs in a browser window. The runtime must allow flexible communication between the bytecode program and the HTML, CSS, and (yes) JavaScript running in the browser.

Thus we have five characteristics required of WebAssembly. But are they characteristics unique to the browser?

Nope.

Let’s direct our gaze from one side of a network connection to the other. Instead of the browser, let’s look at the cloud.

WebAssembly Was About the Web

What the Cloud Needs

Once upon a time, if you wanted to run a web service, you needed a web server. And that meant a big bulky piece of hardware that sat under your desk and was plugged into an ethernet jack in the wall.

Amazon shattered that requirement when it began leasing computational power in their own datacenter. A cloud was born. And soon after, there were many cloud providers.

Leasing computing power is a demanding business. A cloud provider must have strong security. Bandwidth is expensive, so smaller objects are better than large ones. And the organizations that rent these cloud services demand quick load times and high performance. Cloud providers have perennially struggled with the difficulties of supporting different operating systems and architectures. And finally, when it comes to the systems that actually execute code in the cloud, those systems need to have the flexibility to link up the required features of the customer’s application with an opaque and highly complex set of underlying services. In short, we could list these requirements as:

  • Strong security
  • Small binary sizes
  • Fast loading and running
  • Support for many OSes and architectures
  • Interoperability with cloud services

That’s a familiar list.

True, the cloud began with only virtual machines. These were not the pinnacle of security, sizes were certainly not small, and startup times were not fast. None of the five criteria were perfectly satisfied in the early days. Virtual Machines, the heavyweight class of cloud compute, improved vastly. But the technology could only improve so much before another technology appeared, solving these five in a different way and to a different degree.

Docker made containers popular. And within a few short years, they became the middleweight class of computing alongside heavyweight virtual machines. Docker promised smaller sizes and faster loading times. And systems like Kubernetes systematized the interoperability with other cloud services. It is unsurprising that today every major cloud provider supports both virtual machines and Docker-style containers.

Then along came WebAssembly, just a few short years after Docker. Strong security, smaller binaries, faster times, cross-OS, cross-architecture, and built for interoperability. If VMs are the heavyweight class of cloud compute, and containers are the middleweight class, WebAssembly is the perfect fit for a lightweight class. This is why we at Fermyon call WebAssembly the next wave (or third wave) of cloud compute.

But wait! There’s more!

“The Last Plugin Technology We’ll Ever Need!”

A friend once remarked that “WebAssembly is so versatile that it will be the last plugin technology we’ll ever need.” He had intuited about plugins the same thing we had intuited about cloud. Plugins need:

  • A secure sandbox: A plugin shouldn’t be able to take over the host app
  • Small binaries: Plugins need to share resources with the host, and that means not consuming all the disk and memory
  • Fast loading and running: Plugins are run on-demand within a host program. If they slow down the host, users will simply disable or uninstall the plugin.
  • Support for many OSes and architectures: A plugin should run on any platform the host runs on.
  • Interoperability with the host system: The key feature of a plugin is that it can extend the capabilities of the host while acting like it is part of the host.

It has therefore been unsurprising to see WebAssembly make its way into everything from HTTP proxies to databases.

Browsers, servers, plugins… the story goes onward. Edge computing, ML, blockchain, trusted computing, and embedded computing (like Internet of Things, IoT) are also in on the WebAssembly thing. (Luke Wagner, the original author of WebAssembly, now works for the edge computing company Fastly.) And what started as a “better Flash” or “a way to extend JavaScript” has now become a general purpose tool employed in a number of novel ways.

But there is one more detail: WebAssembly is a binary format. As such, it’s only useful if languages compile to that format.

The March of the Languages

The first few languages bandied about as “ideal WebAssembly languages” were the usual suspects. C and C++ power much of modern computing, are well known, and had many existing compile targets.

But an interesting newcomer drew up alongside C/C++. To call Rust a “niche language” in 2017 is an understatement. Very few developers used it, and it was considered hard to learn. But over a few years, it has gained a loyal following. This is partly because its innovative memory manager was not only secure but also resulted in small and fast code. Mozilla, one of the organizations behind WebAssembly, was also deeply invested in Rust. Rust and Wasm somehow became the natural fit, and the two ecosystems have co-evolved.

At this moment, Rust is likely not only the best non-browser host system for WebAssembly, but also the best language to compile to WebAssembly. And the developer tooling is amazing (and easy to use).

A few specialty languages arrived on the scene. First came AssemblyScript, a TypeScript-inspired language designed specifically to compile to WebAssembly. Then came Grain and others–languages designed specifically for WebAssembly.

Existing languages also began adding support for WebAssembly. Swift, Go, .NET (with Blazor). And then seemingly the floodgates opened. Kotlin is working on WebAssembly support. Python and Ruby recently merged WebAssembly support. There are community run projects for PHP, R, Haskell, Java, Perl, and even COBOL.

But one language stands apart as truly remarkable.

In late 2021, the Spidermonkey JavaScript engine that powers Mozilla Firefox gained a WebAssembly compile target. The language that so many people expected to be displaced by WebAssembly was suddenly part of the WebAssembly ecosystem. Of course, this made sense on the cloud, where there is no browser runtime. Surprisingly, though, browser-centered JavaScript-in-Wasm has its own use cases (like sandboxing one JavaScript program from another).

The WebAssembly Language Guide By the end of 2022, we at Fermyon expect most of the top 20 languages to have at least some degree of WebAssembly support.

There’s just one piece left to complete the story: To run WebAssembly in all these different places, we need a system to expose the features of the host (be it a browser, IoT device, or cloud service) to the WebAssembly module. And that brings us to WASI.

The WebAssembly System Interface (WASI)

WASI began as an ambitious project. But what it has become is so far beyond its initial aspirations as to make one’s jaw drop.

Originally, WASI was going to be a common set of APIs that allowed a host to provide an implementation of a standard library to the WebAssembly binary. Wasm programs could be written in the usual way, opening files, reading environment variables, making network connections. But instead of those system calls going straight to the operating system, the host implements them. What appears to the guest code to be a file system might actually just be some data loaded into memory and presented like a filesystem. Every network connection might be locked down, or even faked entirely. The host was free to layer on security that was as strict as the environment dictated… but all of this was opaque and unknown to the guest WebAssembly module.

That’s a lofty plan. But part way into the project, the plan changed.

We collectively realized that a standard system library wasn’t what we really wanted. What we really wanted was a way for a guest WebAssembly module to say “I need a filesystem” or “I need a database that acts like MySQL” or “I need a network connection to Fermyon” and the host environment could then figure out how to satisfy that requirement while still meeting its own security, reliability, and performance goals.

The innovations of WASI are now driving a family of specifications for defining, loading, and satisfying dependencies between a WebAssembly module and the host – which may, in turn, satisfy those requirements by loading other WebAssembly modules.

All of this may sound fanciful. But it’s happening.

Conclusion

What is WebAssembly? It’s just a binary executable format. But it happens to be a format that has desirable features for the browser, for the cloud, for IoT, for the edge… for multiple use cases. We’re excited about the application of this technology to cloud computing. Others are rightly enthusiastic about its application in other domains. This has translated to often confusing hype. But the bottom line is this:

WebAssembly is coming into its own. Expect to see it in the browser, on the edge, in the cloud, and perhaps even on a light switch or doorbell! It might just be a binary format, but it’s an exciting one that is opening many new opportunities.


🔥 Recommended Posts


Quickstart Your Serveless Apps with Spin

Get Started