23
A primer on WebAssembly
This first appeared on my Medium blog
As detailed in this LinkedIn post, 2022 is going to be my year of diving into the world of WebAssembly and Rust. With an overwhelming amount of people opting for blog content over other media, here’s the first one in, what I hope will be, a series of posts covering the aforementioned topics.
Although this has been covered in various formats across the internet, I believe any content about a new technology or tool should start with the motivations behind its inception. To understand why there was a requirement for WebAssembly, let’s take a not-so-quick stroll down memory lane.
The world wide web, as we know it today, started off as a single page project on a NeXT computer at CERN. You can still view it here. The page was a simple static page written in HTML and contained links to the project and a few other technical details. The motivation behind this project was to enable information sharing between academics via a document exchange network.
As you probably noticed above, the very first browser wasn’t radically different from the browsers we use today. However, the interactive nature of web content has definitely seen a drastic change ever since. With its ubiquity and maturation, there was a requirement for the content being made available to be more sophisticated and for it to be rendered on different operating systems & devices. This obviously meant interacting with and accessing various elements within the HTML document and one of the frontrunners in this space was JavaScript.
Created in 1995 with a name aimed to capitalize on the widespread adoption of Java, JavaScript had a very low barrier to entry. This meant that even someone who was fairly non-technical could use it to introduce interactivity into their webpage. This contributed to its prominence and rise as a de facto compilation target against competitors like ActiveX, Adobe Flash, JavaBeans etc.
But with this uninhibited rise, there were several challenges as well. JavaScript is an interpreted language. In simple terms, the functions you write are bundled and minified into a source file. Sent as plain text to the Client’s browser, this needs to be parsed into Abstract Syntax Trees, compiled into bytecode and then executed by the interpreter. The browser’s JavaScript engine then spots any potential optimizations via methods such as JIT Compilation allowing for eventual optimization. Keyword here being eventual since it’s a long drawn process with speed as an end goal.
However, the concerns with speed were not only limited to the convoluted process to get there. For more challenging applications where performance is a critical factor, the lack of consistency/predictability in the levels of performance was a significant obstacle.
Additionally, with the popularity of the web, there has been an even greater rush to bring more sophisticated languages into the fray. In the absence of plugins, using JavaScript as a compilation target was the only option. Being an interpreted language itself, the above operations were made complicated due to the amount of efforts required if they were to be achieved efficiently.
Introduced as a subset of JavaScript, the asm.js specification aimed at describing a sandboxed virtual machine for memory-unsafe languages like C or C++ and provide a low-level, efficient target language for compilers. Implemented first by the Mozilla Firefox browser, this spec introduced performance improvements via employment of ahead-of-time optimizing compilation strategy for valid asm.js code by the JavaScript engines.
Quoting Mozilla docs,
It is a very small, strict subset of JavaScript that only allows things like
while
,if
, numbers, top-level named functions, and other simple constructs. It does not allow objects, strings, closures, and basically anything that requires heap allocation. Asm.js code resembles C in many ways, but it’s still completely valid JavaScript that will run in all current engines
While asm.js was an improvement on the performance front, it was still limited to the things that were expressible in JavaScript. Being an informal spec of JavaScript and not an actual standard, every vendor optimized it in a way they saw fit. Although it did lead to an eventual convergence, there definitely was room for improvement with respect to standardization.
Building upon the experience from asm.js, all major browsers worked towards designing a new format for the Web with one of the end goals being speed and efficiency.
WebAssembly, abbreviated Wasm, was designed to be a portable compilation target for programming languages, enabling deployment on the web for client and server applications.
So what exactly is WebAssembly? It is a binary instruction format for stack based machines. Here’s a partial snippet of how a simple “Hello world” program looks like in Wasm.
As is evident in the above snippet, this is closer to machine code than either asm.js or JavaScript. Therefore, it is a no-brainer that decoding, compiling, fetching, and optimizing WebAssembly code takes lesser time. Why?
The typical amount of time a JavaScript Engine takes during startup for an application today is depicted below.
Although the tasks have been separated above for pictorial depiction, in reality they weave into each other and are not discrete. With larger JavaScript applications, of course the overhead of monitoring and compiling the code increases.
Contrast that with how a typical WebAssembly flow looks like.
There’s not only a marked difference in the amount of time being spent on account of it being closer to the machine code, but there is also an elimination of certain steps altogether. This obviously leads to better performances in comparison for most cases but not all, since WebAssembly is still in its nascent stages (the MVP was completed in 2017).
But wait.. does that mean developers will now be expected to write entire codebases in WebAssembly instead of JavaScript? Since this is a like-to-like comparison, the obvious answer to this question would have been a yes. But that is not the case! It is expected that a majority of Wasm developers will continue to code in languages like Rust, C, etc. and then compile to WebAssembly so that users can reap its performance benefits.
So that’s it for this post! Here’s a list of resources that helped me along the way while learning,
- The Mozilla Hacks blog
- This free course by The Linux Foundation on edX
- The sessionstack blog
- CERN webpage
- MDN Web Docs
23