9 min read

In this tutorial, we will dig into the elements that correspond to the official specifications created by the WebAssembly Working Group. We will examine the Wat and the binary format in greater detail to gain a better understanding of how they relate to modules.

This article is an excerpt from a book written by Mike Rourke titled Learn WebAssembly. In this book, you will learn how to build web applications with native performance using Wasm and C/C++<mark.

Common structure and abstract syntax

Before getting into the nuts and bolts of these formats, it’s worth mentioning how these are related within the Core Specification. The following diagram is a visual representation of the table of contents (with some sections excluded for clarity):

Core Specification table of contents

As you can see, the Text Format and Binary Format sections contain subsections for Values, Types, Instructions, and Modules that correlate with the Structure section. Consequently, much of what we cover in the next section for the text format have direct corollaries with the binary format. With that in mind, let’s dive into the text format.

Wat

The Text Format section of the Core Specification provides technical descriptions for common language concepts such as values, types, and instructions. These are important concepts to know and understand if you’re planning on building tooling for WebAssembly, but not necessary if you just plan on using it in your applications. That being said, the text format is an important part of WebAssembly, so there are concepts you should be aware of. In this section, we will dig into some of the details of the text format and highlight important points from the Core Specification.

Definitions and S-expressions

To understand Wat, let’s start with the first sentence of the description taken directly from the WebAssembly Core Specification:

“The textual format for WebAssembly modules is a rendering of their abstract syntax into S-expressions.”

So what are symbolic expressions (S-expressions)? S-expressions are notations for nested list (tree-structured) data. Essentially, they provide a simple and elegant way to represent list-based data in textual form. To understand how textual representations of nested lists map to a tree structure, let’s extrapolate the tree structure from an HTML page. The following example contains a simple HTML page and the corresponding tree structure diagram.

A simple HTML page:

Simple html page

The corresponding tree structure is:

A tree structure diagram for an HTML page

Even if you’ve never seen a tree structure before, it’s still clear to see how the HTML maps to the tree in terms of structure and hierarchy. Mapping HTML elements is relatively simple because it’s a markup language with well-defined tags and no actual logic.

Wat represents modules that can have multiple functions with varying parameters. To demonstrate the relationship between source code, Wat, and the corresponding tree structure, let’s start with a simple C function that adds 2 to the number that is passed in as a parameter:

Here is a C function that adds 2 to the num argument passed in and returns the result:

int addTwo(int num) {
    return num + 2;
}

Converting the addTwo function to valid Wat produces this result:

(module
  (table 0 anyfunc)
  (memory $0 1)
  (export "memory" (memory $0))
  (export "addTwo" (func $addTwo))
  (func $addTwo (; 0 ;) (param $0 i32) (result i32)
    (i32.add
      (get_local $0)
      (i32.const 2)
    )
  )
)

The Structure section defines each of these concepts in the context of an abstract syntax. The Text Format section of the specification corresponds with these concepts as well, and you can see them defined by their keywords in the preceding snippet (func, memory, table).

Tree Structure:

A tree structure diagram for Wat

The entire tree would be too large to fit on a page, so this diagram is limited to the first five lines of the Wat source text. Each filled-in dot represents a list node (or the contents of a set of parentheses). As you can see, code written in s-expressions can be clearly and concisely expressed in a tree structure, which is why s-expressions were chosen for WebAssembly’s text format.

Values, types, and instructions

Although detailed coverage of the Text Format section of the Core Specification is out of the scope of this text, it’s worth demonstrating how some of the language concepts map to the corresponding Wat. The following diagram demonstrates these mappings in a sample Wat snippet. The C code that this was compiled from represents a function that takes a word as a parameter and returns the square root of the character count:

Wat example with language concept details

If you intend on writing or editing Wat, note that it supports block and line comments. The instructions are split up into blocks and consist of setting and getting memory associated with variables with valid types. You are able to control the flow of logic using if statements and loops are supported using the loop keyword.

Role in the development process

The text format allows for the representation of a binary Wasm module in textual form. This has some profound implications with regard to the ease of development and debugging. Having a textual representation of a WebAssembly module allows developers to view the source of a loaded module in a browser, which eliminates the black-box issues that inhibited the adoption of NaCl. It also allows for tooling to be built around troubleshooting modules. The official website describes the use cases that drove the design of the text format:

