📜 ⬆️ ⬇️

How JS Works: Features and Scope of WebAssembly

Today we present to you the sixth part of a series of materials that are devoted to the peculiarities of the work of all that is associated with JavaScript. Here we talk about WebAssembly. Namely, we will analyze this technology in detail, consider the features of its work, as well as how it relates to the usual JavaScript in terms of performance. It’s about code load time, program execution speed, garbage collection, memory usage, access to the platform API, debugging, multithreading and portability of WebAssembly-code. This technology, although it is now at the very beginning of its development, has already begun to change the views on the development of web applications. If the developer needs the highest performance browser code, he simply needs to become familiar with WebAssembly.

image


What is WebAssembly


WebAssembly (or wasm for short) is an effective low-level bytecode for web applications. Wasm enables the development of functional web pages in languages ​​other than JavaScript (for example, C, C ++, Rust, and others). Code in these languages ​​is compiled (statically) into WebAssembly. The result is a web application that loads quickly and has a very high performance.

Load time


In order to run a JavaScript program, the browser must first load all .js files that are stored and transmitted over the network in plain text.
')
Wasm is a low-level language similar to assembler. WebAssembly-programs are loaded by the browser faster, since through the Internet you need to transfer already compiled files in a very compact binary format.

Performance


Today, wasm programs are executed only 20% slower than machine code. This is without a doubt a decent result. After all, this is a format that is compiled in a particular environment and is launched using a variety of restrictions that provide a high level of security. Such a slowdown compared with the machine code in this world does not look so great. In addition, an increase in the performance of the wasm code is expected in the future. More interestingly, the wasm is platform independent. Its support is available in all leading browser engines that demonstrate approximately the same performance when executing a wasm code.

In order to compare the features of wasm and javascript, you can refer to this material , which deals with the features of JS engines using the example of V8. And now we will talk about how the wasm code correlates with other V8 mechanisms.

Wasm and JS V8 engine


Here is a diagram of the V8 engine device, namely, the path that the JavaScript program traverses from a simple text file to executable code.


Dynamic V8 compilation

On the left is the source code in JavaScript, which contains a certain function. First, this code is parsed, the strings are turned into tokens and an abstract syntax tree (AST) is generated. AST is a representation of the logic of a JS program. After creating AST V8 converts what happened in machine code. The abstract syntax tree is traversed and what was previously a function that exists as text is converted to its compiled version. In this case, V8 does not make special efforts to optimize the code.

Let's look now at what happens in the next stages of the engine.


V8 engine conveyor

Here it is shown that now comes TurboFan time - one of the optimizing V8 compilers. While the JavaScript application is running, a lot of auxiliary actions are performed in V8. Namely, TurboFan monitors what is happening in the search for bottlenecks and the most frequently used program fragments in order to optimize the corresponding sections of the code. After that, TurboFan will process the most critical parts of the program, passing them through an optimizing JIT compiler, which will lead to the fact that those functions that “eat up” most of the processor time will be performed much faster.

This approach allows to increase the performance of JavaScript, solves the problem of the speed of the programs, but even here everything is not going smoothly. The fact is that the operations of analyzing the code and making decisions about what needs to be optimized and what is not needed also consume resources. This, in turn, means a higher power consumption of systems, which, in the case of mobile devices, leads to a reduction in their lifespan from a single charge.

If, however, included in the above scheme wasm, it turns out that this code does not need to be analyzed and in several compilation passes. It is already optimized and ready to use.


Wasm and V8 conveyor

Wasm-code is optimized during static compilation. When working with him do not need to parse text files. Thanks to wasm, we have at our disposal binary files that can only be converted into machine code. All improvements to this code were made at compilation, which is done before it gets into the browser.
All this makes wasm execution much more efficient, since you can skip a lot of steps to turn a program's text into optimized machine code.

Memory model



Trusted and Untrusted WebAssembly Memory

The memory of a program written, for example, in C ++ and compiled into WebAssembly, is a continuous block in which there are no “holes”. One of the features of the wasm, which contributes to improved security, is to separate the execution stack from the linear address space. In C ++, there is a bunch of programs; memory for the stack is allocated in its upper part. With such an organization of working with memory, you can use the pointer to access the stack memory in order to affect the state of variables, interaction with which at the current stage of the program is not provided. This feature is used by many malicious programs.

WebAssembly uses a completely different memory model. The execution stack is separated from the memory where the wasm program itself is stored, as a result there is no possibility to gain unauthorized access to this memory, and, for example, to change the state of some variables. In addition, functions do not use pointers, but integer offsets. It uses an indirect addressing mechanism. Necessary direct addresses are calculated during the program operation. This mechanism is designed so that you can simultaneously load several wasm-modules, addresses will be located using offsets, in the end everything will work as it should.

More information about the mechanisms of memory management in JavaScript can be read here .

Garbage collection


In the previous materials of this series, we have already said that the Garbage Collector (GC) participates in managing the memory of JS programs.

In the case of WebAssembly, everything looks a little different. This technology supports languages ​​with manual memory management. As a result, you can use your own garbage collector with the wasm-modules, but this is not an easy task.

