I this post I will show how to use web assembly to integrate C++ code in a Javascript application.

Web Assembly

Web assembly, or wasm, is a web standard that allows us to integrate compiled languages like C++ and C in Javascript applications. Note: At this point there might be support for other platforms as well (e.g. .Net).

Wasm enables us to compile C/C++ code to a binary format that can be executed directly by the browser. As a result the code may execute as fast as native machine code. In most everyday web application this extra boost in performance may not mean much in practice, but still, it makes for a fun experiment :-)

Since this is my first time playing with wasm, I won’t attempt anything fancy. Instead I will keep it simple and implement a recursive version of n-factorial in C++.

I will use the following Javascript implementation as a baseline for the C++ version.

function factorialJS (n) { if (n === 0 || n === 1) { return 1; } else { return n * factorialJS(n-1); } }

C++

It’s probably overkill to do an object oriented implementation of this, but I went ahead and did one anyway. Mainly because I wanted to test out a multi file integration.

Here is the C++ code:

factorial.cpp
#include "factorial-service.h" extern "C" int factorial(int n) { FactorialService factorialService; return factorialService.factorial(n); }
factorial-service.h
class FactorialService { public: int factorial (int n); };
factorial-service.cpp
#include "factorial-service.h" int FactorialService::factorial (int n) { if (n == 0 || n == 1) { return 1; } else { return n * this -> factorial(n-1); } }

For the most part this looks like regular C++ code… Or at least how I remember it from my C++ courses close to 20 years ago :-)…

The only exception might be the extern "C" int factorial(int n) part. This is done to prevent the C++ compiler from mangling the function name into something unpredictable.

Now that we have some C++ code, how do we compile it?

For this experiment I will be using the Emscripten compiler, which seems to be a popular choice btw. Most examples I could find used Emscripten.

I am not aware of an IDE, but running Emscripten from the command line works just fine. Here is the command I used to compile the C++ code:

emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' -s EXPORTED_FUNCTIONS="['_factorial']" factorial.cpp factorial-service.cpp -o factorial.js

The output from the compiler is a .wasm file and a .js file. The wasm file is where you will find the compiled C++ code.

Why is there a Javascript file? The .js file provides a Javascript api for loading the wasm file in Javascript. Technically this file is optional since you could hand code the integration, but this can get tricky. The .js file adds to the payload of your application, but several compiler flags are available to ensure that the file is as small as possible.

How do we call the function from Javascript? Luckily it’s pretty straight forward as you can see from the code below:

Module.onRuntimeInitialized = _ => { const factorialCpp = Module.cwrap('factorial', 'number', ['number']); factorialCpp(10); };

The code looks a bit weird, but at a high level, this wraps the original C++ method in a way that allows us to call it like a regular Javascript method. Notice that the wrapper asks for the function name as well as args and return type. Module is part of the api brought in by the .js file I mentioned earlier.

Performance

Moment of truth! Does the C++ code run faster than the Javascript baseline?

I didn’t expect a huge difference in performance here, but my measurements showed that the C++ version is consistently faster. I measured an average difference of 10-20% when running with large values of n in a long running loop.