Chapter 1. Introduction

Extraordinary claims require extraordinary evidence.

Dr. Carl Sagan

This chapter will introduce WebAssembly and provide context for its expansive reach. In some sense it is a culmination of the evolution of the web over the last several decades. There is quite a bit of history to cover to make sense of it all. If you are not a fan of history and exposition, you can skip this chapter and go to directly to Chapter 2, but I hope you don’t. I think it is important to understand why this technology is so important and where it came from.

What WebAssembly Offers

One of the greatest skills an engineer can develop is the ability to assess what a new technology brings to the table. As Dr. Fred Brooks of the University of North Carolina reminds us, there are no “silver bullets”; everything has trade-offs. Complexity is often not eliminated with a new technology, but is simply moved somewhere else. So when something does actually change what is possible or how we do our work in a positive direction, it deserves our attention and we should figure out why.

When trying to understand the implications of something new, I usually start by trying to determine the motivation of those behind it. Another good source of insight is where an alternative has fallen short. What has come before, and how does it influence this new technology we are trying to decipher? As in art and music, we are constantly borrowing good ideas from multiple sources, so to truly understand why WebAssembly deserves our attention and what it provides, we must first look at what has preceded it and how it makes a difference.

In the paper that formally introduced the world to WebAssembly, the authors indicate that the motivation was about rising to meet the needs of modern, web-delivered software in ways that JavaScript alone could not.1 Ultimately, it was a quest to provide software that is:

  • Safe

  • Fast

  • Portable

  • Compact

In this vision, WebAssembly is centered at the intersection of software development, the web, its history, and how it delivers functionality in a geographically distributed space. Over time, the idea has expanded dramatically beyond this starting point to imagine a ubiquitous, safe, performant computational platform that touches just about every aspect of our professional lives as technologists. WebAssembly will impact the worlds of client-side web development, desktop and enterprise applications, server-side functionality, legacy modernization, games, education, cloud computing, mobile platforms, Internet of Things (IoT) ecosystems, serverless and microservices initiatives, and more. I hope to convince you of this over the course of this book.

Our deployment platforms are more varied than ever, so we need portability at both the code and application levels. A common instruction set or byte code target can make algorithms work across various environments because we just need to map logical steps to how they can be expressed on a particular machine architecture. Programmers use application programming interfaces (APIs) such as OpenGL,2 POSIX,3 or Win324 because they provide the functionality to open files, spawn subprocesses, or draw things to the screen. They are convenient and reduce the amount of code a developer needs to write, but they create a dependency on the presence of libraries to provide the functionality. If the API is not available in a target environment, the application will not run. This was one of the ways Microsoft was able to use its strength in the operating system marketplace to dominate in the application suite space as well. On the other hand, open standards can make it easier to port software into different environments.

Another issue with the runtime side of the software we are building is that different hosts have different hardware capabilities (number of cores, presence of GPUs) or security restrictions (whether files can be opened or network traffic can be sent or received). Software often adapts to what is available by using features-testing approaches to determine what resources an application can take advantage of, but this often complicates the business functionality. We simply cannot afford the time and money needed to rewrite software for multiple platforms constantly. Instead, we need better strategies for reuse. We also need this flexibility without the complexity of modifying the code to support the platform on which it will run. Making the code different for different host environments increases its complexity and complicates testing and deployment strategies.

After several decades, the value proposition of open source software is clear. We gravitate toward valuable, reusable components written by other developers as a means of satisficing our own needs.5 However, not all available code is trustworthy, and we open ourselves up to software supply chain attacks when we execute untrusted bits we have downloaded from the internet. We become vulnerable to the risks, business impacts, and personal costs of insecure software systems through phishing attacks, data breaches, malware, and ransomware.