Now WebAssembly is focused on the ways of working with memory used in C ++ and Rust. Since wasm is a low-level technology, it is quite logical that programming languages ​​that are only one step above the assembler will easily be compiled into wasm. So, when programming in C, you can use the usual command malloc , in C ++ you can use smart pointers. Rust uses a completely different approach (we will not go into this, as everything is completely different there). These languages ​​do not use garbage collectors; as a result, they don’t need complex runtime mechanisms that are responsible for memory management. WebAssembly fits perfectly with similar memory models.

In addition, these languages ​​are not designed to perform complex operations that are typically implemented using JavaScript, such as DOM manipulations. It makes no sense to write an HTML application entirely in C ++, since C ++ is simply not designed for such an application. In most cases, code for web applications in C ++ or Rust is written to work with WebGL or create highly optimized libraries on it, for example, those that are responsible for mathematical calculations.

In the future, however, support is expected for languages ​​that use other memory models.

Access to external APIs


Depending on the runtime, the JavaScript program can directly interact with specialized APIs. For example, if the program is written for the browser, it has at its disposal a set of Web APIs that the application uses to control the browser or device, and to work with DOM , CSSOM , WebGL , IndexedDB , Web Audio API, and so on.

WebAssembly modules do not have direct access to the API provided by the platform. Modules can interact with the API only with the mediation of JavaScript. If, from a wasm module, you need to access a similar API, this call must be made via JavaScript. For example, if you need to execute the console.log command, you will have to call it through JS. Similar appeals to JavaScript tools affect performance.

We can not say that it will always be so. In the future, the appearance of the corresponding API is expected to directly use them in the wasm code. As a result, you can create wasm applications without using JavaScript calls.

Code maps (source maps)


If, after the minification of the JS code, it needs to be debugged, source maps come into play. This is a way of mapping between a JS code that is minified or combined from different files and its initial state. When a project is collected for production, minification and combination of files are made, they also create a code map that stores information about the source files. When referring to a specific place in the generated code, you can check the fragment of the source program, which looks much more understandable than the packaged version of the program, by checking with the code map.

WebAssembly does not support source maps, as long as there is no corresponding specification, but it is quite possible that this possibility will appear very soon.

As a result, when debugging a wasm code obtained, for example, from C ++, you can see the source code and set breakpoints in it. At least that is the purpose of introducing code maps into wasm.

Multithreading


JavaScript runs in one thread, although it supports an asynchronous programming model. Read more about it here . In addition, JS supports Web Workers technology, but it has a rather specific scope.

Predominantly computing-intensive processor resources that can block the main flow of the user interface. However, the Web Workers code cannot work with the DOM.

WebAssembly does not currently support multithreading. However, most likely, this opportunity will appear very soon. The wasm will be close to low-level threads (that is, those used in C ++). The ability to work with “real” streams will create many new opportunities in the development of browser applications. But, of course, multithreading means the emergence of new difficulties.

Code Portability


JavaScript applications can work almost everywhere: in browsers, on servers, even in embedded systems.

WebAssembly is designed with security in mind and code portability. This is very similar to javascript. It will work in any environment that supports wasm, that is, for example, in any browser.

In terms of portability, WebAssembly faces the same goals that Java once tried to achieve through applets.

Results


In early versions of WebAssembly, special attention was paid to heavy calculations, for example, mathematical ones. An obvious area of ​​application for such calculations is games in which one has to work with a myriad of pixels. Such applications can be written in C ++ / Rust using familiar methods of working with OpenGL and compile what happens in wasm. After that, all this will work in the browser. As an example, open this link in Firefox. It uses the Unreal Engine.

Another use of WebAssembly, which focuses on improving the performance of web applications, is to implement libraries that perform resource-intensive calculations using this technology, for example, libraries for image processing.

Using wasm can quite seriously reduce battery consumption on mobile devices (of course, it also depends on the engine), since most of the auxiliary operations of preparing a program for execution will be performed during static code compilation.

It is expected that in the future we will have the opportunity to use binary wasm files without even writing code that compiles into them. In NPM you can find projects that implement this approach.

Is it possible to say that wasm will replace JS? At this stage of development, technology is definitely impossible. For example, if we are talking about working with DOM or using the API of the platform on which the code is executed, JavaScript does not yet have an alternative, since these APIs are available from JS programs directly, without adding additional levels of abstraction.

The author of the material notes that SessionStack is watching with interest the WebAssembly, hoping to speed up the most resource-intensive parts of its developments with this technology.

Previous parts of a series of articles:

Part 1: How JS Works: Overview of the Engine, Runtime Mechanisms, Call Stack
Part 2: How JS Works: About V8 Inside and Code Optimization
Part 3: How JS works: memory management, four types of memory leaks and how to deal with them
Part 4: How JS works: event loop, asynchrony, and five ways to improve code with async / await
Part 5: How JS: WebSocket and HTTP / 2 + SSE work. What to choose?

Dear readers! Do you plan to use WebAssembly in your projects?

Source: https://habr.com/ru/post/343568/


All Articles