Tuesday, January 2, 2018

WebAssembly – Caching when using Emscripten


In our first article about WebAssembly, An Introduction to WebAssembly, we allowed Emscripten to handle all of the plumbing for us, including the HTML, so that we could get a feel for what was possible with WebAssembly modules by jumping right into some code.

In some of the articles that followed, we examined some of the technologies related to WebAssembly and used a bare-bones module (no Emscripten plumbing) to do so.

In this article we're going to circle back to caching a WebAssembly module to an HTML5 IndexedDB database but this time we're going to enable some of Emscripten's plumbing to show how to you can implement caching within Emscripten's framework.

Note: We're not going to dig into some of the details of using Emscripten or working with an IndexedDB database because we've talked about them in previous articles. We will have links to our other WebAssembly articles at the end of this article if you would like to explore the other topics more.


Building the WebAssembly module and JavaScript plumbing code

The following is some C code that we will compile into a .wasm file for today's article:
#include <stdio.h>
#include "../emscripten/emscripten.h"

int main()
{
printf("Hello World from C\n");
return 0;
}

void EMSCRIPTEN_KEEPALIVE TestFunction(int iVal) {
printf("TestFunction called...value passed in was: %i\n", iVal);
}

The following command line is similar to the one we used in our Introduction to WebAssembly article but with one change. Here, we're specifying the output file to have a .js extension rather than .html. This tells Emscripten to only generate the JavaScript plumbing code and not the HTML file.

emcc test.c -s WASM=1 -o test.js -s NO_EXIT_RUNTIME=1


Controlling the module's instantiation

Emscripten allows you to override methods of the Module object in order to control execution (e.g. you can implement Module.print so that you could display stdout messages to an alert or a div rather than the default which writes the messages to the console).

Documentation of the Module methods that can be overridden can be found here: https://kripken.github.io/emscripten-site/docs/api_reference/module.html

In order to control the load of the WebAssembly module, the method we're interested in is instantiateWasm.

The instantiateWasm method accepts two parameters
  • The first parameter is the import object that we need to pass as the second parameter to WebAssembly.instantiate
  • The second parameter is a call back function that we need to use to pass the WebAssembly module instance back to Emscripten once we have it

The following is an example of implementing the instantiateWasm method:
var Module = {

// Override instantiateWasm
'instantiateWasm': function (importObject, fncReceiveInstance) {
// We've set things up in such a way so that each wasm file can have a
// version and we only clear the items from the cache if the version
// doesn't match
var sWasmURI = "test.wasm";
var sWasmVersion = "1.0.0";

// Load the wasm file from cache if it's there. If not, fetch it and cache it.
GetCompiledModuleFromIndexedDB(sWasmURI, sWasmVersion, importObject, fncReceiveInstance);

// Pass back an empty dictionary object if the instantiation is performed
// asynchronously which it is in this case
return {};
}

};

The final piece of the puzzle to get everything working is to include the JavaScript file that was generated by Emscripten. The trick to this, however, is that the JavaScript file needs to be included after our code that implements the instantiateWasm method.

The following is our example HTML page:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<input type="text" id="txtValue" />
<input type="button" value="Test" onclick="OnClickTest();" />

<script type="text/javascript">
// If we need to change the structure of the database, we can
// increment the DB_VERSION value to trigger the
// onupgradeneeded event when opening the database
var DB_VERSION = 1;
var DB_NAME = "WasmCache";
var DB_OBJSTORE_MODULES = "Modules";

var Module = {

// Override instantiateWasm
'instantiateWasm': function (importObject, fncReceiveInstance) {
// We've set things up in such a way so that each wasm file can
// have a version and we only clear the items from the cache if
// the version doesn't match
var sWasmURI = "test.wasm";
var sWasmVersion = "1.0.0";

// Load the wasm file from cache if it's there. If not, fetch it and
// cache it.
GetCompiledModuleFromIndexedDB(sWasmURI, sWasmVersion, importObject, fncReceiveInstance);

// Pass back an empty dictionary object if the instantiation is
// performed asynchronously which it is in this case
return {};
}

};

function GetCompiledModuleFromIndexedDB(sWasmURI, sWasmVersion, importObject, fncReceiveInstance) {

// If we successfully opened the database then...
OpenDB(DB_NAME, DB_VERSION, HandleUpgradeDB).then(dbConnection => {

// If we successfully obtained the requested record then...
GetRecordFromObjectStore(dbConnection, DB_OBJSTORE_MODULES, sWasmURI).then(objRecord => {

// If the version stored for this module doesn't match the
// version we need then the module cached is out of date...
if (objRecord.WasmVersion !== sWasmVersion) {

// Have the record deleted and then fetch the proper file
DeleteRecordFromObjectStore(dbConnection, DB_OBJSTORE_MODULES, sWasmURI).then(result => {
LoadWebAssemblyFromFile(dbConnection, sWasmURI, sWasmVersion, importObject, fncReceiveInstance);
});

}
else { // The cached record is the version we need...

// Have the module instantiated.
//
// NOTE: Unlike when we pass in the bytes to instantiate
// in the LoadWebAssemblyFromFile method below, we
// don't have a separate 'instance' and 'modules' object
// returned in this case since we started out with the
// module object. We're only passed back the instance in
// this case.
WebAssembly.instantiate(objRecord.WasmModule, importObject).then(instance =>
// Pass the instance back to the emscripten
// receiveInstance method
fncReceiveInstance(instance)
);

}

}, sErrorMsg => { // Error in GetRecordFromObjectStore...

// We weren't able to pull the module from cache (most
// likely because it doesn't exist yet - hasn't been cached
// yet). Log the error and then fetch the file.
console.log(sErrorMsg);
LoadWebAssemblyFromFile(dbConnection, sWasmURI, sWasmVersion, importObject, fncReceiveInstance);

});

}, sErrorMsg => { // Error in OpenDB...

// Log the error and then fetch the file (won't be able to
// cache it in this case because we don't have a database
// connection to work with)
console.log(sErrorMsg);
LoadWebAssemblyFromFile(null, sWasmURI, sWasmVersion, importObject, fncReceiveInstance);

});

}

// Called by indexeddb if the database was just created or if the
// database version was changed
function HandleUpgradeDB(evt) {
// Create the object store which will hold 3 properties:
// • WasmURI - (primary key) e.g. 'test.wasm'
// • WasmVersion - e.g. '1.0.1'
// • WasmModule - the compiled module
var dbConnection = evt.target.result;
dbConnection.createObjectStore(DB_OBJSTORE_MODULES, { keyPath: "WasmURI" });
}