• View Source on a WebAssembly module, thus fitting into the Web (where every source can be viewed) in a natural way.

• Presentation in browser development tools when source maps aren’t present (which is necessarily the case with the Minimum Viable Product (MVP)).

• Writing WebAssembly code directly for reasons including pedagogical, experimental, debugging, optimization, and testing of the spec itself.

The last item in the list reflects that the text format isn’t intended to be written by hand in the course of normal development, but rather generated from a tool like Emscripten. You probably won’t see or manipulate any .wat files when you’re generating modules, but you may be viewing them in a debugging context.

Not only is the text format valuable with regards to debugging, but having this intermediate format reduces the amount of reliance on a single tool for compilation. Several different tools currently exist to consume and emit this s-expression syntax, some of which are used by Emscripten to compile your code down to a .wasm file.

Binary format and the module file (Wasm)

The Binary Format section of the Core Specification provides the same level of detail with regard to language concepts as the Text format section. In this section, we will briefly cover some high-level details about the binary format and discuss the various sections that make up a Wasm module.

Definition and module overview

The binary format is defined as a dense linear encoding of the abstract syntax. Without getting too technical, that essentially means it’s an efficient form of binary that allows for fast decoding, small file size, and reduced memory usage. The file representation of the binary format is a .wasm file.

The ValuesTypes, and Instructions subsections of the Core Specification for the binary format correlate directly to the Text Format section. Each of these concepts is covered in the context of encoding. For example, according to the specification, the Integer types are encoded using the LEB128 variable-length integer encoding, in either unsigned or signed variant. These are important details to know if you wish to develop tooling for WebAssembly, but not necessary if you just plan on using it on your website.

The Structure, Binary Format, and Text Format (wat) sections of the Core Specification have a Module subsection. We didn’t cover aspects of the module in the previous section because it’s more prudent to describe them in the context of a binary. The official WebAssembly site offers the following description for a module:

“The distributable, loadable, and executable unit of code in WebAssembly is called a module. At runtime, a module can be instantiated with a set of import values to produce an instance, which is an immutable tuple referencing all the state accessible to the running module.”

Module sections

A module is made up of several sections, some of which you’ll be interacting with through the JavaScript API:

  • Imports (import) are elements that can be accessed within the module and can be one of the following:
    • Function, which can be called inside the module using the call operator
    • Global, which can be accessed inside the module via the global operators
    • Linear Memory, which can be accessed inside the module via the memory operators
    • Table, which can be accessed inside the module using call_indirect
  • Exports (export) are elements that can be accessed by the consuming API (that is, called by a JavaScript function)
  • Module start function (start) is called after the module instance is initialized
  • Global (global) contains the internal definition of global variables
  • Linear memory (memory) contains the internal definition of linear memory with an initial memory size and optional maximum size
  • Data (data) contains an array of data segments which specify the initial contents of fixed ranges of a given memory
  • Table (table) is a linear memory whose elements are opaque values of a particular table element type:
    • In the MVP, its primary purpose is to implement indirect function calls in C/C++
  • Elements (elements) is a section that allows a module to initialize the elements of any import or internally defined table with any other definition in the module
  • Function and code:
    • The function section declares the signatures of each internal function defined in the module
    • The code section contains the function body of each function declared by the function section

Some of the keywords (import, export, and so on) should look familiar; they’re present in the contents of the Wat file in the previous section. WebAssembly’s components follow a logical mapping that directly correspond to the APIs  (for example, you pass a memory and table instance into JavaScript’s WebAssembly.instantiate() function). Your primary interaction with a module in binary format will be through these APIs.

In this tutorial, we looked at the WebAssembly modules Wat and Wasm. We covered Wat definitions, values, types, instructions, and its role. We looked at Wasm overview and its module sections. To know more about another element of WebAssembly, the JavaScript API and build applications on WebAssembly check out the book Learn WebAssembly.

Read next

How has Rust and WebAssembly evolved in 2018

WebAssembly – Trick or Treat?

Mozilla shares plans to bring desktop applications, games to WebAssembly and make deeper inroads for the future web

Data science enthusiast. Cycling, music, food, movies. Likes FPS and strategy games.