The text/cold wild goose

The best time to create a programming language was 10 years ago, and the second best time is now.

From Emscripten to asm.js to WebAssembly, from a side project to a W3C standard, it was almost a full 10 years.

Emscripten

In 2010, Dr. Alon Zakai, a failed startup, joined Mozilla, the developer of Firefox. Although he gave up on starting his own business, he continued to work on the games he developed in C++. Alon wanted to run C++ games in a browser, but he didn’t want to rewrite them by hand with JavaScript, so he wanted to compile C++ into JavaScript.

The idea was a bit far-off, and even 10 years later it sounds hard to believe. As the saying goes “Talk is cheap, show me the code”, Alon started developing Emscripten in the evenings and weekends. On the importance of not working evenings and weekends…

JavaScript also belongs to the C/C++ language family, so the basic syntax is very similar, such as the add function. The only difference is how the function is defined and whether it has a type:

// add the C++ version
int add(int a, int b) {
    return a + b;
}
Copy the code
// JavaScript version add function
function add(a, b) {
  return a + b;
}
Copy the code

It seems that compiling C++ into JavaScript is not difficult either. However, in fact, there are a lot of pits, for the simplest example, integer division:

// the C++ version divide function
int divde(int a, int b) {
  return a / b;
}
Copy the code

// JavaScript version divide function
function divide(a, b) {
  return Math.floor(a / b);
}
Copy the code

The result of integer division in C++ is an integer, so JavaScript must use math.floor to take the integer.

In 2011,Emscripten is officially released. Emscripten uses LLVM to compile C++ to bytecode, and then bytecode to JavaScript, and successfully runs C++ games in a browser.

Alon Zakai used Emscripten to make some interesting demos that sound magical even now:

  • Compile Python to JavaScript and run the Python script in your browser
  • Compile SQLite to JavaScript, run the database in the browser, and execute CURD

There are two kinds of programmers in the world. Those who write compilers, and the rest belong to the second kind. The former creates the programming language, and the latter uses the programming language. Alon clearly belongs to the former, while most of us belong to the latter 🙁

JavaScript writer Brendan Eich, who was Mozilla’s CTO at the time, decided to let Alon work on Emscripten full-time. Turning an amateur open source project into a formal corporate project isn’t going to do commercial companies much good in the short term, but in the long term, Emscripten is what Firefox is doing to solidify its position as a browser and avoid being marginalized by Chrome.

Brendan Eich’s dream has always been to increase the power and performance of the Web so that it can run any application, and Alon is making his dream come true.

asm.js

Since THE introduction of V8 engines into the browser performance wars, JavaScript performance has been magically improved by an order of magnitude through the introduction of JIT (just-in-time) compilation techniques and various optimization techniques, which is one of the fundamental reasons why the JS ecosystem has flourished. However, JavaScript is a dynamically typed language, which means that its performance is inherently flawed. Simply put, variable types in JavaScript code are uncertain, which means that the JS engine must dynamically determine variable types when generating machine code. These judgment logic will bring a lot of redundant code, and theoretically there must be performance loss.

Therefore, it’s not enough to just compile a C++ game to JavaScript, which works in a browser, but not very well. When Emscripten was used to compile the game engine Unity into JS and run it in the browser, the performance was poor.

Luke Wagner, a JS engine engineer at Mozilla, has found that the JS engine performs well for JavaScript code that can implicitly infer what type it is, and may be able to take advantage of this to improve performance. He then told Alon that performance could be improved by having Emscripten generate specific JS code, and that Luke could further optimize specific JS code by optimizing the JS engine. (on the importance of mastering JS engine this kind of underlying technology, encountered real technical difficulties, the upper application and then so can not fundamentally solve the problem……)

The following code, for example, by or zero, i.e., | 0, JS engine can deduce the add function parameters and return value is a 32-bit integer, it can be directly compiled to integer additions:

function add(x, y){
  a = x | 0; // Parameter x is an integer
  b = y | 0; // The parameter y is an integer
  return a + b | 0; // The return value of the add function is an integer
}
Copy the code

The Bitwise OR (|) operator can convert floating point number to 32-bit integer:

var x = 3.5 | 0
console.log(x) / / 3
Copy the code