function LoadWebAssemblyFromFile(dbConnection, sWasmURI, sWasmVersion, importObject, fncReceiveInstance) {
// Request the wasm file from the server and compile it... fetch(sWasmURI).then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, importObject)
).then(results => {
// Pass the instance back to the emscripten receiveInstance
// method
fncReceiveInstance(results.instance);

// Only do the following if we have a database connection
// object (this method will be passed a null if we failed to load
// the module from cache due to an error when trying to open
// the database)
if (dbConnection !== null) {
// WARNING: Not all browsers that support WebAssembly
// also support the ability to store the module in IndexedDB
// (seems to work fine in Edge 16 and in Firefox but it
// doesn't work for me in Chrome 63)
try {
// Create the object we're about to store
var objRecord = { "WasmURI": sWasmURI, "WasmVersion": sWasmVersion, "WasmModule": results.module };

// Cache the compiled module so that we don't have to
// pull the file from the server again unless we change
// the module's version number.
SaveRecordToObjectStore(dbConnection, DB_OBJSTORE_MODULES, objRecord);
}
catch (ex) {
console.log(`Unable to save the WebAssembly module to IndexedDB: ${ex.message}`);
}
}
});
}

function OnClickTest() {
Module.ccall('TestFunction', // name of C function
null, //return type
['number'],//argument types
[ parseInt(document.getElementById("txtValue").value,10) ]);
}
</script>
<script src="IndexedDB.js"></script>
<script src="test.js"></script><!-- Emscripten plumbing. Very important that this comes *after* our JavaScript that creates the Module object and sets the 'instantiateWasm' method. -->
</body>
</html>

The following is the content of our IndexDB.js file:

// Helper methods to work with an IndexedDB database
//
// Note: IndexedDB methods are asynchronous. To make things a bit
// easier to work with for the calling code, I've added Promises.

function OpenDB(sDatabaseName, sDatabaseVersion, fncUpgradeDB) {
return new Promise(function (fncResolve, fncReject) {

// Make a request for the database to be opened
var dbRequest = indexedDB.open(sDatabaseName, sDatabaseVersion);

dbRequest.onerror = function (evt) { fncReject(`Error in OpenDB: ${evt.target.error}`); }

// Pass the database connection object to the resolve method of the
// promise
dbRequest.onsuccess = function (evt) { fncResolve(evt.target.result); }

// This event handler will only be called if we're creating the database
// for the first time or if we're upgrading the database to a new
// version (this will be triggered before the onsuccess event handler
// above if it does get called). Let the calling code handle upgrading
// the database if needed to keep this file as generic as possible.
dbRequest.onupgradeneeded = fncUpgradeDB;

});
}


// Helper method to simplify the code some
function GetObjectStore(dbConnection, sObjectStoreName, sTransactionMode) {
// Create a transation and, from the transaction, get the object store
// object
return dbConnection.transaction([sObjectStoreName], sTransactionMode).objectStore(sObjectStoreName);
}


function GetRecordFromObjectStore(dbConnection, sObjectStoreName, sRecordID) {
return new Promise(function (fncResolve, fncReject) {

// Request the record specified
var dbGetRequest = GetObjectStore(dbConnection, sObjectStoreName, "readonly").get(sRecordID);

dbGetRequest.onerror = function (evt) { fncReject(`Error in GetRecordFromObjectStore: ${evt.target.error}`); }

dbGetRequest.onsuccess = function (evt) {
// If we have a record then...(we have to check because there
// won't be a record if the database was just created)
var objRecord = evt.target.result;
if (objRecord) { fncResolve(objRecord); }
else { fncReject(`The record '${sRecordID}' was not found in the object store '${sObjectStoreName}'`); }
}

});
}


function DeleteRecordFromObjectStore(dbConnection, sObjectStoreName, sRecordID) {
return new Promise(function (fncResolve, fncReject) {

// Request the delete of the record specified
var dbDeleteRequest = GetObjectStore(dbConnection, sObjectStoreName, "readwrite").delete(sRecordID);

dbDeleteRequest.onerror = function (evt) { fncReject(`Error in DeleteRecordFromObjectStore: ${evt.target.error}`); }

dbDeleteRequest.onsuccess = function (evt) { fncResolve(); }

});
}


function SaveRecordToObjectStore(dbConnection, sObjectStoreName, objRecord) {

// Request the put of our record (if it doesn't already exist, it gets added. otherwise, it gets updated)
var dbPutRequest = GetObjectStore(dbConnection, sObjectStoreName, "readwrite").put(objRecord);

dbPutRequest.onerror = function (evt) { console.log(`Error in SaveToIndexedDB: ${evt.target.error}`); }

dbPutRequest.onsuccess = function (evt) { console.log(`Successfully stored the record`); }

}


Since we have already discussed some of Emscripten's basics, like the EMSCRIPTEN_KEEPALIVE attribute in the C code above, as well as caching WebAssembly modules to HTML5 IndexedDB databases in previous articles, we didn't explain those details today.

If you'd like to know more about WebAssembly, the following are a few articles that might be of interest:

Saturday, December 30, 2017

WebAssembly - WasmFiddle and Inline WebAssembly Modules


WasmFiddle

JSFiddle, and tools like it, allow you to test code in the browser to see how it will work instead of having to write an application just to test something. Another advantage of tools like this is that you can share your example code on sites like Stack Overflow.

It turns out that there is a similar tool for WebAssembly called WasmFiddle: https://wasdk.github.io/WasmFiddle


If we replace the code that is in the top-left pane with our code below we can compile the code by pressing the Build button:

int add(int x, int y){ return x + y; }

Because we changed the method in the top-left pain from 'main' to 'add', we need to adjust the logic in the top-right pane from this:
log(wasmInstance.exports.main());
to this:
log(wasmInstance.exports.add(1, 2));

Once you make this change, you can click the Run button which will display the result of the call in the bottom-right pane.

Note: One difference between WasmFiddle's output as compared to Emscripten's output is that there is no underscore character before the method's name when using WasmFiddle.

To share your WebAssembly code with someone, you first need to click on the Share button (above the top-right pane) which will update the URI both in the browser's address bar and just above the top-left pane. You can then copy and share the address.


Inline WebAssembly Modules

WasmFiddle also allows you to download the wasm file or simply view the file's text format or binary representation in the bottom-left pane.