Until now, JavaScript has been the only way to solve some of these problems. When it is run in a sandboxed environment, it gives us some manner of security. It is ubiquitous and portable. The engines have gotten faster. The ecosystem has exploded into an avalanche of productivity. Once you leave the confines of browser-based protections, however, we still have security concerns. There is a difference between JavaScript code running as a client and JavaScript running on the server. The single-threaded design complicates long-running or highly concurrent tasks. Due to its origins as a dynamic language, there are several classes of optimizations that are available to other programming languages that are, and will remain, unavailable as options to even the fastest and most modern JavaScript runtimes.

Additionally, it is too easy to add JavaScript dependencies and not realize how much baggage and risk are being pulled in transitively. Developers who do not take the time to consider these decisions carefully end up encumbering every aspect of upstream software testing, deployment, and use. Each of these scripts has to be loaded and validated once it is transferred over the network. This slows down the time to use and makes everything feel sluggish. When a dependent package is modified or removed, it has the potential to disrupt enormous amounts of deployed software.6

There is a perception among casual observers that WebAssembly is an assault on JavaScript, but that simply is not the case. Sure, you will be able to avoid JavaScript if you want to, but it is mostly about giving you options to solve problems in the language of your choice without requiring a separate runtime or having to care what language another piece of software is written in. It is already possible to use a WebAssembly module without knowing how it was built. This is going to increase the lifetime of business value we get out of our software and yet simultaneously allow us to innovate in adopting new languages without impacting everything else.

We have experienced several tools, languages, platforms, and frameworks over the course of the past several decades that have attempted to solve these problems, but WebAssembly represents one of the first times we are getting it right. Its designers are not attempting to overspecify anything. They are learning from the past, embracing the web, and applying problem-space thinking to what is ultimately a hard and multidimensional problem. Let’s look at the formative influences on this exciting new technology before we dive into it further.

History of the Web

There is a running joke in the WebAssembly community that WebAssembly is “neither web nor assembly.”7 While this is true on some levels, the name is suggestive enough of what it provides. It is a target platform with a series of instructions that are vaguely assemblyesque.8 The fact that WebAssembly modules are frequently going to be delivered over the web as another type of URL-addressable resource justifies the inclusion of the word Web in the name.

One of the main distinctions between “conventional software development” and “web development” is that there is effectively no installation required with the latter once you have a browser available. This is a game-changer in terms of costs to deliver and the ability to quickly turn new releases around in the face of bugs and feature requests. When couched in other cross-platform technology ecosystems such as the internet and the web, it makes supporting multiple hardware and software environments much easier too.

Sir Tim Berners-Lee, the inventor of the World Wide Web, worked at the European Organization for Nuclear Research (CERN), where he submitted a proposal for interlinking documents, images, and data in the pursuance of CERN’s larger research goals.9 Even though the impact is clear in hindsight, he had to advertise his ideas internally several times before he was asked to act on them.10 As an organization, CERN was represented by dozens of research facilities around the world, which sent scientists with their own computers, applications, and data. There was no real capacity to force everyone to use the same operating systems or platforms, so he recognized the need for a technical solution to solve the problem.

Prior to the web, there were services such as Archie,11 Gopher,12 and WAIS,13 but he imagined a more user-friendly platform that was ultimately engendered as an application-level innovation at the top of the internet’s layered architecture. He also took ideas from the Standard Generalized Markup Language (SGML) and made them the basis of the HyperText Markup Language (HTML).14

The result of these designs quickly became the major mechanism for delivering information, documentation, and eventually application functionality to the world. It did so without requiring the various stakeholders to agree on specific technologies or platforms by defining the exchange of standards, and included both how requests were made and what was returned in response. Any piece of software that understood the standards could communicate with any other piece of software that did as well. This gives us freedom of choice and the ability to evolve either side independent of the other.

Origins of JavaScript

