Web Assembly

A New Era?

Anuragjain
Nybles
6 min readFeb 28, 2023

--

On June 17th, 2015, a new project was announced by Brendan Eich named “Web Assembly”, with a vision to easily use projects written in C and C++ on the web with native-like speed. It has rapidly become one of the most talked-about topics in the web development community, and for good reason. Web Assembly has the potential to change the way we build and run web applications, making the web faster, more capable, and more accessible.

What is Web Assembly?

Web Assembly Logo

From the official organization:

WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications.”

Web Assembly (WASM) is a binary format that can run on modern web browsers, providing a way to run low-level code on the web with high performance.

In easier form, Web Assembly is an intermediate language between your program written in C, C++, etc., and the machine assembly code, specific to any machine it runs on, with a difference that now your program runs on a browser.

Code written in C/C++/Rust can be used in Web via WASM

So what Web Assembly allows you to do is, write a program in your favorite language that can be compiled to Web Assembly, convert it into a Web Assembly Module, load the module in your web application, and call it from your application’s JavaScript.

What does it Change?

The benefits of using Web Assembly are numerous. Firstly, it is faster than JavaScript. Because Web Assembly is a low-level language, it can be optimized for performance, making it a great choice for applications that require a lot of computational power. Secondly, it is portable. Web Assembly can run on any platform that has a web browser, making it a great choice for building cross-platform applications. Finally, it is secure. Because Web Assembly runs in a sandboxed environment within the web browser, it is isolated from the rest of the system, reducing the risk of security vulnerabilities.

Web Assembly in Real World

So, how can Web Assembly be used in the real world? Here are just a few examples:

  1. Gaming: Web Assembly can be used to create high-performance games that run in the web browser. This means that games can be played on any device with a web browser, without needing a native app.
  2. Image and video processing: Web Assembly can be used to perform complex image and video processing tasks in the browser, such as image and video compression, rendering, and analysis.
  3. Scientific computing: Web Assembly can be used to run complex scientific simulations and computations in the browser, making it possible to perform data analysis and modeling on the web.
  4. Virtual and augmented reality: Web Assembly can be used to build high-performance virtual and Augmented Reality applications that run in the web browser.

Hand’s-On with Web Assembly

Now we have discussed what is Web Assembly and what it brings, its benefits, and where it can be used. Let us see how we can use our own function written in C language inside our website’s JavaScript.

Let’s take the following C code to calculate the factorial of any number. We will create this function in a file named factorial.c .

int factorial(int n)
{
if (n <= 1)
return 1;
return n * factorial(n - 1);
}

Now we will have to compile this C code to WASM binary, for which we will use the Emscripten compiler. After Installing the compiler, run the following command to compile the C file to generate factorial.wasm a binary file along with HTML-js glue code. A list of output targets is referenced here.

emcc factorial.c -s WASM=1 -o factorial.html

If we convert the factorial.wasm binary to a more human-readable format WAT, we will get the following code.