The binary representation from WasmFiddle offers an interesting option when it comes instantiating WebAssembly modules. With the array that you're given, you can bypass the fetch of the wasm file and instantiate a WebAssembly module directly with the array.

The following is some sample code using our Code Buffer from WasmFiddle:
var wasmCode = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 135, 128, 128, 128, 0, 1, 96, 2, 127, 127, 1, 127, 3, 130, 128, 128, 128, 0, 1, 0, 4, 132, 128, 128, 128, 0, 1, 112, 0, 0, 5, 131, 128, 128, 128, 0, 1, 0, 1, 6, 129, 128, 128, 128, 0, 0, 7, 144, 128, 128, 128, 0, 2, 6, 109, 101, 109, 111, 114, 121, 2, 0, 3, 97, 100, 100, 0, 0, 10, 141, 128, 128, 128, 0, 1, 135, 128, 128, 128, 0, 0, 32, 1, 32, 0, 106, 11]);

WebAssembly.compile(wasmCode).then(wasmModule =>
WebAssembly.instantiate(wasmModule, g_importObject)
).then(instance =>
//Warning: No underscore character when using WasmFiddle
alert(instance.exports.add(1, 2))
);

Note: WasmFiddle shows the use of WebAssembly.Module in the top-right pane but that is not recommended because that compiles the module synchronously. The recommended way to compile a module is by using the asynchronous WebAssembly.Compile method as shown in our example above.



If you'd like to know more about WebAssembly, the following are a few articles that might be of interest:

Wednesday, December 27, 2017

WebAssembly - Web Workers


This is a continuation of a series of articles exploring how we can build and work with WebAssembly modules using Emscripten. The previous articles are not required reading to understand what we're going to cover today but, if you're curious, you can find them here:
Today we're going to continue using a bare-bones WebAssembly module (no Emscripten built-in helper methods) just to keep things as clear as possible as we examine HTML5 Web Workers.

Web Workers allow JavaScript code to run in a separate thread from the browser window's UI thread. This allows long-running scripts to do their processing without interfering with the responsiveness of the browser's UI.

Because Web Workers are running in a separate thread from the UI, the worker threads have no access to the DOM or other UI functionality. In addition, Web Workers are not intended to be used in large numbers and are expected to be long-lived since they have a high start-up performance cost and high memory cost per worker instance.

WebAssembly modules can be loaded in either the UI thread or in a Web Worker. You would then take the compiled module and pass that to another thread, or even another window, by using the postMessage method.

Since you will only be passing the compiled module to the other thread, you can call WebAssembly.compile rather than WebAssembly.instantiate to get just the module.

The following is some code that will request the wasm file from the server, compile it into a module, and then pass the compiled module to a Web Worker:

fetch("test.wasm").then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.compile(bytes)
).then(WasmModule =>
g_WebWorker.postMessage(WasmModule)
);

The code above will also work in a Web Worker if you wanted to do this in reverse (load and compile the module in a Web Worker and then pass the module to the UI thread). The only difference would be that you would use self.postMessage as opposed to g_WebWorker.postMessge in the example above.

The following is some example code that creates a Web Worker, loads the wasm file, and passes the compiled module to the Web Worker:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<input type="button" value="Test" onclick="OnClickTest();" />

<script type="text/javascript">
// Create a Web Worker (separate thread) that we'll pass the
// WebAssembly module to.
var g_WebWorker = new Worker("WebWorker.js");
g_WebWorker.onerror = function (evt) {
console.log(`Error from Web Worker: ${evt.message}`);
}
g_WebWorker.onmessage = function (evt) {
alert(`Message from the Web Worker:\n\n ${evt.data}`);
}


// Request the wasm file from the server and compile it...(Typically
// we would call 'WebAssembly.instantiate' which compiles and
// instantiates the module. In this case, however, we just want the
// compiled module which will be passed to the Web Worker. The
// Web Worker will be responsible for instantiating the module.)
fetch("test.wasm").then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.compile(bytes)
).then(WasmModule =>
g_WebWorker.postMessage({ "MessagePurpose": "CompiledModule", "WasmModule": WasmModule })
);

function OnClickTest() {
// Ask the Web Worker to add two values
g_WebWorker.postMessage({ "MessagePurpose": "AddValues", "Val1": 1, "Val2": 2 });
}
</script>
</body>
</html>

The following is the content of our WebWorker.js file:

var g_importObject = {
'env': {
'memoryBase': 0,
'tableBase': 0,
'memory': new WebAssembly.Memory({ initial: 256 }),
'table': new WebAssembly.Table({ initial: 0, element: 'anyfunc' })
}
};

// The WebAssembly module instance that we'll be working with
var g_objInstance = null;


// Listen for messages from the main thread. Because all messages to this
// thread come through this method, we need a way to know what is being
// asked of us which is why we included the MessagePurpose property.
self.onmessage = function (evt) {
// If we've been asked to call the module's Add method then...
var objData = evt.data;
var sMessagePurpose = objData.MessagePurpose;
if (sMessagePurpose === "AddValues") {

// Call the add method in the WebAssembly module and pass the
// result back to the main thread
var iResult = g_objInstance.exports._add(objData.Val1, objData.Val2);
self.postMessage(`This is the Web Worker...The result of ${objData.Val1.toString()} + ${objData.Val2.toString()} is ${iResult.toString()}.`);

} // If we've been passed a compiled WebAssembly module then...
else if (sMessagePurpose === "CompiledModule") {

// NOTE: Unlike when we pass in the bytes to instantiate, we don't
// have a separate 'instance' and 'modules' object returned in this
// case since we started out with the module object. We're only
// passed back the instance in this case.
WebAssembly.instantiate(objData.WasmModule, g_importObject).then(instance =>
g_objInstance = instance // Hold onto the module's instance so that we can reuse it
);

}
}

The following is the C code as well as the command line needed to turn the code into a WebAssembly module for today's article:

int add(int x, int y){ return x + y; }

emcc test.c -s WASM=1 -s SIDE_MODULE=1 -O1 -o test.wasm


Inline Web Workers

