Select Page

The video is a tale of four friends helping the Rovers

The Rovers – Discovering the destination – WebAssembly with JavaScript

So these odd great folks have formed a league of their own. Rust -> LLVM -> WebAssembly <-> JavaScript

This blog is to introduce you to the two new members of this league – WebAssembly, and LLVM. (If you know them already please be stateless and re-introduce)

When I requested the two to introduce themselves, they gave me a mysterious reply, “I’m WebAssembly (abbreviated Wasm) and my friend LLVM is responsible for I’m being in this binary instruction format for the stack-based virtual machines.” LLVM just nodded approvingly.

I guess that she likes to talk to computers than to humans.

“Pardon me”, I jested, “I could not understand anything from that cryptic sentence. Can you please show me how you all work together so that I get some idea of what you are?

A less than 2 minutes video on What is WebAssembly

“So you folks”, I said, ” are helping JavaScript to inter-operate with other languages like Rust, C, C++,etc., etc.. Right?”

“Precisely” they replied in unity.

The rest of the conversations are compiled here for humans.

Hmm, what is in it for the world?

Since 1995, when JavaScript was introduced by Netscape, the great Javascript has been the only option available for a programmer, to realize performing programs in the Browser.

Now we have one more option. The new option is WebAssembly.

WebAssembly aims to enable high-performance applications on the Web without sacrificing safety and portability.

Before we reason into the secret of high-performance and safety promises, let us critically examine the history of such promises.

Hence please wait. We had Java Applet and Flash in the past…

True but they remained external to the Web ecosystem and never acted like partners.

They integrated poorly with the browser and refused to avail the features offered by the browser. Besides, they expected certain special privileges. They are fond of Thani Avarthanam, Solo Performance, and Individual Contribution.

For example, Applet requires a run-time and Flash requires a vendor plugin. If you need to render it on a WebPage, you need to provide a separate frame. Worse is that you can’t apply the same CSS rules to the java.awt.Button of Applet.

Besides, Applet and Flash continue to pose security challenges and the browsers have ceased their support to these folks.

From the programmer’s point of view, the collaboration between (people and) the components should be straightforward for successful adaption.

However, it puzzles me why the community did not recognize the values of Google Web Toolkit, though it brings all the best traits, to the table of a programmer. Okay, let us mark this as an exception and proceed.

Then How is WebAssembly different?

WebAssembly is not a replacement for Javascript. It is designed to be an enabler and is meant to complement JavaScript and is designed to live in the same ecosystem where JavaScript lives.

Let us see the synopsis of the 2-minutes video, from a different angle, to understand the flow.

From the angle of Collaboration
  1. You continue your art of crafting a code in a language of your choice. My choice is Rust
  2. Then you annotate the functions that you want to export and import
  3. Request the Rust ecosystem to emit a binary code. The Rust compiler and LLVM work together to generate .wasm.
  4. Thus your WebAssembly is born and ready to work for you.
  5. The JavaScript fetches this binary and instantiates the WebAssembly
  6. Then you know how to invoke the exported function and you know how to play with the result

Don’t Skip this section even if you are not interested in the making of .wasm

This is a blog within a blog. Like dream within a dream of Inception.

The creation of a .wasm file or an executable or a library is always a curious subject to me because I don’t know much about this code generation part. In fact, that is the final code my system understands. Very poor isn’t it?

Despite the target platforms are different in terms of the Instruction Set Architecture and the Operating Systems, who is helping me, sitting silently in my laptop, cross-compile my poor code in a way that is understandable by these diverging target platforms. For me, that mechanism is God.

For example, You want your Rust code to be executed in a machine whose ISA is AMD/Intel x86_64 and the platform is Linux-gnu. Then you got another order and want this code to run on Mac whose ISA may be x86_64 and the OS is darwin. In Rust parlance, we define a target as a combination of ISA-Vendor-OS. For example, the Target Triple of my Laptop is X86_64-apple-darwin.

You pass a few configuration information to the rust ecosystem indicating the required target.

Like magic, you obtain an executable or .so file, in ELF format, suitable for the Linux Target or dylib in Mach-O format or .dll for Windows.

The visible piece of the Rust ecosystem, to a programmer, in the whole process is the rust compiler.

Does rust directly create an executable for every target platform? If yes, then will not such a process be complex and inefficient? So how is that being performed?

The Process of creating a machine-understandable code is a two-phase activity.

Behind the scene, sits silently our great library. LLVM