Therefore, if Emscripten can compile C++ into JS code that pretends to be type-loaded, performance can be greatly improved. To further normalize “JS code that pretends to have types”, asm.js is a subset of JavaScript code. Asm. js is compiled as a result of Emscripten and is not written directly by the developer.

What does amJ.js look like? Try compiling C++ code to asm.js using Emscripten. However, the latest version of Emscripten only supports compiling to WebAssembly, not asm.js, so you need to install Emscripten 1.38.0:

git clone https://github.com/emscripten-core/emsdk.git

cdEmsdk./emsdk install SDK-fastcomp-1.38.0-64bit./emsdk activate SDK-fastcomp-1.38.0-64bitsource/emsdk_env.sh emcc -v emcc (Emscripten GCC /clang-like replacement + linker Emulating GNU LD) 1.38.0 clang version 5.0.0 (emscripten 1.38.0:1.38.0) Target: x86_64-apple-darwin20.5.0 Thread Model: POSIx InstalledDir: / Users/kiwenlau/Desktop/emsdk/fastcomp - clang/e1.38.0 _64bit INFO: root: (Emscripten: Running sanity checks)Copy the code

The add. CPP for:

#include <emscripten.h>

EMSCRIPTEN_KEEPALIVE
double add(double a, double b) {
    return a + b;
}
Copy the code

Compile C++ to asm.js using Emscripten:

emcc add.cpp -O2 -profiling -s ONLY_MY_CODE=1 -g2 --separate-asm -o add.js
Copy the code

The generated asm.js code add.asm.js is:

function __Z3adddd(d1, d2) {
  d1 = +d1;
  d2 = +d2;
  return +(d1 + d2);
}
Copy the code

For floating point numbers, ask.js simply adds a + sign before the variable, because the Unary plus (+) operator converts variables of various types to number:

console.log(+true); / / 1
Copy the code

In 2013, after nearly developing asm.js, they worked with game company Epic and, in four days, successfully compiled the Unreal game engine with one million lines of C++ code into asm.js and ported it to the browser to run Epic castle smoothly.

This video is 8 years old, it was before the birth of King of Glory and Peace Elite, but it is still amazing, thanks to the charm of the game and asm.js.

In order to further optimize asm.js performance, the JS engine needed to do some optimization, which was not particularly difficult for the compiler master, Luke did it in a few months. Through constant optimization, asm.js performance has reached 50% or even 70% of the performance of native C code. For example, since asm.js has implicit type information, the JS engine can compile Ahead Of Time(AOT) to improve performance.

Since then, other browsers such as Edge, Chrome, and Safari have optimized their JS engines to perform ASm. JS, and companies such as Facebook, Adobe, and Wikipedia have made asm. JS widely available in their products. The browser competitors started collaborating with asm.js and laid the foundation for the later development of WebAssembly together.

WebAssembly

The story doesn’t end when it comes to asm.js.

Asm.js is only a subset of JavaScript, and targeting JavaScript as a compilation target is a very hackable way to do this and that.

Math.imul(x, y) is used to multiply 32-bit integers, and Math.fround(x) is used to convert 64-bit doubles to 32-bit single-precision floating-point numbers. There is no such thing as 32-bit, 64-bit, single-precision, or double-precision in JavaScript. Math. Imul (x, y) and Math.fround(x) have been added to support asm.js. It’s a bit awkward to change JavaScript itself to support ask.js.

Asm. js is a subset of JavaScript and can run in any browser, but to get better performance, you still need to extend ECMAScript itself, which is not easy to use. Who wants to add a lot of weird features to JavaScript to support asm.js?

JavaScript gets a bad rap for not having types, but that’s part of the reason it’s so easy to use. Ease of use and performance are hard to combine in the same programming language. Otherwise, how could TypeScript be written AnyScript by most programmers (and sometimes ME)? Adding many types and related features to JavaScript in order to support ASm.js might not be acceptable to the community at this stage.

Whether or not to add types to JavaScript is a controversial topic, but it’s fine. It doesn’t matter. However, if asm.js were to implement more complex features, such as more efficient memory management, it would be difficult…

Another easy to understand problem with asm.js is that it is a JS file that the browser still has to parse and compile, which slows startup time. If the execution of the game is faster, but the startup is slower, it will be teased by users.

In conclusion, using asm.js as the Emscripten compilation target has its limitations.

