Writing WebAssembly modules

A WebAssembly module is similar to a JavaScript module. We need to explicitly import anything we need from other WebAssembly/JavaScript modules. Whatever we write in our WebAssembly module can't be found by another WebAssembly module unless we explicitly export it. We can think of it as a JavaScript module  it is a sandboxed environment.

Let's start off with the most basic and useless version of a WebAssembly module:

(module)

With this, we can go to the command line and run the following command:

> wat2wasm useless.wat

This preceding code will spit out a file with the wasm extension. This is what we need to pass into the web browser to run WebAssembly. All this shows us is that WebAssembly, just like ESNext for JavaScript, wants to have everything declared in modules. It is easier to think of it like so, which is what happens when loading in JavaScript:

<script type="module"></script>

This means that all of the code loaded in the WebAssembly context can't spill into other WebAssembly modules that we set. Now, to load this wasm file into our browser, we need to utilize the static server that we utilized in Chapter 9, Practical Example - Building a Static Server.

Once you've loaded this up, follow these steps:

  1. Create a basic index.html file that looks as follows:
<!DOCTYPE html>
<html>
<head></head>
<body>
<script type="text/javascript">
</script>
</body>
</html>
  1. Inside our script element, we will add the following code to load the module:
WebAssembly.instantiateStreaming(fetch('useless.wasm')).then(obj => {
// nothing here
});

We have loaded our first WebAssembly module into the browser. The API is heavily promise-based and due to this, we need to utilize the Fetch interface. Once we've fetched the object, it's loaded in the WebAssembly context for the browser, which means this object is available to us. This is the WebAssembly module that we have just loaded up!

Let's go ahead and make a WebAssembly module that is a bit more useful. Let's take in two numbers and add them together. Follow these steps:

  1. Create a file called math.wat.
  2. Put the following code into the file:
(module
(func $add (param $p1 i32) (param $p2 i32) (result i32)
local.get $p1
local.get $p2
i32.add
)
(export "add" (func $add))
)
  1. Compile this by running wat2wasm math.wat.
  2. Load the new wasm file into the browser and add the following to the then body:
console.log(obj.instance.exports.add(100,200));
  1. Make sure that the static server is running by going into the folder and running the static-server command.
For those that have skipped ahead to this chapter, you can install a static server by running npm install -g static-server. This will install this static server globally. Then, all we need to do is run static-server in the folder that we want to deploy files from. Now that we've done this, we can hit our index.html file by going to localhost:9080.

If we launch our browser, go to localhost:9080, and open up the console, we will see that the number 300 has been printed out. We have just written our first accessible WebAssembly module!

Let's go over some of the concepts we covered in the preceding code. First, we defined a function. We stated that the name of this function is $add (all variables start with a dollar sign in WebAssembly). Then, we stated that it will take two parameters that we called $p1 and $p2. Finally, we will output a result; that is, a 32-bit integer.

Now, we take the two parameters and store them on our stack. Finally, we add them together and use this as a result. Remember at the beginning of this chapter when we talked about how programs are stacks? This showcases the exact same concept. We loaded our two variables onto the stack. We popped them off so that we could use them in the add function, which put a new value onto the stack. Finally, we popped that value off of the stack and returned it to the main function body; in our case, the module.

Next, we exported the function so that our JavaScript code has access to it. This makes sure that our WebAssembly code is held in our sandbox, just like we want it to be. Now, as we mentioned previously, the object that is returned is the WebAssembly context. We grab the instance and look at the exports that are available. In our case, this is the add function, which we can now utilize in our JavaScript code.

Now that we have learned how we can export WebAssembly modules into the JavaScript context, you may be wondering if we can load JavaScript functions into the WebAssembly context. We can! Let's go ahead and add the following code to our index.html file:

const add = function(p1, p2) {
return p1 + p2;
}
const importObject = { math : { add : add }};
WebAssembly.instantiateStreaming(fetch('math.wasm'), importObject).then(obj => {
console.log(obj.instance.exports.add(100, 200));
console.log(obj.instance.exports.add2(100, 200));
});

Here, we loaded in the add function we took from the JavaScript context and created an associated function that has the same function signature that our add function has in JavaScript. Now, we create a new add function called $add2 that has a similar signature. We put our two parameters onto the stack and use the new call instruction. This instruction allows us to call other functions that have been declared in our context:

(func $add2 (param $p1 i32) (param $p2 i32) (result i32)
local.get $p1
local.get $p2
call $externalAdd
)

Finally, we export this function, just like we did with the other add function. Now, if we compile our code, go back into our browser, and reload the page, we will see that the number 300 is printed out twice.

Now, we know how to use WebAssembly functions in JavaScript and how to load JavaScript functions into WebAssembly. We are close to being able to write a program famous for being asked in an JavaScript coding interview. Before we do this, though, we will need to look at heap space and utilizing memory between JavaScript and WebAssembly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.187.233