While reading about using Web Workers, I ran across one comment about how this adds yet another network request (one for the wasm file and now another for the Web Worker's JavaScript file).

The following may not work for every situation, especially if the Web Worker's code is large or complex, but there is a way to create an inline Web Worker by using a Blob object.

You can pass a Blob object a string of JavaScript but I found that using a literal string was difficult to work with and that having a section in the HTML felt more natural which is why we're using a custom Script tag in the sample code below.

The following is an example of how you can create an inline Web Worker:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<input type="button" value="Test" onclick="OnClickTest();" />

<script id="scriptWorker" type="javascript/worker">
var g_importObject = {
'env': {
'memoryBase': 0,
'tableBase': 0,
'memory': new WebAssembly.Memory({ initial: 256 }),
'table': new WebAssembly.Table({ initial: 0, element: 'anyfunc' })
}
};

// The WebAssembly module instance that we'll be working with
var g_objInstance = null;

// Listen for messages from the main thread. Because all
// messages to this thread come through this method, we need a
// way to know what is being asked of us which is why we included
// the MessagePurpose property.
self.onmessage = function (evt) {
// If we've been asked to call the module's Add method then...
var objData = evt.data;
var sMessagePurpose = objData.MessagePurpose;
if (sMessagePurpose === "AddValues") {

// Call the add method in the WebAssembly module and pass
// the result back to the main thread
var iResult = g_objInstance.exports._add(objData.Val1, objData.Val2);
self.postMessage(`This is the Web Worker...The result of ${objData.Val1.toString()} + ${objData.Val2.toString()} is ${iResult.toString()}.`);

}// If we've been passed a compiled WebAssembly module then...
else if (sMessagePurpose === "CompiledModule") {

// NOTE: Unlike when we pass in the bytes to instantiate, we
// don't have a separate 'instance' and 'modules' object
// returned in this case since we started out with the module
// object. We're only passed back the instance in this case.
WebAssembly.instantiate(objData.WasmModule, g_importObject).then(instance =>
g_objInstance = instance // Hold onto the module's instance so that we can reuse it
);

}
}
</script>

<script type="text/javascript">
// Load the text from our special Script tag into a Blob and then
// grab the URI from the blob
var bInlineWorker = new Blob([document.getElementById("scriptWorker").textContent]);
var sBlobURL = window.URL.createObjectURL(bInlineWorker);

// Create a Web Worker (separate thread) that we'll pass the
// WebAssembly module to.
var g_WebWorker = new Worker(sBlobURL);
g_WebWorker.onerror = function (evt) {
console.log(`Error from Web Worker: ${evt.message}`);
}
g_WebWorker.onmessage = function (evt) {
alert(`Message from the Web Worker:\n\n ${evt.data}`);
}


// Request the wasm file from the server and compile it...(Typically
// we would call 'WebAssembly.instantiate' which compiles and
// instantiates the module. In this case, however, we just want the
// compiled module which will be passed to the Web Worker. The
// Web Worker will be responsible for instantiating the module.)
fetch("test.wasm").then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.compile(bytes)
).then(WasmModule =>
g_WebWorker.postMessage({ "MessagePurpose": "CompiledModule", "WasmModule": WasmModule })
);

function OnClickTest() {
// Ask the Web Worker to add two values
g_WebWorker.postMessage({ "MessagePurpose": "AddValues", "Val1": 1, "Val2": 2 });
}
</script>
</body>
</html>


Summary

One nice thing about Web Workers is that they also have access to IndexedDB which means the worker thread can handle caching too if you wish to work with WebAssembly modules entirely from the worker thread.

We didn't dig into caching a WebAssembly module in this article but, if you're interested, you can check out our previous article: WebAssembly - Caching to HTML5 IndexedDB

The focus of today's article with Web Workers was just around what was needed when working with WebAssembly modules. If you'd like to know more about Web Workers, I have several articles that may be of interest:

Thursday, December 21, 2017

WebAssembly – Caching to HTML5 IndexedDB


This article is a continuation of a series exploring how we can build and work with WebAssembly modules using Emscripten. The previous articles are not required reading to understand what we're going to cover today but, if you're curious, you can find them here:
Today we're going to continue using a bare-bones WebAssembly module (no Emscripten built-in helper methods) just to keep things as clear as possible as we dig into an important topic.

One of the main reasons why we would want to use a WebAssembly module in the first place is for the performance improvements that it brings but we haven't yet made use of one key performance item.

Typically, when you go to a webpage that has a JavaScript file, the browser will cache it so that it doesn't have to download it again. The next time you go to that same webpage, if the file is in the browser's cache, it will load that rather than pull it from the server which saves time.

If you've been watching your network traffic, while working with the WebAssembly examples so far, you may have noticed that the wasm file is requested every time your page is loaded which isn't desired if the module hasn't changed.


HTML5 IndexedDB

WebAssembly modules were created with the ability to cache the compiled module in mind but the trick is that the caching is something that needs to be done explicitly by us.

In JavaScript, modules are cached to IndexedDB.

Up until this point, with all of my WebAssembly testing, I've simply been using the file system and double clicking on the html file to test things in the browser.

For security reasons, however, browsers will not allow websites to access IndexedDB from a local file which means we need to set up a server of some sort. I'm a developer on Windows so I'm going to use IIS.

IIS has a whitelist of file extensions that it will allow a website to provide and .wasm was not in my list which resulted in a 404 error when the page tried to fetch the wasm file.

Adding .wasm to the list in IIS is fairly simple:
  • Open up Internet Information Services (IIS) Manager (found in Control Panel, Administrative Tools)
  • You can set this at the root, Default Web Site, or at the individual Application level
  • Double click on the MIME Types link
  • Click the Add... link on the Actions pane to the right
  • Enter wasm for the file name extension
  • Enter application/wasm for the MIME type
  • Click OK


Caching

So far, we've been working with the module's instance but the result object from the WebAssembly.instantiate call also returns a module object which is the compiled module that we can cache in an IndexedDB database:

// Request the wasm file from the server and compile it... fetch(sWasmURI).then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, g_importObject)
).then(results => {
// We've been working with the .instance object so far
objModuleInstance = results.instance;

// The results object also holds a .module object which is
// what we can cache:
// results.module
});

When we retrieve the compiled module from the cache, we will need to pass it to WebAssembly.instantiate but there are a couple of differences compared to when we download the file.

The first difference is that we don't need to do a fetch or set up an arrayBuffer.

The second difference is that the return object from the instantiate object is the instance itself.

WebAssembly.instantiate(objModule, g_importObject).then(instance =>
g_objModuleInstance = instance
);


The following is some example code that shows how you can work with IndexedDB to cache and load WebAssembly modules:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<input type="button" value="Test" onclick="OnClickTest();" />

<script src="IndexedDB.js"></script>
<script type="text/javascript">
var g_importObject = {
'env': {
'memoryBase': 0,
'tableBase': 0,
'memory': new WebAssembly.Memory({ initial: 256 }),
'table': new WebAssembly.Table({ initial: 0, element: 'anyfunc' })
}
};