Asm.js isn’t perfect, but it proves that it’s technically possible and marketable to compile a typed language into a target language and run it in a browser to improve the performance of some highly performance-demanding Web applications.

In that case, why not create a new programming language for the Web and make it the target of compilation? Why not just compile Intermediate Representation(IR) with Ahead Of Time(AOT) and run IR directly? Why bother converting IR to JS code with asm.js code?

As a matter of fact, I worked on how the V8 Engine Works. I didn’t really know WebAssembly at the time, but they were already doing it, and I was just talking about it.

An Intermediate Representation(IR) specification, which adds a corresponding virtual machine to the browser, will not only get rid of JavaScript constraints, but also optimize the compilation speed and the volume of the compilation results. Technically, this isn’t too hard for the compiler gurus who have been churning for years.

The hard part is, will the browser manufacturers work together? Chrome is the browser leader, Edge is the browser aristocrat, Safari comes from Apple, which likes to be unique, why should they follow Firefox? This matter can be likened to the domestic multifited small program platform, no trouble, each small program developers have to install N each manufacturer’s IDE!

Whether it can be done or not depends on Chrome’s attitude, because it is the boss and the one who has the right to speak. Chrome’s status is so unshakeable that it has nothing to worry about commercially. Also, as I wrote in How Did Chrome Succeed? “Chrome’s mission is to drive the development of Web technology. A faster, better browser can drive the development of Web technology. Web pages will become more and better, and users will spend more and more time on the Web, which is critical to Google’s core search business in the long run. WebAssembly’s ability to make the browser faster and more versatile fits with Google’s corporate strategy and Chrome’s product strategy.

In 2015, four browser makers (Firefox, Chrome, Safari, Edge) teamed up, and the four competitors announced that they were collaborating on WebAssembly.

In 2017, Firefox, Chrome, Safari, and Edge supported WebAssembly. He also published the Bringing the Web Up to Speed with WebAssembly paper at PLDI, the top conference in the programming language field.

In 2019, W3C released WebAssembly official standard, WebAssembly became the fourth Web language after HTML, CSS and JavaScript. Some may argue that HTML and CSS are not programming languages, but the W3C says so.

What does WebAssembly look like? Try compiling C++ code to WebAssembly using the latest version of Emscripten.

Install latest Emscripten 2.0.24:

git clonehttps://github.com/emscripten-core/emsdk.git/emsdk install 2.0.24. / emsdk activate 2.0.24source/emsdk_env. Sh emcc -v emcc (Emscripten GCC /clang-like replacement + linker Emulating GNU ld) 2.0.24 (416685 fb964c14cde4be3e8a45ad26d75bac3e33) clang version 13.0.0 (https://github.com/llvm/llvm-project 91f147792e815d401ae408989992f3c1530cc18a) Target: wasm32-unknown-emscripten Thread model: posix InstalledDir: /Users/kiwenlau/Desktop/emsdk/upstream/binCopy the code

Using Emscripten to compile C++ into asm.js, the resulting WebAssembly code a.out.wasm is over 200 lines long, but it’s not hard to see that one of them is the add function:

  (func $_Z3adddd (type $t4) (param $p0 f64) (param $p1 f64) (result f64)
    (local $l2 i32) (local $l3 i32) (local $l4 i32) (local $l5 f64) (local $l6 f64) (local $l7 f64)
    global.get $g0
    local.set $l2
    i32.const 16
    local.set $l3
    local.get $l2
    local.get $l3
    i32.sub
    local.set $l4
    local.get $l4
    local.get $p0
    f64.store offset=8
    local.get $l4
    local.get $p1
    f64.store
    local.get $l4
    f64.load offset=8
    local.set $l5
    local.get $l4
    f64.load
    local.set $l6
    local.get $l5
    local.get $l6
    f64.add
    local.set $l7
    local.get $l7
    return)
Copy the code

Z3adddd takes two arguments. Z3adddd takes two arguments, p0 and $P0, both of type F64, which is a double, and its return value, resut, is a double.

From the results, according to the paper Bringing the Web Up to Speed with WebAssembly, WebAssembly is 33.7% faster than asm.js on average, and the file volume is 62.5% smaller on average. In addition, WebAssembly has excellent compilation speed, startup speed, and memory usage.

