Buildtide
Author: Hussain Mir Ali

I am interested in web and mobile technologies.

If you have any questions or feedback then message me at devtips@Buildtide.com.

WebAssembly at a Glance


Evolution:



Figure 1.0 WebAssembly Evolution



asm.js which first appeared in 2013 and was developed by Mozilla as a sub-set of JavaScript. It is meant to be a compile target for languages like C/C++. This allows porting of existing applications written in C/C++ to run in the browser without the need for any additional third party library.  Using asm.js significantly increases performance when compared to same code written in JavaScript. Although asm.js runs on all browsers(https://caniuse.com/#feat=asmjs) it has highest performance on Firefox. 

Web assembly is a new compile target being standardized by W3C along with companies such as Google, Microsoft, Apple and Mozilla. Although asm.js performed close to native speed it was not consistent across all browsers but WebAssembly promises to perform consistently. Web assembly is influenced by asm.js and it can be thought of as an optimized version of asm.js for faster performance. 


Compared to asm.js WebAssembly provides the following advantages to developers:

  • Reduced load time.
  • Reduced run-time memory consumption for code.
  • Smooth performance.
  • Full set of capabilities for C/C++ applications with almost native performance.

Current Spec:
Figure 2.0 WebAssembly Pipeline (Stable)



Figure 3.0 WebAssembly Pipeline (Unstable)

WebAssembly is essentially efficient low level byte code which is fast to load and execute. It is stack machine language that loads values on to the stack to use them for computation later. 

It supports the following value types:



  • i32: 32-bit integer
  • i64: 64-bit integer
  • f32: 32-bit floating point
  • f64: 64-bit floating point
Currently Emscripten can be used to convert existing C/C++ code to '.wasm' files. The conversion pipeline from C/C++ to wasm is visible in figure 2.0 which is the stable pipeline. And figure 3.0 show shows the unstable pipeline as of 12/16/2017. Browser compatibility for WebAssembly can be found at https://caniuse.com/#feat=wasm .

Example: Adding two integers
emcc add.c -O3 -s WASM=1 -s SIDE_MODULE=1 -o add.wasm
The above script builds the C file to wasm. It is built as a stand alone module using 'SIDE_MODULE=1' option. And the optimization level is O3.

C:
//File: add.c
int add(int a, int b) {
return a + b;
}

WASM(WAST representation):
//File: add.wasm

(module
(type $type0 (func (param i32 i32) (result i32)))
(type $type1 (func))
(import "env" "memoryBase" (global $global0 i32))
(import "env" "memory" (memory (;0;) 256))
(import "env" "table" (table $table0 0 anyfunc))
(import "env" "tableBase" (global $global1 i32))
(global $global2 (mut i32) (i32.const 0))
(global $global3 (mut i32) (i32.const 0))
(export "_add" (func $func0))
(export "__post_instantiate" (func $func2))
(export "runPostSets" (func $func1))
(func $func0 (param $var0 i32) (param $var1 i32) (result i32)
get_local $var1
get_local $var0
i32.add
)
(func $func1
nop
)
(func $func2
get_global $global0
set_global $global2
get_global $global2
i32.const 5242880
i32.add
set_global $global3
)
)

HMTL/JS:
<!doctype html><!-- index.html -->
<html>
<head>
<meta charset="utf-8">
<title>WASM add example</title>
</head>
<body>
<script>
function loadModule(filename) {
return fetch(filename)
.then(response => response.arrayBuffer())
.then(buffer => WebAssembly.compile(buffer))
.then(module => {
const imports = {
env: {
memoryBase: 0,
tableBase: 0,
memory: new WebAssembly.Memory({
initial: 256
}),
table: new WebAssembly.Table({
initial: 0,
element: 'anyfunc'
})
}
};

return new WebAssembly.Instance(module, imports);
});
}

loadModule('add.wasm').then(instance => {
const add = instance.exports._add;

console.log(add(1, 6));//7
});
</script>
</body>
</html>


In the example above a function adding two integers in C is complied to wasm. Here '.wasm' binary file contains complied code but here the intermediary textual representation (s-expression) is shown. The '.wasm' file will be loaded into the browser using the provided JavaScript code. Finally the function 'add' can be called by passing in two arguments 1 and 6 which leads to 7. 

Performance:


    JSperf link: https://jsperf.com/fibonacci-wasm



Fig 4.0 Performance Measurement Fibonacci Sequence

This performance setup implements two versions of Fibonacci sequence generator methods. One is slow(recursive version) and the other one is fast(iterative version). Both JS and wasm implementation are compared and it is evident that wasm is the fastest.

Learning/Exploration Tools:


WebAssembly Explorer(https://mbebenita.github.io/WasmExplorer/):



Fig 5.0 WebAssembly Explorer

This is a great tool for exploring and understanding WebAssembly. Developers can input their C/C++ code in the first pane and this tool automatically compiles that code to appropriate 'wast' format visible in the second pane. It then converts 'wast' to 'x86' assembly format on the right most pane. 

Alternatively users can input 'wast' directly and it will be converted to 'x86' assembly.

Developers can toggle 'LLVM x86 Assembly'  to allow LLVM compiler to do the conversion to 'x86' assembly rather than Firefox's compiler. 


There are also built-in examples and other features that developers can choose from the options pane.


WebAssembly Fiddle(https://wasdk.github.io/WasmFiddle/):


Fig 6.0 WebAssembly Fiddle

This is tool can be used to share WebAssembly snippets with others using unique URL. It has 4 panes on each corner.


Top-left pane: The top-left pane is where developers can write C/C++ code.

Top-right pane:This is where the JavaScript resides for utilizing the wasm module.


Bottom-left: This is where the compiled 'wast' can be seen. There is also an options drop down to show other representations of the compiled C/C++ code.


Bottom-Right: This is where the output of the compiled program can be seen for debugging purposes. 

WebAssembly Binaries(https://wasdk.github.io/wasmcodeexplorer/):

Fig 7.0 WebAssembly Binary Explorer

This tool is good for understanding the binary representation of WebAssembly. On the left pane there is binary representation and on the right pane developers can open a 'wasm' or 'wast' file. 

Future:


The development team is trying to improve on the following aspects:

  • Improve the WebAssembly LLVM backend from experimental to stable implementation in Emscripten.
  • Add support for more languages to be source for wasm compile target.
  • Backward compatibility of new WebAssembly features.
  • Developer tools integration for WebAssembly in the browsers.
  • Add support for multi-threading.
  • Efficiently allocate and manipulate GC objects directly from WebAssembly code.