If you missed the previous chapters, you can find them here:
The way we build web apps is on the brink of revolution — this is still the early days but the way we think about web applications is going to change.
First, let’s see what WebAssembly does
WebAssembly (a.k.a. wasm) is an efficient, low-level bytecode for the web.
The result is a web app that’s very fast to load and execute.
.js files which are textual.
WebAssembly is faster to load inside the browser because only the already-compiled wasm files have to be transported over the internet. And wasm is a low-level assembly-like language with a very compact binary format.
Today Wasm runs just 20% slower than native code execution. This is by, all means, an astonishing result. It’s a format that’s compiled into a sandbox environment and runs within a whole lot of constraints to make sure it has no security vulnerabilities or is very hardened against them. The slowdown is minimal compared to truly native code. What’s more, it will be even faster in the future.
Better yet, it’s browser-agnostic — all major engines added support for WebAessembly and offer similar execution times now.
Let’s take a look at what happens in V8 as a quick overview:
V8 Approach: lazy compilation
Now, let’s take a look at what the V8 pipeline does at the next stage:
V8 Pipeline Design
It solves the problem but the gotcha here is that the process of analyzing the code and deciding what to optimize also consumes CPU. This, in turn, means higher battery consumption, especially on mobile devices.
Well, wasm doesn’t need all that — it gets plugged into the workflow like this:
V8 Pipeline Design + WASM
The wasm has already gone through optimization during the compilation phase. On top, parsing is not needed either. You have an optimized binary that can directly hook into the backend which can generate machine code. All the optimizations have been done by the compiler at the front end.
This makes the execution of wasm a lot more efficient since quite a few of the steps in the process can simply be skipped.
WebAssembly trusted and untrusted state
The memory of a C++ program, for example, compiled into WebAssembly, is a contiguous block of memory with no “holes” in it. One of the features of wasm that helps boost security is the concept of the execution stack being separate from the linear memory. In a C++ program, you have a heap, you allocate from the bottom of the heap, and grow the stack from the top of the heap. It’s possible to take a pointer and then look up in the stack memory in order to play with variables you’re not supposed to touch.
This is a pitfall that a lot of malware exploit.
WebAssembly employs a completely different model. The execution stack is separated from the WebAssembly program itself, so there is no way you can modify inside it and change things like variables. Also, the functions use integer offsets rather than pointers. Functions point into an indirection function table. And then those direct, calculated numbers jump in the function inside the module. It’s been built this way so that you can load multiple wasm modules side by side, offset all the indexes and it all works well.
WebAssembly’s case is a bit different. It supports languages that manage memory manually. You can ship your own GC with your wasm modules, but it’s a complicated task.
Currently, WebAssembly is designed around the C++ and RUST use cases. Since wasm is very low-level, it makes sense that programming languages that are just one step above assembly language would be easy to compile to it. C can use normal malloc, C++ might use smart pointers, Rust employs a totally different paradigm (a whole different topic). These languages don’t use GCs, so they don’t need all the complicated runtime stuff to keep track memory. WebAssembly is a natural fit for them.
In the future, however, WebAssembly will support languages that don’t come with a GC.
Platform API access
For example, if you want to
WebAssembly does not currently support source maps because there is no specification but it will, eventually (probably quite soon).
When you set a breakpoint in your C++ code, you’ll see the C++ code instead of WebAssembly. At least, that’s the goal.
WebAssembly doesn’t currently support multithreading. However, this is probably the next thing to come. Wasm is going to get closer to native threads (e.g. C++ style threads). Having “real” threads is going to create a lot of new opportunities in the browser. And of course, it’s going to open the door to more possibilities for abuse.
WebAssembly has the same portability goal as the one Java attempted to achieve in the early days with the Applets.
In the first versions of WebAssembly, the main focus is on heavy CPU-bound computations (dealing with math for example). The most mainstream use that comes to mind is games — there are tons of pixel manipulations there. You can write your app in C++/Rust using OpenGL bindings that you’re used to, and compile it to wasm. And it will run in the browser.
Take a look at this (Run it in Firefox) — http://s3.amazonaws.com/mozilla-games/tmp/2017-02-21-SunTemple/SunTemple.html. That’s running the Unreal engine.
Another case where it could make sense to use WebAssembly (performance-wise) is implementing some library that is doing very CPU-intensive work. For example, some image manipulation.
As mentioned earlier, wasm can reduce quite a bit the battery consumption on mobile devices (depending on the engine), since most of the processing steps have been completed ahead of time during compilation.
In the future, you’ll be able to consume WASM binaries even if you’re not actually writing code that compiles to it. You can find projects in NPM that are starting to use this approach.