Understand WebAssembly Text Format : From WTF to WAT
Tags: webdev, webassembly, beginners, javascript
Published: 2020-01-24 18:57:10

WebAssembly enables compiling various languages into binary that runs on JavaScript engine. The compiled WebAssembly binary is size and load time efficient. The binary is optimised at different levels. If you are wondering how to reduce your binary size refer 👇

{% link https://dev.to/sendilkumarn/increase-rust-and-webassembly-performance-382h %} 


The WebAssembly binary module is filled with opcode in hexadecimal format. This makes it nearly impossible for us to read and contextually understand what is happening in a WebAssembly Module. 

For most of us minified and transpile(d) JavaScript is very difficult to read. With the help of sourcemap, browsers show the source that makes the JavaScript readable and easily debuggable. 

{% github mozilla/source-map %}

Similarly, for WebAssembly, it is nearly impossible for us to understand/ read and infer/debug the compiled, optimised binary code. We have WebAssembly Text Format for representing WebAssembly binary code into the human-readable way.

---

Check out my book on Rust and WebAssembly [here](https://sendilkumarn.com/wasm-book)

---


## WebAssembly Text Format

WebAssembly Text Format (or) WAST provides a way to represent the binaries into an S-Expression. This makes it (slightly) easy for us to understand, debug, and evaluate the WebAssembly module.

{% twitter 1215818405523025920 %}

Some text editors use the WebAssembly Text Format to show the WebAssembly module contents. Browsers or the Node environment use the WebAssembly Text Format to debug (along with source map).

The basic WebAssembly Module is

```bash
00 61 73 6d 01 00 00 00  ; Magic Header ; Version
```
The `WebAssembly magic header` (that translates into \0asm ) followed by the version that it currently supports `1`.

The textual representation of the above binary module is

```bash
(module )
```

The `module` is the basic building block of WebAssembly Module. All the contents of a WebAssembly Module live inside the module segment.

> Does this expression look familiar?
> You ever worked with [LISP](https://en.wikipedia.org/wiki/Lisp_(programming_language)) (or languages that are inspired by LISP) then it will look very familiar.
> The expression is called the "s-expression".
> The expressions are a simplified form of `XML`. They are concise and don't have much of boilerplate things like `XML`.
> They are commonly used in defining a nested list or structured tree. Many research papers on tree-based data structure use this notation to show it.

In the [previous post](https://sendilkumarn.com/blog/wasm-sections/), we saw the structure of WebAssembly module in binary format. For example, each section starts with specified `section id`. In WebAssembly Text Format, this `section id` is represented with a `name`. The name provides better readability. The syntax for `function` expression in WebAssembly Text Format is as follows:

```clojure
(func <name>? <func_type> <local>* <inst>* )
```

That is, a simple add function is defined in WebAssembly Text Format:

```clojure
(func $add (param $lhs i32) (param $rhs i32) (result i32)
    get_local $lhs
    get_local $rhs
    i32.add)
```

The above code specifies a function. The entire block is wrapped inside the parenthesis.

The function block starts with a `func` keyword. Then an optional identifier. The identifier can be a name or a number. The name is used as a reference and better readability.

> Note that all the name, both the function name and the parameter's name, have been named with a `$` prefix. In the binary format, this will be the index number of the segment inside its segment group.

Followed by the function name, we have the type signature. For add function, we have two numbers as input parameters namely `$lhs` and `$rhs`. Both of them are of the type `i32`. The `param` keyword denotes the `parameter`.

Then we define the result of the function with its block. The result has a `result` keyword followed by the type of the result `i32`.

> In the binary format, the parameters and results are defined via the type section. But in the text format for brevity and easy to understand we will define it in every function.

Then we have a set of instructions.

The first instruction `get_local` gets the local value of `$lhs`. Then we fetch the local value of `$rhs`. Then we add them both with `i32.add` instruction.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/chy2n127g26b2zug5ubf.gif)

### So how does it work?

We have mentioned that the WebAssembly is executed as a `stack machine`. That is the instructions either push or pop the data (in our case only numbers) in the stack.

When a function is called, it creates an empty value stack, control-flow stack, locals vector.

* The value stack is where the values are stored and loaded
* The control-flow stack that holds the information about the label of instructions (including branching instructions), the limit size, return type signature.
* The locals' vector hold all the local variable definitions.

When the `get_local $lhs` instruction is executed, it gets the value from the locals' vector and returns the value. Similarly for `get_local $rhs`.

Then when the `i32.add` instruction is called. It performs an add operation and returns the result.

If we want to export this function to the outside world then we can add an export block.

```bash
(export <name in which we have to export> (func <function reference>))
```

To export the add function.

```bash
(export "add" (func $add))
```

The keyword for the exporting a function is `export`. Then we define the `name` of the function exported. In our example, we are exporting the add function with the name "add".

Then we add a block to refer to the function. With a `func` keyword and followed by the `identifier` for the function.

> Note the name is an optional value in the function section. If the name is not specified, the index of the function is used.

Both the `function` and `export` section is wrapped inside the `module` section.

```clojure
(module
    (func $add (param $lhs i32) (param $rhs i32) (result i32)
        get_local $lhs
        get_local $rhs
        i32.add)
    (export "add" (func $add))
)
```

The above is a valid WebAssembly module. Congratulations you created your first WebAssembly module. Imagine it as a tree structure. With the module as its root and both function and export are its children.

Well `Add` is boring let us try to write something more complex than `add`.

---

## Fibonacci Series generator

This is a simple recursive Fibonacci series generator in `C`.

```c
# Sample code in C
int fib(n) {
    if (n <= 1)
        return 1;
    else
        return fib(n-1)+ fib(n-2);
}
```

Let us convert this into WebAssembly Text Format.

The function is defined using `func` block along with its type signature.

```clojure
(func $fib (param $n i32) (result i32)
    ...
)
```

So here the `fib` function takes in a number `n` as a parameter and returns a number. The function definition follows the same signature as we have in `C`.

Similar to the add example, we define the parameter with a `param` keyword followed by an optional name (`$n`) and the type of the variable.

The return type is specified with `result` block. The `result` block contains `result` keyword followed by the `return` type.

The WebAssembly does not have in-memory. To handle temporary variables, it has to assign the temporary variables to value and push it into the stack and then retrieve it.

So for checking `n<=1` we have to first create a local variable `$tmp`. To create a local variable use the `local` block `(local $tmp i32)`.

```clojure
(local $tmp i32)
i32.const 1
set_local $tmp
```
> `(local $tmp i32)` is not an instruction. It is part of the function declaration.

Then we create a constant 1 using `i32.const 1` instruction.

> `i32.const 1` returns the value provided.

We then assign the value into the `$tmp` variable using `set_local $tmp`.
The `set_local` instruction modifies the value in the locals' vector. At the end of execution, the `$tmp` is `1`.

> To create a local variable, first, we have to define the variable and then value, finally push the value.


```clojure
(func $fib (param $n i32) (result i32)
   (local $tmp i32)
    i32.const 1
    set_local $tmp
    .... ; the block of code goes in here
    get_local $tmp
)
```

We return the `$tmp` as the output. The `get_local` instruction gets the value and returns it as a result.

---

## What is in the block?

> The WebAssembly stack machine is restricted to structured control flow and structure use of a stack. The structured control flow provides simple and size efficient binary encoding and compilation.

Block is a part of WebAssembly Module that creates a new entry into the control-flow stack. Imagine, the block creates a new boundary and operates within the boundary and returns a value.

In the above `fib` function, we are missing the actual Fibonacci implementation. We create a block and define the Fibonacci calculation inside it. A block is defined with a keyword `block` followed by a name to identify the block. i.e.,

```clojure
block $block
...
end
```

The `end` specifies the end of the block. All the `block` entry should have an `end` instruction.

In a stack machine, the following instructions are made to check the if condition:

```clojure
get_local $n
i32.const 2
i32.lt_s
br_if $block
```

The first instruction returns the value of `$n` from the local vector. The next instruction returns the value `2` to the stack. The instruction `i32.lt_s` checks for less than condition and returns the output.

> why lt_s, because it is less than a signed integer. For unsigned integer, we can use lt_u.

The `br_if` instruction operates based on `i32.lt_s` result. When it is evaluated `false`, the loop continues. When it is evaluated true, it pops the block from the control flow and returns the value of the operands. The `br_if block` closes over the block `$block` segment.

> Note lt_s returns i32.

---

## Loop

The loop is a special branching instruction. It creates a new label and pushes an entry to the control-flow stack.

WebAssembly Text Format has the `loop` instruction to do the looping:

```clojure
i32.const 1
set_local $tmp
loop $loop
.....
end
```

Assign a value to the `$tmp` to 1 and start the loop. The loop segment starts with a loop keyword followed by the name of the loop (`$loop`). The loop is terminated with an `end` instruction.

---

## Function Calls

Inside the loop, we have to call the fib function for `n-1` and `n-2` values. To call a function use `call <function name or index>` instruction.

We will have to first pop the value of $n and then reduce 1 from it. Then call the Fibonacci function.

```clojure
; inside the loop
get_local $n
i32.const -1
i32.add
call $fib
```

The `call $fib` returns an `i32`. We will add this result to the `$tmp` and then set the value of `$tmp` to the new value.

```clojure
get_local $tmp
i32.add
set_local $tmp
```

Execute similarly for `n-2`.

```clojure
get_local $n
i32.const -2
i32.add
```

Then we run the loop until the value of `$n` is greater than `1`. If the condition is okay, the loop continues.

```clojure
tee_local $n
i32.const 1
i32.gt_s
br_if $loop
```

> The tee_local is similar to set_local, but additionally, it returns the value.

Once all the looping is done return the value `$tmp`.

```clojure
get_local $tmp
```

The final fibonacci series using WebAssembly Text Format is:

```clojure
(func $fib (export "fib") (param $n i32) (result i32)
    (local $tmp i32)
    i32.const 1
    set_local $tmp
    block $B0
      get_local $n
      i32.const 2
      i32.lt_s
      br_if $B0
      i32.const 1
      set_local $tmp
      loop $L1
        get_local $n
        i32.const -1
        i32.add
        call $fib
        get_local $tmp
        i32.add
        set_local $tmp
        get_local $n
        i32.const -2
        i32.add
        tee_local $n
        i32.const 1
        i32.gt_s
        br_if $L1
      end
    end
    get_local $tmp)
```

---

## Explore further

[Raw WebAssembly - Das Surma](https://dassur.ma/things/raw-wasm/)

[WebAssembly Text Reference](https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md)

[Relooper Algorithm](https://github.com/kripken/emscripten/raw/master/docs/paper.pdf)

{% twitter 1169277894402695176 %}

---

If you have enjoyed the post, then you might like my book on Rust and WebAssembly. Check them out [here](https://sendilkumarn.com/wasm-book)

---
---


Discussions [🐦 Twitter](https://twitter.com/sendilkumarn) // [💻 GitHub](https://github.com/sendilkumarn) // [✍️ Blog](https://sendilkumarn.com/blog) // [🔸 Hacker Rank](https://news.ycombinator.com/item?id=22146275)

If you like this article, please leave a like or a comment. ❤️