// The WebAssembly module instance that we'll be working with
var g_objModuleInstance = null;

// If we need to change the structure of the database, we can
// increment the DB_VERSION value to trigger the
// onupgradeneeded event when opening the database
var DB_VERSION = 1;
var DB_NAME = "WasmCache";
var DB_OBJSTORE_MODULES = "Modules";

// We've set things up in such a way so that each wasm file can
// have a version and we only clear the items from the cache if
// the version doesn't match
var g_sTestWasmURI = "test.wasm";
var g_sTestWasmVersion = "1.0.0";

// Check to see if the module is cached and, if so, use that.
// Otherwise, download the module and cache it.
GetCompiledModuleFromIndexedDB(g_sTestWasmURI, g_sTestWasmVersion);


function GetCompiledModuleFromIndexedDB(sWasmURI, sWasmVersion) {

// If we successfully opened the database then...
OpenDB(DB_NAME, DB_VERSION, HandleUpgradeDB).then(dbConnection => {

// If we successfully obtained the requested record then...
GetRecordFromObjectStore(dbConnection, DB_OBJSTORE_MODULES, sWasmURI).then(objRecord => {

// If the version stored for this module doesn't match the
// version we need then the module cached is out of date...
if (objRecord.WasmVersion !== sWasmVersion) {

// Have the record deleted and then fetch the proper file
DeleteRecordFromObjectStore(dbConnection, DB_OBJSTORE_MODULES, sWasmURI).then(result => {
LoadWebAssemblyFromFile(dbConnection, sWasmURI, sWasmVersion);
});

}
else { // The cached record is the version we need...

// Have the module instantiated.
//
// NOTE: Unlike when we pass in the bytes to instantiate
// in the LoadWebAssemblyFromFile method below, we
// don't have a separate 'instance' and 'modules' object
// returned in this case since we started out with the
// module object. We're only passed back the instance in
// this case.
WebAssembly.instantiate(objRecord.WasmModule, g_importObject).then(instance =>
g_objModuleInstance = instance // Hold onto the module's instance so that we can reuse it
);

}

}, sErrorMsg => { // Error in GetRecordFromObjectStore...

// We weren't able to pull the module from cache (most
// likely because it doesn't exist yet - hasn't been cached
// yet). Log the error and then fetch the file.
console.log(sErrorMsg);
LoadWebAssemblyFromFile(dbConnection, sWasmURI, sWasmVersion);

});

}, sErrorMsg => { // Error in OpenDB...

// Log the error and then fetch the file (won't be able to
// cache it in this case because we don't have a database
// connection to work with)
console.log(sErrorMsg);
LoadWebAssemblyFromFile(null, sWasmURI, sWasmVersion);

});

}

// Called by indexeddb if the database was just created or if the
// database version was changed
function HandleUpgradeDB(evt) {
// Create the object store which will hold 3 properties:
// • WasmURI - (primary key) e.g. 'test.wasm'
// • WasmVersion - e.g. '1.0.1'
// • WasmModule - the compiled module
var dbConnection = evt.target.result;
dbConnection.createObjectStore(DB_OBJSTORE_MODULES, { keyPath: "WasmURI" });
}

function LoadWebAssemblyFromFile(dbConnection, sWasmURI, sWasmVersion) {
// Request the wasm file from the server and compile it...
fetch(sWasmURI).then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, g_importObject)
).then(results => {
// Hold onto the module's instance so that we can reuse it
g_objModuleInstance = results.instance;

// Only do the following if we have a database connection
// object (this method will be passed a null if we failed to load
// the module from cache due to an error when trying to open
// the database)
if (dbConnection !== null) {
// WARNING: Not all browsers that support WebAssembly
// also support the ability to store the module in IndexedDB
// (seems to work fine in Edge 16 and in Firefox but it
// doesn't work for me in Chrome 63)
try {
// Create the object we're about to store
var objRecord = { "WasmURI": sWasmURI, "WasmVersion": sWasmVersion, "WasmModule": results.module };

// Cache the compiled module so that we don't have to
// pull the file from the server again unless we change
// the module's version number.
SaveRecordToObjectStore(dbConnection, DB_OBJSTORE_MODULES, objRecord);
}
catch (ex) {
console.log(`Unable to save the WebAssembly module to IndexedDB: ${ex.message}`);
}
}
});
}

function OnClickTest() {
// Call the module's add method and display the results
var iResult = g_objModuleInstance.exports._add(1, 2);
alert(iResult.toString());
}
</script>
</body>
</html>

The following is the content of our IndexDB.js file:

// Helper methods to work with an IndexedDB database
//
// Note: IndexedDB methods are asynchronous. To make things a bit
// easier to work with for the calling code, I've added Promises.

function OpenDB(sDatabaseName, sDatabaseVersion, fncUpgradeDB) {
return new Promise(function (fncResolve, fncReject) {

// Make a request for the database to be opened
var dbRequest = indexedDB.open(sDatabaseName, sDatabaseVersion);

dbRequest.onerror = function (evt) { fncReject(`Error in OpenDB: ${evt.target.error}`); }

// Pass the database connection object to the resolve method of the
// promise
dbRequest.onsuccess = function (evt) { fncResolve(evt.target.result); }

// This event handler will only be called if we're creating the database
// for the first time or if we're upgrading the database to a new
// version (this will be triggered before the onsuccess event handler
// above if it does get called). Let the calling code handle upgrading
// the database if needed to keep this file as generic as possible.
dbRequest.onupgradeneeded = fncUpgradeDB;

});
}


// Helper method to simplify the code some
function GetObjectStore(dbConnection, sObjectStoreName, sTransactionMode) {
// Create a transation and, from the transaction, get the object store
// object
return dbConnection.transaction([sObjectStoreName], sTransactionMode).objectStore(sObjectStoreName);
}


function GetRecordFromObjectStore(dbConnection, sObjectStoreName, sRecordID) {
return new Promise(function (fncResolve, fncReject) {

// Request the record specified
var dbGetRequest = GetObjectStore(dbConnection, sObjectStoreName, "readonly").get(sRecordID);

dbGetRequest.onerror = function (evt) { fncReject(`Error in GetRecordFromObjectStore: ${evt.target.error}`); }

dbGetRequest.onsuccess = function (evt) {
// If we have a record then...(we have to check because there
// won't be a record if the database was just created)
var objRecord = evt.target.result;
if (objRecord) { fncResolve(objRecord); }
else { fncReject(`The record '${sRecordID}' was not found in the object store '${sObjectStoreName}'`); }
}

});
}


