In identifying and describing the core elements, we shared some rules of thumb for building SessionStack, a lightweight but robust and high-performance JavaScript application to help users view and reproduce flaws in their Web applications in real time. This time we’ll take a look at how WebAssembly works and compare it to JavaScript in several areas: load time, execution speed, garbage collection, memory usage, platform API access, debugging, multithreading, and portability.

First, let’s look at the capabilities of WebAssembly.

WebAssembly (also known as WASM) is an efficient, low-level programming language. It allows us to write programs in languages other than JavaScript (such as C, C ++, Rust, or others) and then compile them into WebAssembly, resulting in a Web application that loads and executes very quickly.

Loading time

In order to load JavaScript, the browser must load all.js text files. WebAssembly loads faster in a browser because only compiled WASM files are transferred over the Internet. And WASM is a low-level assembly language in a very compact binary format, with smaller files.

perform

Wasm currently executes 20% slower than native code. This is a surprising result, but it is a format that is compiled into a sandbox environment and runs under many constraints to ensure that it does not have security holes or is difficult to exploit. The actual speed drop is small compared to real native code. But it will be faster in the future.

Even better, it’s browser-neutral – all the major engines have added support for WebAssembly and now offer similar execution times. Let’s take a quick look at what happened in V8:

V8 Approach: lazy compilation

On the left, we have some JavaScript source code that contains JavaScript functions. It first needs to be parsed to convert all strings into tags and generate an abstract syntax tree (AST). The AST is an in-memory representation of the JavaScript program logic. Once this representation is generated, V8 goes directly to machine code. In general, you just need to traverse the tree, generate the machine code, and generate the compiled function. As you can see from this process, this stage does not have the advantage of compilation speed. Now, let’s look at the next phase of the V8 pipeline:

V8 pipeline design

This time we have TurboFan, one of V8’s optimized compilers. While your JavaScript application is running, a lot of code runs in V8. TurboFan monitors slowly-running content for bottlenecks and hot spots to optimize them. It pushes them to the back end, which is an optimized JIT that optimizes code that is very CPU intensive. While it solves the above problems, what’s new is that the process of analyzing the code and deciding what to optimize also consumes CPU. That, in turn, means higher battery consumption, especially on mobile devices. However, wASM is different in that it is inserted into the workflow as follows:

The memory model



WebAssembly trusted and untrusted States For example, the memory of a C ++ program compiled into WebAssembly is a contiguity block of memory with no “holes” in it. One of the features of WASM that helps improve security is the concept of implementing stack separation from linear memory. In a C ++ program, you have a heap of memory, you allocate from the bottom of the heap, and then increase the heap size from the top. This creates a vulnerability that many malware exploit: using a pointer to change variables by looking up data in stack memory that you’re not supposed to have access to.

WebAssembly takes a completely different model. The execution stack is separate from the WebAssembly program itself, so you can’t modify and change things like variables in it. Furthermore, these functions use integer offsets instead of Pointers. The function points to a table of indirect functions. These directly computed numbers then jump to functions inside the module. It is built in such a way that you can load multiple WASM modules at the same time, forming multiple indexed lists, and all is well. For more information about memory models and management in JavaScript, check out the very detailed post on this topic.

The garbage collection

You already know that JavaScript memory management is handled using the garbage collector.

WebAssembly is a little different. It supports languages that manage memory manually. You can customize the garbage collection module on WASM, but this is more complicated.

Currently, WebAssembly is designed around C ++ and RUST use cases. Because WASM is very low-level, only the programming language above assembly language is easy to compile. C can use plain malloc, C ++ can use smart Pointers, and Rust uses a completely different schema (a completely different topic). These languages don’t use GC, so they don’t need all the complicated runtime content to keep track of memory. WebAssembly is a match made in heaven for them.

Also, these languages are not 100% designed to call complex JavaScript things like DOM. It doesn’t make sense to write an entire HTML application in C ++, because C ++ isn’t designed for it. In most cases, when engineers write C ++ or Rust, their target is WebGL or a highly optimized library (heavy math, for example).

In the future, however, WebAssembly will support languages without GC.

Platform API access