Compilers like Rust/Swift/C++/Kotlin and many others perform the frontend job of enforcing their language-specific rules on the source code to produce an LLVM Intermediate Representation. The LLVM backend takes this IR to produce a machine code that is understandable by the target.

Thus, your compiled code, whether it is an executable or a shared library, becomes language-agnostic when it is represented in the Intermediate Representation. Samarasam Ulavum Idam.

This is the actual code generation part. That is the central idea that is used in the creation of a .wasm binary format.

As a corollary, What I write is the code for me and for my fellow programmers to understand and to enhance, and what LLVM writes is the Code for the Computer.

Now, I hope you are viewing WebAssembly as a Virtual Instruction Set Architecture and apply this idea of cross-compilation to emit a platform-agnostic Intermediate Representation. Interestingly the target triple for this in Rust is wasm32-unknown-unknown. Where “unknown” should be read as “independent of”. It is independent of the Vendor and Independent of the Operating System.

The .wasm file is thus language agnostic. And please wait.

Support by Major browsers

And most importantly, you can run this .wasm file in all the aforesaid Browsers side-by-side with JavaScript.

Now one can appreciate this fact. Yes, Rust is not the only way to produce a WebAssembly. I prefer Rust for the comprehensive ecosystem it offers. If the language compiler can produce an LLVM-IR, then we can generate a .wasm binary from there.

Hope now we have answers to lot of unasked questions and particularly answers to the portability aspect of the WebAssembly across browsers.

But still, we did not reason the promise and benefits part. What is in it for me?

The Promise

WebAssembly aims to enable high-performance applications on the Web without sacrificing safety and portability.

The promise emphasizes two vectors Fast and Safety and the Qualifier word enabler.

Performance

You know that our PM-Power Consulting office is located at Jaya Nagar, Bangalore. (The location is a pointer for my memory due to Covid). Assuming that two rovers, using a similar vehicle specification and having identical horoscope that is free from the curses of any traffic doshas. One starts from Hosur to reach our PM-Power office and the other starts from Electronic City.

Who is likely to reach our Office first?

Let us consult the map.

Certainly, the rover that starts from the Intermediate location, the electronic city, is likely to reach the Office early. Isn’t it?

WebAssembly works by the same philosophy.

The WebAssembly is expected to be Faster than JavaScript, for many cases, because it is precompiled and optimized ahead of time into an intermediate representation. This intermediate representation is relatively closer to the target machine code than the Javascript source.

Whereas, the Just-in-Time JavaScript compiler, spends time on a series of tasks that involves parsing, compiling, coercing the type (being JavaScript is a dynamically typed language), and optimize and reoptimize the JavaScript code every time.

Hence the central idea is that the just-in-time compilation activity can be reduced considerably through the pre-compiled WebAssembly instruction.

Another driver that is expected to improve is the first-reaction time from the user. The rationale is that the compact size is expected to reduce I/O in fetching the .wasm. I guess it not only just the I/O overhead, it may be due to the fact that the IR is just a few steps before the executable state. Hence the probability of a WebAssembly reaching the ready state to serve the user is high.

Security

Security is the most important vector for any web application. The main storage of a WebAssembly is a large array of bytes called Linear memory. The linear memory is disjoint from the code space and the execution stack.

This insulates the compiled program from corrupting the execution environment by jumping to arbitrary locations to open gates for compromising security.

Maintainability

WebAssemblies, though are language agnostic, the process of building them using Rust bestows all the benefits which complement JavaScript. The important benefits are TypeSafety, improved Testability, and improved predictability to the performance.

WebAssembly helps to improve the maintainability of the Web Application.

Potential Usecases

WebAssembly can help you to move portions of the heavy-duty operations that are being performed at the Server-Side to the Browser. This will help in reducing the Total Cost of Ownership by freeing up the server resources and in reducing I/O overheads.

WebAssembly can help you to optimize and modernize parts of JavaScript modules that perform computationally intensive operations.

Some of the famous use-cases are:

  • Encoding Audio and Video on the fly
  • PDF annotations
  • Data Analysis
  • Games

Finally

A language like Rust combined with ideas like WebAssembly enables JavaScript and Web application in achieving a blazingly fast and highly maintainable application.

The founding pillars of software engineering are the programmers, their algorithm, their application of common sense, and their clean coding skills. These are the vital drivers that make an application better in every dimension. From Throughput to Maintenance.

Please visit my youtube channel krscleancode to know more about Rust, Cross-Compilation, Foreign Function Interface, and WebAssembly.

Thank you,