function DeleteRecordFromObjectStore(dbConnection, sObjectStoreName, sRecordID) {
return new Promise(function (fncResolve, fncReject) {

// Request the delete of the record specified
var dbDeleteRequest = GetObjectStore(dbConnection, sObjectStoreName, "readwrite").delete(sRecordID);

dbDeleteRequest.onerror = function (evt) { fncReject(`Error in DeleteRecordFromObjectStore: ${evt.target.error}`); }

dbDeleteRequest.onsuccess = function (evt) { fncResolve(); }

});
}


function SaveRecordToObjectStore(dbConnection, sObjectStoreName, objRecord) {

// Request the put of our record (if it doesn't already exist, it gets added. otherwise, it gets updated)
var dbPutRequest = GetObjectStore(dbConnection, sObjectStoreName, "readwrite").put(objRecord);

dbPutRequest.onerror = function (evt) { console.log(`Error in SaveToIndexedDB: ${evt.target.error}`); }

dbPutRequest.onsuccess = function (evt) { console.log(`Successfully stored the record`); }

}


The following is the C code and command line needed to turn the C code into a WebAssembly module for today's article:

int add(int x, int y) { return x + y; }

emcc test.c -s WASM=1 -s SIDE_MODULE=1 -O1 -o test.wasm


Summary

Even though we tried to keep the code as clean as possible, this article was a bit more involved because of everything that is involved when working with IndexedDB databases.

Because this article was focused around WebAssembly caching, we only dug into IndexedDB as deep as was needed.

Fortunately, I had the privilege of writing a DZone Refcard on HTML5 IndexedDB a little while ago that you're more than welcome to check out if you would like more information on the technology.


Edit made on Monday, January 1st, 2018: Changed the MIME Type from application/octet-stream to application/wasm after discovering the WebAssembly meeting notes from October 23rd, 2017 proposing the MIME Type be submitted to IANA to make it official.

Saturday, December 16, 2017

WebAssembly – Calling into JavaScript from bare bones C code


In my previous blog post, we explored the idea of creating a bare bones WebAssembly module with no Emscripten plumbing. In that article, we were able to call into the module from JavaScript but we didn't get into the reverse:

How does one call into JavaScript from a module?


Calling into JavaScript from a WebAssembly module

In this article we're going to try and get a WebAssembly module to call a method that's defined in our JavaScript.

In order to compile C code, when the method being used isn't in the source code, you need to define the method signature using the extern keyword as shown in the following example:

// Define the JavaScript method's signature that we're going to be calling.
extern void CallJS(int iVal);

// A method that the JavaScript will call into to trigger our code
// that will in turn call a JavaScript method passing along the value
// received.
void Test(int iVal){ CallJS(iVal); }

You can run the following command line to build the wasm file:

emcc test.c -s WASM=1 -s SIDE_MODULE=1 -O1 -o test.wasm

To define the method in our JavaScript, we just need to add it to the env object that is part of the main object that we pass as the 2nd parameter to the WebAssembly.instantiate method:

var importObject = {
'env': {
// ... (other properties/methods of this object)

'_CallJS': function(iVal){ alert("value received: " + iVal.toString()); }
}
};

Just like how we needed to add an underscore character before the method name when calling into the module from JavaScript, we also need to include an underscore before the method name here.

The following is the full HTML/JavaScript for our example module:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<input type="text" id="txtValue" />
<input type="button" value="Pass Value" onclick="PassValue();" />

<script type="text/javascript">
var gModule = null;

var importObject = {
'env': {
'memoryBase': 0,
'tableBase': 0,
'memory': new WebAssembly.Memory({initial: 256}),
'table': new WebAssembly.Table({initial: 0, element: 'anyfunc'}),

'_CallJS': function(iVal){ alert("value received: " + iVal.toString()); }
}
};

fetch('test.wasm').then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, importObject)
).then(results => {
gModule = results.instance; // Hold onto the module's instance so that we can reuse it
});

function PassValue(){
// Get the value from the textbox (convert the value from a string to an int)
var iVal = parseInt(document.getElementById("txtValue").value,10);

// Call the method in the module
gModule.exports._Test(iVal);
}
</script>
</body>
</html>

Thursday, December 14, 2017

WebAssembly – Using Emscripten to create a bare bones module


In my last blog post, An Introduction to WebAssembly, I showed you some of the basics of working with a WebAssembly module by using Emscripten.

This article is the result of some research and experiments to see if it’s possible to build a WebAssembly module using Emscripten but to not have any of the plumbing code.

For example, if we were to build the following C file using the following command line, the result would be an HTML file that is 101 KB, a JS file that is 80.2 KB, and a wasm file that is 9.4 KB!

#include <stdio.h>
#include "../emscripten/emscripten.h"

int main() { return 0; }

int EMSCRIPTEN_KEEPALIVE add(int x, int y) { return x + y; }

emcc test.c -s WASM=1 -s NO_EXIT_RUNTIME=1 -O1 -o hello.html


Having all of that plumbing is very convenient because it lets you start playing around with WebAssembly modules right away but what if we want just the bare minimum and will handle the HTML and JavaScript ourselves?

Fortunately, there is a way to tell Emscripten to output just the bare bones wasm file.

Let's first strip the C file down to just the bare minimum. In this case, we only want the add method:

int add(int x, int y) { return x + y; }

If we use the following command line, we will get just the wasm file and it’s only 202 bytes!

emcc test.c -s WASM=1 -s SIDE_MODULE=1 -O1 -o test.wasm

The SIDE_MODULE flag tells Emscripten to compile only our methods and nothing else which means you will also not have access to things like printf or malloc.

If not specified, the default optimization flag used is -O0 (capital letter o and the number 0) but that results in the following error being thrown when you try to load the module:

LinkError: import object field 'DYNAMICTOP_PTR' is not a Number

Adding any optimization flag other than -O0 will fix the issue so we went with -O1 (capital letter o and the number 1) for this example.

One thing to note, however, is that the O appears to be case sensitive. The various optimization flags that are available can be found here: https://kripken.github.io/emscripten-site/docs/optimizing/Optimizing-Code.html

We also need to specify the name of the output file in the command line because, if we don't, Emscripten will output the file with the name a.out.wasm.