Depending on the runtime that executes JavaScript, platform-specific apis can be accessed through your JavaScript application. For example, if you are running JavaScript in a browser, you have a set of Web APIs that Web applications can call to control Web browser/device functionality and access DOM, CSSOM, WebGL, IndexedDB, Web Audio API, and so on.

However, the WebAssembly module does not have access to any platform API. Everything is called by JavaScript. If you want to access some platform-specific API in a WebAssembly module, you must call it through JavaScript.

For example, if you want console.log, you have to call it through JavaScript, not your C ++ code. The cost of these JavaScript calls has been reduced.

This is not always the case. The specification will provide WASM for platform apis in the future, and you will be able to distribute your applications without JavaScript.

Source maps

When you strip down JavaScript source code, you need a way to debug it properly. This requires Source Maps. Basically, Source Maps is a way to map composite/shrink files back to an unestablished state. When you build for production, while shrinking and combining your JavaScript files, you generate a source map that contains information about the original files. When you query for a row and column number in the generated JavaScript, you can perform the lookup in the source map that returns the original location.

WebAssembly does not currently support Source Maps because there is no specification, but it will eventually (probably soon). When you set breakpoints in C ++ code, you will see C ++ code instead of WebAssembly.

multithreading

JavaScript runs on a single thread. There are many ways to take advantage of Event Loops and take advantage of asynchronous programming.

JavaScript also uses Web Workers, but they have a very specific use case – basically, any CPU intensive computation that might block the main UI thread can go into the Web Worker to improve performance. However, Web Workers cannot access the DOM.

WebAssembly does not currently support multithreading. But that could be in the future. Wasm will be closer to native threads (such as C ++ style threads). Having “real” threads will create many new opportunities in browsers. This, of course, opens the door to more abuse.

portability

Today, JavaScript can run almost anywhere, from browsers to server-side and even embedded systems.

WebAssembly is designed to be secure and portable. Just like JavaScript. It will run in every environment that supports the host (for example, every browser). Just like Java Applets, WebAssembly has the same vision of portability.

What are the best scenarios for using WebAssembly in JavaScript?

In the first version of WebAssembly, the focus was on CPU intensive computing (such as processing mathematics). The most mainstream use that comes to mind is games — where there’s a lot of pixel manipulation. You can write your application in C ++ / Rust and compile it into WASM using your accustomed OpenGL. It runs in the browser. Take a look at this (running in Firefox) – http://s3.amazonaws.com/mozilla-games/tmp/2017-02-21-SunTemple/SunTemple.html. This is Unreal Engine. Another situation where it might make sense to use WebAssembly (performance-wise) is to implement some libraries, which is cpu-intensive. For example, some image processing.

As mentioned earlier, because most of the processing steps are done ahead of time at compile time, WASM can reduce battery consumption on mobile devices (depending on the engine).

In the future, you can use WASM binaries even if you don’t actually write compilation code. You can find the project that started using this approach in NPM.

For DOM manipulation and heavy platform API usage, it really makes sense to use JavaScript because it doesn’t add any extra overhead and has a native-provided API.

In SessionStack, we continuously enhance JavaScript performance to write highly optimized and efficient code. Our solutions need to deliver super fast performance because we can’t hinder the performance of our customer applications. Once you integrate SessionStack into a production Web application or Web site, it starts logging everything: all DOM changes, user interactions, JavaScript exceptions, stack traces, failed network requests, and debug data. All of this takes place in your production environment without affecting any UX and performance of the product. We need to optimize our code a lot and make it as asynchronous as possible.

Not just the library file, when we replay the user’s reply in the SessionStack, we render all the events that happened in the user’s browser, and we have to refactor the entire state to allow you to jump back and forth in the session timeline. For lack of a better alternative, we made extensive use of the asynchronous opportunities provided by JavaScript to do this.

With WebAssembly, we’ll be able to convert some of the most onerous processing and rendering into a more job-friendly language and leave data collection and DOM manipulation to JavaScript.

If you want to try SessionStack, you can get started for free. There is a free plan) that offers 1,000 sessions per month.



Reference:

  • https://www.youtube.com/watch?v=6v4E6oksar0
  • https://www.youtube.com/watch?v=6Y3W94_8scw