wasm-encoder
2021-06-30
Library for serializing WebAssembly modules to binary .wasm files
Upstream URL
Author
Alexander Gutev <alex.gutev@mail.bg>, Alexander Gutev
License
MIT
= WASM-ENCODER =
:AUTHOR: Alexander Gutev
:EMAIL: <alex.gutev@mail.bg>
:toc: preamble
:toclevels: 4
:icons: font
:idprefix:
ifdef::env-github[]
:tip-caption: :bulb:
:note-caption: :information_source:
:caution-caption: :fire:
:important-caption: :exclamation:
:warning-caption: :warning:
endif::[]
This is a simple library for serializing a representation of
WebAssembly modules to the binary wasm format.
== Documentation ==
[[value_types]]
=== Value Types ===
The value types of various entities, such as global variables,
function arguments and return values, local and global variables, are
identified by the following symbols:
.Numeric Types
`I32`:: 32-bit integer
`I64`:: 64-bit integer
`F32`:: 32-bit single precision floating point value
`F64`:: 64-bit double precision floating point value
.Reference Types
`FUNCREF`:: Function reference
`EXTERNREF`:: All reference objects that can be passed to WebAssembly
NOTE: A symbol is considered equivalent to one of the above if its
symbol name is equivalent, regardless of its package. Thus you don't
have to import `I32`, etc from the `WASM-ENCODER` package.
=== Instructions ===
A WebAssembly instruction is represented by a symbol of which the
symbol name is equal to the instruction's mnemonic. Any symbol, in any
package, with a symbol name that is equal to a WebAssembly instruction
mnemonic can be used.
Instructions which accept static options are represented by a list in
which the first element (the `CAR`) is the instruction mnemonic and
the remaining elements are the options. The interpretation of the
options depends on the instruction.
==== Branch Instructions ====
The `BR` and `BR_IF` branch instructions each take a single option, an
unsigned integer interpreted as the index of the block which is the
branch target.
The `BR_TABLE` takes a variable number of options, where each option
is an unsigned integer, interpreted as a block index.
.Examples
--------------------------------------------------
(BR 0) ;; Branch to block 0
(BR_IF 2) ;; Branch to block 2
(BR_TABLE 0 1 2)
--------------------------------------------------
==== Call Instructions ====
The `CALL` instruction takes a single option, an unsigned integer
interpreted as the index of the function being called.
The `CALL_INDIRECT` instruction takes a single option, an unsigned
integer interpreted as the index, within the type section, of the
function's type signature.
.Examples
--------------------------------------------------
(CALL 5) ;; Call function 5
(CALL_INDIRECT 2) ;; Indirect call to a function with type signature index 2
--------------------------------------------------
==== Select Instruction ====
The select instruction takes an optional list of type identifier which
represent the value types of the operands to be selected. If there is
more than one type specifier then there is more than one value per
operand.
.Example
--------------------------------------------------
(select f32 f64)
--------------------------------------------------
In the above example `SELECT` consumes, off the stack, two operands,
following the condition, each consisting of two values the first being
an `F32` and the second being an `F64`. The two values of the result
operand, of type `F32` and `F64`, are pushed back onto the stack.
If `SELECT` is not given the type identifier of it's operand values,
the operands must be of a numeric type.
NOTE: In the current version of WebAssembly `SELECT` may only specify
a single value type, for a single value per operand. This library
supports `SELECT` with multiple operand value types.
==== Local and Global Variable Instructions ====
The instructions for retrieving/setting the value of a local/global
variable, each take a single options, an unsigned integer interpreted
as the local/global variable index.
- `LOCAL.GET`
- `LOCAL.SET`
- `LOCAL.TEE`
- `GLOBAL.GET`
- `GLOBAL.SET`
==== Memory Instructions ====
Memory load/store instructions take an optional list specifying the
expected alignment and offset. These operands take the following form:
--------------------------------------------------
(I32.STORE (ALIGN a) (OFFSET o)) ;; Alignment = a, Offset = o
--------------------------------------------------
The alignment option is a list of two elements where the first element
is a symbol, with name `ALIGN`, and the second element is an unsigned
integer specifying the alignment as a power of two. If the alignment
option is omitted a default alignment of `2` is assumed.
The offset option is a list of two elements where the first element is
a symbol, with name `OFFSET`, and the second element is an unsigned
integer specifying the offset. If this option is omitted a default
offset of `0` is assumed.
TIP: As with the instruction mnemonics any symbol, in any package,
with symbol name `ALIGN` or `OFFSET` can be used to specify the
alignment and offset options.
The alignment and offset options can be specified in any order and
either one, or both, can be omitted. If both options are omitted the
instruction can either take the form of a list containing only the
instruction mnemonic, or the instruction mnemonic symbol by itself.
.Examples:
--------------------------------------------------
(I32.LOAD (OFFSET 8)) ;; Offset = 8
(I32.STORE (ALIGN 1)) ;; Alignment = 1
I64.STORE ;; Default Alignment = 2 and Offset = 0
--------------------------------------------------
The instructions falling within this group are all the typed `xx.LOAD`
and `xx.STORE` instructions (where `xx` is the value type), including
the instructions with a storage size which is smaller than the size of
the type.
==== Constant Instructions ====
Constant instructions take a single option which is the literal
constant value.
- `I32.CONST` and `I64.CONST` take either a signed or unsigned 32-bit
(64-bit in the case of `I64.CONST`) integer option. However,
regardless of whether the operand value is signed or not, the value
itself is always encoded as a signed integer in twos-complement.
- `F32.CONST` takes a single precision floating-point
(`SINGLE-FLOAT`) value as its option.
- `F64.CONST` takes either a single or double precision floating-point
value as its option.
==== Reference Instructions ====
The `REF.NULL` instruction takes a single option which is interpreted
as the reference type identifier, either `FUNCREF` or `EXTERNREF`. See
<<value_types>>.
The `REF.FUNC` instruction takes a single option, an unsigned integer
interpreted as the index of the function, within the function section,
to which to return a reference.
==== Memory and Table Instructions ====
The `MEMORY.INIT` and `DATA.DROP` instructions both take a single
option, an unsigned integer which is interpreted as the index of a
data segment within the data section.
The `TABLE.INIT` and `TABLE.COPY` instructions take two options, both
unsigned integers which are interpreted as a table index and element
segment index.
The `ELEM.DROP` instruction takes a single instruction, an unsigned
integer interpreted as an element segment index.
The `TABLE.GET`, `TABLE.SET`, `TABLE.SIZE`, `TABLE.GROW` and
`TABLE.FILL` instructions each take a single option, an unsigned
integer interpreted as a table index.
==== Structured Block Instructions ====
Structured block instructions are represented by a list with the block
type in the first element being and the instructions, comprising the
body of the block, in the remaining elements.
The second element of the list may be either an instruction, in which
case it is the first instruction of the block, or one of the
following:
`(RESULT type)`:: Indicates the type of value returned (on the stack)
by the block, where `type` is the value type identifier, see
<<value_types>>.
`(TYPE index)`:: Indicates the of the values consumed (from the stack)
and returned by the block, where `index` is the index of a function
type specifier, with the type section, see <<type_section>>.
If neither a result type nor type signature is specified, then it is
assumed that the block neither consumes nor returns a value and hence
does not have a return value type.
The `BLOCK` and `LOOP` block instructions follow this representation
exactly.
.Example: Simple block (no result type)
--------------------------------------------------
(block
(local.get 1)
(br_if 0)
(call 0))
--------------------------------------------------
.Example: Block with result type
--------------------------------------------------
(block (result i32)
(local.get 1)
(br_if 0)
(local.get 2)
(local.get 3)
i32.add)
--------------------------------------------------
.Example: Block with type signature
--------------------------------------------------
(block (type 1) ;; (i32 i32 i32) => i32
i32.add
i32.mul)
--------------------------------------------------
.Example: Simple loop
--------------------------------------------------
(loop
(call 0)
(local.get 1)
(i32.const 5)
i32.lt
(br_if 0))
--------------------------------------------------
The `IF` instruction is represented by a list of the following form:
--------------------------------------------------
(IF (THEN instructions...)
(ELSE instructions...))
--------------------------------------------------
Where `instructions` are the instructions comprising the body of the
`THEN` and `ELSE` branches. The `(ELSE ...)` element may be omitted in
which case the if instruction does not have an else branch.
The `IF` instruction may also have an optional result type or type
signature specified in the second element by `(RESULT type)` or `(TYPE
index)`. If this is omitted the `IF` instruction is assumed to have no
result type.
.Example: If without else branch
--------------------------------------------------
(local.get 0)
(if (then (call 0))
--------------------------------------------------
.Example: If with else branch
--------------------------------------------------
(local.get 0)
(if (then (call 0))
(else (call 1)))
--------------------------------------------------
.Example: If with result type
--------------------------------------------------
(local.get 0)
(i32.const 0)
i32.ge
(if (result i32)
(then (local.get 0))
(else (local.get 0)
(i32.const -1)
i32.mul))
--------------------------------------------------
=== Modules ===
A WebAssembly module is represented by the `WASM-MODULE` structure,
which contains a slot for each section. A `WASM-MODULE` object can be
serialized to an output stream using the `SERIALIZE-MODULE` function.
==== WASM-MODULE ====
Structure: `WASM-MODULE`
Represents a WebAssembly module with a lot for each section:
Slots:
- `TYPES`
- `IMPORTS`
- `FUNCTIONS`
- `TABLES`
- `MEMORY`
- `GLOBALS`
- `EXPORTS`
- `START`
- `ELEMENTS`
- `DATA`
==== SERIALIZE-MODULE ====
Function: `SERIALIZE-MODULE MODULE STREAM`
Serialize a module to the wasm binary format and write the output to a
given stream.
`MODULE`:: The `WASM-MODULE` to serialize.
`STREAM`:: Output stream to which to serialize the module. This must
be a binary output stream with element type `(UNSIGNED-BYTE 8)`.
[[type_section]]
=== Type Section ===
The `TYPES` slot, of `WASM-MODULE` ,is a list of `WASM-FUNCTION-TYPE`
objects which represent the function type signatures of the module's
functions.
==== WASM-FUNCTION-TYPE ====
Structure: `WASM-FUNCTION-TYPE`
Represents a function type signature.
Slots:
`PARAMS`:: List of the argument types
`RESULTS`:: List of the return value types
=== Imports Section ===
The `IMPORTS` slot, of `WASM-MODULE`, is a list of `WASM-IMPORT`
objects which represent the module's imports.
[[wasm_import]]
==== WASM-IMPORT ====
Structure: `WASM-IMPORT`
Represents an imported entity.
Slots:
`MODULE`:: Module component (first level) of the import name
`NAME`:: Name component (second level) of the import name
`TYPE`:: Keyword identifying type of imported entity:
+
--
`:FUNC`:: The imported entity is a function
`:TABLE`:: The imported entity is a table object
`:MEMORY`:: The imported entity is a memory object
`:GLOBAL`:: The imported entity is a global variable
--
`DESC`:: Description of the imported entity, which depends on `TYPE`:
+
--
`:FUNC`:: Index of the function's type signature within the module's
type section.
`:TABLE`:: A `WASM-TABLE` object specifying the table type and limits.
`:MEMORY`:: A `WASM-LIMIT` object specifying the memory limits.
`:GLOBAL`:: A list of the form `(TYPE MUTABLE-P)` where `TYPE` is the
value type of the variable and `MUTABLE-P` is a flag, which if true,
indicates that the variable is mutable.
--
=== Functions ===
The slot `FUNCTIONS`, of `WASM-MODULE`, is a list of `WASM-FUNCTION`
objects which represent the module's functions.
==== WASM-FUNCTION ====
Structure: `WASM-FUNCTION`
Represents a function.
Slots:
`TYPE`:: Index of the function's type signature within the type section.
`LOCALS`:: List of the types of the local variables.
`CODE`:: List of instructions comprising the body of the function.
=== Memory and Table Sections ===
The `MEMORY` slot is a list of `WASM-LIMIT` objects which specify the
limits of the module's memory objects.
The slot `TABLES`, of `WASM-MODULE`, is a list of `WASM-TABLE` objects
which specify the type and limits of the module's table objects.
NOTE: In the current version of WebAssembly, modules may contain a
maximum of one table and memory object. This library supports
serializing modules with more than one memory and table object.
==== WASM-LIMIT ====
Structure: `WASM-LIMIT`
Specifies the limits of a memory and table objects.
Slots:
`MIN`:: The lower-bound of the memory / table limit. Must be greater
than or equal to 0.
`MAX`:: The upper-bound of the limit. If NIL the limit has no
upper-bound.
==== WASM-TABLE ====
Structure: `WASM-TABLE (:INCLUDE WASM-LIMIT)`
Specifies the type and limits of a table object. Includes the slots of
the structure `WASM-LIMIT`.
Slots:
`TYPE`:: Table element type, either `FUNCREF` (the default) or `EXTERNREF`.
NOTE: In the current version of WebAssembly only tables of type
`FUNCREF` are supported.
=== Global Variable Section ===
The `GLOBALS` slot, of `WASM-MODULE`, is a list of `WASM-GLOBAL`
objects which represent the module's global variables.
==== WASM-GLOBAL ====
Structure: `WASM-GLOBAL`
Represents a global variable
.Slots
`TYPE`:: Value type of the variable.
`MUTABLE-P`:: Flag, which if true, indicates the variable is
mutable. Otherwise the variable is immutable.
`INIT`:: Expression which computes the variable's initial value. May
be `NIL`.
=== Exports Section ===
The `EXPORTS` slot, of `WASM-MODULE`, is a list of `WASM-EXPORT`
objects which represent the entities exported by the module.
==== WASM-EXPORT ====
Structure: `WASM-EXPORT`
Represents an exported entity.
.Slots
`NAME`:: The name (as a string) under which the entity is exported.
`TYPE`:: Keyword describing the type of entity. See the `TYPE` slot of
<<wasm_import>>.
`INDEX`:: Index of the exported entity within its sections.
=== Start Function ===
The `START` slot, of `WASM-MODULE`, is the index of the function, with
functions list in the `FUNCTIONS` slot, of the function which serves
as the module's entry point. If `NIL` the module does not have an
entry point.
=== Element Section ===
The `ELEMENTS` slot, of `WASM-MODULE`, is a list of `WASM-ELEMENT`
objects which represent the module's element segments.
Each element segment specifies the initial values of a range of
elements in a table object.
==== WASM-ELEMENT ====
Structure `WASM-ELEMENT`
Represents an element segment.
.Slots
`MODE`:: Keyword specifying the element segment mode.
+
--
`:ACTIVE`:: An 'active' segment , which is used to initialize the
table elements during module instantiation. This is the default.
`:PASSIVE`:: A 'passive' segment, which can be used to initialize the
table elements at runtime with the `TABLE.INIT` instruction.
`:DECLARATIVE`:: A 'declarative' segment, which is used only to
forward declare the function references that will be added to the
table, using the `REF.FUNC` instruction.
--
`INDEX`:: Index of the table object, 0 by default, which this element
initializes. This slot is only used when `MODE` is `:ACTIVE`.
+
--
NOTE: In the current version of WebAssembly the only valid index is 0.
--
`OFFSET`:: Expression which computes the starting index of the
location within the table where the elements in this segment are
copied to.
`INIT`:: Object specifying the values of the elements in this
segment. This can be either a `WASM-ELEMENT-INIT-INDEX` or
`WASM-ELEMENT-INIT-EXPRESSIONS` object.
==== WASM-ELEMENT-INIT-INDEX ====
Structure `WASM-ELEMENT-INIT-INDEX`
Represents a table element segment where the initial element values
are function indices.
.Slots
`FUNCTIONS`:: List of indices of the functions, within the function
section (`FUNCTIONs` slot), to which the table elements are set.
==== WASM-ELEMENT-INIT-EXPRESSIONS ====
Structure `WASM-ELEMENT-INIT-EXPRESSIONS`
Represents a table element segment where the initial element values
are computed by expressions.
.Slots
`TYPE`:: Table element type, either `FUNCREF` (default) or
`EXTERNREF`.
`EXPRESSIONS`:: List of expressions which compute the initial element
values. Each expression should leave a function reference on the
stack, which is obtained with the `REF.FUNC` instruction.
=== Data Section ===
The `DATA` slot, of `WASM-MODULE`, is a list of `WASM-DATA` objects
which represent the module's data segments.
Each data segment specifies the initial values of a range of bytes
in a memory object.
==== WASM-DATA ====
Structure `WASM-DATA`
Represents a data segment.
.Slots
`MODE`:: Keyword specifying the element segment mode.
+
--
`:ACTIVE`:: An 'active' segment, which is used to initialize the
memory object during module instantiation. This is the default.
`:PASSIVE`:: A 'passive' segment, which can be used to initialize the
memory object at runtime with the `MEMORY.INIT` instruction.
--
`MEMORY`:: Index of the memory object, 0 by default, which this element
initializes. This slot is only used when `MODE` is `:ACTIVE`.
+
--
NOTE: In the current version of WebAssembly the only valid index is 0.
--
`OFFSET`:: Expression which computes the starting index of the
location within the memory object where the bytes in this segment are
copied to.
`BYTES`:: Byte array containing the values to which the bytes in the
memory object are set.