The web’s interaction model is called Hypertext Transfer Protocol (HTTP). It is based upon a constrained set of verbs for exchanging text-based messages. While it was a simple and effective model that was easy to implement, it was quickly seen to be inadequate for the task of interactive, modern applications because of inherent latencies in returning to the server constantly. The idea of being able to send code down to the browser has always been compelling. If it ran on the user’s side of the interaction, not every activity would require a return to the server. This would make web applications dramatically more interactive, responsive, and enjoyable to use. How to achieve this was not entirely clear, though. Which programming language would make the most sense? How would we balance expressive power with shallow learning curves so more individuals could participate in the development process? Which languages performed better than others, and how would we protect sensitive resources on the client side from malicious software?

Most of the innovation in the browser space was originally driven by Netscape Communications Corp. Believe it or not, Netscape Navigator was originally a paid piece of software, but the company’s larger interest was in selling server-side software.15 By extending what was possible on the client, it could create and sell more powerful and lucrative server functionality.

At the time, Java was emerging from its beginnings as an embedded language for consumer devices, but it did not yet have much of a track record of success. It was a compelling idea as a simplified version of C++ that ran on a virtual platform and was therefore inherently cross-platform. As an environment designed to run software downloaded over the network, it had security built in via language design, sandboxed containers, and fine-grained permission models.

Porting applications between various operating systems was tricky business, and the prospect of not needing to do so created a frenzy around what the future of software development would be. Sun Microsystems found itself in the enviable position of having a solution to a perfect storm of problems and opportunities. Given this potential, discussions were underway to bring Java to the browser, but it was not clear what that deal would look like or when it would land.

As an object-oriented programming (OOP) language, Java contained sophisticated language features such as threads and inheritance. There was concern at Netscape that this might prove too difficult for nonprofessional software developers to master, so the company hired Brendan Eich to create a “Scheme16 for the browser,” imagining an easier, lightweight scripting language.17 Brendan had the freedom to make some decisions about what he wanted to include in the language, but he was also under pressure to get it done as quickly as possible. A language for interactive applications was seen as a crucial step forward for this emerging platform, and everyone wanted it yesterday. As Sebastián Peyrott notes in the blog post, “A Brief History of JavaScript,” what emerged was “a premature lovechild of Scheme and Self, with Java looks.”18

Initially JavaScript in the browser was limited to simple interactions such as dynamic menus, pop-up dialogs, and responding to button clicks. These were significant advances over roundtrips to the server for every action, but they were still toys compared to what was possible on desktop and workstation machines at the time.

The company I worked for during the early days of the web created the first whole-earth visualization environment, involving terabytes of terrain information, hyperspectral imagery, and pulling video frames from drone videos.19 This required Silicon Graphics workstations initially, of course, but it was able to run on PCs with consumer-grade graphics processing units (GPUs) within a couple of years. Nothing like that was remotely possible on the web back then, although, thanks to WebAssembly, that is no longer true.20

There was simply no confusing real software development with web development. As we have noted, though, one of the nice things about the separation of concerns between the client and the server was that the client could evolve independently of the server. While Java and the Java Enterprise model came to dominate the backend, JavaScript evolved in the browser and eventually became the dominant force that it is.

Evolution of the Web Platform

As Java applets and JavaScript became available in the Netscape browser, developers began to experiment with dynamic pages, animations, and more sophisticated user interface components. For years these were still just toy applications, but the vision had appeal and it was not difficult to imagine where it could eventually lead.

Microsoft felt the need to keep up but was not overly interested in directly supporting its competitors’ technologies. It (rightly) felt that this web development might eventually upend its operating system dominance. When Microsoft released Internet Explorer with scripting support, the company called it JScript to avoid legal issues and reverse-engineered Netscape’s interpreter. Microsoft’s version supported interaction with Windows-based Component Object Model (COM) elements and had other twists that made it easy to write incompatible scripts between the browsers. Its initial support of the efforts to standardize JavaScript as ECMAScript waned for a while and eventually the Browser Wars began.21 This was a frustrating time for developers and ultimately involved anticompetitive lawsuits against Microsoft by the US government.