Because we've decided not to use Emscripten's plumbing code, we need to write our own HTML and JavaScript. The following is some example HTML and JavaScript to load in the module:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<input type="button" value="test" onclick="javascript:OnClickTest();" />

<script type="text/javascript">
var gModule = null;

var importObject = {
'env': {
'memoryBase': 0,
'tableBase': 0,
'memory': new WebAssembly.Memory({initial: 256}),
'table': new WebAssembly.Table({initial: 0, element: 'anyfunc'})
}
};

fetch('test.wasm').then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, importObject)
).then(results => {
gModule = results.instance; // Hold onto the module's instance so that we can reuse it
});

function OnClickTest(){
alert(gModule.exports._add(1, 2));
}
</script>
</body>
</html>


One thing that you may have noticed that is different with our call to the C method, as compared to what we did in the previous blog post, is that we're not using Module.ccall or Module.cwrap. Those are Emscripten helper methods. Here, we're calling the C method directly.

Something else to be aware of here is that your JavaScript will need to include an underscore character before the method name. For example, in our case, our method is called add. When you call the add method in JavaScript you would use _add(1, 2); rather than add(1, 2);

Although this approach might not be a solution that will work in every situation, given that you don't have access to things like malloc, it might be a useful way of creating a helper library if you're doing things like number crunching and don't need all of the overhead that comes with Emscripten's plumbing.

Friday, November 10, 2017

An Introduction to WebAssembly


The concept behind WebAssembly isn't new and is based on work that was pioneered by Mozilla (asm.js) and Google (Native Client – NaCl and Portable Native Client – PNaCl).

One of WebAssembly's main goals is parity with asm.js so I'll give you a little background on that before we start digging into WebAssembly.

When I first heard of asm.js a few years ago I was excited. The ability to write code in C/C++ and have it compiled down into a special form of JavaScript that the browser could then run at near native speeds if it supported asm.js.

You don't typically write asm.js code by hand, it's usually created by a compiler.

The code starts off with the asm pragma statement ("use asm";) and then typing hints are included that allow JavaScript interpreters, that support asm.js, to know that they can use low-level CPU operations rather than the more expensive JavaScript operations.

For example, a | 0 is used to hint that the variable 'a' is a 32-bit integer. This works because a bitwise operation of zero doesn't change the original value so there are no side effects to doing this. Because there are no side effects to this, it can be used wherever it's required in the code to hint the type for either the return value or the parameters passed into a method as in the following example:

function AsmModule() {
"use asm";
return {
add: function(a, b) {
a = a | 0;
b = b | 0;
return (a + b) | 0;
}
}
}

The nice thing about asm.js is that, even if the browser doesn't support it, it would still run and you would get identical results since the code is still valid JavaScript. The only difference is that it would be slower compared to if the browser did support asm.js.

Being able to write code in C/C++ and have it compiled into a special form of JavaScript that is significantly faster than standard JavaScript is pretty cool but asm.js did have some disadvantages:
  • The extra type hints could result in very large asm.js files
  • Things still need to be parsed so a large file could be expensive on lower end devices like phones
  • asm.js needs to be valid JavaScript so adding new features is complex and would affect the JavaScript language itself as well


WebAssembly

To solve the issues of asm.js, the major browser venders got together and started working on a W3C standard and an MVP of WebAssembly that is already live in most browsers! The browsers that currently support WebAssembly are:

Firefox, Chrome, Opera, Edge 16, Safari 11, iOS Safari 11, Android browsers 56, Chrome for Android, and Firefox for Android!

It can be turned on in Edge 15 by turning on the browser's Experimental JavaScript Features flag.

WebAssembly, or wasm for short, is intended to be a portable bytecode that will be efficient for browsers to download and load. The bytecode is transmitted in a binary format and, due to how the modules are structured, things can be compiled by the browser in parallel speeding things up even further.

Once the binary has been compiled into executable machine code, the module is stateless and as a result can be explicitly cached in IndexedDB or even shared between windows and workers via postMessage calls.

WebAssembly is currently an MVP so not everything is there yet but it will eventually include both a binary notation, that compilers will produce, and a corresponding text notation for display in debuggers or development environments.


Emscripten

For the examples that follow, I'll be using Emscripten to compile C code into a wasm module. You can download Emscripten from the following location: https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html

On Windows it was simply a matter of unzipping the contents and then running some command line arguments.

I was getting errors when I first tried running a wasm module and it turned out that the version of Emscripten that came with the zip files wasn't recent enough.

You'll need git on your system in order to have the command line arguments build the latest version of the Emscripten compiler for you. The following command line downloaded git for me:

emsdk install git-1.9.4

Once you have the latest version of git on your system, run the command lines indicated on the download page to update, install, and activate Emscripten.

Note: When you run the 'activate latest' command line, you will probably want to include the --global flag.

Otherwise, the path variables are only remembered for the current command line window and you'll have to run the emsdk_env.bat file each time you open a command line window:

emsdk activate latest --global



Hello World