WebAssembly is still a relatively new technology to most front-end developers, but it already has some pretty impressive applications.

In 2018, AutoCAD was compiled as WebAssembly and fully ported to the browser (web.autocad.com), which not only ensures the consistency of desktop applications and Web applications, but also greatly reduces development costs and improves performance. AutoCAD is a software that must be mastered by architectural and mechanical professionals. It is equivalent to the code editor for programmers. When I was a freshman, I learned mechanics, so I also drew drawings with AutoCAD, which is very powerful, so I can imagine how complex its code will be. I found I was more interested in programming, so I switched to computer science.

In 2019,, Google Earth is compiled into WebAssembly and ported to the browser (earth.google.com) to implement cross-browser support. Google Earth has been available on Chrome since 2017, but in a similar way to WebAssemblyNative ClientThe technology, which has some technical issues with Native Client and is only supported by Chrome, was deprecated last year.

In 2020,With the help of WebAssembly, Google Meet implements real-time background blur and background substitution of video, which enables participants in online meetings to focus on the person rather than the environment. The performance requirements for processing video data in real time are so high that all cpu-intensive calculations are done in C++ and then compiled to WebAssembly, taking advantage of the latestWebAssembly SIMDFeatures.

conclusion

WebAssembly is a revolutionary technology that brings more possibilities to the Web for CPU-intensive applications such as graphics, audio, video, live streaming, machine learning, AR, VR, games, online meetings, online documents, online ides, online games, and more. WebAssembly can both help us break through performance bottlenecks and allow us to leverage code bases in other languages. As you can see, the application of WebAssembly is still in its infancy, and it’s time for teams and businesses with potential needs to start digging into it.

This blog is more about technical history than technical details. On the one hand, to understand a technology thoroughly, the first thing is to understand its history. On the other hand, I’ve never actually used WebAssembly in a production environment, and I’ve only run Hello, World, so I’m afraid to write. I can write a separate blog post about it when I’m more familiar with the technical details of WebAssembly.

I was going to include this blog post in the Awesome Chrome series, but once I became familiar with The history of WebAssembly, it became clear that Mozilla Firefox, not Google Chrome, was driving the development of WebAssembly technology. Writing to respect the objective facts, every sentence to withstand scrutiny, let alone the title.

From Emscripten to asm.js to WebAssembly, it took 10 years for talented developers to find the best solution. Everything looks natural in the rearview mirror, but it’s not easy. Hats off to the genius who’s crazy enough to believe they can really change the world! Only the Paranoid Survive!

Chrome is amazing, and it’s driving a lot of rapid advances in Web technology, but it would be pretty scary if it was just Chrome. Fortunately, there is a respectable competitor like Firefox that allows a revolutionary technology like WebAssembly to evolve.

I am Hanyan, a programmer who loves writing code and articles. Welcome to follow my wechat official account, Hanyan Talk.

The resources

  • How does the V8 engine Work?
  • How did Chrome succeed?
  • Great Chrome browser (3) : Chrome 91 supports The WebAssembly SIMD, accelerating the use of the Web in areas like AI
  • Bringing the Web up to Speed with WebAssembly
  • Emscripten: An LLVM-to-JavaScript Compiler
  • Alon Zakai: Emscripten
  • Alon Zakai: The History of WebAssembly
  • Luke Wagner: WebAssembly Will Finally Let You Run High-Performance Applications in Your Browser
  • Unreal Engine 3 in Firefox with asm.js
  • WebAssembly: Under the hood with Mozilla
  • WebAssembly: A game changer for the Web
  • World Wide Web Consortium (W3C) brings a new language to the Web as WebAssembly becomes a W3C Recommendation
  • Background Features in Google Meet, Powered by Web ML
  • How we’re bringing Google Earth to the web
  • asm.js: closing the gap between JavaScript and native
  • A cartoon intro to WebAssembly
  • Introducing the WebAssembly backend for TensorFlow.js
  • Supercharging the TensorFlow.js WebAssembly backend with SIMD and multi-threading
  • From ASM.JS to WebAssembly
  • Celebrating 10 years of V8

recruitment

Alibaba business Platform Division is recruiting P6 and above front-end leaders for a long time to participate in the construction of the most cutting-edge Ali front-end ecosystem and promote the development of industry technology

Welcome to follow my wechat official account, HanyanTalk.