As Netscape’s fortunes waned, Internet Explorer began to dominate the browser space and cross-platform innovation subsided for a while even as JavaScript went through the standardization process. Java applets became widely used in some circles, but they ran in a sandboxed environment, so it was trickier to use them as the basis for driving dynamic web page activity. You could certainly use Sun’s graphics and user interface APIs to do productive and fun things, but they ran in a separate memory space than the HTML Document Object Model (DOM).22 They were incompatible and had different programming and event models. User interfaces did not look the same between the sandboxed elements and the web elements. It was overall a wholly unsuitable development experience.

Other nonportable technologies such as ActiveX became popular in the Microsoft web development space. Macromedia’s Flash became Adobe’s Flash and had a short but active period of popularity for about a decade. The problems remained with all of these secondary options, however. The memory spaces were walled off from each other and the security models were less robust than anyone had hoped. The engines were new and under constant development, so bugs were common. ActiveX provided code-signing protections but no sandboxing, so rather terrifying attacks became possible if certificates could be forged.

Firefox emerged from Mozilla as a viable competitor from the ashes of Netscape. It and Google’s Chrome eventually became suitable alternatives to Internet Explorer. Each camp had its adherents, but there was a growing interest in solving the incompatibilities between them. The introduction of choice in the browser space forced each of the vendors to work harder and do better to outshine each other as a means of achieving technical dominance and attracting market share.

As a result, JavaScript engines got significantly faster. Even though HTML 4 was still “quirky” and painful to use across browsers and platforms, it was starting to be possible to isolate those differences. The combination of these developments and a desire to work within the structures of the standards-based environments encouraged Jesse James Garrett to imagine a different approach to web development. He introduced the term Ajax, which stood for the combination of a set of standards: asynchronous JavaScript and XML. The idea was to let data from backend systems flow into the frontend applications, which would respond dynamically to the new inputs. By working at the level of manipulating the DOM rather than having a separate, sandboxed user interface space, browsers could become universal application consumers in web-based client-server architectures.

The long-suffering HTML 5 standardization process had begun during this period as well in an attempt to improve consistency across browsers, introduce new input elements and metadata models, and provide hardware-accelerated 2D graphics and video elements, among other features. The convergence of the Ajax style, the standardization and maturation of ECMAScript as a language, easier cross-browser support, and an increasingly feature-rich web-based environment caused an explosion of activity and innovation. We have seen innumerable JavaScript-based application frameworks come and go, but there was a steady forward momentum in terms of what was possible. As developers pushed the envelope, the browser vendors improved their engines to allow the envelope to be pushed further still. It was a virtuous cycle that ushered in new visions of the potential for safe, portable, zero-installation software systems.

As other obstacles and limitations were removed, this strange little language at the heart of it all became an increasingly high-inertia drag on forward motion. The engines were becoming world-class development environments with better tools for debugging and performance analysis. New programming paradigms such as the Promise-based style allowed better modularized and asynchronous-friendly application code to achieve powerful results in JavaScript’s notoriously single-threaded environment.23 But the language itself was incapable of the kinds of optimizations that were possible in other languages such as C or C++. There were simply limits on what was going to be possible from a language-performance perspective.

The web platform standards continued to advance with the development and adoption of technologies such as WebGL24 and WebRTC.25 Unfortunately, JavaScript’s performance limitations made it ill suited to extend the browsers with features involving low-level networking, multithreaded code, and graphics and streaming video codecs.

The platform’s evolution required the painful slog of the W3C member organizations to decide what was important to design and build and then roll it out in the various browser implementations. As people became ever more interested in using the web as a platform for heavier-weight, interactive applications, this process was seen as increasingly untenable. Everything either had to be written (or rewritten) in JavaScript or the browsers had to standardize the behavior and interfaces, which could mean it would take years to realize new advancements.

