WebAssembly | An Introduction

Apoorva Sharma
Walmart Global Tech Blog
7 min readAug 19, 2021
Photo Credit

What if I told you that you can now write code in your favorite language, and it will work on web. Daunting, isn’t it? I know JavaScript has vast libraries and great support system; we have experienced a fair share of struggle when it comes to implementing in JavaScript. And don’t forget about the performance!

In 2017, when WEB ASSEMBLY was announced, it was the solution that we were all waiting for. Converting high-level language like C, C++ into machine code and then run on the browser. Sounds like magic, doesn’t it?

Let’s dive into it see what it is.

What is WebAssembly?

WebAssembly is a low-level assembly-like language that runs with near native performances. It can be looked something like this — 50% web and 50% assembly, which means it is an assembly language for modern web browsers. In simplest terms, we can define assembly language as a bunch of instructions which gets converted into machine code and gives super-fast performance. Web Assembly brings this same functionality to web.

Compilation and Execution in Micro-Processors

The above figure explains how generally the high language code executes on the microprocessors. High-level language code is written, which gets compiled and further converted into machine code. Then after that, there is a layer of abstraction called virtual microprocessor which has its own assembly language and helps the code to run on multiple physical microprocessors. WebAssembly is the same idea for browser. Any high-level language like C/C++ or C#, code can be compiled to WebAssembly byte code and create a file that all the major browsers can run and work with.

Why WebAssembly, when JavaScript is there

JavaScript is a very powerful language when it comes to the web. Historically, web platforms have been able only to load JavaScript. It is easy to code in, human readable. It has a vast ecosystem that provides powerful libraries, frameworks, and tools.

Despite all this, there are some challenging corners in JavaScript. It has some serious performance issues in 3D games, music applications, image/video editing, or virtual and augmented reality. Besides this, the JavaScript file needs to be downloaded, tokenised, parsed before executing in the browsers. This process happens every time. Yeah, caching is there in browsers, but it is an expensive process that affects JavaScript’s performance in browsers.

WebAssembly solves this problem. All the pre-processing before execution of the file in browsers can be prohibited. Compilation is the only pre-processing that is required to convert any high-level language code into compact binary format. Therefore, this near-native performance vastly differs from that of JavaScript.

But WebAssembly is not a replacement for JavaScript. It is designed to complement JavaScript allowing web developers to make use of both. WebAssembly can be thought of as a feature in JavaScript for efficiently generating high performance functions. WebAssembly JavaScript API provides the ability to create modules, memories, tables, and instances. One can be imported into the other and can call the methods defined in the other.

Interaction between files

The above is a basic example of how these files interacts with each other. In the present scenario, WebAssembly does not have the functionality to interact with DOM thus, JavaScript “glue” code is used to make this happen. To create a web-assembly module, fetch is used and the path of WASM file is given. This fetch is then used to instantiate streaming which will asynchronously retrieve the module. Once the module is imported, methods can be called and can used like JavaScript functions.

JavaScript WebAssembly APIs

Here is the list of necessary APIs which are required to load WASM file and execute in the browser:

  1. fetch() Browser API — fetch() API is meant to load WASM file network resource. It returns promise.
Source Link

2. WebAssembly.compile(buffer) — It is used to compile the module details that are fetched from WASM file. The code from WASM file must be converted to a typed array or array buffer, before giving as input to compile. This API returns a promise that will have compiled module.

3. WebAssembly.instance — This API will give you the executable instance of the compiled module that can be further executed to get the output. The return value will be an object with an array of exports function that can be executed.

4. WebAssembly.instantiateStreaming — This takes care of compiling and instantiates the WebAssembly module from the WASM code given. It will return a promise, that will have module and instance details.

Key Concepts

Module

It is a byte code in the file with WASM extension. It is compiled by browsers into executable machine code and has the functions as exports. It is considered as stateless thus can be shared between multiple windows and web workers.

Memory

Memory in WebAssembly is an array-buffer that holds the data read and written by the instructions in binary code. You can allocate memory using JavaScript API WebAssembly.memory().

Table

It is a resizable typed array of references that resided outside the WebAssembly memory and has the addresses of the methods.

Instance

The Instance is an object/module with all the state it uses at the runtime including memory, table, and all set of imports. It is called from JavaScript to execute inside the browser.

Stack Machine Model

WebAssembly uses a stack machine model to execute the instructions. In WASM, all the instructions are pushed on to the stack. The arguments are popped, and the result is pushed back to the stack.

Code

The above is a sample WASM code in text format. Everything resides inside the module. and can be considered as a container. Functions can be declared using the “func” keyword syntax. For example, the add functions takes two arguments as 32-bit integer and return the result of them as 32-bit integer. To export these functions, “export” keyword is used.

When line “local.get $a” is executed, it will get the first parameter which was passed to the add function and put on the stack. The same will happen when the “local.get $b” is executed. When add is called, it will pop both values from the stack, add them and put the result back in the stack.

WebAssembly with C/C++

For a C/C++ code to be compiled with WebAssembly, the emscripten tool is required. It is a low-level virtual machine (LLVM) that takes bytecode generated from C/C++ and compiles it into JavaScript that can efficiently execute inside the browser

Setup For Emscripten Tool:

To begin with, clone git repo of the Emscripten tool and go to the directory.

Source Link

Run the following command to install and activate the PATH and environment variables in the current terminal :

Source Link

Getting started with Hello World:

Suppose we have this sample C code which prints “Hello World” on the screen and file is saved as helloWorld.c.

Source Link

For the compilation, in the same terminal where you have activated the path for the Emscripten tool, move to the path where your C code file is, then run the following command to create WASM file :

Source Link

Command arguments are described as:

1. -s WASM=1 : this specifies that we want WASM output

2. -o helloWorld.html : this specifies that we want to have an HTML file also to run it on the browser and the WASM module and the JavaScript glue code to compile and instantiate the WASM so it can be used in the web environment

So, after running this command, in your current directory there will be three new files created with following names:

1. A binary WASM module code: helloWorld.wasm

2. A JavaScript file which contains glue code which can interact with WebAssembly code: helloWorld.js

3. A HTML file to load, compile and display output in the browser: helloWorld.html

NOTE: If you want only WASM file and wish to write your own HTML template and JS file then you can use this command:

Source Link

Load HTML on Browser:

The HTML file needs to run through HTTP Server for it to load on the browser, Otherwise you will receive an error stating async and sync fetching of WASM has failed. The simplest way is to have python installed in your local machine, and at the directory where all these files reside, run the following command to run a simple python HTTP server on port 8000:

Source Link

After Server is up, open the browser, go to http://localhost:8000/. You will see all the files in that directory listed there; click on the helloWorld.html. The file will get loaded on browser and you can see “Hello World” printed there.

References:

https://developer.mozilla.org/en-US/docs/WebAssembly/

https://emscripten.org/docs/getting_started/downloads.html

https://webassembly.org/

https://wasmbyexample.dev/home.en-us.html

--

--