(module
(type $t0 (func (result i32)))
(type $t1 (func))
(type $t2 (func (param i32)))
(type $t3 (func (param i32) (result i32)))
(type $t4 (func (param i32 i32 i32) (result i32)))
(type $t5 (func (param i32 i64 i32) (result i64)))
(func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1)
(call $emscripten_stack_init))
(func $stackSave (export "stackSave") (type $t0) (result i32)
(global.get $g0))
(func $stackRestore (export "stackRestore") (type $t2) (param $p0 i32)
(global.set $g0
(local.get $p0)))
(func $stackAlloc (export "stackAlloc") (type $t3) (param $p0 i32) (result i32)
(local $l1 i32) (local $l2 i32)
(global.set $g0
(local.tee $l1
(i32.and
(i32.sub
(global.get $g0)
(local.get $p0))
(i32.const -16))))
(local.get $l1))
(func $emscripten_stack_init (export "emscripten_stack_init") (type $t1)
(global.set $g2
(i32.const 5243920))
(global.set $g1
(i32.and
(i32.add
(i32.const 1040)
(i32.const 15))
(i32.const -16))))
(func $emscripten_stack_get_free (export "emscripten_stack_get_free") (type $t0) (result i32)
(i32.sub
(global.get $g0)
(global.get $g1)))
(func $emscripten_stack_get_base (export "emscripten_stack_get_base") (type $t0) (result i32)
(global.get $g2))
(func $emscripten_stack_get_end (export "emscripten_stack_get_end") (type $t0) (result i32)
(global.get $g1))
(func $f8 (type $t2) (param $p0 i32))
(func $f9 (type $t0) (result i32)
(call $f8
(i32.const 1024))
(i32.const 1028))
(func $f10 (type $t3) (param $p0 i32) (result i32)
(i32.const 1))
(func $__stdio_exit (export "__stdio_exit") (type $t1)
(local $l0 i32)
(block $B0
(br_if $B0
(i32.eqz
(local.tee $l0
(i32.load
(call $f9)))))
(loop $L1
(call $f12
(local.get $l0))
(br_if $L1
(local.tee $l0
(i32.load offset=56
(local.get $l0))))))
(call $f12
(i32.load offset=1032
(i32.const 0)))
(call $f12
(i32.load offset=1032
(i32.const 0)))
(call $f12
(i32.load offset=1032
(i32.const 0))))
(func $f12 (type $t2) (param $p0 i32)
(local $l1 i32) (local $l2 i32)
(block $B0
(br_if $B0
(i32.eqz
(local.get $p0)))
(block $B1
(br_if $B1
(i32.lt_s
(i32.load offset=76
(local.get $p0))
(i32.const 0)))
(drop
(call $f10
(local.get $p0))))
(block $B2
(br_if $B2
(i32.eq
(i32.load offset=20
(local.get $p0))
(i32.load offset=28
(local.get $p0))))
(drop
(call_indirect $__indirect_function_table (type $t4)
(local.get $p0)
(i32.const 0)
(i32.const 0)
(i32.load offset=36
(local.get $p0)))))
(br_if $B0
(i32.eq
(local.tee $l1
(i32.load offset=4
(local.get $p0)))
(local.tee $l2
(i32.load offset=8
(local.get $p0)))))
(drop
(call_indirect $__indirect_function_table (type $t5)
(local.get $p0)
(i64.extend_i32_s
(i32.sub
(local.get $l1)
(local.get $l2)))
(i32.const 1)
(i32.load offset=40
(local.get $p0))))))
(func $__errno_location (export "__errno_location") (type $t0) (result i32)
(i32.const 1036))
(table $__indirect_function_table (export "__indirect_function_table") 1 1 funcref)
(memory $memory (export "memory") 256 256)
(global $g0 (mut i32) (i32.const 5243920))
(global $g1 (mut i32) (i32.const 0))
(global $g2 (mut i32) (i32.const 0)))

Now, we can use the generated factorial.wasm file in our Javascript code, using the WebAssembly API. The most efficient, optimized way to load WASM code is to use WebAssembly.instantiateStreaming() a function that compiles and instantiates a WebAssembly module directly from a streamed underlying source.

Following is the example code of using instantiateStreaming for consuming previously generated factorial.wasm file, which can be served by our server and can be called by our web client on demand. We can then instantiate the received WASM module using the following JS code and can access the exported factorial function.

WebAssembly.instantiateStreaming(fetch("factorial.wasm"))
.then((results) => {
console.log(results.instance.exports.factorial(4))
});

All modern browsers support Web Assembly.

In conclusion, Web Assembly is the future of web development. Its ability to run high-performance, low-level code in the web browser makes it a game-changer for the web. With its fast speed, portability, and security, Web Assembly has the potential to change the way we build and run web applications. Whether you’re a game developer, data scientist, or virtual reality creator, Web Assembly is a technology that you should definitely be paying attention to.

--

--