It was for these and other reasons that Google began to consider an alternative approach to safe, fast, and portable client-side web development.

Native Client (NaCl)

In 2011, Google released a new open source project called Native Client (NaCl). The idea was to provide near-native speed execution of code in the browser while running in a limited privilege sandbox for safety reasons. You can think of it as a bit like ActiveX with a real security model behind it. The technology was a good fit for some of Google’s larger goals such as supporting ChromeOS and moving things away from desktop applications and into web applications. It was not initially meant to extend the capabilities of the open web for everyone.

The use cases were mainly to support browser-based delivery of computationally intensive software such as:

  • Games

  • Audio and video editing systems

  • Scientific computing and CAD systems

  • Simulations

The initial focus was on C and C++ as source languages, but because it was based upon the LLVM compiler toolchain,26 it would be possible to support additional languages that could generate the LLVM Intermediate Representation (IR).27 This will be a recurring theme in our transition to WebAssembly, as you will see.

There were two forms of distributable code here. The first was the eponymous NaCl, which resulted in “nexe” modules that would target a specific hardware architecture (e.g., ARM or x86-64) and could only be distributed through the Google Play store. The other was a portable form called PNaCl28 that would be expressed in LLVM’s Bitcode format, making it target independent. These were called “pexe” modules and would need to be transformed into a native architecture in the client’s host environment.

The technology was successful in the sense that the performance demonstrated in the browser was only minimally off of native execution speeds. By using software fault isolation (SFI) techniques, it was possible to download high-performance, secure code from the web and run it in browsers. Several popular games such as Quake and Doom were compiled to this format to show what was ultimately possible. The problem was that the NaCl binaries would need to be generated and maintained for each target platform and would only run in Chrome. They also ran in an out-of-process space, so they could not directly interact with other Web APIs or JavaScript code.

While running in limited-privilege sandboxes was achievable, it did require static validation of the binary files to ensure that they did not attempt to invoke operating system services directly. The generated code had to follow certain address boundary-alignment patterns to make sure it did not violate allocated memory spaces.

As indicated above, the PNaCl modules were more portable. The LLVM infrastructure could generate either the NaCl-native code or the portable Bitcode without modifying the original source. This was a nice outcome, but there is a difference between code portability and application portability. Applications require the APIs that they rely upon to be available in order to work. Google provided an application binary interface (ABI) called the Pepper APIs29 for low-level services such as 3D graphics libraries, audio playback, file access (emulated over IndexedDB or LocalStorage), and more. While PNaCl modules could run in Chrome on different platforms because of LLVM, they could only run in browsers that provided suitable implementations of the Pepper APIs. While Mozilla had originally expressed interest in doing so, they eventually decided they wanted to try a different approach that came to be known as asm.js. NaCl deserves a tremendous amount of credit for moving the industry in this direction, but it was ultimately too fiddly and too Chrome-specific to carry the open web forward. Mozilla’s attempt was more successful on that front even if it did not provide the same level of performance that the native client approach did.

asm.js

The asm.js project was at least partially motivated by an attempt to bring a better gaming story to the web. This soon expanded to include a desire to allow arbitrary applications to be delivered securely to browser sandboxes without having to substantively modify the existing code.

As we have previously discussed, the browser ecosystem was already advancing to make 2D and 3D graphics, audio handling, hardware-accelerated video, and more available in standards-based, cross-platform ways. The idea was that operating within that environment would allow applications to use any of those features that were defined to be invoked from JavaScript. The JavaScript engines were efficient and had robust sandboxed environments that had undergone significant security audits, so no one felt like starting from scratch there. The real issue remained the inability to optimize JavaScript ahead-of-time (AOT) so runtime performance could be improved even further.

Because of its dynamic nature and lack of proper integer support, there were several performance obstacles that could not meaningfully be managed until the code was loaded into the browser. Once that happened, just-in-time (JIT) optimizing compilers were able to speed things up nicely, but there were still inherent issues like slow bounds-checked array references. While JavaScript in its entirety could not be optimized ahead-of-time, a subset of it could be.

