This is the 1st article in a 3-part series:
- Memory in WebAssembly (and why it’s safer than you think)
- WebAssembly table imports… what are they?
WebAssembly is a new way of running code on the web. With it, you can write modules in languages like C or C++ and run them in the browser.
Currently modules can’t run on their own, though. This is expected to change as ES module support comes to browsers. Once that’s in place, WebAssembly modules will likely be loaded in the same way as other ES modules, e.g. using
For example, let’s look at how React would instantiate a WebAssembly module. (You can learn more in this video about how React could use WebAssembly.)
When the user loads the page, it would start in the same way.
The browser would download the JS file. In addition, a .wasm file would be fetched. That contains the WebAssembly code, which is binary.
To do that, it will call
Let’s take a closer look at this.
The first thing we pass into
WebAssembly.instantiate is going to be the binary code that we got in that .wasm file. That’s the module code.
So we extract the binary into a buffer, and then pass it in.
The engine will start compiling the module code down to something that is specific to the machine that it’s running on.
WebAssembly.instantiate returns is a promise.
This lets the main thread get back to its other work. The main thread knows that once the compiler is finished compiling this module, it will be notified by the promise. That promise will give it the instance.
But the compiled module is not the only thing needed to create the instance. I think of the module as kind of like an instruction book.
The instance is like a person who’s trying to make something with the instruction book. In order to make that thing, they also need raw materials. They need things that they can work with.
This is where the second parameter to
WebAssembly.instantiate comes in. That is the imports object.
I think of the imports object as a box of those raw materials, like you would get from IKEA. The instance uses these raw materials—these imports—to build a thing, as directed by the instructions. Just as an instruction manual expects a certain set of raw materials, each module expects a specific set of imports.
So when you are instantiating a module, you pass it an imports object that has those imports attached to it. Each import can be one of these four kinds of imports:
- function closures
It can have values, which are basically global variables. The only types that WebAssembly supports right now are integers and floats, so values have to be one of those two types. That will change as more types are added in the WebAssembly spec.
This is particularly useful because in the current version of WebAssembly, you can’t call DOM methods directly. Direct DOM access is on the WebAssembly roadmap, but not part of the spec yet.
Another kind of import is the memory object. This object makes it possible for WebAssembly code to emulate manual memory management. The concept of the memory object confuses people, so I‘ve gone into a little bit more depth in another article, the next post in this series.
The final type of import is related to security as well. It’s called a table. It makes it possible for you to use something called function pointers. Again, this is kind of complicated, so I explain it in the third part of this series.
Those are the different kinds of imports that you can equip your instance with.
To return the instance, the promise returned from
WebAssembly.instantiate is resolved. It contains two things: the instance and, separately, the compiled module.
The nice thing about having the compiled module is that you can spin up other instances of the same module quickly. All you do is pass the module in as the
source parameter. The module itself doesn’t have any state (that’s all attached to the instance). That means that instances can share the compiled module code.
Your instance is now fully equipped and ready to go. It has its instruction manual, which is the compiled code, and all of its imports. You can now call its methods.
In the next two articles, we’ll dig deeper into the memory import and the table import.
About Lin Clark
Lin works in Advanced Development at Mozilla, with a focus on Rust and WebAssembly.