For the examples that follow, I simply create a text file named test.c and use notepad to adjust the text (you don't need an IDE for the examples I give you here).

As with any new programming technology, it's almost a requirement to start off with a hello world program so let's create a very basic hello world app using C. The following will simply write a string to the command line as soon as the module gets loaded:

#include <stdio.h>

int main()
{
printf("Hello World from C\n");
return 0;
}

To compile the code into a WebAssembly module, we need to run the following command line:

emcc test.c -s WASM=1 -o hello.html

-s WASM=1 specifies that we want a wasm module output

The nice thing about this tool is that it gives you all the JavaScript 'glue' needed allowing you to play with WebAssembly modules right away. As you get more experienced with the technology, you can customize it.

If you open the generated hello.html file in a browser, you'll see the Hello World from C text displayed in the textbox.


For the rest of the examples, I'm going to adjust the command line to generate a more minimal html template just to make things easier (less to scroll through when we edit the html file).

I've copied the emscripten.h and shell_minimal.html files into folders in the root directory where I'm creating my code files. For each code example, I've created a subfolder for the .c file I create and for the generated files just to keep each example separate which is why you'll see a relative path stepping back a folder in the following examples.

You can find the shell_minimal.html file in the emscripten src folder.

You can find the emscripten.h file in the emscripten system\include\emscripten folder.


Calling into a module from JavaScript

Let's take our code a step further and build a function that you can call from JavaScript.

First, let's add a function to our code called TestFunction that accepts an integer:

#include <stdio.h>
#include "../emscripten/emscripten.h"

int main()
{
printf("Hello World from C\n");
return 0;
}

void EMSCRIPTEN_KEEPALIVE TestFunction(int iVal) {
printf("TestFunction called...value passed in was: %i\n", iVal);
}

The EMSCRIPTEN_KEEPALIVE declaration adds our functions to the exported functions list so that they're seen by the JavaScript code.

Because we have a function we want to call in the WebAssembly, we don't want the runtime to shut down after the main method finishes executing so we're also going to include the NO_EXIT_RUNTIME flag.

Run the following to generate the new files:

emcc test.c -s WASM=1 -o hello2.html --shell-file ../html_template/shell_minimal.html -s NO_EXIT_RUNTIME=1

If you opened the html file in a browser at this point, you won't see anything other than the Hello World output because the JavaScript doesn't yet have the code to call TestFunction.

Open up the generated hello2.html file using a tool like notepad, scroll down to just before the opening Script tag, and add the following HTML:

<input type="text" id="txtValue" />
<input type="button" value="Pass Value" onclick="PassValue();" />

Scroll further down the html file and add the following just before the closing script tag (after the window.onerror method's code):

function PassValue(){
Module.ccall('TestFunction', // name of C function
null, //return type
['number'],//argument types
[ parseInt(document.getElementById("txtValue").value,10) ]);
}

Save the html file and then open it up in a browser.

If you type a number into the textbox next to the Pass Value button and then press the button you should see that value echoed back into the textbox.


In the example above, we used the ccall method which calls the module right away.

Another approach is that we can use the cwrap method to create a function pointer that can then be used multiple times. The JavaScript would look like this:

var fncTestFunction = Module.cwrap('TestFunction', null, ['number']);
fncTestFunction(1); //passing in an integer directly for this test
fncTestFunction(2); //passing in an integer directly for this test


Calling into JavaScript from a module using macros

Being able to talk to the WebAssembly from JavaScript is nice but what if you want to talk to JavaScript from the WebAssembly?

There are different ways that this can be achieved.

The simplest way is through macros like emscripten_run_script() or EM_ASM() which basically trigger a JavaScript eval statement.

Macros are not my recommended approach for production code especially if you're dealing with user supplied data but they could come in handy if you needed to do some quick debugging.

Note: You need to use single quotes in the macros. Double quotes will cause a syntax error that is not detected by the compiler.

To test out the EM_ASM macro, let's adjust TestFunction to simply call into JavaScript and display an alert:

#include <stdio.h>
#include "../emscripten/emscripten.h"

int main()
{
printf("Hello World from C\n");
return 0;
}

void EMSCRIPTEN_KEEPALIVE TestFunction(int iVal) {
printf("TestFunction called...value passed in was: %i\n", iVal);

EM_ASM(
alert('Test call from C to JS');
throw 'all done';
);
}

Run the following to generate the new files:

emcc test.c -s WASM=1 -o hello3.html --shell-file ../html_template/shell_minimal.html -s NO_EXIT_RUNTIME=1

Open up the hello3.html file that was generated, scroll down to just before the opening Script tag, and add the following HTML:

<input type="text" id="txtValue" />
<input type="button" value="Pass Value" onclick="PassValue();" />

Scroll further down the html file and add the following just before the closing script tag (after the window.onerror method's code):

function PassValue(){
Module.ccall('TestFunction', // name of C function
null, //return type
['number'], //argument types
[ parseInt(document.getElementById("txtValue").value,10) ]);
}

Save the html file and then open it up in a browser. If you type a number into the textbox next to the Pass Value button and then press the button you will see that value echoed back into the textbox but you'll also see an alert displayed.


Calling into JavaScript from a module using function pointers

In the previous example we used a macro to call into the JavaScript code but that's generally taboo, especially if you have user supplied data, since it uses eval in the background.

The better approach, in my opinion, is to pass a function pointer to the WebAssembly module and have the C code call into that.

In the JavaScript code, you can use Runtime.addFunction to return an integer value that represents a function pointer. You can then pass that integer to the C code which can be used as a function pointer.

When using Runtime.addFunction, there is a backing array where these functions are stored. The array size must be explicitly set, which can be done via a compile-time setting: RESERVED_FUNCTION_POINTERS.

Let's adjust our code by getting rid of TestFunction and adding in a new function called CallFunctionPointer that simply calls the function pointer that was specified:

#include <stdio.h>
#include "../emscripten/emscripten.h"

int main(){
printf("Hello World from C\n");
return 0;
}

void EMSCRIPTEN_KEEPALIVE CallFunctionPointer(void(*f)(void)){
(*f)();
}

Run the following to generate the new files and indicate that we will have 1 function pointer:

emcc test.c -s WASM=1 -o hello4.html --shell-file ../html_template/shell_minimal.html -s NO_EXIT_RUNTIME=1 -s RESERVED_FUNCTION_POINTERS=1

Open up the hello4.html file that was generated, scroll down to just before the opening Script tag, and add the following HTML:

<input type="button" value="Test Pointer" onclick="TestPointer();" />

Scroll further down the html file and add the following just before the closing script tag (after the window.onerror method's code):

function TestPointer(){
// Create an anonymous function that will be called by the C code
var pointer = Runtime.addFunction(function() { alert('I was called from C!'); });

// Call the C code passing in the pointer reference
Module.ccall('CallFunctionPointer', null, ['number'], [pointer]);

// Remove the function pointer from the array
Runtime.removeFunction(pointer);
}

Save the html file and then open it up in a browser. If you press the Test Pointer button you will see an alert displayed.


Current Limitations

Like with JavaScript, WebAssembly is specified to be run in a safe, sandboxed execution environment which means it will enforce the browser's same-origin and permission policies too.

WebAssembly is currently an MVP which means there are a number of things still missing. For example, at the moment there is no direct DOM access from the assembly which means you will have to call into the JavaScript code if you need to update the UI.


Future Improvements

The browser makers are pushing ahead with this technology (for example, Google's Native Client has been depreciated in favor of this) so I expect to see improvements start showing up.

The following are some of the improvements that browser makers have identified:
  • Faster function calls between JavaScript and WebAssembly
  • You won't notice this overhead if you're passing a single large task off to the WebAssembly module. But, if you have lots of back-and-forth between the module and JavaScript, then this overhead becomes noticeable apparently.
  • Faster load times
  • The browser makers had to make trade-offs between fast load times and optimized code so there are more improvements that can be made here.
  • Working directly with the DOM
  • Exception handling
  • Better tooling support for things like debugging
  • Garbage collection which will make it easier for some languages like C# to target WebAssembly too