The exact details of what that means are not super relevant to our historical narrative, but the end result is. asm.js also used the LLVM-based clang30 frontend parser via the Emscripten toolchain.31 Compiled C and C++ code is very optimizable ahead-of-time, so the generated instructions can be made very fast through existing optimization passes. LLVM represents a clean, modular architecture, so pieces of it can be replaced, including the backend generation of machine code. In essence, the Emscripten team could reuse the first two stages (parsing and optimization) and then emit this subset of JavaScript as a custom backend. Because the output was all “just JavaScript,” it would be much more portable than the NaCl/PNaCl approach. The trade-off, unfortunately, was in performance. It represented a significant improvement over straight JavaScript but was not nearly as performant as Google’s approach. It was good enough to amaze developers, though. Beyond the modest performance improvements, however, the mere fact that you could deploy existing C and C++ applications into a browser with reasonable performance and virtually no code changes was compelling. While there were extremely compelling demos involving the Unity engine,32 let’s look at a simple example. “Hello, World!” seems like a good place to start:

#include <stdio.h>
int main() {
  printf("Hello, world!\n");
  return 0;
}

Notice there is nothing unusual about this version of the classic program. If you stored it in a file called hello.c, the Emscripten toolchain would allow you to emit a file called a.out.js, which can be run directly in Node.js33 or, via some scaffolding, in a browser:

brian@tweezer ~/s/w/ch01> emcc hello.c
brian@tweezer ~/s/w/ch01> node a.out.js
Hello, world!

Pretty cool, no?

There’s only one problem:

brian@tweezer ~/s/w/ch01> ls -lah a.out.js
-rw-r--r--  1 brian  staff   119K Aug 17 19:08 a.out.js

At 119 kilobytes, that is an awfully large “Hello, World” program! A quick look at the native executable might give you a sense of what is going on:

brian@tweezer ~/s/w/ch01> clang hello.c
brian@tweezer ~/s/w/ch01> ls -lah a.out
-rwxr-xr-x  1 brian  staff    48K Aug 17 19:11 a.out

Why is our supposedly optimized JavaScript program close to three times bigger than the native version? It is not just because as a text-based file, JavaScript is more verbose. Look at the program again:

#include <stdio.h> 1
int main() {
  printf("Hello, world!\n"); 2
  return 0;
}
1

The header identifies the source for standard IO-related function definitions.

2

The reference to the printf() function will be satisfied by a dynamic library loaded at runtime.

If we look at the symbols defined in the compiled executable using nm, we will see that the definition of the printf() function is not contained in the binary.34 It is marked “U” for “undefined”:

brian@tweezer ~/s/w/ch01> nm -a a.out
0000000100002008 d __dyld_private
0000000100000000 T __mh_execute_header
0000000100000f50 T _main
                 U _printf
                 U dyld_stub_binder

When Clang generated the executable, it left a placeholder reference to the function that it expects to be provided by the operating system. There is no standard library available in this way for a browser, at least not in the dynamically loadable sense, so the library function and anything it needs have to be provided. Additionally, this version cannot talk directly to the console in a browser, so it will need to be given hooks to call into a function such as the browser’s console.log() functionality. In order to work in the browser, the functionality has to be shipped with the application, which is why it ends up being so big.

This highlights nicely the difference between portable code and portable applications, another common theme in this book. For now, we can marvel that it works at all, but there is a reason this book is not called asm.js: The Definitive Guide. asm.js was a remarkable stepping-stone that demonstrated it was possible to generate reasonably performant sandboxed JavaScript code from various optimizable languages. The JavaScript itself could be optimized further as well in ways that the superset could not. By being able to generate this subset through LLVM-based toolchains and a custom backend, the level of effort was much smaller than it might otherwise have been.

asm.js represents a nice fallback position for browsers that do not support the WebAssembly standards, but it is now time to set the stage for the subject of the book.

Rise of WebAssembly

With NaCl, we found a solution that provided sandboxing and performance. With PNaCl, we found platform portability but not browser portability. With asm.js, we found browser portability and sandboxing, but not the same level of performance. We also were limited to dealing with JavaScript, which meant we could not extend the platform with new features (e.g., efficient 64-bit integers) without first changing the language itself. Given that this was governed by an international standards organization, this was unlikely to be an approach with quick turnarounds.

Additionally, JavaScript has certain issues with how browsers loaded and validated it from the web. The browser has to wait until it finishes downloading all of the referenced files before it starts to validate and optimize them (while further optimizations will require us to wait until the application is already running). Given what we have already said about how developers encumber their applications with ridiculously large amounts of transitive dependencies, the network transfer and load-time performance of JavaScript is another bottleneck to overcome beyond the established run-time issues.

After seeing what was possible with these partial solutions, there arose a strong appetite for high-performance, sandboxed, portable code. Various stakeholders in the browser, web standard, and JavaScript environments felt a need for a solution that worked within the confines of the existing ecosystem. There had been a tremendous amount of work done to get the browsers as far as they had gone. It was entirely possible to create dynamic, attractive, and interactive applications across operating system platforms and browser implementations. With just a bit more effort, it seemed possible to merge these visions together into a unifying, standards-based approach.

It was under these circumstances in 2015 that none other than Brendan Eich, the creator of JavaScript, announced that work had begun on WebAssembly.35 He highlighted a few specific reasons for the effort and called it a “binary syntax for low-level safe code, initially co-expressive with asm.js, but in the long run able to diverge from JS’s semantics, in order to best serve as common object-level format for multiple source-level programming languages.”

He continued: “Examples of possible longer-term divergence: zero-cost exceptions, dynamic linking, call/cc. Yes, we are aiming to develop the Web’s polyglot-programming-language object-file format.”

As to why these various parties were interested in this, he offered this justification: “asm.js is great, but once engines optimize for it, the parser becomes the hot spot—very hot on mobile devices. Transport compression is required and saves bandwidth, but decompression before parsing hurts.”

And finally, perhaps the most surprising part of the announcement was who was to be involved:

A W3C Community Group, the WebAssembly CG, open to all. As you can see from the GitHub logs, WebAssembly has so far been a joint effort among Google, Microsoft, Mozilla, and a few other folks. I’m sorry the work was done via a private GitHub account at first, but that was a temporary measure to help the several big companies reach consensus and buy into the long-term cooperative game that must be played to pull this off.

In short order, other companies such as Apple, Adobe, AutoCAD, Unity, and Figma got behind the effort. This vision that had started decades before and had involved no end of conflict and self-interest was transforming into a unified initiative to finally bring us a safe, fast, portable, and web-compatible runtime environment.

There was no end to the potential confounding complexities involved in shepherding this platform into existence. It was not entirely clear exactly what should be specified up front. Not every language supports threads natively. Not every language uses exceptions. C/C++ and Rust were examples of languages that had runtimes that did not require garbage collection. The devil is always in the details, but the will to collaborate was there. And, as they say, where there is a will, there is a way.

Over the next year or so, the CG became a W3C Working Group (WG), which was tasked with defining actual standards. They made a series of decisions to define a Minimum Viable Product (MVP) WebAssembly platform that would be supported by all major browser vendors. Additionally, the Node.js community was excited as this could provide a solution to the drudgery of managing native libraries for the portions of Node applications that needed to be written in a lower-level language. Rather than having dependencies on Windows, Linux, and macOS libraries, a Node.js application could have a WebAssembly library that could be loaded into the V8 environment and converted to native assembly code on the fly. Suddenly, WebAssembly seemed poised to move beyond the goals of deploying code in browsers, but let’s not get ahead of ourselves. We have the rest of this book to tell you that part of the story.

1 Andreas Haas et al., “Bringing the Web Up to Speed with WebAssembly,” presented at the 38th ACM SIGPLAN Conference on Programming Language Design and Implementation, June 2017, http://dx.doi.org/10.1145/3062341.3062363.

2 For many years, OpenGL was the defining standard for portable 3D graphics applications. These days it is being supplanted by more modern APIs such as Vulkan and Metal, but you can learn more about the standards on the OpenGL website.

3 The Portable Operating System Interface (POSIX) is a collection of IEEE standards for defining common application functionality so that it works across multiple operating systems.

4 Win32 is one part of a larger collection of APIs that provide developers with access to common functionality available from the Windows operating systems.

5 This technique allows a decision-maker to establish minimum criteria for deciding when their needs are being met. The goal of satisficing is not to find a perfect solution, but one that is acceptable given the situation at hand.

6 The Wikipedia page on npm highlights several cases where broken dependencies have had large impacts.

7 Best anyone can tell it was J.F. Bastien who first said it, but even he is not sure.

8 Assembly language is a low-level programming language usually associated with a particular machine’s processor architecture and instruction set.

9 The name CERN comes from the French Conseil Européen pour la Recherche Nucléaire. Its many exciting projects are detailed on its homepage.

10 On his own time!

11 Archie was an early search engine for helping people find files on FTP servers.

12 Gopher was an exciting precursor to the HTTP-based web we have become dependent upon.

13 Wide Area Information Server (WAIS) was another early system for searching for and requesting text information in distributed systems.

14 SGML is an ISO standard for defining structured, declarative documents that served as the basis of HTML, DocBook, and LinuxDoc.

15 I bought a license for Netscape 1.0 Silicon Graphics IRIX at the time. I still have the CD floating around someplace for…historical reasons.

16 Scheme is a fairly lightweight version of Lisp.

17 There is a nice summary of the early history of JavaScript online.

18 Self is an object-oriented programming language that influenced JavaScript’s prototype-based inheritance.

19 Autometric had a wild background involving Paramount Pictures, the Trinitron tube, and helping NASA decide where to land on the moon! It has since been purchased by Boeing.

20 Google Earth now runs in the browser.

21 While browser vendors tend to work together more closely on standards these days, for a while they competed fiercely. This time period is discussed on Wikipedia.

22 The DOM is the tree structure of a web page or application that is rendered by the browser. It is often sent in a declarative textual form from server to client as HTML, but JavaScript is able to manipulate it in the browser.

23 Promises (or futures) allow developers relatively simple programming models while still providing concurrent-enabled applications.

24 WebGL brought a similar model of 3D graphics from the OpenGL world to the web.

25 WebRTC provides mechanisms for establishing permissioned access to cameras and microphones as well as encrypted peer-to-peer connections.

26 LLVM does not stand for anything, but it is an extremely influential toolchain you should know more about. We will mention it frequently in this book.

27 Normally, software is compiled to a binary, executable form. The IR allows it to exist in a parsed, structured form for the purposes of optimization, among other reasons.

28 Pronounced “pinnacle.”

29 Because, NaCl…get it?

30 Clang is an LLVM compiler toolsuite for C, C++, and Objective-C.

31 We will learn more about Emscripten over the course of the book, but if you are curious.

32 Getting a zero-installation gaming experience in the browser is driving much of this innovation. You can see an example of the Unity engine using WebGL in the browser.

33 Node.js is an extremely popular server-side JavaScript environment that we will discuss more in Chapter 8.

34 nm is a Unix command to display the symbol table of an executable file.

35 Brendan Eich, “From ASM.JS to WebAssembly,” June 17, 2015, https://brendaneich.com/2015/06/from-asm-js-to-webassembly.

Get WebAssembly: The Definitive Guide now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.