0% found this document useful (0 votes)
11 views321 pages

WebAssembly 3.0 Specification Guide

Uploaded by

eatshit
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views321 pages

WebAssembly 3.0 Specification Guide

Uploaded by

eatshit
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

WebAssembly Specification

Release 3.0 (2025-11-14)

WebAssembly Community Group


Andreas Rossberg (editor)

Nov 14, 2025


Contents

1 Introduction 1
1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2 Structure 5
2.1 Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.4 Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.5 Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

3 Validation 29
3.1 Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.2 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.3 Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.4 Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.5 Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

4 Execution 79
4.1 Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
4.2 Runtime Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
4.3 Numerics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
4.4 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
4.5 Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
4.6 Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
4.7 Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165

5 Binary Format 177


5.1 Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
5.2 Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
5.3 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
5.4 Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
5.5 Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198

6 Text Format 205


6.1 Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
6.2 Lexical Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
6.3 Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
6.4 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
6.5 Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
6.6 Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231

i
7 Appendix 239
7.1 Embedding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
7.2 Profiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
7.3 Implementation Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
7.4 Type Soundness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
7.5 Type System Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
7.6 Validation Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
7.7 Custom Sections and Annotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
7.8 Change History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
7.9 Index of Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
7.10 Index of Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
7.11 Index of Semantic Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304

Index 307

ii
CHAPTER 1

Introduction

1.1 Introduction
WebAssembly (abbreviated Wasm2 ) is a safe, portable, low-level code format designed for efficient execution and
compact representation. Its main goal is to enable high performance applications on the Web, but it does not make
any Web-specific assumptions or provide Web-specific features, so it can be employed in other environments as
well.
WebAssembly is an open standard developed by a W3C Community Group1 .
This document describes version 3.0 (2025-11-14) of the core WebAssembly standard. It is intended that it will
be superseded by new incremental releases with additional features in the future.

1.1.1 Design Goals


The design goals of WebAssembly are the following:
• Fast, safe, and portable semantics:
– Fast: executes with near native code performance, taking advantage of capabilities common to all
contemporary hardware.
– Safe: code is validated and executes in a memory-safe3 , sandboxed environment preventing data cor-
ruption or security breaches.
– Well-defined: fully and precisely defines valid programs and their behavior in a way that is easy to
reason about informally and formally.
– Hardware-independent: can be compiled on all modern architectures, desktop or mobile devices and
embedded systems alike.
– Language-independent: does not privilege any particular language, programming model, or object
model.
– Platform-independent: can be embedded in browsers, run as a stand-alone VM, or integrated in other
environments.
– Open: programs can interoperate with their environment in a simple and universal manner.
2 A contraction of “WebAssembly”, not an acronym, hence not using all-caps.
1 [Link]
3 No program can break WebAssembly’s memory model. Of course, it cannot guarantee that an unsafe language compiling to WebAssembly

does not corrupt its own memory layout, e.g. inside WebAssembly’s linear memory.

1
WebAssembly Specification, Release 3.0 (2025-11-14)

• Efficient and portable representation:


– Compact: has a binary format that is fast to transmit by being smaller than typical text or native code
formats.
– Modular: programs can be split up in smaller parts that can be transmitted, cached, and consumed
separately.
– Efficient: can be decoded, validated, and compiled in a fast single pass, equally with either just-in-time
(JIT) or ahead-of-time (AOT) compilation.
– Streamable: allows decoding, validation, and compilation to begin as soon as possible, before all data
has been seen.
– Parallelizable: allows decoding, validation, and compilation to be split into many independent parallel
tasks.
– Portable: makes no architectural assumptions that are not broadly supported across modern hardware.
WebAssembly code is also intended to be easy to inspect and debug, especially in environments like web browsers,
but such features are beyond the scope of this specification.

1.1.2 Scope
At its core, WebAssembly is a virtual instruction set architecture (virtual ISA). As such, it has many use cases
and can be embedded in many different environments. To encompass their variety and enable maximum reuse, the
WebAssembly specification is split and layered into several documents.
This document is concerned with the core ISA layer of WebAssembly. It defines the instruction set, binary en-
coding, validation, and execution semantics, as well as a textual representation. It does not, however, define how
WebAssembly programs can interact with a specific environment they execute in, nor how they are invoked from
such an environment.
Instead, this specification is complemented by additional documents defining interfaces to specific embedding
environments such as the Web. These will each define a WebAssembly application programming interface (API)
suitable for a given environment.

1.1.3 Security Considerations


WebAssembly provides no ambient access to the computing environment in which code is executed. Any inter-
action with the environment, such as I/O, access to resources, or operating system calls, can only be performed
by invoking functions provided by the embedder and imported into a WebAssembly module. An embedder can
establish security policies suitable for a respective environment by controlling or limiting which functional capa-
bilities it makes available for import. Such considerations are an embedder’s responsibility and the subject of API
definitions for a specific environment.
Because WebAssembly is designed to be translated into machine code running directly on the host’s hardware, it
is potentially vulnerable to side channel attacks on the hardware level. In environments where this is a concern, an
embedder may have to put suitable mitigations into place to isolate WebAssembly computations.

1.1.4 Dependencies
WebAssembly depends on two existing standards:
• IEEE 7544 , for the representation of floating-point data and the semantics of respective numeric operations.
• Unicode5 , for the representation of import/export names and the text format.
However, to make this specification self-contained, relevant aspects of the aforementioned standards are defined
and formalized as part of this specification, such as the binary representation and rounding of floating-point values,
and the value range and UTF-8 encoding of Unicode characters.

4 [Link]
5 [Link]

2 Chapter 1. Introduction
WebAssembly Specification, Release 3.0 (2025-11-14)

Note

The aforementioned standards are the authoritative source of all respective definitions. Formalizations given in
this specification are intended to match these definitions. Any discrepancy in the syntax or semantics described
is to be considered an error.

1.2 Overview
1.2.1 Concepts
WebAssembly encodes a low-level, assembly-like programming language. This language is structured around the
following concepts.
Values
WebAssembly provides only four basic number types. These are integers and IEEE 7546 numbers, each in
32 and 64 bit width. 32-bit integers also serve as Booleans and as memory addresses. The usual operations
on these types are available, including the full matrix of conversions between them. There is no distinction
between signed and unsigned integer types. Instead, integers are interpreted by respective operations as
either unsigned or signed in two’s complement representation.
In addition to these basic number types, there is a single 128 bit wide vector type representing different types
of packed data. The supported representations are four 32-bit, or two 64-bit IEEE 7547 numbers, or different
widths of packed integer values, specifically two 64-bit integers, four 32-bit integers, eight 16-bit integers,
or sixteen 8-bit integers.
Finally, values can consist of opaque references that represent pointers towards different sorts of entities.
Unlike with other types, their size or representation is not observable.
Instructions
The computational model of WebAssembly is based on a stack machine. Code consists of sequences of
instructions that are executed in order. Instructions manipulate values on an implicit operand stack 8 and
fall into two main categories. Simple instructions perform basic operations on data. They pop arguments
from the operand stack and push results back to it. Control instructions alter control flow. Control flow
is structured, meaning it is expressed with well-nested constructs such as blocks, loops, and conditionals.
Branches can only target such constructs.
Traps
Under some conditions, certain instructions may produce a trap, which immediately aborts execution. Traps
cannot be handled by WebAssembly code, but are reported to the outside environment, where they typically
can be caught.
Functions
Code is organized into separate functions. Each function takes a sequence of values as parameters and returns
a sequence of values as results. Functions can call each other, including recursively, resulting in an implicit
call stack that cannot be accessed directly. Functions may also declare mutable local variables that are usable
as virtual registers.
Tables
A table is an array of opaque values of a particular reference type. It allows programs to select such values
indirectly through a dynamic index operand. Thereby, for example, a program can call functions indirectly
through a dynamic index into a table. This allows emulating function pointers by way of table indices.
Linear Memory
A linear memory is a contiguous, mutable array of raw bytes. Such a memory is created with an initial size
but can be grown dynamically. A program can load and store values from/to a linear memory at any byte
address (including unaligned). Integer loads and stores can specify a storage size which is smaller than the
6 [Link]
7 [Link]
8 In practice, implementations need not maintain an actual operand stack. Instead, the stack can be viewed as a set of anonymous registers

that are implicitly referenced by instructions. The type system ensures that the stack height, and thus any referenced register, is always known
statically.

1.2. Overview 3
WebAssembly Specification, Release 3.0 (2025-11-14)

size of the respective value type. A trap occurs if an access is not within the bounds of the current memory
size.
Modules
A WebAssembly binary takes the form of a module that contains definitions for functions, tables, and linear
memories, as well as mutable or immutable global variables. Definitions can also be imported, specifying a
module/name pair and a suitable type. Each definition can optionally be exported under one or more names.
In addition to definitions, modules can define initialization data for their memories or tables that takes the
form of segments copied to given offsets. They can also define a start function that is automatically executed.
Embedder
A WebAssembly implementation will typically be embedded into a host environment. This environment
defines how loading of modules is initiated, how imports are provided (including host-side definitions), and
how exports can be accessed. However, the details of any particular embedding are beyond the scope of this
specification, and will instead be provided by complementary, environment-specific API definitions.

1.2.2 Semantic Phases


Conceptually, the semantics of WebAssembly is divided into three phases. For each part of the language, the
specification specifies each of them.
Decoding
WebAssembly modules are distributed in a binary format. Decoding processes that format and converts it
into an internal representation of a module. In this specification, this representation is modelled by abstract
syntax, but a real implementation could compile directly to machine code instead.
Validation
A decoded module has to be valid. Validation checks a number of well-formedness conditions to guaran-
tee that the module is meaningful and safe. In particular, it performs type checking of functions and the
instruction sequences in their bodies, ensuring for example that the operand stack is used consistently.
Execution
Finally, a valid module can be executed. Execution can be further divided into two phases:
Instantiation. A module instance is the dynamic representation of a module, complete with its own state
and execution stack. Instantiation executes the module body itself, given definitions for all its imports. It
initializes globals, memories and tables and invokes the module’s start function if defined. It returns the
instances of the module’s exports.
Invocation. Once instantiated, further WebAssembly computations can be initiated by invoking an exported
function on a module instance. Given the required arguments, that executes the respective function and
returns its results.
Instantiation and invocation are operations within the embedding environment.

4 Chapter 1. Introduction
CHAPTER 2

Structure

2.1 Conventions
WebAssembly is a programming language that has multiple concrete representations (its binary format and the text
format). Both map to a common structure. For conciseness, this structure is described in the form of an abstract
syntax. All parts of this specification are defined in terms of this abstract syntax.

2.1.1 Grammar Notation


The following conventions are adopted in defining grammar rules for abstract syntax.
• Terminal symbols (atoms) are written in sans-serif font or in symbolic form: i32, nop, →, [, ].
• Nonterminal symbols are written in italic font: valtype, instr .
• 𝐴𝑛 is a sequence of 𝑛 ≥ 0 iterations of 𝐴.
• 𝐴* is a possibly empty sequence of iterations of 𝐴. (This is a shorthand for 𝐴𝑛 used where 𝑛 is not relevant.)
• 𝐴+ is a non-empty sequence of iterations of 𝐴. (This is a shorthand for 𝐴𝑛 where 𝑛 ≥ 1.)
• 𝐴? is an optional occurrence of 𝐴. (This is a shorthand for 𝐴𝑛 where 𝑛 ≤ 1.)
• Productions are written sym ::= 𝐴1 | . . . | 𝐴𝑛 .
• Large productions may be split into multiple definitions, indicated by ending the first one with explicit el-
lipses, sym ::= 𝐴1 , and starting continuations with ellipses, sym ::= . . . | 𝐴2 .
• Some productions are augmented with side conditions, “if condition”, that provide a shorthand for a com-
binatorial expansion of the production into many separate cases.
• If the same meta variable or non-terminal symbol appears multiple times in a production, then all those
occurrences must have the same instantiation. (This is a shorthand for a side condition requiring multiple
different variables to be equal.)

2.1.2 Auxiliary Notation


When dealing with syntactic constructs the following notation is also used:
• 𝜖 denotes the empty sequence.
• |𝑠| denotes the length of a sequence 𝑠.
• 𝑠[𝑖] denotes the 𝑖-th element of a sequence 𝑠, starting from 0.

5
WebAssembly Specification, Release 3.0 (2025-11-14)

• 𝑠[𝑖 : 𝑛] denotes the sub-sequence 𝑠[𝑖] . . . 𝑠[𝑖 + 𝑛 − 1] of a sequence 𝑠.


• 𝑠[[𝑖] = 𝐴] denotes the same sequence as 𝑠, except that the 𝑖-th element is replaced with 𝐴.
• 𝑠[[𝑖 : 𝑛] = 𝐴𝑛 ] denotes the same sequence as 𝑠, except that the sub-sequence 𝑠[𝑖 : 𝑛] is replaced with 𝐴𝑛 .
• 𝑠1 ⊕ 𝑠2 denotes the sequence 𝑠1 concatenated with 𝑠2 ; this is equivalent to 𝑠1 𝑠2 , but used for clarity.
• 𝑠 denotes the flattened sequence, formed by concatenating all sequences 𝑠𝑖 in 𝑠* .
⨁︀ *

• 𝐴 ∈ 𝑠 denotes that 𝐴 is a member of the sequence 𝑠, that is, 𝑠 is of the form 𝑠1 𝐴 𝑠2 for some sequences 𝑠1 ,
𝑠2 .
Moreover, the following conventions are employed:
• The notation 𝑥𝑛 , where 𝑥 is a non-terminal symbol, is treated as a meta variable ranging over respective
sequences of 𝑥 (similarly for 𝑥* , 𝑥+ , 𝑥? ).
• When given a sequence 𝑥𝑛 , then the occurrences of 𝑥 in an iterated sequence (. . . 𝑥 . . .)𝑛 are assumed to
denote the individual elements of 𝑥𝑛 , respectively (similarly for 𝑥* , 𝑥+ , 𝑥? ). This implicitly expresses a
form of mapping syntactic constructions over a sequence.
• 𝑒𝑖<𝑛 denotes the same sequence as 𝑒𝑛 , but implicitly also defines 𝑖𝑛 to be the sequence of values 0 to (𝑛−1).

Note

For example, if 𝑥𝑛 is the sequence 𝑎 𝑏 𝑐, then (f(𝑥) + 1)𝑛 denotes the sequence (f(𝑎) + 1) (f(𝑏) + 1) (f(𝑐) + 1).
The form 𝑒𝑖<𝑛 additionally gives access to an index variable inside the iteration. For example, (f(𝑥) + 𝑖)𝑖<𝑛
denotes the sequence (f(𝑎) + 0) (f(𝑏) + 1) (f(𝑐) + 2).

Productions of the following form are interpreted as records that map a fixed set of fields field𝑖 to “values” 𝐴𝑖 ,
respectively:

𝑟 ::= {field1 𝐴1 , field2 𝐴2 , . . . }

The following notation is adopted for manipulating such records:


• Where the type of a record is clear from context, empty fields with value 𝜖 are often omitted.
• 𝑟.field denotes the contents of the field component of 𝑟.
• 𝑟[.field = 𝐴] denotes the same record as 𝑟, except that the value of the field component is replaced with 𝐴.
• 𝑟[.field =⊕ 𝐴* ] denotes the same record as 𝑟, except that 𝐴* is appended to the sequence value of the field
component, that is, it is short for 𝑟[.field = 𝑟.field ⊕ 𝐴* ].
• 𝑟1 ⊕ 𝑟2 denotes the composition of two identically shaped records by concatenating each field of sequences
point-wise:

{field1 𝐴*1 , field2 𝐴*2 , . . .} ⊕ {field1 𝐵1* , field2 𝐵2* , . . .} = {field1 (𝐴*1 ⊕ 𝐵1* ), field2 (𝐴*2 ⊕ 𝐵2* ), . . .}

• 𝑟* denotes the composition of a sequence of records, respectively; if the sequence is empty, then all fields
⨁︀
of the resulting record are empty.
The update notation for sequences and records generalizes recursively to nested components accessed by “paths”
pth ::= ([𝑖] | .field)+ :
• 𝑠[[𝑖]pth = 𝐴] is short for 𝑠[[𝑖] = 𝑠[𝑖][pth = 𝐴]],
• 𝑟[.field pth = 𝐴] is short for 𝑟[.field = 𝑟.field[pth = 𝐴]].

6 Chapter 2. Structure
WebAssembly Specification, Release 3.0 (2025-11-14)

2.1.3 Lists
Lists are bounded sequences of the form 𝐴𝑛 (or 𝐴* ), where the 𝐴 can either be values or complex constructions.
A list can have at most 232 − 1 elements.

list(𝑋) ::= 𝑋 * if |𝑋 * | < 232

2.2 Values
WebAssembly programs operate on primitive numeric values. Moreover, in the definition of programs, immutable
sequences of values occur to represent more complex data, such as text strings or other vectors.

2.2.1 Bytes
The simplest form of value are raw uninterpreted bytes. In the abstract syntax they are represented as hexadecimal
literals.

byte ::= 0x00 | . . . | 0xFF

Conventions
• The meta variable 𝑏 ranges over bytes.
• Bytes are sometimes interpreted as natural numbers 𝑛 < 256.

2.2.2 Integers
Different classes of integers with different value ranges are distinguished by their bit width 𝑁 and by whether they
are unsigned or signed.

u𝑁 ::= 0 | . . . | 2𝑁 − 1
s𝑁 ::= −2𝑁 −1 | . . . | −1 | 0 | +1 | . . . | +2𝑁 −1 − 1
i𝑁 ::= u𝑁

The class i defines uninterpreted integers, whose signedness interpretation can vary depending on context. In the
abstract syntax, they are represented as unsigned values. However, some operations convert them to signed based
on a two’s complement interpretation.

Note

The main integer types occurring in this specification are u8 , u32 , u64 , and u128 . However, other sizes occur
as auxiliary constructions, e.g., in the definition of floating-point numbers.

Conventions
• The meta variables 𝑚, 𝑛, 𝑖, 𝑗 range over integers.
• Numbers may be denoted by simple arithmetics, as in the grammar above. In order to distinguish arithmetics
like 2𝑁 from sequences like (1)𝑁 , the latter is distinguished with parentheses.

2.2.3 Floating-Point
Floating-point data represents 32 or 64 bit values that correspond to the respective binary formats of the IEEE
7549 standard (Section 3.3).
Every value has a sign and a magnitude. Magnitudes can either be expressed as normal numbers of the form
𝑚0 . 𝑚1 𝑚2 . . . 𝑚m · 2𝑒 , where 𝑒 is the exponent and 𝑚 is the significand whose most significant bit 𝑚0 is 1, or as
a subnormal number where the exponent is fixed to the smallest possible value and 𝑚0 is 0; among the subnormals
9 [Link]

2.2. Values 7
WebAssembly Specification, Release 3.0 (2025-11-14)

are positive and negative zero values. Since the significands are binary values, normals are represented in the form
(1 + 𝑚 · 2−𝑀 ) · 2𝑒 in the abstract syntax, where 𝑀 is the bit width of 𝑚; similarly for subnormals.
Possible magnitudes also include the special values ∞ (infinity) and nan (NaN, not a number). NaN values have a
payload that describes the mantissa bits in the underlying binary representation. No distinction is made between
signalling and quiet NaNs.

f𝑁 ::= +fmag𝑁 | −fmag𝑁


fmag𝑁 ::= (1 + 𝑚 · 2−𝑀 ) · 2𝑒 if 𝑚 < 2𝑀 ∧ 2 − 2𝐸−1 ≤ 𝑒 ≤ 2𝐸−1 − 1
| (0 + 𝑚 · 2−𝑀 ) · 2𝑒 if 𝑚 < 2𝑀 ∧ 2 − 2𝐸−1 = 𝑒
| ∞
| nan(𝑚) if 1 ≤ 𝑚 < 2𝑀

where 𝑀 = signif(𝑁 ) and 𝐸 = expon(𝑁 ) with

signif(32) = 23
signif(64) = 52
expon(32) = 8
expon(64) = 11

A canonical NaN is a floating-point value ±nan(canon𝑁 ) where canon𝑁 is a payload whose most significant bit
is 1 while all others are 0:

canon𝑁 = 2signif(𝑁 )−1

An arithmetic NaN is a floating-point value ±nan(𝑚) with 𝑚 ≥ canon𝑁 , such that the most significant bit is 1
while all others are arbitrary.

Note

In the abstract syntax, subnormals are distinguished by the leading 0 of the significand. The exponent of
subnormals has the same value as the smallest possible exponent of a normal number. Only in the binary
representation the exponent of a subnormal is encoded differently than the exponent of any normal number.
The notion of canonical NaN defined here is unrelated to the notion of canonical NaN that the IEEE 75410
standard (Section 3.5.2) defines for decimal interchange formats.

Conventions
• The meta variable 𝑧 ranges over floating-point values where clear from context.
• Where clear from context, shorthands like +1 denote floating point values like +(1 + 0 · 2−𝑀 ) · 20 .

2.2.4 Vectors
Numeric vectors are 128-bit values that are processed by vector instructions (also known as SIMD instructions,
single instruction multiple data). They are represented in the abstract syntax using u128 . The interpretation of
lane types (integer or floating-point numbers) and lane sizes are determined by the specific instruction operating
on them.

2.2.5 Names
Names are sequences of characters, which are scalar values as defined by Unicode11 (Section 2.4).

name ::= char * if |utf 8(char * )| < 232


char ::= U+00 | . . . | U+D7FF | U+E000 | . . . | U+10FFFF

Due to the limitations of the binary format, the length of a name is bounded by the length of its UTF-8 encoding.
10 [Link]
11 [Link]

8 Chapter 2. Structure
WebAssembly Specification, Release 3.0 (2025-11-14)

Convention
• Characters (Unicode scalar values) are sometimes used interchangeably with natural numbers 𝑛 < 1114112.

2.3 Types
Various entities in WebAssembly are classified by types. Types are checked during validation, instantiation, and
possibly execution.

2.3.1 Number Types


Number types classify numeric values.

numtype ::= i32 | i64 | f 32 | f 64

The types i32 and i64 classify 32 and 64 bit integers, respectively. Integers are not inherently signed or unsigned,
their interpretation is determined by individual operations.
The types f 32 and f 64 classify 32 and 64 bit floating-point data, respectively. They correspond to the respective
binary floating-point representations, also known as single and double precision, as defined by the IEEE 75412
standard (Section 3.3).
Number types are transparent, meaning that their bit patterns can be observed. Values of number type can be stored
in memories.

Conventions
• The notation |𝑡| denotes the bit width of a number type 𝑡. That is, |i32| = |f 32| = 32 and |i64| = |f 64| = 64.

2.3.2 Vector Types


Vector types classify vectors of numeric values processed by vector instructions (also known as SIMD instructions,
single instruction multiple data).

vectype ::= v128

The type v128 corresponds to a 128 bit vector of packed integer or floating-point data. The packed data can be
interpreted as signed or unsigned integers, single or double precision floating-point values, or a single 128 bit type.
The interpretation is determined by individual operations.
Vector types, like number types are transparent, meaning that their bit patterns can be observed. Values of vector
type can be stored in memories.

Conventions
• The notation |𝑡| for bit width extends to vector types as well, that is, |v128| = 128.

2.3.3 Type Uses


A type use is the use site of a type index referencing a composite type defined in a module. It classifies objects of
the respective type.

typeuse ::= typeidx

The syntax of type uses is extended with additional forms for the purpose of specifying validation and execution.
12 [Link]

2.3. Types 9
WebAssembly Specification, Release 3.0 (2025-11-14)

2.3.4 Heap Types


Heap types classify objects in the runtime store. There are three disjoint hierarchies of heap types:
• function types classify functions,
• aggregate types classify dynamically allocated managed data, such as structures, arrays, or unboxed scalars,
• external types classify external references possibly owned by the embedder.
The values from the latter two hierarchies are interconvertible by ways of the extern.convert_any and
any.convert_extern instructions. That is, both type hierarchies are inhabited by an isomorphic set of values, but
may have different, incompatible representations in practice.

absheaptype ::= any | eq | i31 | struct | array | none


| func | nofunc
| exn | noexn
| extern | noextern
heaptype ::= absheaptype | typeuse

A heap type is either abstract or concrete. A concrete heap type consists of a type use that classifies an object of
the respective type defined in a module. Abstract types are denoted by individual keywords.
The type func denotes the common supertype of all function types, regardless of their concrete definition. Dually,
the type nofunc denotes the common subtype of all function types, regardless of their concrete definition. This
type has no values.
The type exn denotes the common supertype of all exception references. This type has no concrete subtypes.
Dually, the type noexn denotes the common subtype of all forms of exception references. This type has no values.
The type extern denotes the common supertype of all external references received through the embedder. This
type has no concrete subtypes. Dually, the type noextern denotes the common subtype of all forms of external
references. This type has no values.
The type any denotes the common supertype of all aggregate types, as well as possibly abstract values produced by
internalizing an external reference of type extern. Dually, the type none denotes the common subtype of all forms
of aggregate types. This type has no values.
The type eq is a subtype of any that includes all types for which references can be compared, i.e., aggregate values
and i31.
The types struct and array denote the common supertypes of all structure and array aggregates, respectively.
The type i31 denotes unboxed scalars, that is, integers injected into references. Their observable value range is
limited to 31 bits.

Note

Values of type i31 are not actually allocated in the store, but represented in a way that allows them to be mixed
with actual references into the store without ambiguity. Engines need to perform some form of pointer tagging
to achieve this, which is why one bit is reserved. Since this type is to be reliably unboxed on all hardware
platforms supported by WebAssembly, it cannot be wider than 32 bits minus the tag bit.
Although the types none, nofunc, noexn, and noextern are not inhabited by any values, they can be used to
form the types of all null references in their respective hierarchy. For example, (ref null nofunc) is the generic
type of a null reference compatible with all function reference types.

The syntax of abstract heap types is extended with additional forms for the purpose of specifying validation and
execution.

10 Chapter 2. Structure
WebAssembly Specification, Release 3.0 (2025-11-14)

2.3.5 Reference Types


Reference types classify values that are first-class references to objects in the runtime store.

reftype ::= ref null? heaptype

A reference type is characterised by the heap type it points to.


In addition, a reference type of the form ref null ht is nullable, meaning that it can either be a proper reference to
ht or null. Other references are non-null.
Reference types are opaque, meaning that neither their size nor their bit pattern can be observed. Values of reference
type can be stored in tables but not in memories.

Conventions
• The reference type anyref is an abbreviation for (ref null any).
• The reference type eqref is an abbreviation for (ref null eq).
• The reference type i31ref is an abbreviation for (ref null i31).
• The reference type structref is an abbreviation for (ref null struct).
• The reference type arrayref is an abbreviation for (ref null array).
• The reference type funcref is an abbreviation for (ref null func).
• The reference type exnref is an abbreviation for (ref null exn).
• The reference type externref is an abbreviation for (ref null extern).
• The reference type nullref is an abbreviation for (ref null none).
• The reference type nullfuncref is an abbreviation for (ref null nofunc).
• The reference type nullexnref is an abbreviation for (ref null noexn).
• The reference type nullexternref is an abbreviation for (ref null noextern).

2.3.6 Value Types


Value types classify the individual values that WebAssembly code can compute with and the values that a variable
accepts. They are either number types, vector types, or reference types.

consttype ::= numtype | vectype


valtype ::= numtype | vectype | reftype

The syntax of value types is extended with additional forms for the purpose of specifying validation.

Conventions
• The meta variable 𝑡 ranges over value types or subclasses thereof where clear from context.

2.3.7 Result Types


Result types classify the result of executing instructions or functions, which is a sequence of values, written with
brackets.

resulttype ::= list(valtype)

2.3. Types 11
WebAssembly Specification, Release 3.0 (2025-11-14)

2.3.8 Block Types


Block types classify the input and output of structured control instructions delimiting blocks of instructions.

blocktype ::= valtype ?


| typeidx
They are given either as a type index that refers to a suitable function type reinterpreted as an instruction type, or
as an optional value type inline, which is a shorthand for the instruction type 𝜖 → valtype ? .

2.3.9 Composite Types


Composite types are all types composed from simpler types, including function types, structure types and array
types.
comptype ::= struct list(fieldtype)
| array fieldtype
| func resulttype → resulttype
fieldtype ::= mut? storagetype
storagetype ::= valtype | packtype
packtype ::= i8 | i16
Function types classify the signature of functions, mapping a list of parameters to a list of results. They are also
used to classify the inputs and outputs of instructions.
Aggregate types like structure or array types consist of a list of possibly mutable, possibly packed field types de-
scribing their components. Structures are heterogeneous, but require static indexing, while arrays need to be ho-
mogeneous, but allow dynamic indexing.

Conventions
• The notation |𝑡| for the bit width of a value type 𝑡 extends to packed types as well, that is, |i8| = 8 and
|i16| = 16.
• The auxiliary function unpack maps a storage type to the value type obtained when accessing a field:
unpack(valtype) = valtype
unpack(packtype) = i32

2.3.10 Recursive Types


Recursive types denote a group of mutually recursive composite types, each of which can optionally declare a list
of type uses of supertypes that it matches. Each type can also be declared final, preventing further subtyping.
rectype ::= rec list(subtype)
subtype ::= sub final? typeuse * comptype
In a module, each member of a recursive type is assigned a separate type index.

2.3.11 Address Types


Address types are a subset of number types that classify the values that can be used as offsets into memories and
tables.

addrtype ::= i32 | i64

Conventions
The minimum of two address types is defined as the address type whose bit width is the minimum of the two.
min(at 1 , at 2 ) = at 1 if |at 1 | ≤ |at 2 |
min(at 1 , at 2 ) = at 2 otherwise

12 Chapter 2. Structure
WebAssembly Specification, Release 3.0 (2025-11-14)

2.3.12 Limits
Limits classify the size range of resizeable storage associated with memory types and table types.

limits ::= [u64 .. u64 ? ]

If no maximum is present, then the respective storage can grow to any valid size.

2.3.13 Tag Types


Tag types classify the signature tags with a type use referring to the definition of a function type that declares the
types of parameter and result values associated with the tag. The result type is empty for exception tags.

tagtype ::= typeuse

2.3.14 Global Types


Global types classify global variables, which hold a value and can either be mutable or immutable.

globaltype ::= mut? valtype

2.3.15 Memory Types


Memory types classify linear memories and their size range.

memtype ::= addrtype limits page

The limits constrain the minimum and optionally the maximum size of a memory. The limits are given in units of
page size.

2.3.16 Table Types


Table types classify tables over elements of reference type within a size range.

tabletype ::= addrtype limits reftype

Like memories, tables are constrained by limits for their minimum and optionally maximum size. The limits are
given in numbers of entries.

2.3.17 Data Types


Data types classify data segments. Since the contents of a data segment requires no further classification, they
merely consist of a universal marker ok indicating well-formedness.

datatype ::= ok

2.3.18 Element Types


Element types classify element segments by the reference type of its elements.

elemtype ::= reftype

2.3. Types 13
WebAssembly Specification, Release 3.0 (2025-11-14)

2.3.19 External Types


External types classify imports and external addresses with their respective types.

externtype ::= tag tagtype | global globaltype | mem memtype | table tabletype | func typeuse

For functions, the type use has to refer to the definition of a function type.

Note

Future versions of WebAssembly may have additional uses for tags, and may allow non-empty result types in
the function types of tags.

Conventions
The following auxiliary notation is defined for sequences of external types. It filters out entries of a specific kind
in an order-preserving fashion:

funcs(𝜖) = 𝜖
funcs((func dt) xt * ) = dt funcs(xt * )
funcs(externtype xt * ) = funcs(xt * ) otherwise
tables(𝜖) = 𝜖
tables((table tt) xt * ) = tt tables(xt * )
tables(externtype xt * ) = tables(xt * ) otherwise
mems(𝜖) = 𝜖
mems((mem mt) xt * ) = mt mems(xt * )
mems(externtype xt * ) = mems(xt * ) otherwise
globals(𝜖) = 𝜖
globals((global gt) xt * ) = gt globals(xt * )
globals(externtype xt * ) = globals(xt * ) otherwise
tags(𝜖) = 𝜖
tags((tag jt) xt * ) = jt tags(xt * )
tags(externtype xt * ) = tags(xt * ) otherwise

2.4 Instructions
WebAssembly code consists of sequences of instructions. Its computational model is based on a stack machine
in that instructions manipulate values on an implicit operand stack, consuming (popping) argument values and
producing or returning (pushing) result values.
In addition to dynamic operands from the stack, some instructions also have static immediate arguments, typically
indices or type annotations, which are part of the instruction itself.
Some instructions are structured in that they contain nested sequences of instructions.
The following sections group instructions into a number of different categories.
The syntax of instruction is further extended with additional forms for the purpose of specifying execution.

2.4.1 Parametric Instructions


Instructions in this group can operate on operands of any value type.

instr ::= nop


| unreachable
| drop
| select (valtype * )?

The nop instruction does nothing.

14 Chapter 2. Structure
WebAssembly Specification, Release 3.0 (2025-11-14)

The unreachable instruction causes an unconditional trap.


The drop instruction simply throws away a single operand.
The select instruction selects one of its first two operands based on whether its third operand is zero or not. It may
include a value type determining the type of these operands. If missing, the operands must be of numeric or vector
type.

Note

In future versions of WebAssembly, the type annotation on select may allow for more than a single value being
selected at the same time.

2.4.2 Control Instructions


Instructions in this group affect the flow of control.

instr ::= ...


| block blocktype instr *
| loop blocktype instr *
| if blocktype instr * else instr *
| br labelidx
| br_if labelidx
| br_table labelidx * labelidx
| br_on_null labelidx
| br_on_non_null labelidx
| br_on_cast labelidx reftype reftype
| br_on_cast_fail labelidx reftype reftype
| call funcidx
| call_ref typeuse
| call_indirect tableidx typeuse
| return
| return_call funcidx
| return_call_ref typeuse
| return_call_indirect tableidx typeuse
| throw tagidx
| throw_ref
| try_table blocktype list(catch) instr *
catch ::= catch tagidx labelidx
| catch_ref tagidx labelidx
| catch_all labelidx
| catch_all_ref labelidx

The block, loop, if and try_table instructions are structured instructions. They bracket nested sequences of in-
structions, called blocks. As the grammar prescribes, they must be well-nested.
A structured instruction can consume input and produce output on the operand stack according to its annotated
block type.
Each structured control instruction introduces an implicit label. Labels are targets for branch instructions that
reference them with label indices. Unlike with other index spaces, indexing of labels is relative by nesting depth,
that is, label 0 refers to the innermost structured control instruction enclosing the referring branch instruction, while
increasing indices refer to those farther out. Consequently, labels can only be referenced from within the associated
structured control instruction. This also implies that branches can only be directed outwards, “breaking” from the
block of the control construct they target. The exact effect depends on that control construct. In case of block or
if it is a forward jump, resuming execution after the end of the block. In case of loop it is a backward jump to the
beginning of the loop.

2.4. Instructions 15
WebAssembly Specification, Release 3.0 (2025-11-14)

Note

This enforces structured control flow. Intuitively, a branch targeting a block or if behaves like a break statement
in most C-like languages, while a branch targeting a loop behaves like a continue statement.

Branch instructions come in several flavors: br performs an unconditional branch, br_if performs a conditional
branch, and br_table performs an indirect branch through an operand indexing into the label list that is an immediate
to the instruction, or to a default target if the operand is out of bounds. The br_on_null and br_on_non_null
instructions check whether a reference operand is null and branch if that is the case or not the case, respectively.
Similarly, br_on_cast and br_on_cast_fail attempt a downcast on a reference operand and branch if that succeeds,
or fails, respectively.
The return instruction is a shortcut for an unconditional branch to the outermost block, which implicitly is the body
of the current function. Taking a branch unwinds the operand stack up to the height where the targeted structured
control instruction was entered. However, branches may additionally consume operands themselves, which they
push back on the operand stack after unwinding. Forward branches require operands according to the output of
the targeted block’s type, i.e., represent the values produced by the terminated block. Backward branches require
operands according to the input of the targeted block’s type, i.e., represent the values consumed by the restarted
block.
The call instruction invokes another function, consuming the necessary arguments from the stack and returning
the result values of the call. The call_ref instruction invokes a function indirectly through a function reference
operand. The call_indirect instruction calls a function indirectly through an operand indexing into a table that is
denoted by a table index and must contain function references. Since it may contain functions of heterogeneous
type, the callee is dynamically checked against the function type indexed by the instruction’s second immediate,
and the call is aborted with a trap if it does not match.
The return_call, return_call_ref, and return_call_indirect instructions are tail-call variants of the previous ones.
That is, they first return from the current function before actually performing the respective call. It is guaranteed
that no sequence of nested calls using only these instructions can cause resource exhaustion due to hitting an
implementation’s limit on the number of active calls.
The instructions throw, throw_ref, and try_table are concerned with exceptions. The throw and throw_ref instruc-
tions raise and reraise an exception, respectively, and transfers control to the innermost enclosing exception handler
that has a matching catch clause. The try_table instruction installs an exception handler that handles exceptions
as specified by its catch clauses.

2.4.3 Variable Instructions


Variable instructions are concerned with access to local or global variables.

instr ::= ...


| [Link] localidx
| [Link] localidx
| [Link] localidx
| [Link] globalidx
| [Link] globalidx

These instructions get or set the values of respective variables. The [Link] instruction is like [Link] but also
returns its argument.

16 Chapter 2. Structure
WebAssembly Specification, Release 3.0 (2025-11-14)

2.4.4 Table Instructions


Instructions in this group are concerned with tables table.

instr ::= ...


| [Link] tableidx
| [Link] tableidx
| [Link] tableidx
| [Link] tableidx
| [Link] tableidx
| [Link] tableidx tableidx
| [Link] tableidx elemidx
| [Link] elemidx

The [Link] and [Link] instructions load or store an element in a table, respectively.
The [Link] instruction returns the current size of a table. The [Link] instruction grows table by a given
delta and returns the previous size, or −1 if enough space cannot be allocated. It also takes an initialization value
for the newly allocated entries.
The [Link] instruction sets all entries in a range to a given value. The [Link] instruction copies elements
from a source table region to a possibly overlapping destination region; the first index denotes the destination. The
[Link] instruction copies elements from a passive element segment into a table.
The [Link] instruction prevents further use of a passive element segment. This instruction is intended to be
used as an optimization hint. After an element segment is dropped its elements can no longer be retrieved, so the
memory used by this segment may be freed.

Note

An additional instruction that accesses a table is the control instruction call_indirect.

2.4.5 Memory Instructions


Instructions in this group are concerned with linear memory.

memarg ::= {align u32 , offset u64 }


loadop i𝑁 ::= sz _sx if sz < 𝑁
storeop i𝑁 ::= sz if sz < 𝑁
vloadop vectype ::= sz x𝑀 _sx if sz · 𝑀 = |vectype|/2
| sz _splat
| sz _zero if sz ≥ 32
instr ::= ...
| [Link] ?numtype memidx memarg
| [Link] ?numtype memidx memarg
| [Link] ?vectype memidx memarg
| [Link] _lane memidx memarg laneidx
| [Link] memidx memarg
| [Link] _lane memidx memarg laneidx
| [Link] memidx
| [Link] memidx
| [Link] memidx
| [Link] memidx memidx
| [Link] memidx dataidx
| [Link] dataidx

Memory is accessed with load and store instructions for the different number types and vector types. They all
take a memory index and a memory argument memarg that contains an address offset and the expected alignment
(expressed as the exponent of a power of 2).

2.4. Instructions 17
WebAssembly Specification, Release 3.0 (2025-11-14)

Integer loads and stores can optionally specify a storage size sz that is smaller than the bit width of the respective
value type. In the case of loads, a sign extension mode sx is then required to select appropriate behavior.
Vector loads can specify a shape that is half the bit width of v128. Each lane is half its usual size, and the sign
extension mode sx then specifies how the smaller lane is extended to the larger lane. Alternatively, vector loads
can perform a splat, such that only a single lane of the specified storage size is loaded, and the result is duplicated
to all lanes.
The static address offset is added to the dynamic address operand, yielding a 33-bit or 65-bit effective address that
is the zero-based index at which the memory is accessed. All values are read and written in little endian13 byte
order. A trap results if any of the accessed memory bytes lies outside the address range implied by the memory’s
current size.
The [Link] instruction returns the current size of a memory. The [Link] instruction grows a memory
by a given delta and returns the previous size, or −1 if enough memory cannot be allocated. Both instructions
operate in units of page size.
The [Link] instruction sets all values in a region of memory to a given byte. The [Link] instruction
copies data from a source memory region to a possibly overlapping destination region in another or the same
memory; the first index denotes the destination. The [Link] instruction copies data from a passive data
segment into a memory.
The [Link] instruction prevents further use of a passive data segment. This instruction is intended to be used
as an optimization hint. After a data segment is dropped its data can no longer be retrieved, so the memory used
by this segment may be freed.

2.4.6 Reference Instructions


Instructions in this group are concerned with accessing references.

instr ::= ...


| [Link] funcidx
| [Link] heaptype
| ref.is_null
| ref.as_non_null
| [Link]
| [Link] reftype
| [Link] reftype

The [Link] and [Link] instructions produce a null reference or a reference to a given function, respectively.
The instruction ref.is_null checks for null, while ref.as_non_null converts a nullable to a non-null one, and traps
if it encounters null.
The [Link] compares two references.
The instructions [Link] and [Link] test the dynamic type of a reference operand. The former merely returns the
result of the test, while the latter performs a downcast and traps if the operand’s type does not match.

Note

The br_on_null and br_on_non_null instructions provide versions of ref.as_null that branch depending on the
success of failure of a null test instead of trapping. Similarly, the br_on_cast and br_on_cast_fail instructions
provides versions of [Link] that branch depending on the success of the downcast instead of trapping.
An additional instruction operating on function references is the control instruction call_ref.

13 [Link]

18 Chapter 2. Structure
WebAssembly Specification, Release 3.0 (2025-11-14)

2.4.7 Aggregate Instructions


Instructions in this group are concerned with creating and accessing references to aggregate types.

instr ::= ...


| [Link] typeidx
| struct.new_default typeidx
| struct.get_sx ? typeidx u32
| [Link] typeidx u32
| [Link] typeidx
| array.new_default typeidx
| array.new_fixed typeidx u32
| array.new_data typeidx dataidx
| array.new_elem typeidx elemidx
| array.get_sx ? typeidx
| [Link] typeidx
| [Link]
| [Link] typeidx
| [Link] typeidx typeidx
| array.init_data typeidx dataidx
| array.init_elem typeidx elemidx
| ref.i31
| i31.get_sx
| extern.convert_any
| any.convert_extern

The instructions [Link] and struct.new_default allocate a new structure, initializing them either with operands
or with default values. The remaining instructions on structs access individual fields, allowing for different sign
extension modes in the case of packed storage types.
Similarly, arrays can be allocated either with an explicit initialization operand or a default value. Furthermore,
array.new_fixed allocates an array with statically fixed size, and array.new_data and array.new_elem allocate an
array and initialize it from a data or element segment, respectively. The instructions [Link], [Link] sx , and
[Link] access individual slots, again allowing for different sign extension modes in the case of a packed storage
type; [Link] produces the length of an array; [Link] fills a specified slice of an array with a given value and
[Link], array.init_data, and array.init_elem copy elements to a specified slice of an array from a given array,
data segment, or element segment, respectively.
The instructions ref.i31 and [Link] sx convert between type i32 and an unboxed scalar.
The instructions any.convert_extern and extern.convert_any allow lossless conversion between references repre-
sented as type (ref null extern) and as (ref null any).

2.4. Instructions 19
WebAssembly Specification, Release 3.0 (2025-11-14)

2.4.8 Numeric Instructions


Numeric instructions provide basic operations over numeric values of specific type. These operations closely match
respective operations available in hardware.

sz ::= 8 | 16 | 32 | 64
sx ::= u | s
num i𝑁 ::= i𝑁
num f𝑁 ::= f𝑁
instr ::= ...
| [Link] num numtype
| [Link] numtype
| [Link] numtype
| [Link] numtype
| [Link] numtype
| numtype 1 .cvtop numtype 2 ,numtype 1 _numtype 2
unop i𝑁 ::= clz | ctz | popcnt | extendsz _s if sz < 𝑁
unop f𝑁 ::= abs | neg | sqrt | ceil | floor | trunc | nearest
binop i𝑁 ::= add | sub | mul | div_sx | rem_sx
| and | or | xor | shl | shr_sx | rotl | rotr
binop f𝑁 ::= add | sub | mul | div | min | max | copysign
testop i𝑁 ::= eqz
relop i𝑁 ::= eq | ne | lt_sx | gt_sx | le_sx | ge_sx
relop f𝑁 ::= eq | ne | lt | gt | le | ge
cvtop i𝑁 1 ,i𝑁 2 ::= extend_sx if 𝑁1 < 𝑁2
| wrap if 𝑁1 > 𝑁2
cvtop i𝑁 1 ,f𝑁 2 ::= convert_sx
| reinterpret if 𝑁1 = 𝑁2
cvtop f𝑁 1 ,i𝑁 2 ::= trunc_sx
| trunc_sat_sx
| reinterpret if 𝑁1 = 𝑁2
cvtop f𝑁 1 ,f𝑁 2 ::= promote if 𝑁1 < 𝑁2
| demote if 𝑁1 > 𝑁2

Numeric instructions are divided by number type. For each type, several subcategories can be distinguished:
• Constants: return a static constant.
• Unary operations: consume one operand and produce one result of the respective type.
• Binary operations: consume two operands and produce one result of the respective type.
• Tests: consume one operand of the respective type and produce a Boolean integer result.
• Comparisons: consume two operands of the respective type and produce a Boolean integer result.
• Conversions: consume a value of one type and produce a result of another (the source type of the conversion
is the one after the “_”).
Some integer instructions come in two flavors, where a signedness annotation sx distinguishes whether the operands
are to be interpreted as unsigned or signed integers. For the other integer instructions, the use of two’s complement
for the signed interpretation means that they behave the same regardless of signedness.

20 Chapter 2. Structure
WebAssembly Specification, Release 3.0 (2025-11-14)

2.4.9 Vector Instructions


Vector instructions (also known as SIMD instructions, single instruction multiple data) provide basic operations
over values of vector type.

lanetype ::= numtype | packtype


dim ::= 1 | 2 | 4 | 8 | 16
shape ::= lanetypexdim if |lanetype| · dim = 128
ishape ::= shape if lanetype(shape) = i𝑁
bshape ::= shape if lanetype(shape) = i8
half ::= low | high
zero ::= zero
laneidx ::= u8
instr ::= ...
| [Link] vec vectype
| [Link]
| [Link]
| [Link]
| [Link]
| [Link] shape
| [Link] shape
| [Link] shape
| [Link] shape
| [Link] shape
| [Link] ishape
| [Link]
| [Link] bshape
| [Link] laneidx * if |laneidx * | = dim(bshape)
| ishape 1 .vextunop ishape 2 ,ishape 1 _ishape 2
| ishape 1 .vextbinop ishape 2 ,ishape 1 _ishape 2
| ishape 1 .vextternop ishape 2 ,ishape 1 _ishape 2
| ishape 1 .narrow_ishape 2 _sx if |lanetype(ishape 2 )| = 2 · |lanetype(ishape 1 )| ≤ 32
| shape 1 .vcvtop shape 2 ,shape 1 _shape 2
| [Link]
| shape.extract_lane_sx ? laneidx if sx ? = 𝜖 ⇔ lanetype(shape) ∈ i32 i64 f 32 f 64
| shape.replace_lane laneidx

Vector instructions have a naming convention involving a shape prefix that determines how their operands will be
interpreted, written 𝑡x𝑁 , and consisting of a lane type 𝑡, a possibly packed numeric type, and its dimension 𝑁 ,
which denotes the number of lanes of that type. Operations are performed point-wise on the values of each lane.
Instructions prefixed with v128 do not involve a specific interpretation, and treat the v128 as either an i128 value or
a vector of 128 individual bits.

Note

For example, the shape i32x4 interprets the operand as four i32 values, packed into an i128 . The bit width of the
lane type 𝑡 times 𝑁 always is 128.

2.4. Instructions 21
WebAssembly Specification, Release 3.0 (2025-11-14)

vvunop ::= not


vvbinop ::= and | andnot | or | xor
vvternop ::= bitselect
vvtestop ::= any_true
vunop i𝑁 x𝑀 ::= abs | neg
| popcnt if 𝑁 = 8
vunop f𝑁 x𝑀 ::= abs | neg | sqrt | ceil | floor | trunc | nearest
vbinop i𝑁 x𝑀 ::= add
| sub
| add_sat_sx if 𝑁 ≤ 16
| sub_sat_sx if 𝑁 ≤ 16
| mul if 𝑁 ≥ 16
| avgr_u if 𝑁 ≤ 16
| q15mulr_sat_s if 𝑁 = 16
| relaxed_q15mulr_s if 𝑁 = 16
| min_sx if 𝑁 ≤ 32
| max_sx if 𝑁 ≤ 32
vbinop f𝑁 x𝑀 ::= add | sub | mul | div | min | max | pmin | pmax
| relaxed_min | relaxed_max
vternop i𝑁 x𝑀 ::= relaxed_laneselect
vternop f𝑁 x𝑀 ::= relaxed_madd | relaxed_nmadd
vtestop i𝑁 x𝑀 ::= all_true
vrelop i𝑁 x𝑀 ::= eq | ne
| lt_sx if 𝑁 ̸= 64 ∨ sx =s
| gt_sx if 𝑁 ̸ 64 ∨ sx
= =s
| le_sx if 𝑁 ̸= 64 ∨ sx =s
| ge_sx if 𝑁 ̸= 64 ∨ sx =s
vrelop f𝑁 x𝑀 ::= eq | ne | lt | gt | le | ge
vswizzlop i8x𝑀 ::= swizzle | relaxed_swizzle
vshiftop i𝑁 x𝑀 ::= shl | shr_sx
vextunop i𝑁 1 x𝑀1 ,i𝑁 2 x𝑀2 ::= extadd_pairwise_sx if 16 ≤ 2 · 𝑁1 = 𝑁2 ≤ 32
vextbinop i𝑁 1 x𝑀1 ,i𝑁 2 x𝑀2 ::= extmul_half _sx if 2 · 𝑁1 = 𝑁2 ≥ 16
| dot_s if 2 · 𝑁1 = 𝑁2 = 32
| relaxed_dot_s if 2 · 𝑁1 = 𝑁2 = 16
vextternop i𝑁 1 x𝑀1 ,i𝑁 2 x𝑀2 ::= relaxed_dot_add_s if 4 · 𝑁1 = 𝑁2 = 32
vcvtop i𝑁 1 x𝑀1 ,i𝑁 2 x𝑀2 ::= extend_half _sx if 𝑁2 = 2 · 𝑁1
vcvtop i𝑁 1 x𝑀1 ,f𝑁 2 x𝑀2 ::= convert_half ? _sx if 𝑁2 = 𝑁1 = 32 ∧ half ? = 𝜖 ∨ 𝑁2 = 2
vcvtop f𝑁 1 x𝑀1 ,i𝑁 2 x𝑀2 ::= trunc_sat_sx _zero ? if 𝑁1 = 𝑁2 = 32 ∧ zero ? = 𝜖 ∨ 𝑁1 = 2
| relaxed_trunc_sx _zero ? if 𝑁1 = 𝑁2 = 32 ∧ zero ? = 𝜖 ∨ 𝑁1 = 2
vcvtop f𝑁 1 x𝑀1 ,f𝑁 2 x𝑀2 ::= demote_zero if 𝑁1 = 2 · 𝑁2
| promote_low if 2 · 𝑁1 = 𝑁2

Vector instructions can be grouped into several subcategories:


• Constants: return a static constant.
• Unary Operations: consume one v128 operand and produce one v128 result.
• Binary Operations: consume two v128 operands and produce one v128 result.
• Ternary Operations: consume three v128 operands and produce one v128 result.
• Tests: consume one v128 operand and produce a Boolean integer result.
• Shifts: consume a v128 operand and an i32 operand, producing one v128 result.

22 Chapter 2. Structure
WebAssembly Specification, Release 3.0 (2025-11-14)

• Splats: consume a value of numeric type and produce a v128 result of a specified shape.
• Extract lanes: consume a v128 operand and return the numeric value in a given lane.
• Replace lanes: consume a v128 operand and a numeric value for a given lane, and produce a v128 result.
Some vector instructions have a signedness annotation sx which distinguishes whether the elements in the operands
are to be interpreted as unsigned or signed integers. For the other vector instructions, the use of two’s complement
for the signed interpretation means that they behave the same regardless of signedness.

Conventions
• The function lanetype(shape) extracts the lane type of a shape.
• The function dim(shape) extracts the dimension of a shape.
• The function zeroop(vcvtop) extracts the zero flag from a vector conversion operator, or returns 𝜖 if it does
not contain any.
• The function halfop(vcvtop) extracts the half flag from a vector conversion operator, or returns 𝜖 if it does
not contain any.

2.4.10 Expressions
Function bodies, initialization values for globals, elements and offsets of element segments, and offsets of data
segments are given as expressions, which are sequences of instructions.

expr ::= instr *

In some places, validation restricts expressions to be constant, which limits the set of allowable instructions.

2.5 Modules
WebAssembly programs are organized into modules, which are the unit of deployment, loading, and compilation.
A module collects definitions for types, tags, and globals, memories, tables, functions. In addition, it can declare
imports and exports and provide initialization in the form of data and element segments, or a start function.

module ::= module type * import * tag * global * mem * table * func * data * elem * start ? export *

Each of the lists — and thus the entire module — may be empty.

2.5.1 Indices
Definitions are referenced with zero-based indices. Each class of definition has its own index space, as distinguished
by the following classes.

idx ::= u32


typeidx ::= idx
funcidx ::= idx
globalidx ::= idx
tableidx ::= idx
memidx ::= idx
tagidx ::= idx
elemidx ::= idx
dataidx ::= idx
labelidx ::= idx
localidx ::= idx
fieldidx ::= idx

The index space for tags, globals, memories, tables, and functions includes respective imports declared in the same
module. The indices of these imports precede the indices of other definitions in the same index space.
Data indices reference data segments and element indices reference element segments.

2.5. Modules 23
WebAssembly Specification, Release 3.0 (2025-11-14)

The index space for locals is only accessible inside a function and includes the parameters of that function, which
precede the local variables.
Label indices reference structured control instructions inside an instruction sequence.
Each aggregate type provides an index space for its fields.

Conventions
• The meta variable 𝑙 ranges over label indices.
• The meta variables 𝑥, 𝑦 range over indices in any of the other index spaces.
• For every index space abcidx , the notation abcidx(𝐴) denotes the set of indices from that index space
occurring free in 𝐴. Sometimes this set is reinterpreted as the list of its elements.

Note

For example, if instr * is ([Link] 1) ([Link] 2 3), then dataidxinstrs (instr * ) = 1 3, or equivalently,
the set {1, 3}.

2.5.2 Types
The type section of a module defines a list of recursive types, each consisting of a list of sub types referenced by
individual type indices. All function, structure, or array types used in a module must be defined in this section.

type ::= type rectype

2.5.3 Tags
The tag section of a module defines a list of tags:

tag ::= tag tagtype

The type index of a tag must refer to a function type that declares its tag type.
Tags are referenced through tag indices, starting with the smallest index not referencing a tag import.

2.5.4 Globals
The global section of a module defines a list of global variables (or globals for short):

global ::= global globaltype expr

Each global stores a single value of the type specified in the global type. It also specifies whether a global is
immutable or mutable. Moreover, each global is initialized with a value given by a constant initializer expression.
Globals are referenced through global indices, starting with the smallest index not referencing a global import.

2.5.5 Memories
The mem section of a module defines a list of linear memories (or memories for short) as described by their
memory type:

mem ::= memory memtype

A memory is a list of raw uninterpreted bytes. The minimum size in the limits of its memory type specifies the
initial size of that memory, while its maximum, if present, restricts the size to which it can grow later. Both are in
units of page size.

24 Chapter 2. Structure
WebAssembly Specification, Release 3.0 (2025-11-14)

Memories can be initialized through data segments.


Memories are referenced through memory indices, starting with the smallest index not referencing a memory
import. Most constructs implicitly reference memory index 0.

2.5.6 Tables
The table section of a module defines a list of tables described by their table type:

table ::= table tabletype expr

A table is an array of opaque values of a particular reference type that is specified by the table type. Each table
slot is initialized with a value given by a constant initializer expression. Tables can further be initialized through
element segments.
The minimum size in the limits of the table type specifies the initial size of that table, while its maximum restricts
the size to which it can grow later.
Tables are referenced through table indices, starting with the smallest index not referencing a table import. Most
constructs implicitly reference table index 0.

2.5.7 Functions
The func section of a module defines a list of functions with the following structure:

func ::= func typeidx local * expr


local ::= local valtype

The type index of a function declares its signature by reference to a function type defined in the module. The
parameters of the function are referenced through 0-based local indices in the function’s body; they are mutable.
The locals declare a list of mutable local variables and their types. These variables are referenced through local
indices in the function’s body. The index of the first local is the smallest index not referencing a parameter.
A function’s expression is an instruction sequence that represents the body of the function. Upon termination it
must produce a stack matching the function type’s result type.
Functions are referenced through function indices, starting with the smallest index not referencing a function im-
port.

2.5.8 Data Segments


The data section of a module defines a list of data segments, which can be used to initialize a range of memory
from a static list of bytes.

data ::= data byte * datamode


datamode ::= active memidx expr | passive

Similar to element segments, data segments have a mode that identifies them as either active or passive. A passive
data segment’s contents can be copied into a memory using the [Link] instruction. An active data segment
copies its contents into a memory during instantiation, as specified by a memory index and a constant expression
defining an offset into that memory.
Data segments are referenced through data indices.

2.5.9 Element Segments


The elem section of a module defines a list of element segments, which can be used to initialize a subrange of a
table from a static list of elements.
elem ::= elem reftype expr * elemmode
elemmode ::= active tableidx expr | passive | declare

Each element segment defines a reference type and a corresponding list of constant element expressions.

2.5. Modules 25
WebAssembly Specification, Release 3.0 (2025-11-14)

Element segments have a mode that identifies them as either active, passive, or declarative. A passive element
segment’s elements can be copied to a table using the [Link] instruction. An active element segment copies
its elements into a table during instantiation, as specified by a table index and a constant expression defining an
offset into that table. A declarative element segment is not available at runtime but merely serves to forward-
declare references that are formed in code with instructions like [Link]. The offset is given by another constant
expression.
Element segments are referenced through element indices.

2.5.10 Start Function


The start section of a module declares the function index of a start function that is automatically invoked when
the module is instantiated, after tables and memories have been initialized.

start ::= start funcidx

Note

The start function is intended for initializing the state of a module. The module and its exports are not accessible
externally before this initialization has completed.

2.5.11 Imports
The import section of a module defines a set of imports that are required for instantiation.

import ::= import name name externtype

Each import is labeled by a two-level name space, consisting of a module name and an item name for an entity
within that module. Importable definitions are tags, globals, memories, tables, and functions. Each import is
specified by a respective external type that a definition provided during instantiation is required to match.
Every import defines an index in the respective index space. In each index space, the indices of imports go before
the first index of any definition contained in the module itself.

Note

Unlike export names, import names are not necessarily unique. It is possible to import the same module/item
name pair multiple times; such imports may even have different type descriptions, including different kinds of
entities. A module with such imports can still be instantiated depending on the specifics of how an embedder
allows resolving and supplying imports. However, embedders are not required to support such overloading, and
a WebAssembly module itself cannot implement an overloaded name.

2.5.12 Exports
The export section of a module defines a set of exports that become accessible to the host environment once the
module has been instantiated.
export ::= export name externidx
externidx ::= func funcidx | global globalidx | table tableidx | memory memidx | tag tagidx

Each export is labeled by a unique name. Exportable definitions are tags, globals, memories, tables, and functions,
which are referenced through a respective index.

26 Chapter 2. Structure
WebAssembly Specification, Release 3.0 (2025-11-14)

Conventions
The following auxiliary notation is defined for sequences of exports, filtering out indices of a specific kind in an
order-preserving fashion:

funcs(𝜖) = 𝜖
funcs((func 𝑥) xx * ) = 𝑥 funcs(xx * )
funcs(externidx xx * ) = funcs(xx * ) otherwise
tables(𝜖) = 𝜖
tables((table 𝑥) xx * ) = 𝑥 tables(xx * )
tables(externidx xx * ) = tables(xx * ) otherwise
mems(𝜖) = 𝜖
mems((memory 𝑥) xx * ) = 𝑥 mems(xx * )
mems(externidx xx * ) = mems(xx * ) otherwise
globals(𝜖) = 𝜖
globals((global 𝑥) xx * ) = 𝑥 globals(xx * )
globals(externidx xx * ) = globals(xx * ) otherwise
tags(𝜖) = 𝜖
tags((tag 𝑥) xx * ) = 𝑥 tags(xx * )
tags(externidx xx * ) = tags(xx * ) otherwise

2.5. Modules 27
WebAssembly Specification, Release 3.0 (2025-11-14)

28 Chapter 2. Structure
CHAPTER 3

Validation

3.1 Conventions
Validation checks that a WebAssembly module is well-formed. Only valid modules can be instantiated.
Validity is defined by a type system over the abstract syntax of a module and its contents. For each piece of abstract
syntax, there is a typing rule that specifies the constraints that apply to it. All rules are given in two equivalent
forms:
1. In prose, describing the meaning in intuitive form.
2. In formal notation, describing the rule in mathematical form.14

Note

The prose and formal rules are equivalent, so that understanding of the formal notation is not required to read this
specification. The formalism offers a more concise description in notation that is used widely in programming
languages semantics and is readily amenable to mathematical proof.

In both cases, the rules are formulated in a declarative manner. That is, they only formulate the constraints, they do
not define an algorithm. The skeleton of a sound and complete algorithm for type-checking instruction sequences
according to this specification is provided in the appendix.

3.1.1 Types
To define the semantics, the definition of some sorts of types is extended to include additional forms. By virtue
of not being representable in either the binary format or the text format, these forms cannot be used in a program;
they only occur during validation or execution.
valtype ::= . . . | bot
absheaptype ::= . . . | bot
typeuse ::= . . . | deftype | rec.𝑛
The unique value type bot is a bottom type that matches all value types. Similarly, bot is also used as a bottom
type of all heap types.
14 The semantics is derived from the following article: Andreas Haas, Andreas Rossberg, Derek Schuff, Ben Titzer, Dan Gohman, Luke

Wagner, Alon Zakai, JF Bastien, Michael Holman. Bringing the Web up to Speed with WebAssembly15 . Proceedings of the 38th ACM
SIGPLAN Conference on Programming Language Design and Implementation (PLDI 2017). ACM 2017.
15 [Link]

29
WebAssembly Specification, Release 3.0 (2025-11-14)

Note

No validation rule uses bottom types explicitly, but various rules can pick any value or heap type, including
bottom. This ensures the existence of principal types, and thus a validation algorithm without back tracking.

A type use can consist directly of a defined type. This occurs as the result of substituting a type index with its
definition.
A type use may also be a recursive type index. Such an index refers to the 𝑖-th component of a surrounding recursive
type. It occurs as the result of rolling up the definition of a recursive type.
Both extensions affect occurrences of type uses in concrete heap types, in sub types and in instructions.
A type of any form is closed when it does not contain a heap type that is a type index or a recursive type index
without a surrounding recursive type, i.e., all type indices have been substituted with their defined type and all free
recursive type indices have been unrolled.

Note

It is an invariant of the semantics that sub types occur only in one of two forms: either as “syntactic” types
as in a source module, where all supertypes are type indices, or as “semantic” types, where all supertypes are
resolved to either defined types or recursive type indices.
Recursive type indices are local to a recursive type. They are distinguished from regular type indices and rep-
resented such that two closed types are syntactically equal if and only if they have the same recursive structure.

Convention
• The difference rt 1 ∖ rt 2 between two reference types is defined as follows:

(ref null?1 ht 1 ) ∖ (ref null ht 2 ) = (ref ht 1 )


(ref null?1 ht 1 ) ∖ (ref ht 2 ) = (ref null?1 ht 1 )

Note

This definition computes an approximation of the reference type that is inhabited by all values from rt 1 except
those from rt 2 . Since the type system does not have general union types, the definition only affects the presence
of null and cannot express the absence of other values.

3.1.2 Defined Types


Defined types denote the individual types defined in a module. Each such type is represented as a projection from
the recursive type group it originates from, indexed by its position in that group.

deftype ::= rectype.𝑛

Defined types do not occur in the binary or text format, but are formed by rolling up the recursive types defined in
a module.

Note

It is an invariant of the semantics that all recursive types occurring in defined types are rolled up.

30 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

Conventions
• 𝑡[𝑥* := dt * ] denotes the parallel substitution of type indices 𝑥* with corresponding defined types dt * in type
𝑡, provided |𝑥* | = |dt * |.
• 𝑡[(rec 𝑖)* := dt * ] denotes the parallel substitution of recursive type indices (rec 𝑖)* with defined types dt *
in type 𝑡, provided |(rec 𝑖)* | = |dt * |. This substitution does not proceed under recursive types, since they
are considered local binders for all recursive type indices.
• 𝑡[:= dt * ] is shorthand for the substitution 𝑡[𝑥* := dt * ], where 𝑥* = 0 . . . (|dt * | − 1).

Note

All recursive types formed by the semantics are closed with respect to recursive type indices that occur inside
them. Hence, substitution of recursive type indices never needs to modify the bodies of recursive types. In
addition, all types used for substitution are closed with respect to recursive type indices, such that name capture
of recursive type indices cannot occur.

3.1.3 Rolling and Unrolling


In order to allow comparing recursive types for equivalence, their representation is changed such that all type
indices internal to the same recursive type are replaced by recursive type indices.

Note

This representation is independent of the type index space, so that it is meaningful across module boundaries.
Moreover, this representation ensures that types with equivalent recursive structure are also syntactically equal,
hence allowing a simple equality check on (closed) types. It gives rise to an iso-recursive interpretation of
types.

The representation change is performed by two auxiliary operations on the syntax of recursive types:
• Rolling up a recursive type substitutes its internal type indices with corresponding recursive type indices.
• Unrolling a recursive type substitutes its recursive type indices with the corresponding defined types.
These operations are extended to defined types and defined as follows:
roll𝑥 (rectype) = rec (subtype[(𝑥 + 𝑖)𝑖<𝑛 := (rec.𝑖)𝑖<𝑛 ])𝑛 if rectype = rec subtype 𝑛
unroll(rectype) = rec (subtype[(rec.𝑖)𝑖<𝑛 := (rectype.𝑖)𝑖<𝑛 ])𝑛 if rectype = rec subtype 𝑛
roll*𝑥 (rectype) = ((rec subtype 𝑛 ).𝑖)𝑖<𝑛 if roll𝑥 (rectype) = rec subtype 𝑛
*
unroll(rectype.𝑖) = subtype [𝑖] if unroll(rectype) = rec subtype *
In addition, the following auxiliary relation denotes the expansion of a defined type or type use:
deftype ≈ comptype if expand(deftype) = comptype
deftype ≈𝐶 comptype if deftype ≈ comptype
typeidx ≈𝐶 comptype if 𝐶.types[typeidx ] ≈ comptype

3.1.4 Instruction Types


Instruction types classify the behaviour of instructions or instruction sequences, by describing how they manipulate
the operand stack and the initialization status of locals:

instrtype ::= resulttype →localidx * resulttype

An instruction type 𝑡*1 →𝑥* 𝑡*2 describes the required input stack with argument values of types 𝑡*1 that an instruction
pops off and the provided output stack with result values of types 𝑡*2 that it pushes back. Moreover, it enumerates
the indices 𝑥* of locals that have been set by the instruction or sequence.

3.1. Conventions 31
WebAssembly Specification, Release 3.0 (2025-11-14)

Note

Instruction types are only used for validation, they do not occur in programs.

3.1.5 Local Types


Local types classify locals, by describing their value type as well as their initialization status:

localtype ::= init valtype


init ::= set | unset

Note

Local types are only used for validation, they do not occur in programs.

3.1.6 Contexts
Validity of an individual definition is specified relative to a context, which collects relevant information about the
surrounding module and the definitions in scope:
• Types: the list of types defined in the current module.
• Recursive Types: the list of sub types in the current group of recursive types.
• Functions: the list of functions declared in the current module, represented by a defined type that expands
to their function type.
• Tables: the list of tables declared in the current module, represented by their table type.
• Memories: the list of memories declared in the current module, represented by their memory type.
• Globals: the list of globals declared in the current module, represented by their global type.
• Tags: the list of tags declared in the current module, represented by their tag type.
• Element Segments: the list of element segments declared in the current module, represented by the elements’
reference type.
• Data Segments: the list of data segments declared in the current module, each represented by an ok entry.
• Locals: the list of locals declared in the current function (including parameters), represented by their local
type.
• Labels: the stack of labels accessible from the current position, represented by their result type.
• Return: the return type of the current function, represented as an optional result type that is absent when no
return is allowed, as in free-standing expressions.
• References: the list of function indices that occur in the module outside functions and can hence be used to
form references inside them.
In other words, a context contains a sequence of suitable types for each index space, describing each defined entry
in that space. Locals, labels and return type are only used for validating instructions in function bodies, and are
left empty elsewhere. The label stack is the only part of the context that changes as validation of an instruction
sequence proceeds.

32 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

More concretely, contexts are defined as records 𝐶 with abstract syntax:

context ::= {types deftype *


recs subtype *
tags tagtype *
globals globaltype *
mems memtype *
tables tabletype *
funcs deftype *
datas datatype *
elems elemtype *
locals localtype *
labels resulttype *
return resulttype ?
refs funcidx * }

Convention
A type of any shape can be closed to bring it into closed form relative to a context it is valid in, by substituting
each type index 𝑥 occurring in it with its own corresponding defined type 𝐶.types[𝑥], after first closing the types
in 𝐶.types themselves.

clos𝐶 (𝑡) = 𝑡[:= dt * ] if dt * = clos* (𝐶.types)


clos* (𝜖) = 𝜖
* * *
clos* (dt * dt 𝑛 ) = dt ′ dt 𝑛 [:= dt ′ ] if dt ′ = clos* (dt * )

Note

Free type indices referring to types within the same recursive type are handled separately by rolling up recursive
types before closing them.

3.1.7 Prose Notation


Validation is specified by stylised rules for each relevant part of the abstract syntax. The rules not only state
constraints defining when a phrase is valid, they also classify it with a type. The following conventions are adopted
in stating these rules.
• A phrase 𝐴 is said to be “valid with type 𝑇 ” if and only if all constraints expressed by the respective rules
are met. The form of 𝑇 depends on the syntactic class of 𝐴.

Note

For example, if 𝐴 is a function, then 𝑇 is a defined function type; for an 𝐴 that is a global, 𝑇 is a global
type; and so on.

• The rules implicitly assume a given context 𝐶.


• In some places, this context is locally extended to a context 𝐶 ′ with additional entries. The formulation
“Under context 𝐶 ′ , . . . statement . . . ” is adopted to express that the following statement must apply under
the assumptions embodied in the extended context.

3.1.8 Formal Notation

3.1. Conventions 33
WebAssembly Specification, Release 3.0 (2025-11-14)

Note

This section gives a brief explanation of the notation for specifying typing rules formally. For the interested
reader, a more thorough introduction can be found in respective text books.16

The proposition that a phrase 𝐴 has a respective type 𝑇 is written 𝐴 : 𝑇 . In general, however, typing is dependent
on a context 𝐶. To express this explicitly, the complete form is a judgement 𝐶 ⊢ 𝐴 : 𝑇 , which says that 𝐴 : 𝑇
holds under the assumptions encoded in 𝐶.
The formal typing rules use a standard approach for specifying type systems, rendering them into deduction rules.
Every rule has the following general form:
premise 1 premise 2 ... premise 𝑛
conclusion
Such a rule is read as a big implication: if all premises hold, then the conclusion holds. Some rules have
no premises; they are axioms whose conclusion holds unconditionally. The conclusion always is a judgment
𝐶 ⊢ 𝐴 : 𝑇 , and there usually is one respective rule for each relevant construct 𝐴 of the abstract syntax.

Note

For example, the typing rule for the [Link] instruction can be given as an axiom:

𝐶 ⊢ [Link] : i32 i32 → i32


The instruction is always valid with type i32 i32 → i32 (saying that it consumes two i32 values and produces one),
independent of any side conditions.
An instruction like [Link] can be typed as follows:

𝐶.globals[𝑥] = mut 𝑡
𝐶 ⊢ [Link] 𝑥 : 𝜖 → 𝑡
Here, the premise enforces that the immediate global index 𝑥 exists in the context. The instruction produces a
value of its respective type 𝑡 (and does not consume any values). If 𝐶.globals[𝑥] does not exist then the premise
does not hold, and the instruction is ill-typed.
Finally, a structured instruction requires a recursive rule, where the premise is itself a typing judgement:

𝐶 ⊢ blocktype : 𝑡*1 → 𝑡*2 {labels (𝑡*2 )} ⊕ 𝐶 ⊢ instr * : 𝑡*1 → 𝑡*2


𝐶 ⊢ block blocktype instr * : 𝑡*1 → 𝑡*2

A block instruction is only valid when the instruction sequence in its body is. Moreover, the result type must
match the block’s annotation blocktype. If so, then the block instruction has the same type as the body. Inside
the body an additional label of the corresponding result type is available, which is expressed by extending the
context 𝐶 with the additional label information for the premise.

3.2 Types
Simple types, such as number types are universally valid. However, restrictions apply to most other types, such
as reference types, function types, as well as the limits of table types and memory types, which must be checked
during validation.
Moreover, block types are converted to instruction types for ease of processing.
16 For example: Benjamin Pierce. Types and Programming Languages17 . The MIT Press 2002
17 [Link]

34 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

3.2.1 Number Types


The number type numtype is always valid.

𝐶 ⊢ numtype : ok

3.2.2 Vector Types


The vector type vectype is always valid.

𝐶 ⊢ vectype : ok

3.2.3 Type Uses


The type use typeidx is valid if:
• The type 𝐶.types[typeidx ] exists.
𝐶.types[typeidx ] = dt
𝐶 ⊢ typeidx : ok

3.2.4 Heap Types


The heap type absheaptype is always valid.

𝐶 ⊢ absheaptype : ok

3.2.5 Reference Types


The reference type (ref null? heaptype) is valid if:
• The heap type heaptype is valid.
𝐶 ⊢ heaptype : ok
𝐶 ⊢ ref null? heaptype : ok

3.2.6 Value Types


The value type valtype is valid if:
• Either:
– The value type valtype is of the form numtype.
– The number type numtype is valid.
• Or:
– The value type valtype is of the form vectype.
– The vector type vectype is valid.
• Or:
– The value type valtype is of the form reftype.
– The reference type reftype is valid.
• Or:

3.2. Types 35
WebAssembly Specification, Release 3.0 (2025-11-14)

– The value type valtype is of the form bot.

𝐶 ⊢ bot : ok

3.2.7 Result Types


The result type 𝑡* is valid if:
• For all 𝑡 in 𝑡* :
– The value type 𝑡 is valid.
(𝐶 ⊢ 𝑡 : ok)*
𝐶 ⊢ 𝑡* : ok

3.2.8 Block Types


Block types may be expressed in one of two forms, both of which are converted to instruction types by the following
rules.
The block type typeidx is valid as the instruction type 𝑡*1 → 𝑡*2 if:
• The type 𝐶.types[typeidx ] exists.
• The expansion of 𝐶.types[typeidx ] is (func 𝑡*1 → 𝑡*2 ).
𝐶.types[typeidx ] ≈ func 𝑡*1 → 𝑡*2
𝐶 ⊢ typeidx : 𝑡*1 → 𝑡*2
The block type valtype ? is valid as the instruction type 𝜖 → valtype ? if:
• If valtype is defined, then:
– The value type valtype is valid.
(𝐶 ⊢ valtype : ok)?
𝐶 ⊢ valtype ? : 𝜖 → valtype ?

3.2.9 Instruction Types


The instruction type 𝑡*1 →𝑥* 𝑡*2 is valid if:
• The result type 𝑡*1 is valid.
• The result type 𝑡*2 is valid.
• For all 𝑥 in 𝑥* :
– The local 𝐶.locals[𝑥] exists.
𝐶 ⊢ 𝑡*1 : ok 𝐶 ⊢ 𝑡*2 : ok (𝐶.locals[𝑥] = lt)*
* *
𝐶 ⊢ 𝑡1 →𝑥* 𝑡2 : ok

3.2.10 Composite Types


The composite type (struct fieldtype * ) is valid if:
• For all fieldtype in fieldtype * :
– The field type fieldtype is valid.
(𝐶 ⊢ fieldtype : ok)*
𝐶 ⊢ struct fieldtype * : ok
The composite type (array fieldtype) is valid if:

36 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

• The field type fieldtype is valid.


𝐶 ⊢ fieldtype : ok
𝐶 ⊢ array fieldtype : ok
The composite type (func 𝑡*1 → 𝑡*2 ) is valid if:
• The result type 𝑡*1 is valid.
• The result type 𝑡*2 is valid.
𝐶 ⊢ 𝑡*1 : ok 𝐶 ⊢ 𝑡*2 : ok
𝐶 ⊢ func 𝑡1 → 𝑡*2 : ok
*

The field type (mut? storagetype) is valid if:


• The storage type storagetype is valid.
𝐶 ⊢ storagetype : ok
𝐶 ⊢ mut? storagetype : ok
The packed type packtype is always valid.

𝐶 ⊢ packtype : ok

3.2.11 Recursive Types


Recursive types are validated with respect to the first type index defined by the recursive group.

rec subtype *
The recursive type (rec subtype * ) is valid for the type index 𝑥 if:
• Either:
– The sub type sequence subtype * is empty.
• Or:
*
– The sub type sequence subtype * is of the form subtype 1 subtype ′ .
– The sub type subtype 1 is valid for the type index 𝑥.
*
– The recursive type (rec subtype ′ ) is valid for the type index 𝑥 + 1.
𝐶 ⊢ subtype 1 : ok(𝑥) 𝐶 ⊢ rec subtype * : ok(𝑥 + 1)
𝐶 ⊢ rec 𝜖 : ok(𝑥) 𝐶 ⊢ rec (subtype 1 subtype * ) : ok(𝑥)

sub final? 𝑦 * comptype


The sub type (sub final? 𝑥* comptype) is valid for the type index 𝑥0 if:
• The length of 𝑥* is less than or equal to 1.
• For all 𝑥 in 𝑥* :
– The index 𝑥 is less than 𝑥0 .
– The type 𝐶.types[𝑥] exists.
*
– The sub type unroll(𝐶.types[𝑥]) is of the form (sub 𝑥′ comptype ′ ).
*
• comptype ′ is the concatenation of all such comptype ′ .
• The composite type comptype is valid.
*
• For all comptype ′ in comptype ′ :
– The composite type comptype matches the composite type comptype ′ .

3.2. Types 37
WebAssembly Specification, Release 3.0 (2025-11-14)

*
|𝑥* | ≤ 1 (𝑥 < 𝑥0 )* (unroll(𝐶.types[𝑥]) = sub 𝑥′ comptype ′ )*
𝐶 ⊢ comptype : ok (𝐶 ⊢ comptype ≤ comptype ′ )*
𝐶 ⊢ sub final? 𝑥* comptype : ok(𝑥0 )

Note

The side condition on the index ensures that a declared supertype is a previously defined types, preventing
cyclic subtype hierarchies.
Future versions of WebAssembly may allow more than one supertype.

3.2.12 Limits
Limits must have meaningful bounds that are within a given range.
The limits range [𝑛 .. 𝑚? ] is valid within 𝑘 if:
• 𝑛 is less than or equal to 𝑘.
• If 𝑚 is defined, then:
– 𝑛 is less than or equal to 𝑚.
– 𝑚 is less than or equal to 𝑘.
𝑛≤𝑘 (𝑛 ≤ 𝑚 ≤ 𝑘)?
𝐶 ⊢ [𝑛 .. 𝑚? ] : 𝑘

3.2.13 Tag Types


The tag type typeuse is valid if:
• The type use typeuse is valid.
• The expansion of 𝐶 is (func 𝑡*1 → 𝑡*2 ).
𝐶 ⊢ typeuse : ok typeuse ≈𝐶 func 𝑡*1 → 𝑡*2
𝐶 ⊢ typeuse : ok

3.2.14 Global Types


The global type (mut? 𝑡) is valid if:
• The value type 𝑡 is valid.
𝐶 ⊢ 𝑡 : ok
𝐶 ⊢ mut? 𝑡 : ok

3.2.15 Memory Types


The memory type (addrtype limits page) is valid if:
• The limits range limits is valid within 216 .
𝐶 ⊢ limits : 216
𝐶 ⊢ addrtype limits page : ok

38 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

3.2.16 Table Types


The table type (addrtype limits reftype) is valid if:
• The limits range limits is valid within 232 − 1.
• The reference type reftype is valid.
𝐶 ⊢ limits : 232 − 1 𝐶 ⊢ reftype : ok
𝐶 ⊢ addrtype limits reftype : ok

3.2.17 External Types


The external type (tag tagtype) is valid if:
• The tag type tagtype is valid.
𝐶 ⊢ tagtype : ok
𝐶 ⊢ tag tagtype : ok
The external type (global globaltype) is valid if:
• The global type globaltype is valid.
𝐶 ⊢ globaltype : ok
𝐶 ⊢ global globaltype : ok
The external type (mem memtype) is valid if:
• The memory type memtype is valid.
𝐶 ⊢ memtype : ok
𝐶 ⊢ mem memtype : ok
The external type (table tabletype) is valid if:
• The table type tabletype is valid.
𝐶 ⊢ tabletype : ok
𝐶 ⊢ table tabletype : ok
The external type (func typeuse) is valid if:
• The type use typeuse is valid.
• The expansion of 𝐶 is (func 𝑡*1 → 𝑡*2 ).
𝐶 ⊢ typeuse : ok typeuse ≈𝐶 func 𝑡*1 → 𝑡*2
𝐶 ⊢ func typeuse : ok

3.3 Matching
On most types, a notion of subtyping is defined that is applicable in validation rules, during module instantiation
when checking the types of imports, or during execution, when performing casts.

3.3.1 Number Types


The number type numtype matches only itself.

𝐶 ⊢ numtype ≤ numtype

3.3. Matching 39
WebAssembly Specification, Release 3.0 (2025-11-14)

3.3.2 Vector Types


The vector type vectype matches only itself.

𝐶 ⊢ vectype ≤ vectype

3.3.3 Heap Types


The heap type heaptype 1 matches the heap type heaptype 2 if:
• Either:
– The heap type heaptype 2 is of the form heaptype 1 .
• Or:
– The heap type heaptype ′ is valid.
– The heap type heaptype 1 matches the heap type heaptype ′ .
– The heap type heaptype ′ matches the heap type heaptype 2 .
• Or:
– The heap type heaptype 1 is of the form eq.
– The heap type heaptype 2 is of the form any.
• Or:
– The heap type heaptype 1 is of the form i31.
– The heap type heaptype 2 is of the form eq.
• Or:
– The heap type heaptype 1 is of the form struct.
– The heap type heaptype 2 is of the form eq.
• Or:
– The heap type heaptype 1 is of the form array.
– The heap type heaptype 2 is of the form eq.
• Or:
– The heap type heaptype 1 is of the form deftype.
– The heap type heaptype 2 is of the form struct.
– The expansion of deftype is (struct fieldtype * ).
• Or:
– The heap type heaptype 1 is of the form deftype.
– The heap type heaptype 2 is of the form array.
– The expansion of deftype is (array fieldtype).
• Or:
– The heap type heaptype 1 is of the form deftype.
– The heap type heaptype 2 is of the form func.
– The expansion of deftype is (func 𝑡*1 → 𝑡*2 ).
• Or:
– The heap type heaptype 1 is of the form deftype 1 .

40 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

– The heap type heaptype 2 is of the form deftype 2 .


– The defined type deftype 1 matches the defined type deftype 2 .
• Or:
– The heap type heaptype 1 is of the form typeidx .
– The type 𝐶.types[typeidx ] exists.
– The type 𝐶.types[typeidx ] matches the heap type heaptype 2 .
• Or:
– The heap type heaptype 2 is of the form typeidx .
– The type 𝐶.types[typeidx ] exists.
– The heap type heaptype 1 matches the type 𝐶.types[typeidx ].
• Or:
– The heap type heaptype 1 is of the form (rec.𝑖).
– The length of typeuse * is greater than 𝑗.
– The heap type heaptype 2 is of the form typeuse * [𝑗].
– The recursive type 𝐶.recs[𝑖] exists.
– The recursive type 𝐶.recs[𝑖] is of the form (sub final? typeuse * ct).
• Or:
– The heap type heaptype 1 is of the form none.
– The heap type heaptype 2 matches the heap type any.
• Or:
– The heap type heaptype 1 is of the form nofunc.
– The heap type heaptype 2 matches the heap type func.
• Or:
– The heap type heaptype 1 is of the form noexn.
– The heap type heaptype 2 matches the heap type exn.
• Or:
– The heap type heaptype 1 is of the form noextern.
– The heap type heaptype 2 matches the heap type extern.
• Or:
– The heap type heaptype 1 is of the form bot.

3.3. Matching 41
WebAssembly Specification, Release 3.0 (2025-11-14)

𝐶 ⊢ heaptype ′ : ok 𝐶 ⊢ heaptype 1 ≤ heaptype ′ 𝐶 ⊢ heaptype ′ ≤ heaptype 2


𝐶 ⊢ heaptype ≤ heaptype 𝐶 ⊢ heaptype 1 ≤ heaptype 2

𝐶 ⊢ eq ≤ any 𝐶 ⊢ i31 ≤ eq 𝐶 ⊢ struct ≤ eq 𝐶 ⊢ array ≤ eq


deftype ≈ struct fieldtype * deftype ≈ array fieldtype deftype ≈ func 𝑡*1 → 𝑡*2
𝐶 ⊢ deftype ≤ struct 𝐶 ⊢ deftype ≤ array 𝐶 ⊢ deftype ≤ func
𝐶 ⊢ 𝐶.types[typeidx ] ≤ heaptype 𝐶 ⊢ heaptype ≤ 𝐶.types[typeidx ]
𝐶 ⊢ typeidx ≤ heaptype 𝐶 ⊢ heaptype ≤ typeidx
𝐶.recs[𝑖] = sub final? typeuse * ct
𝐶 ⊢ rec.𝑖 ≤ typeuse * [𝑗]
𝐶 ⊢ heaptype ≤ any 𝐶 ⊢ heaptype ≤ func 𝐶 ⊢ heaptype ≤ exn 𝐶 ⊢ heaptype ≤ extern
𝐶 ⊢ none ≤ heaptype 𝐶 ⊢ nofunc ≤ heaptype 𝐶 ⊢ noexn ≤ heaptype 𝐶 ⊢ noextern ≤ heaptype

𝐶 ⊢ bot ≤ heaptype

3.3.4 Reference Types


The reference type (ref null?1 ht 1 ) matches the reference type (ref null?2 ht 2 ) if:
• The heap type ht 1 matches the heap type ht 2 .
• Either:
– null?1 is absent.
– null?2 is absent.
• Or:
– null?1 is of the form null? .
– null?2 is of the form null.
𝐶 ⊢ ht 1 ≤ ht 2 𝐶 ⊢ ht 1 ≤ ht 2
𝐶 ⊢ ref ht 1 ≤ ref ht 2 𝐶 ⊢ ref null? ht 1 ≤ ref null ht 2

3.3.5 Value Types


The value type valtype 1 matches the value type valtype 2 if:
• Either:
– The value type valtype 1 is of the form numtype 1 .
– The value type valtype 2 is of the form numtype 2 .
– The number type numtype 1 matches the number type numtype 2 .
• Or:
– The value type valtype 1 is of the form vectype 1 .
– The value type valtype 2 is of the form vectype 2 .
– The vector type vectype 1 matches the vector type vectype 2 .
• Or:
– The value type valtype 1 is of the form reftype 1 .
– The value type valtype 2 is of the form reftype 2 .
– The reference type reftype 1 matches the reference type reftype 2 .
• Or:

42 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

– The value type valtype 1 is of the form bot.

𝐶 ⊢ bot ≤ valtype

3.3.6 Result Types


Subtyping is lifted to result types in a pointwise manner.
The result type 𝑡*1 matches the result type 𝑡*2 if:
• For all 𝑡1 in 𝑡*1 , and corresponding 𝑡2 in 𝑡*2 :
– The value type 𝑡1 matches the value type 𝑡2 .
(𝐶 ⊢ 𝑡1 ≤ 𝑡2 )*
𝐶 ⊢ 𝑡*1 ≤ 𝑡*2

3.3.7 Instruction Types


Subtyping is further lifted to instruction types.
The instruction type 𝑡*11 →𝑥*1 𝑡*12 matches the instruction type 𝑡*21 →𝑥*2 𝑡*22 if:
• The result type 𝑡*21 matches the result type 𝑡*11 .
• The result type 𝑡*12 matches the result type 𝑡*22 .
• The local index sequence 𝑥* is of the form 𝑥*2 ∖ 𝑥*1 .
• For all 𝑥 in 𝑥* :
– The local 𝐶.locals[𝑥] exists.
– The local 𝐶.locals[𝑥] is of the form (set 𝑡).
𝐶 ⊢ 𝑡*21 ≤ 𝑡*11 𝐶 ⊢ 𝑡*12 ≤ 𝑡*22 𝑥* = 𝑥*2 ∖ 𝑥*1 (𝐶.locals[𝑥] = set 𝑡)*
* * * *
𝐶 ⊢ 𝑡11 →𝑥*1 𝑡12 ≤ 𝑡21 →𝑥*2 𝑡22

Note

Instruction types are contravariant in their input and covariant in their output. Moreover, the supertype may
ignore variables from the init set 𝑥*1 . It may also add variables to the init set, provided these are already set in
the context, i.e., are vacuously initialized.

3.3.8 Composite Types


The composite type comptype 1 matches the composite type comptype 2 if:
• Either:
*
– The composite type comptype 1 is of the form (struct ft *1 ft ′ 1 ).
– The composite type comptype 2 is of the form (struct ft *2 ).
– For all ft 1 in ft *1 , and corresponding ft 2 in ft *2 :
∗ The field type ft 1 matches the field type ft 2 .
• Or:
– The composite type comptype 1 is of the form (array ft 1 ).
– The composite type comptype 2 is of the form (array ft 2 ).
– The field type ft 1 matches the field type ft 2 .

3.3. Matching 43
WebAssembly Specification, Release 3.0 (2025-11-14)

• Or:
– The composite type comptype 1 is of the form (func 𝑡*11 → 𝑡*12 ).
– The composite type comptype 2 is of the form (func 𝑡*21 → 𝑡*22 ).
– The result type 𝑡*21 matches the result type 𝑡*11 .
– The result type 𝑡*12 matches the result type 𝑡*22 .
(𝐶 ⊢ ft 1 ≤ ft 2 )* 𝐶 ⊢ ft 1 ≤ ft 2 𝐶 ⊢ 𝑡*21 ≤ 𝑡*11 𝐶 ⊢ 𝑡*12 ≤ 𝑡*22
*
𝐶 ⊢ struct (ft *1 ft ′ 1 ) ≤ struct ft *2 𝐶 ⊢ array ft 1 ≤ array ft 2 𝐶 ⊢ func 𝑡*11 → 𝑡*12 ≤ func 𝑡*21 → 𝑡*22

3.3.9 Field Types


The field type (mut?1 zt 1 ) matches the field type (mut?2 zt 2 ) if:
• The storage type zt 1 matches the storage type zt 2 .
• Either:
– mut?1 is absent.
– mut?2 is absent.
• Or:
– mut?1 is of the form mut.
– mut?2 is of the form mut.
– The storage type zt 2 matches the storage type zt 1 .
𝐶 ⊢ zt 1 ≤ zt 2 𝐶 ⊢ zt 1 ≤ zt 2 𝐶 ⊢ zt 2 ≤ zt 1
𝐶 ⊢ zt 1 ≤ zt 2 𝐶 ⊢ mut zt 1 ≤ mut zt 2
The storage type storagetype 1 matches the storage type storagetype 2 if:
• Either:
– The storage type storagetype 1 is of the form valtype 1 .
– The storage type storagetype 2 is of the form valtype 2 .
– The value type valtype 1 matches the value type valtype 2 .
• Or:
– The storage type storagetype 1 is of the form packtype 1 .
– The storage type storagetype 2 is of the form packtype 2 .
– The packed type packtype 1 matches the packed type packtype 2 .
The packed type packtype matches only itself.

𝐶 ⊢ packtype ≤ packtype

3.3.10 Defined Types


The defined type deftype 1 matches the defined type deftype 2 if:
• Either:
– The defined type clos𝐶 (deftype 1 ) is of the form clos𝐶 (deftype 2 ).
• Or:
– The sub type unroll(deftype 1 ) is of the form (sub final? typeuse * ct).

44 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

– The length of typeuse * is greater than 𝑖.


– The type use typeuse * [𝑖] matches the heap type deftype 2 .
clos𝐶 (deftype 1 ) = clos𝐶 (deftype 2 )
𝐶 ⊢ deftype 1 ≤ deftype 2
unroll(deftype 1 ) = sub final? typeuse * ct 𝐶 ⊢ typeuse * [𝑖] ≤ deftype 2
𝐶 ⊢ deftype 1 ≤ deftype 2

Note

Note that there is no explicit definition of type equivalence, since it coincides with syntactic equality, as used
in the premise of the former rule above.

3.3.11 Limits
The limits range [𝑛1 .. u64 ?1 ] matches the limits range [𝑛2 .. u64 ?2 ] if:
• 𝑛1 is greater than or equal to 𝑛2 .
• Either:
– u64 ?1 is of the form 𝑚1 .
– If u64 2 is defined, then:
∗ 𝑚1 is less than or equal to u64 2 .
• Or:
– u64 ?1 is absent.
– u64 ?2 is absent.
𝑛1 ≥ 𝑛2 (𝑚1 ≤ 𝑚2 )? 𝑛1 ≥ 𝑛2
𝐶 ⊢ [𝑛1 .. 𝑚1 ] ≤ [𝑛2 .. 𝑚?2 ] 𝐶 ⊢ [𝑛1 .. 𝜖] ≤ [𝑛2 .. 𝜖]

3.3.12 Tag Types


The tag type deftype 1 matches the tag type deftype 2 if:
• The defined type deftype 1 matches the defined type deftype 2 .
• The defined type deftype 2 matches the defined type deftype 1 .
𝐶 ⊢ deftype 1 ≤ deftype 2 𝐶 ⊢ deftype 2 ≤ deftype 1
𝐶 ⊢ deftype 1 ≤ deftype 2

Note

Although the conclusion of this rule looks identical to its premise, they in fact describe different relations: the
premise invokes subtyping on defined types, while the conclusion defines it on tag types that happen to be
expressed as defined types.

3.3.13 Global Types


The global type (mut?1 valtype 1 ) matches the global type (mut?2 valtype 2 ) if:
• The value type valtype 1 matches the value type valtype 2 .
• Either:

3.3. Matching 45
WebAssembly Specification, Release 3.0 (2025-11-14)

– mut?1 is absent.
– mut?2 is absent.
• Or:
– mut?1 is of the form mut.
– mut?2 is of the form mut.
– The value type valtype 2 matches the value type valtype 1 .
𝐶 ⊢ valtype 1 ≤ valtype 2 𝐶 ⊢ valtype 1 ≤ valtype 2 𝐶 ⊢ valtype 2 ≤ valtype 1
𝐶 ⊢ valtype 1 ≤ valtype 2 𝐶 ⊢ mut valtype 1 ≤ mut valtype 2

3.3.14 Memory Types


The memory type (addrtype limits 1 page) matches the memory type (addrtype limits 2 page) if:
• The limits range limits 1 matches the limits range limits 2 .
𝐶 ⊢ limits 1 ≤ limits 2
𝐶 ⊢ addrtype limits 1 page ≤ addrtype limits 2 page

3.3.15 Table Types


The table type (addrtype limits 1 reftype 1 ) matches the table type (addrtype limits 2 reftype 2 ) if:
• The limits range limits 1 matches the limits range limits 2 .
• The reference type reftype 1 matches the reference type reftype 2 .
• The reference type reftype 2 matches the reference type reftype 1 .
𝐶 ⊢ limits 1 ≤ limits 2 𝐶 ⊢ reftype 1 ≤ reftype 2 𝐶 ⊢ reftype 2 ≤ reftype 1
𝐶 ⊢ addrtype limits 1 reftype 1 ≤ addrtype limits 2 reftype 2

3.3.16 External Types


The external type (tag tagtype 1 ) matches the external type (tag tagtype 2 ) if:
• The tag type tagtype 1 matches the tag type tagtype 2 .
𝐶 ⊢ tagtype 1 ≤ tagtype 2
𝐶 ⊢ tag tagtype 1 ≤ tag tagtype 2
The external type (global globaltype 1 ) matches the external type (global globaltype 2 ) if:
• The global type globaltype 1 matches the global type globaltype 2 .
𝐶 ⊢ globaltype 1 ≤ globaltype 2
𝐶 ⊢ global globaltype 1 ≤ global globaltype 2
The external type (mem memtype 1 ) matches the external type (mem memtype 2 ) if:
• The memory type memtype 1 matches the memory type memtype 2 .
𝐶 ⊢ memtype 1 ≤ memtype 2
𝐶 ⊢ mem memtype 1 ≤ mem memtype 2
The external type (table tabletype 1 ) matches the external type (table tabletype 2 ) if:
• The table type tabletype 1 matches the table type tabletype 2 .
𝐶 ⊢ tabletype 1 ≤ tabletype 2
𝐶 ⊢ table tabletype 1 ≤ table tabletype 2
The external type (func deftype 1 ) matches the external type (func deftype 2 ) if:

46 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

• The defined type deftype 1 matches the defined type deftype 2 .


𝐶 ⊢ deftype 1 ≤ deftype 2
𝐶 ⊢ func deftype 1 ≤ func deftype 2

3.4 Instructions
Instructions are classified by instruction types that describe how they manipulate the operand stack and initialize
locals: A type 𝑡*1 →𝑥* 𝑡*2 describes the required input stack with argument values of types 𝑡*1 that an instruction
pops off and the provided output stack with result values of types 𝑡*2 that it pushes back. Moreover, it enumerates
the indices 𝑥* of locals that have been set by the instruction. In most cases, this is empty.

Note

For example, the instruction [Link] has type i32 i32 → i32, consuming two i32 values and producing one. The
instruction ([Link] 𝑥) has type 𝑡 →𝑥 𝜖, provided 𝑡 is the type declared for the local 𝑥.

Typing extends to instruction sequences instr * . Such a sequence has an instruction type 𝑡*1 →𝑥* 𝑡*2 if the accumu-
lative effect of executing the instructions is consuming values of types 𝑡*1 off the operand stack, pushing new values
of types 𝑡*2 , and setting all locals 𝑥* .
For some instructions, the typing rules do not fully constrain the type, and therefore allow for multiple types. Such
instructions are called polymorphic. Two degrees of polymorphism can be distinguished:
• value-polymorphic: the value type 𝑡 of one or several individual operands is unconstrained. That is the case
for all parametric instructions like drop and select.
• stack-polymorphic: the entire (or most of the) instruction type 𝑡*1 → 𝑡*2 of the instruction is uncon-
strained. That is the case for all control instructions that perform an unconditional control transfer, such
as unreachable, br, or return.
In both cases, the unconstrained types or type sequences can be chosen arbitrarily, as long as they meet the con-
straints imposed for the surrounding parts of the program.

Note

For example, the select instruction is valid with type 𝑡 𝑡 i32 → 𝑡, for any possible number type 𝑡. Consequently,
both instruction sequences

([Link] 1) ([Link] 2) ([Link] 3) (select)

and

(f [Link] +64) (f [Link] +64) (f [Link] +64) (select)

are valid, with 𝑡 in the typing of select being instantiated to i32 or f 64, respectively.
The unreachable instruction is stack-polymorphic, and hence valid with type 𝑡*1 → 𝑡*2 for any possible sequences
of value types 𝑡*1 and 𝑡*2 . Consequently,

(unreachable) ([Link])

is valid by assuming type 𝜖 → i32 for the unreachable instruction. In contrast,

(unreachable) ([Link] 0) ([Link])

is invalid, because there is no possible type to pick for the unreachable instruction that would make the sequence
well-typed.

3.4. Instructions 47
WebAssembly Specification, Release 3.0 (2025-11-14)

The Appendix describes a type checking algorithm that efficiently implements validation of instruction sequences
as prescribed by the rules given here.

3.4.1 Parametric Instructions


nop
The instruction nop is valid with the instruction type 𝜖 → 𝜖.

𝐶 ⊢ nop : 𝜖 → 𝜖

unreachable
The instruction unreachable is valid with the instruction type 𝑡*1 → 𝑡*2 if:
• The instruction type 𝑡*1 → 𝑡*2 is valid.
𝐶 ⊢ 𝑡*1 → 𝑡*2 : ok
𝐶 ⊢ unreachable : 𝑡*1 → 𝑡*2

Note

The unreachable instruction is stack-polymorphic.

drop
The instruction drop is valid with the instruction type 𝑡 → 𝜖 if:
• The value type 𝑡 is valid.
𝐶 ⊢ 𝑡 : ok
𝐶 ⊢ drop : 𝑡 → 𝜖

Note

Both drop and select without annotation are value-polymorphic instructions.

select (𝑡* )?

The instruction (select valtype ? ) is valid with the instruction type 𝑡 𝑡 i32 → 𝑡 if:
• The value type 𝑡 is valid.
• Either:
– The value type sequence valtype ? is of the form 𝑡.
• Or:
– The value type sequence valtype ? is absent.
– The value type 𝑡 matches the value type 𝑡′ .
– The value type 𝑡′ is of the form numtype or 𝑡′ is of the form vectype.
𝐶 ⊢ 𝑡 : ok 𝐶 ⊢ 𝑡 : ok 𝐶 ⊢ 𝑡 ≤ 𝑡′ 𝑡′ = numtype ∨ 𝑡′ = vectype
𝐶 ⊢ select 𝑡 : 𝑡 𝑡 i32 → 𝑡 𝐶 ⊢ select : 𝑡 𝑡 i32 → 𝑡

Note

In future versions of WebAssembly, select may allow more than one value per choice.

48 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

3.4.2 Control Instructions


block blocktype instr *
The instruction (block bt instr * ) is valid with the instruction type 𝑡*1 → 𝑡*2 if:
• The block type bt is valid as the instruction type 𝑡*1 → 𝑡*2 .
• Let 𝐶 ′ be the same context as 𝐶, but with the result type sequence 𝑡*2 prepended to the field labels.
• Under the context 𝐶 ′ , the instruction sequence instr * is valid with the instruction type 𝑡*1 →𝑥* 𝑡*2 .
𝐶 ⊢ bt : 𝑡*1 → 𝑡*2 {labels (𝑡*2 )} ⊕ 𝐶 ⊢ instr * : 𝑡*1 →𝑥* 𝑡*2
𝐶 ⊢ block bt instr * : 𝑡*1 → 𝑡*2

Note

The notation {labels (𝑡* )} ⊕ 𝐶 inserts the new label type at index 0, shifting all others. The same applies to all
other block instructions.

loop blocktype instr *


The instruction (loop bt instr * ) is valid with the instruction type 𝑡*1 → 𝑡*2 if:
• The block type bt is valid as the instruction type 𝑡*1 → 𝑡*2 .
• Let 𝐶 ′ be the same context as 𝐶, but with the result type sequence 𝑡*1 prepended to the field labels.
• Under the context 𝐶 ′ , the instruction sequence instr * is valid with the instruction type 𝑡*1 →𝑥* 𝑡*2 .
𝐶 ⊢ bt : 𝑡*1 → 𝑡*2 {labels (𝑡*1 )} ⊕ 𝐶 ⊢ instr * : 𝑡*1 →𝑥* 𝑡*2
𝐶 ⊢ loop bt instr * : 𝑡*1 → 𝑡*2

if blocktype instr *1 else instr *2


The instruction (if bt instr *1 else instr *2 ) is valid with the instruction type 𝑡*1 i32 → 𝑡*2 if:
• The block type bt is valid as the instruction type 𝑡*1 → 𝑡*2 .
• Let 𝐶 ′ be the same context as 𝐶, but with the result type sequence 𝑡*2 prepended to the field labels.
• Under the context 𝐶 ′ , the instruction sequence instr *1 is valid with the instruction type 𝑡*1 →𝑥*1 𝑡*2 .
• Under the context 𝐶 ′ , the instruction sequence instr *2 is valid with the instruction type 𝑡*1 →𝑥*2 𝑡*2 .
𝐶 ⊢ bt : 𝑡*1 → 𝑡*2 {labels (𝑡*2 )} ⊕ 𝐶 ⊢ instr *1 : 𝑡*1 →𝑥*1 𝑡*2 {labels (𝑡*2 )} ⊕ 𝐶 ⊢ instr *2 : 𝑡*1 →𝑥*2 𝑡*2
* *
𝐶 ⊢ if bt instr 1 else instr 2 : 𝑡*1 i32 → 𝑡*2

br 𝑙
The instruction (br 𝑙) is valid with the instruction type 𝑡*1 𝑡* → 𝑡*2 if:
• The label 𝐶.labels[𝑙] exists.
• The label 𝐶.labels[𝑙] is of the form 𝑡* .
• The instruction type 𝑡*1 → 𝑡*2 is valid.
𝐶.labels[𝑙] = 𝑡* 𝐶 ⊢ 𝑡*1 → 𝑡*2 : ok
𝐶 ⊢ br 𝑙 : 𝑡*1 𝑡* → 𝑡*2

Note

The label index space in the context 𝐶 contains the most recent label first, so that 𝐶.labels[𝑙] performs a relative
lookup as expected. This applies to other branch instructions as well.

3.4. Instructions 49
WebAssembly Specification, Release 3.0 (2025-11-14)

The br instruction is stack-polymorphic.

br_if 𝑙
The instruction (br_if 𝑙) is valid with the instruction type 𝑡* i32 → 𝑡* if:
• The label 𝐶.labels[𝑙] exists.
• The label 𝐶.labels[𝑙] is of the form 𝑡* .
𝐶.labels[𝑙] = 𝑡*
𝐶 ⊢ br_if 𝑙 : 𝑡* i32 → 𝑡*

br_table 𝑙* 𝑙𝑁
The instruction (br_table 𝑙* 𝑙′ ) is valid with the instruction type 𝑡*1 𝑡* i32 → 𝑡*2 if:
• For all 𝑙 in 𝑙* :
– The label 𝐶.labels[𝑙] exists.
– The result type 𝑡* matches the label 𝐶.labels[𝑙].
• The label 𝐶.labels[𝑙′ ] exists.
• The result type 𝑡* matches the label 𝐶.labels[𝑙′ ].
• The instruction type 𝑡*1 𝑡* i32 → 𝑡*2 is valid.
(𝐶 ⊢ 𝑡* ≤ 𝐶.labels[𝑙])* 𝐶 ⊢ 𝑡* ≤ 𝐶.labels[𝑙′ ] 𝐶 ⊢ 𝑡*1 𝑡* i32 → 𝑡*2 : ok
𝐶 ⊢ br_table 𝑙* 𝑙′ : 𝑡*1 𝑡* i32 → 𝑡*2

Note

The br_table instruction is stack-polymorphic.


Furthermore, the result type 𝑡* is also chosen non-deterministically in this rule. Although it may seem necessary
to compute 𝑡* as the greatest lower bound of all label types in practice, a simple sequential algorithm does not
require this.

br_on_null 𝑙
The instruction (br_on_null 𝑙) is valid with the instruction type 𝑡* (ref null ht) → 𝑡* (ref ht) if:
• The label 𝐶.labels[𝑙] exists.
• The label 𝐶.labels[𝑙] is of the form 𝑡* .
• The heap type ht is valid.
𝐶.labels[𝑙] = 𝑡* 𝐶 ⊢ ht : ok
𝐶 ⊢ br_on_null 𝑙 : 𝑡* (ref null ht) → 𝑡* (ref ht)

br_on_non_null 𝑙
The instruction (br_on_non_null 𝑙) is valid with the instruction type 𝑡* (ref null ht) → 𝑡* if:
• The label 𝐶.labels[𝑙] exists.
• The label 𝐶.labels[𝑙] is of the form 𝑡* (ref null? ht).
𝐶.labels[𝑙] = 𝑡* (ref null? ht)
𝐶 ⊢ br_on_non_null 𝑙 : 𝑡* (ref null ht) → 𝑡*

50 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

br_on_cast 𝑙 rt 1 rt 2
The instruction (br_on_cast 𝑙 rt 1 rt 2 ) is valid with the instruction type 𝑡* rt 1 → 𝑡* reftype if:
• The label 𝐶.labels[𝑙] exists.
• The label 𝐶.labels[𝑙] is of the form 𝑡* rt.
• The reference type rt 1 is valid.
• The reference type rt 2 is valid.
• The reference type rt 2 matches the reference type rt 1 .
• The reference type rt 2 matches the reference type rt.
• The reference type reftype is rt 1 ∖ rt 2 .
𝐶.labels[𝑙] = 𝑡* rt 𝐶 ⊢ rt 1 : ok 𝐶 ⊢ rt 2 : ok 𝐶 ⊢ rt 2 ≤ rt 1 𝐶 ⊢ rt 2 ≤ rt
* *
𝐶 ⊢ br_on_cast 𝑙 rt 1 rt 2 : 𝑡 rt 1 → 𝑡 (rt 1 ∖ rt 2 )

br_on_cast_fail 𝑙 rt 1 rt 2
The instruction (br_on_cast_fail 𝑙 rt 1 rt 2 ) is valid with the instruction type 𝑡* rt 1 → 𝑡* rt 2 if:
• The label 𝐶.labels[𝑙] exists.
• The label 𝐶.labels[𝑙] is of the form 𝑡* rt.
• The reference type rt 1 is valid.
• The reference type rt 2 is valid.
• The reference type rt 2 matches the reference type rt 1 .
• The reference type rt 1 ∖ rt 2 matches the reference type rt.
𝐶.labels[𝑙] = 𝑡* rt 𝐶 ⊢ rt 1 : ok 𝐶 ⊢ rt 2 : ok 𝐶 ⊢ rt 2 ≤ rt 1 𝐶 ⊢ rt 1 ∖ rt 2 ≤ rt
𝐶 ⊢ br_on_cast_fail 𝑙 rt 1 rt 2 : 𝑡* rt 1 → 𝑡* rt 2

call 𝑥
The instruction (call 𝑥) is valid with the instruction type 𝑡*1 → 𝑡*2 if:
• The function 𝐶.funcs[𝑥] exists.
• The expansion of 𝐶.funcs[𝑥] is (func 𝑡*1 → 𝑡*2 ).
𝐶.funcs[𝑥] ≈ func 𝑡*1 → 𝑡*2
𝐶 ⊢ call 𝑥 : 𝑡*1 → 𝑡*2

call_ref 𝑥
The instruction (call_ref 𝑥) is valid with the instruction type 𝑡*1 (ref null 𝑥) → 𝑡*2 if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (func 𝑡*1 → 𝑡*2 ).
𝐶.types[𝑥] ≈ func 𝑡*1 → 𝑡*2
𝐶 ⊢ call_ref 𝑥 : 𝑡*1 (ref null 𝑥) → 𝑡*2

call_indirect 𝑥 𝑦
The instruction (call_indirect 𝑥 𝑦) is valid with the instruction type 𝑡*1 at → 𝑡*2 if:
• The table 𝐶.tables[𝑥] exists.
• The table 𝐶.tables[𝑥] is of the form (at lim rt).
• The reference type rt matches the reference type (ref null func).

3.4. Instructions 51
WebAssembly Specification, Release 3.0 (2025-11-14)

• The type 𝐶.types[𝑦] exists.


• The expansion of 𝐶.types[𝑦] is (func 𝑡*1 → 𝑡*2 ).
𝐶.tables[𝑥] = at lim rt 𝐶 ⊢ rt ≤ (ref null func) 𝐶.types[𝑦] ≈ func 𝑡*1 → 𝑡*2
𝐶 ⊢ call_indirect 𝑥 𝑦 : 𝑡1 at → 𝑡*2
*

return
The instruction return is valid with the instruction type 𝑡*1 𝑡* → 𝑡*2 if:
• The result type 𝐶.return is of the form 𝑡* .
• The instruction type 𝑡*1 → 𝑡*2 is valid.
𝐶.return = (𝑡* ) 𝐶 ⊢ 𝑡*1 → 𝑡*2 : ok
𝐶 ⊢ return : 𝑡*1 𝑡* → 𝑡*2

Note

The return instruction is stack-polymorphic.


𝐶.return is absent (set to 𝜖) when validating an expression that is not a function body. This differs from it being
set to the empty result type [𝜖], which is the case for functions not returning anything.

return_call 𝑥
The instruction (return_call 𝑥) is valid with the instruction type 𝑡*3 𝑡*1 → 𝑡*4 if:
• The function 𝐶.funcs[𝑥] exists.
• The expansion of 𝐶.funcs[𝑥] is (func 𝑡*1 → 𝑡*2 ).
*
• The result type 𝐶.return is of the form 𝑡′ 2 .
*
• The result type 𝑡*2 matches the result type 𝑡′ 2 .
• The instruction type 𝑡*3 → 𝑡*4 is valid.
* *
𝐶.funcs[𝑥] ≈ func 𝑡*1 → 𝑡*2 𝐶.return = (𝑡′ 2 ) 𝐶 ⊢ 𝑡*2 ≤ 𝑡′ 2 𝐶 ⊢ 𝑡*3 → 𝑡*4 : ok
𝐶 ⊢ return_call 𝑥 : 𝑡*3 𝑡*1 → 𝑡*4

Note

The return_call instruction is stack-polymorphic.

return_call_ref 𝑥
The instruction (return_call_ref 𝑥) is valid with the instruction type 𝑡*3 𝑡*1 (ref null 𝑥) → 𝑡*4 if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (func 𝑡*1 → 𝑡*2 ).
*
• The result type 𝐶.return is of the form 𝑡′ 2 .
*
• The result type 𝑡*2 matches the result type 𝑡′ 2 .
• The instruction type 𝑡*3 → 𝑡*4 is valid.
* *
𝐶.types[𝑥] ≈ func 𝑡*1 → 𝑡*2 𝐶.return = (𝑡′ 2 ) 𝐶 ⊢ 𝑡*2 ≤ 𝑡′ 2 𝐶 ⊢ 𝑡*3 → 𝑡*4 : ok
𝐶 ⊢ return_call_ref 𝑥 : 𝑡*3 𝑡*1 (ref null 𝑥) → 𝑡*4

52 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

Note

The return_call_ref instruction is stack-polymorphic.

return_call_indirect 𝑥 𝑦
The instruction (return_call_indirect 𝑥 𝑦) is valid with the instruction type 𝑡*3 𝑡*1 at → 𝑡*4 if:
• The table 𝐶.tables[𝑥] exists.
• The table 𝐶.tables[𝑥] is of the form (at lim rt).
• The reference type rt matches the reference type (ref null func).
• The type 𝐶.types[𝑦] exists.
• The expansion of 𝐶.types[𝑦] is (func 𝑡*1 → 𝑡*2 ).
*
• The result type 𝐶.return is of the form 𝑡′ 2 .
*
• The result type 𝑡*2 matches the result type 𝑡′ 2 .
• The instruction type 𝑡*3 → 𝑡*4 is valid.
𝐶.tables[𝑥] = at lim rt 𝐶 ⊢ rt ≤ (ref null func)
* *
𝐶.types[𝑦] ≈ func 𝑡*1 → 𝑡*2 𝐶.return = (𝑡′ 2 ) 𝐶 ⊢ 𝑡*2 ≤ 𝑡′ 2 𝐶 ⊢ 𝑡*3 → 𝑡*4 : ok
𝐶 ⊢ return_call_indirect 𝑥 𝑦 : 𝑡*3 𝑡*1 at → 𝑡*4

Note

The return_call_indirect instruction is stack-polymorphic.

throw 𝑥
The instruction (throw 𝑥) is valid with the instruction type 𝑡*1 𝑡* → 𝑡*2 if:
• The tag 𝐶.tags[𝑥] exists.
• The expansion of 𝐶.tags[𝑥] is (func 𝑡* →).
• The instruction type 𝑡*1 → 𝑡*2 is valid.
𝐶.tags[𝑥] ≈ func 𝑡* → 𝜖 𝐶 ⊢ 𝑡*1 → 𝑡*2 : ok
𝐶 ⊢ throw 𝑥 : 𝑡1 𝑡 → 𝑡*2
* *

Note

The throw instruction is stack-polymorphic.

throw_ref
The instruction throw_ref is valid with the instruction type 𝑡*1 (ref null exn) → 𝑡*2 if:
• The instruction type 𝑡*1 → 𝑡*2 is valid.
𝐶 ⊢ 𝑡*1 → 𝑡*2 : ok
𝐶 ⊢ throw_ref : 𝑡*1 (ref null exn) → 𝑡*2

Note

The throw_ref instruction is stack-polymorphic.

3.4. Instructions 53
WebAssembly Specification, Release 3.0 (2025-11-14)

try_table blocktype catch * instr *


The instruction (try_table bt catch * instr * ) is valid with the instruction type 𝑡*1 → 𝑡*2 if:
• The block type bt is valid as the instruction type 𝑡*1 → 𝑡*2 .
• Let 𝐶 ′ be the same context as 𝐶, but with the result type sequence 𝑡*2 prepended to the field labels.
• Under the context 𝐶 ′ , the instruction sequence instr * is valid with the instruction type 𝑡*1 →𝑥* 𝑡*2 .
• For all catch in catch * :
– The catch clause catch is valid.
𝐶 ⊢ bt : 𝑡*1 → 𝑡*2 {labels (𝑡*2 )} ⊕ 𝐶 ⊢ instr * : 𝑡*1 →𝑥* 𝑡*2 (𝐶 ⊢ catch : ok)*
𝐶 ⊢ try_table bt catch * instr * : 𝑡*1 → 𝑡*2

catch 𝑥 𝑙
The catch clause (catch 𝑥 𝑙) is valid if:
• The tag 𝐶.tags[𝑥] exists.
• The expansion of 𝐶.tags[𝑥] is (func 𝑡* →).
• The label 𝐶.labels[𝑙] exists.
• The result type 𝑡* matches the label 𝐶.labels[𝑙].
𝐶.tags[𝑥] ≈ func 𝑡* → 𝜖 𝐶 ⊢ 𝑡* ≤ 𝐶.labels[𝑙]
𝐶 ⊢ catch 𝑥 𝑙 : ok

catch_ref 𝑥 𝑙
The catch clause (catch_ref 𝑥 𝑙) is valid if:
• The tag 𝐶.tags[𝑥] exists.
• The expansion of 𝐶.tags[𝑥] is (func 𝑡* →).
• The label 𝐶.labels[𝑙] exists.
• The result type 𝑡* (ref exn) matches the label 𝐶.labels[𝑙].
𝐶.tags[𝑥] ≈ func 𝑡* → 𝜖 𝐶 ⊢ 𝑡* (ref exn) ≤ 𝐶.labels[𝑙]
𝐶 ⊢ catch_ref 𝑥 𝑙 : ok

catch_all 𝑙
The catch clause (catch_all 𝑙) is valid if:
• The label 𝐶.labels[𝑙] exists.
• The result type 𝜖 matches the label 𝐶.labels[𝑙].
𝐶 ⊢ 𝜖 ≤ 𝐶.labels[𝑙]
𝐶 ⊢ catch_all 𝑙 : ok

catch_all_ref 𝑙
The catch clause (catch_all_ref 𝑙) is valid if:
• The label 𝐶.labels[𝑙] exists.
• The result type (ref exn) matches the label 𝐶.labels[𝑙].
𝐶 ⊢ (ref exn) ≤ 𝐶.labels[𝑙]
𝐶 ⊢ catch_all_ref 𝑙 : ok

54 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

3.4.3 Variable Instructions


[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type 𝜖 → 𝑡 if:
• The local 𝐶.locals[𝑥] exists.
• The local 𝐶.locals[𝑥] is of the form (set 𝑡).
𝐶.locals[𝑥] = set 𝑡
𝐶 ⊢ [Link] 𝑥 : 𝜖 → 𝑡

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type 𝑡 →𝑥 𝜖 if:
• The local 𝐶.locals[𝑥] exists.
• The local 𝐶.locals[𝑥] is of the form (init 𝑡).
𝐶.locals[𝑥] = init 𝑡
𝐶 ⊢ [Link] 𝑥 : 𝑡 →𝑥 𝜖

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type 𝑡 →𝑥 𝑡 if:
• The local 𝐶.locals[𝑥] exists.
• The local 𝐶.locals[𝑥] is of the form (init 𝑡).
𝐶.locals[𝑥] = init 𝑡
𝐶 ⊢ [Link] 𝑥 : 𝑡 →𝑥 𝑡

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type 𝜖 → 𝑡 if:
• The global 𝐶.globals[𝑥] exists.
• The global 𝐶.globals[𝑥] is of the form (mut? 𝑡).
𝐶.globals[𝑥] = mut? 𝑡
𝐶 ⊢ [Link] 𝑥 : 𝜖 → 𝑡

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type 𝑡 → 𝜖 if:
• The global 𝐶.globals[𝑥] exists.
• The global 𝐶.globals[𝑥] is of the form (mut 𝑡).
𝐶.globals[𝑥] = mut 𝑡
𝐶 ⊢ [Link] 𝑥 : 𝑡 → 𝜖

3.4.4 Table Instructions


[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type at → rt if:
• The table 𝐶.tables[𝑥] exists.
• The table 𝐶.tables[𝑥] is of the form (at lim rt).
𝐶.tables[𝑥] = at lim rt
𝐶 ⊢ [Link] 𝑥 : at → rt

3.4. Instructions 55
WebAssembly Specification, Release 3.0 (2025-11-14)

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type at rt → 𝜖 if:
• The table 𝐶.tables[𝑥] exists.
• The table 𝐶.tables[𝑥] is of the form (at lim rt).
𝐶.tables[𝑥] = at lim rt
𝐶 ⊢ [Link] 𝑥 : at rt → 𝜖

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type 𝜖 → at if:
• The table 𝐶.tables[𝑥] exists.
• The table 𝐶.tables[𝑥] is of the form (at lim rt).
𝐶.tables[𝑥] = at lim rt
𝐶 ⊢ [Link] 𝑥 : 𝜖 → at

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type rt at → i32 if:
• The table 𝐶.tables[𝑥] exists.
• The table 𝐶.tables[𝑥] is of the form (at lim rt).
𝐶.tables[𝑥] = at lim rt
𝐶 ⊢ [Link] 𝑥 : rt at → i32

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type at rt at → 𝜖 if:
• The table 𝐶.tables[𝑥] exists.
• The table 𝐶.tables[𝑥] is of the form (at lim rt).
𝐶.tables[𝑥] = at lim rt
𝐶 ⊢ [Link] 𝑥 : at rt at → 𝜖

[Link] 𝑥 𝑦
The instruction ([Link] 𝑥1 𝑥2 ) is valid with the instruction type at 1 at 2 addrtype → 𝜖 if:
• The table 𝐶.tables[𝑥1 ] exists.
• The table 𝐶.tables[𝑥1 ] is of the form (at 1 lim 1 rt 1 ).
• The table 𝐶.tables[𝑥2 ] exists.
• The table 𝐶.tables[𝑥2 ] is of the form (at 2 lim 2 rt 2 ).
• The reference type rt 2 matches the reference type rt 1 .
• The address type addrtype is min(at 1 , at 2 ).
𝐶.tables[𝑥1 ] = at 1 lim 1 rt 1 𝐶.tables[𝑥2 ] = at 2 lim 2 rt 2 𝐶 ⊢ rt 2 ≤ rt 1
𝐶 ⊢ [Link] 𝑥1 𝑥2 : at 1 at 2 min(at 1 , at 2 ) → 𝜖

56 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

[Link] 𝑥 𝑦
The instruction ([Link] 𝑥 𝑦) is valid with the instruction type at i32 i32 → 𝜖 if:
• The table 𝐶.tables[𝑥] exists.
• The table 𝐶.tables[𝑥] is of the form (at lim rt 1 ).
• The element segment 𝐶.elems[𝑦] exists.
• The element segment 𝐶.elems[𝑦] is of the form rt 2 .
• The reference type rt 2 matches the reference type rt 1 .
𝐶.tables[𝑥] = at lim rt 1 𝐶.elems[𝑦] = rt 2 𝐶 ⊢ rt 2 ≤ rt 1
𝐶 ⊢ [Link] 𝑥 𝑦 : at i32 i32 → 𝜖

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type 𝜖 → 𝜖 if:
• The element segment 𝐶.elems[𝑥] exists.
𝐶.elems[𝑥] = rt
𝐶 ⊢ [Link] 𝑥 : 𝜖 → 𝜖

3.4.5 Memory Instructions


Memory instructions use memory arguments, which are classified by the address type and the and bit width of the
access they are suitable for.

memarg
{align 𝑛, offset 𝑚} is valid for at and 𝑁 if:
• 2𝑛 is less than or equal to 𝑁/8.
• 𝑚 is less than 2|at| .
2𝑛 ≤ 𝑁/8 𝑚 < 2|at|
⊢ {align 𝑛, offset 𝑚} : at → 𝑁

𝑡.load 𝑥 memarg
The instruction ([Link] 𝑥 memarg) is valid with the instruction type at → nt if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
• memarg is valid for at and |nt|.
𝐶.mems[𝑥] = at lim page ⊢ memarg : at → |nt|
𝐶 ⊢ [Link] 𝑥 memarg : at → nt

𝑡.load𝑁 _sx 𝑥 memarg


The instruction (i𝑁 .load𝑀 _sx 𝑥 memarg) is valid with the instruction type at → i𝑁 if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
• memarg is valid for at and 𝑀 .
𝐶.mems[𝑥] = at lim page ⊢ memarg : at → 𝑀
𝐶 ⊢ i𝑁 .load𝑀 _sx 𝑥 memarg : at → i𝑁

3.4. Instructions 57
WebAssembly Specification, Release 3.0 (2025-11-14)

𝑡.store 𝑥 memarg
The instruction ([Link] 𝑥 memarg) is valid with the instruction type at nt → 𝜖 if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
• memarg is valid for at and |nt|.
𝐶.mems[𝑥] = at lim page ⊢ memarg : at → |nt|
𝐶 ⊢ [Link] 𝑥 memarg : at nt → 𝜖

𝑡.store𝑁 𝑥 memarg
The instruction (i𝑁 .store𝑀 𝑥 memarg) is valid with the instruction type at i𝑁 → 𝜖 if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
• memarg is valid for at and 𝑀 .
𝐶.mems[𝑥] = at lim page ⊢ memarg : at → 𝑀
𝐶 ⊢ i𝑁 .store𝑀 𝑥 memarg : at i𝑁 → 𝜖

[Link] 𝑥 memarg
The instruction ([Link] 𝑥 memarg) is valid with the instruction type at → v128 if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
• memarg is valid for at and |v128|.
𝐶.mems[𝑥] = at lim page ⊢ memarg : at → |v128|
𝐶 ⊢ [Link] 𝑥 memarg : at → v128

[Link]𝑁 x𝑀 _sx 𝑥 memarg


The instruction ([Link]𝑀 x𝑁 _sx 𝑥 memarg) is valid with the instruction type at → v128 if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
• memarg is valid for at and 𝑀 · 𝑁 .
𝐶.mems[𝑥] = at lim page ⊢ memarg : at → 𝑀 · 𝑁
𝐶 ⊢ [Link]𝑀 x𝑁 _sx 𝑥 memarg : at → v128

[Link]𝑁 _splat 𝑥 memarg


The instruction ([Link]𝑁 _splat 𝑥 memarg) is valid with the instruction type at → v128 if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
• memarg is valid for at and 𝑁 .
𝐶.mems[𝑥] = at lim page ⊢ memarg : at → 𝑁
𝐶 ⊢ [Link]𝑁 _splat 𝑥 memarg : at → v128

58 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

[Link]𝑁 _zero 𝑥 memarg


The instruction ([Link]𝑁 _zero 𝑥 memarg) is valid with the instruction type at → v128 if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
• memarg is valid for at and 𝑁 .
𝐶.mems[𝑥] = at lim page ⊢ memarg : at → 𝑁
𝐶 ⊢ [Link]𝑁 _zero 𝑥 memarg : at → v128

[Link]𝑁 _lane 𝑥 memarg laneidx


The instruction ([Link]𝑁 _lane 𝑥 memarg 𝑖) is valid with the instruction type at v128 → v128 if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
• memarg is valid for at and 𝑁 .
• 𝑖 is less than 128/𝑁 .
𝐶.mems[𝑥] = at lim page ⊢ memarg : at → 𝑁 𝑖 < 128/𝑁
𝐶 ⊢ [Link]𝑁 _lane 𝑥 memarg 𝑖 : at v128 → v128

[Link] 𝑥 memarg
The instruction ([Link] 𝑥 memarg) is valid with the instruction type at v128 → 𝜖 if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
• memarg is valid for at and |v128|.
𝐶.mems[𝑥] = at lim page ⊢ memarg : at → |v128|
𝐶 ⊢ [Link] 𝑥 memarg : at v128 → 𝜖

[Link]𝑁 _lane 𝑥 memarg laneidx


The instruction ([Link]𝑁 _lane 𝑥 memarg 𝑖) is valid with the instruction type at v128 → 𝜖 if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
• memarg is valid for at and 𝑁 .
• 𝑖 is less than 128/𝑁 .
𝐶.mems[𝑥] = at lim page ⊢ memarg : at → 𝑁 𝑖 < 128/𝑁
𝐶 ⊢ [Link]𝑁 _lane 𝑥 memarg 𝑖 : at v128 → 𝜖

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type 𝜖 → at if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
𝐶.mems[𝑥] = at lim page
𝐶 ⊢ [Link] 𝑥 : 𝜖 → at

3.4. Instructions 59
WebAssembly Specification, Release 3.0 (2025-11-14)

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type at → at if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
𝐶.mems[𝑥] = at lim page
𝐶 ⊢ [Link] 𝑥 : at → at

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type at i32 at → 𝜖 if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
𝐶.mems[𝑥] = at lim page
𝐶 ⊢ [Link] 𝑥 : at i32 at → 𝜖

[Link] 𝑥 𝑦
The instruction ([Link] 𝑥1 𝑥2 ) is valid with the instruction type at 1 at 2 addrtype → 𝜖 if:
• The memory 𝐶.mems[𝑥1 ] exists.
• The memory 𝐶.mems[𝑥1 ] is of the form (at 1 lim 1 page).
• The memory 𝐶.mems[𝑥2 ] exists.
• The memory 𝐶.mems[𝑥2 ] is of the form (at 2 lim 2 page).
• The address type addrtype is min(at 1 , at 2 ).
𝐶.mems[𝑥1 ] = at 1 lim 1 page 𝐶.mems[𝑥2 ] = at 2 lim 2 page
𝐶 ⊢ [Link] 𝑥1 𝑥2 : at 1 at 2 min(at 1 , at 2 ) → 𝜖

[Link] 𝑥 𝑦
The instruction ([Link] 𝑥 𝑦) is valid with the instruction type at i32 i32 → 𝜖 if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form (at lim page).
• The data segment 𝐶.datas[𝑦] exists.
• The data segment 𝐶.datas[𝑦] is of the form ok.
𝐶.mems[𝑥] = at lim page 𝐶.datas[𝑦] = ok
𝐶 ⊢ [Link] 𝑥 𝑦 : at i32 i32 → 𝜖

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type 𝜖 → 𝜖 if:
• The data segment 𝐶.datas[𝑥] exists.
• The data segment 𝐶.datas[𝑥] is of the form ok.
𝐶.datas[𝑥] = ok
𝐶 ⊢ [Link] 𝑥 : 𝜖 → 𝜖

60 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

3.4.6 Reference Instructions


[Link] ht
The instruction ([Link] ht) is valid with the instruction type 𝜖 → (ref null ht) if:
• The heap type ht is valid.
𝐶 ⊢ ht : ok
𝐶 ⊢ [Link] ht : 𝜖 → (ref null ht)

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type 𝜖 → (ref dt) if:
• The function 𝐶.funcs[𝑥] exists.
• The function 𝐶.funcs[𝑥] is of the form dt.
• 𝑥 is contained in 𝐶.refs.
𝐶.funcs[𝑥] = dt 𝑥 ∈ 𝐶.refs
𝐶 ⊢ [Link] 𝑥 : 𝜖 → (ref dt)

ref.is_null
The instruction ref.is_null is valid with the instruction type (ref null ht) → i32 if:
• The heap type ht is valid.
𝐶 ⊢ ht : ok
𝐶 ⊢ ref.is_null : (ref null ht) → i32

ref.as_non_null
The instruction ref.as_non_null is valid with the instruction type (ref null ht) → (ref ht) if:
• The heap type ht is valid.
𝐶 ⊢ ht : ok
𝐶 ⊢ ref.as_non_null : (ref null ht) → (ref ht)

[Link]
The instruction [Link] is valid with the instruction type (ref null eq) (ref null eq) → i32.

𝐶 ⊢ [Link] : (ref null eq) (ref null eq) → i32

[Link] rt
The instruction ([Link] rt) is valid with the instruction type rt ′ → i32 if:
• The reference type rt is valid.
• The reference type rt ′ is valid.
• The reference type rt matches the reference type rt ′ .
𝐶 ⊢ rt : ok 𝐶 ⊢ rt ′ : ok 𝐶 ⊢ rt ≤ rt ′
𝐶 ⊢ [Link] rt : rt ′ → i32

Note

The liberty to pick a supertype rt ′ allows typing the instruction with the least precise super type of rt as input,
that is, the top type in the corresponding heap subtyping hierarchy.

3.4. Instructions 61
WebAssembly Specification, Release 3.0 (2025-11-14)

[Link] rt
The instruction ([Link] rt) is valid with the instruction type rt ′ → rt if:
• The reference type rt is valid.
• The reference type rt ′ is valid.
• The reference type rt matches the reference type rt ′ .
𝐶 ⊢ rt : ok 𝐶 ⊢ rt ′ : ok 𝐶 ⊢ rt ≤ rt ′
𝐶 ⊢ [Link] rt : rt ′ → rt

Note

The liberty to pick a supertype rt ′ allows typing the instruction with the least precise super type of rt as input,
that is, the top type in the corresponding heap subtyping hierarchy.

3.4.7 Aggregate Reference Instructions


[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type 𝑡* → (ref 𝑥) if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (struct (mut? zt)* ).
• The value type sequence 𝑡* is unpack(zt)* .
𝐶.types[𝑥] ≈ struct (mut? zt)*
𝐶 ⊢ [Link] 𝑥 : unpack(zt)* → (ref 𝑥)

struct.new_default 𝑥
The instruction (struct.new_default 𝑥) is valid with the instruction type 𝜖 → (ref 𝑥) if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (struct (mut? zt)* ).
• For all zt in zt * :
– A default value for unpack(zt) is defined.
𝐶.types[𝑥] ≈ struct (mut? zt)* (defaultunpack(zt) ̸= 𝜖)*
𝐶 ⊢ struct.new_default 𝑥 : 𝜖 → (ref 𝑥)

struct.get_sx ? 𝑥 𝑦
The instruction (struct.get_sx ? 𝑥 𝑖) is valid with the instruction type (ref null 𝑥) → 𝑡 if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (struct ft * ).
• The length of ft * is greater than 𝑖.
• The field type ft * [𝑖] is of the form (mut? zt).
• The signedness sx ? is absent if and only if zt is a packed type.
• The value type 𝑡 is unpack(zt).
𝐶.types[𝑥] ≈ struct ft * ft * [𝑖] = mut? zt sx ? = 𝜖 ⇔ zt = unpack(zt)
?
𝐶 ⊢ struct.get_sx 𝑥 𝑖 : (ref null 𝑥) → unpack(zt)

62 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

[Link] 𝑥 𝑦
The instruction ([Link] 𝑥 𝑖) is valid with the instruction type (ref null 𝑥) 𝑡 → 𝜖 if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (struct ft * ).
• The length of ft * is greater than 𝑖.
• The field type ft * [𝑖] is of the form (mut zt).
• The value type 𝑡 is unpack(zt).
𝐶.types[𝑥] ≈ struct ft * ft * [𝑖] = mut zt
𝐶 ⊢ [Link] 𝑥 𝑖 : (ref null 𝑥) unpack(zt) → 𝜖

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type 𝑡 i32 → (ref 𝑥) if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (array (mut? zt)).
• The value type 𝑡 is unpack(zt).
𝐶.types[𝑥] ≈ array (mut? zt)
𝐶 ⊢ [Link] 𝑥 : unpack(zt) i32 → (ref 𝑥)

array.new_default 𝑥
The instruction (array.new_default 𝑥) is valid with the instruction type i32 → (ref 𝑥) if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (array (mut? zt)).
• A default value for unpack(zt) is defined.
𝐶.types[𝑥] ≈ array (mut? zt) defaultunpack(zt) ̸= 𝜖
𝐶 ⊢ array.new_default 𝑥 : i32 → (ref 𝑥)

array.new_fixed 𝑥 𝑛
The instruction (array.new_fixed 𝑥 𝑛) is valid with the instruction type 𝑡𝑛 → (ref 𝑥) if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (array (mut? zt)).
• The value type 𝑡 is unpack(zt).
𝐶.types[𝑥] ≈ array (mut? zt)
𝐶 ⊢ array.new_fixed 𝑥 𝑛 : unpack(zt)𝑛 → (ref 𝑥)

array.new_elem 𝑥 𝑦
The instruction (array.new_elem 𝑥 𝑦) is valid with the instruction type i32 i32 → (ref 𝑥) if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (array (mut? rt)).
• The element segment 𝐶.elems[𝑦] exists.
• The element segment 𝐶.elems[𝑦] matches the reference type rt.
𝐶.types[𝑥] ≈ array (mut? rt) 𝐶 ⊢ 𝐶.elems[𝑦] ≤ rt
𝐶 ⊢ array.new_elem 𝑥 𝑦 : i32 i32 → (ref 𝑥)

3.4. Instructions 63
WebAssembly Specification, Release 3.0 (2025-11-14)

array.new_data 𝑥 𝑦
The instruction (array.new_data 𝑥 𝑦) is valid with the instruction type i32 i32 → (ref 𝑥) if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (array (mut? zt)).
• The value type unpack(zt) is of the form numtype or unpack(zt) is of the form vectype.
• The data segment 𝐶.datas[𝑦] exists.
• The data segment 𝐶.datas[𝑦] is of the form ok.
𝐶.types[𝑥] ≈ array (mut? zt) unpack(zt) = numtype ∨ unpack(zt) = vectype 𝐶.datas[𝑦] = ok
𝐶 ⊢ array.new_data 𝑥 𝑦 : i32 i32 → (ref 𝑥)

array.get_sx ? 𝑥
The instruction (array.get_sx ? 𝑥) is valid with the instruction type (ref null 𝑥) i32 → 𝑡 if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (array (mut? zt)).
• The signedness sx ? is absent if and only if zt is a packed type.
• The value type 𝑡 is unpack(zt).
𝐶.types[𝑥] ≈ array (mut? zt) sx ? = 𝜖 ⇔ zt = unpack(zt)
?
𝐶 ⊢ array.get_sx 𝑥 : (ref null 𝑥) i32 → unpack(zt)

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type (ref null 𝑥) i32 𝑡 → 𝜖 if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (array (mut zt)).
• The value type 𝑡 is unpack(zt).
𝐶.types[𝑥] ≈ array (mut zt)
𝐶 ⊢ [Link] 𝑥 : (ref null 𝑥) i32 unpack(zt) → 𝜖

[Link]
The instruction [Link] is valid with the instruction type (ref null array) → i32.

𝐶 ⊢ [Link] : (ref null array) → i32

[Link] 𝑥
The instruction ([Link] 𝑥) is valid with the instruction type (ref null 𝑥) i32 𝑡 i32 → 𝜖 if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (array (mut zt)).
• The value type 𝑡 is unpack(zt).
𝐶.types[𝑥] ≈ array (mut zt)
𝐶 ⊢ [Link] 𝑥 : (ref null 𝑥) i32 unpack(zt) i32 → 𝜖

64 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

[Link] 𝑥 𝑦
The instruction ([Link] 𝑥1 𝑥2 ) is valid with the instruction type (ref null 𝑥1 ) i32 (ref null 𝑥2 ) i32 i32 → 𝜖 if:
• The type 𝐶.types[𝑥1 ] exists.
• The expansion of 𝐶.types[𝑥1 ] is (array (mut zt 1 )).
• The type 𝐶.types[𝑥2 ] exists.
• The expansion of 𝐶.types[𝑥2 ] is (array (mut? zt 2 )).
• The storage type zt 2 matches the storage type zt 1 .
𝐶.types[𝑥1 ] ≈ array (mut zt 1 ) 𝐶.types[𝑥2 ] ≈ array (mut? zt 2 ) 𝐶 ⊢ zt 2 ≤ zt 1
𝐶 ⊢ [Link] 𝑥1 𝑥2 : (ref null 𝑥1 ) i32 (ref null 𝑥2 ) i32 i32 → 𝜖

array.init_elem 𝑥 𝑦
The instruction (array.init_elem 𝑥 𝑦) is valid with the instruction type (ref null 𝑥) i32 i32 i32 → 𝜖 if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (array (mut zt)).
• The element segment 𝐶.elems[𝑦] exists.
• The element segment 𝐶.elems[𝑦] matches the storage type zt.
𝐶.types[𝑥] ≈ array (mut zt) 𝐶 ⊢ 𝐶.elems[𝑦] ≤ zt
𝐶 ⊢ array.init_elem 𝑥 𝑦 : (ref null 𝑥) i32 i32 i32 → 𝜖

array.init_data 𝑥 𝑦
The instruction (array.init_data 𝑥 𝑦) is valid with the instruction type (ref null 𝑥) i32 i32 i32 → 𝜖 if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (array (mut zt)).
• The value type unpack(zt) is of the form numtype or unpack(zt) is of the form vectype.
• The data segment 𝐶.datas[𝑦] exists.
• The data segment 𝐶.datas[𝑦] is of the form ok.
𝐶.types[𝑥] ≈ array (mut zt) unpack(zt) = numtype ∨ unpack(zt) = vectype 𝐶.datas[𝑦] = ok
𝐶 ⊢ array.init_data 𝑥 𝑦 : (ref null 𝑥) i32 i32 i32 → 𝜖

3.4.8 Scalar Reference Instructions


ref.i31
The instruction ref.i31 is valid with the instruction type i32 → (ref i31).

𝐶 ⊢ ref.i31 : i32 → (ref i31)

i31.get_sx
The instruction (i31.get_sx ) is valid with the instruction type (ref null i31) → i32.

𝐶 ⊢ i31.get_sx : (ref null i31) → i32

3.4. Instructions 65
WebAssembly Specification, Release 3.0 (2025-11-14)

3.4.9 External Reference Instructions


any.convert_extern

The instruction any.convert_extern is valid with the instruction type (ref null?1 extern) → (ref null?2 any) if:
• null?1 is of the form null?2 .
null?1 = null?2
𝐶 ⊢ any.convert_extern : (ref null?1 extern) → (ref null?2 any)

extern.convert_any

The instruction extern.convert_any is valid with the instruction type (ref null?1 any) → (ref null?2 extern) if:
• null?1 is of the form null?2 .
null?1 = null?2
𝐶 ⊢ extern.convert_any : (ref null?1 any) → (ref null?2 extern)

3.4.10 Numeric Instructions


𝑡.const 𝑐
The instruction ([Link] 𝑐nt ) is valid with the instruction type 𝜖 → nt.

𝐶 ⊢ [Link] 𝑐nt : 𝜖 → nt

𝑡.unop
The instruction ([Link] nt ) is valid with the instruction type nt → nt.

𝐶 ⊢ [Link] nt : nt → nt

𝑡.binop
The instruction ([Link] nt ) is valid with the instruction type nt nt → nt.

𝐶 ⊢ [Link] nt : nt nt → nt

𝑡.testop
The instruction ([Link] nt ) is valid with the instruction type nt → i32.

𝐶 ⊢ [Link] nt : nt → i32

𝑡.relop
The instruction ([Link] nt ) is valid with the instruction type nt nt → i32.

𝐶 ⊢ [Link] nt : nt nt → i32

𝑡1 .cvtop_𝑡2 _sx ?
The instruction (nt 1 .cvtop_nt 2 ) is valid with the instruction type nt 2 → nt 1 .

𝐶 ⊢ nt 1 .cvtop_nt 2 : nt 2 → nt 1

66 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

3.4.11 Vector Instructions


Vector instructions can have a prefix to describe the shape of the operand. Packed numeric types, i8 and i16, are not
value types. An auxiliary function maps such packed type shapes to value types:

unpack(i𝑁 x𝑁 ) = unpack(i𝑁 )

[Link] 𝑐
The instruction ([Link] 𝑐) is valid with the instruction type 𝜖 → v128.

𝐶 ⊢ [Link] 𝑐 : 𝜖 → v128

[Link]
The instruction ([Link]) is valid with the instruction type v128 → v128.

𝐶 ⊢ [Link] : v128 → v128

[Link]
The instruction ([Link]) is valid with the instruction type v128 v128 → v128.

𝐶 ⊢ [Link] : v128 v128 → v128

[Link]
The instruction ([Link]) is valid with the instruction type v128 v128 v128 → v128.

𝐶 ⊢ [Link] : v128 v128 v128 → v128

[Link]
The instruction ([Link]) is valid with the instruction type v128 → i32.

𝐶 ⊢ [Link] : v128 → i32

[Link]
The instruction ([Link]) is valid with the instruction type v128 → v128.

𝐶 ⊢ [Link] : v128 → v128

[Link]
The instruction ([Link]) is valid with the instruction type v128 v128 → v128.

𝐶 ⊢ [Link] : v128 v128 → v128

[Link]
The instruction ([Link]) is valid with the instruction type v128 v128 v128 → v128.

𝐶 ⊢ [Link] : v128 v128 v128 → v128

[Link]
The instruction ([Link]) is valid with the instruction type v128 → i32.

𝐶 ⊢ [Link] : v128 → i32

3.4. Instructions 67
WebAssembly Specification, Release 3.0 (2025-11-14)

[Link]
The instruction ([Link]) is valid with the instruction type v128 v128 → v128.

𝐶 ⊢ [Link] : v128 v128 → v128

[Link]
The instruction ([Link]) is valid with the instruction type v128 i32 → v128.

𝐶 ⊢ [Link] : v128 i32 → v128

[Link]
The instruction ([Link]) is valid with the instruction type v128 → i32.

𝐶 ⊢ [Link] : v128 → i32

[Link]
The instruction ([Link]) is valid with the instruction type v128 v128 → v128.

𝐶 ⊢ [Link] : v128 v128 → v128

[Link] laneidx 16
The instruction ([Link] 𝑖* ) is valid with the instruction type v128 v128 → v128 if:
• For all 𝑖 in 𝑖* :
– The lane index 𝑖 is less than 2 · dim(sh).
(𝑖 < 2 · dim(sh))*
𝐶 ⊢ [Link] 𝑖* : v128 v128 → v128

[Link]
The instruction ([Link]) is valid with the instruction type numtype → v128 if:
• The number type numtype is unpack(sh).

𝐶 ⊢ [Link] : unpack(sh) → v128

shape.extract_lane_sx ? laneidx
The instruction (sh.extract_lane_sx ? 𝑖) is valid with the instruction type v128 → numtype if:
• The lane index 𝑖 is less than dim(sh).
• The number type numtype is unpack(sh).
𝑖 < dim(sh)
𝐶 ⊢ sh.extract_lane_sx ? 𝑖 : v128 → unpack(sh)

shape.replace_lane laneidx
The instruction (sh.replace_lane 𝑖) is valid with the instruction type v128 numtype → v128 if:
• The lane index 𝑖 is less than dim(sh).
• The number type numtype is unpack(sh).
𝑖 < dim(sh)
𝐶 ⊢ sh.replace_lane 𝑖 : v128 unpack(sh) → v128

68 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

ishape 1 .vextunop_ishape 2
The instruction (sh 1 .vextunop_sh 2 ) is valid with the instruction type v128 → v128.

𝐶 ⊢ sh 1 .vextunop_sh 2 : v128 → v128

ishape 1 .vextbinop_ishape 2
The instruction (sh 1 .vextbinop_sh 2 ) is valid with the instruction type v128 v128 → v128.

𝐶 ⊢ sh 1 .vextbinop_sh 2 : v128 v128 → v128

ishape 1 .vextternop_ishape 2
The instruction (sh 1 .vextternop_sh 2 ) is valid with the instruction type v128 v128 v128 → v128.

𝐶 ⊢ sh 1 .vextternop_sh 2 : v128 v128 v128 → v128

ishape 1 .narrow_ishape 2 _sx


The instruction (sh 1 .narrow_sh 2 _sx ) is valid with the instruction type v128 v128 → v128.

𝐶 ⊢ sh 1 .narrow_sh 2 _sx : v128 v128 → v128

shape.vcvtop_half ? _shape_sx ? _zero?


The instruction (sh 1 .vcvtop_sh 2 ) is valid with the instruction type v128 → v128.

𝐶 ⊢ sh 1 .vcvtop_sh 2 : v128 → v128

3.4.12 Instruction Sequences


Typing of instruction sequences is defined recursively.

Empty Instruction Sequence: 𝜖


The instruction sequence instr * is valid with the instruction type it if:
• Either:
– The instruction sequence instr * is empty.
– The instruction type it is of the form 𝜖 → 𝜖.
• Or:
– The instruction sequence instr * is of the form instr 1 instr *2 .
– The instruction type it is of the form 𝑡*1 →𝑥*1 𝑥*2 𝑡*3 .
– The instruction instr 1 is valid with the instruction type 𝑡*1 →𝑥*1 𝑡*2 .
– For all 𝑥1 in 𝑥*1 :
∗ The local 𝐶.locals[𝑥1 ] exists.
∗ The local 𝐶.locals[𝑥1 ] is of the form (init 𝑡).
– Under the context 𝐶 with the local types of 𝑥*1 updated to (set 𝑡)* , the instruction sequence instr *2 is
valid with the instruction type 𝑡*2 →𝑥*2 𝑡*3 .
• Or:

3.4. Instructions 69
WebAssembly Specification, Release 3.0 (2025-11-14)

– The instruction sequence instr * is valid with the instruction type it ′′ .


– The instruction type it ′′ matches the instruction type it.
– The instruction type it is valid.
• Or:
– The instruction type it is of the form 𝑡* 𝑡*1 →𝑥* 𝑡* 𝑡*2 .
– The instruction sequence instr * is valid with the instruction type 𝑡*1 →𝑥* 𝑡*2 .
– The result type 𝑡* is valid.

𝐶⊢𝜖:𝜖→𝜖
𝐶 ⊢ instr 1 : 𝑡*1 →𝑥*1 𝑡*2 (𝐶.locals[𝑥1 ] = init 𝑡)* 𝐶[.local[𝑥*1 ] = (set 𝑡)* ] ⊢ instr *2 : 𝑡*2 →𝑥*2 𝑡*3
𝐶 ⊢ instr 1 instr *2 : 𝑡*1 →𝑥*1 𝑥*2 𝑡*3
𝐶 ⊢ instr * : it 𝐶 ⊢ it ≤ it ′ 𝐶 ⊢ it ′ : ok 𝐶 ⊢ instr * : 𝑡*1 →𝑥* 𝑡*2 𝐶 ⊢ 𝑡* : ok
*
𝐶 ⊢ instr * : it ′ 𝐶 ⊢ instr : (𝑡 𝑡1 ) →𝑥* (𝑡* 𝑡*2 )
* *

Note

In combination with the previous rule, subsumption allows to compose instructions whose types would not
directly fit otherwise. For example, consider the instruction sequence

([Link] 1) ([Link] 2) ([Link])

To type this sequence, its subsequence ([Link] 2) ([Link]) needs to be valid with an intermediate type. But
the direct type of ([Link] 2) is 𝜖 → i32, not matching the two inputs expected by [Link]. The subsumption
rule allows to weaken the type of (const i32 2) to the supertype i32 → i32 i32, such that it can be composed with
[Link] and yields the intermediate type i32 → i32 i32 for the subsequence. That can in turn be composed with
the first constant.
Furthermore, subsumption allows to drop init variables 𝑥* from the instruction type in a context where they are
not needed, for example, at the end of the body of a block.

3.4.13 Expressions
Expressions expr are classified by result types 𝑡* .
The expression instr * is valid with the result type 𝑡* if:
• The instruction sequence instr * is valid with the instruction type 𝜖 → 𝑡* .
𝐶 ⊢ instr * : 𝜖 →𝜖 𝑡*
𝐶 ⊢ instr * : 𝑡*

Constant Expressions
In a constant expression, all instructions must be constant.
instr * is constant if:
• For all instr in instr * :
– instr is constant.
val is constant if:
• Either:
– The value val is of the form ([Link] 𝑐nt ).
• Or:

70 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

– The value val is of the form ([Link] 𝑐vt ).


• Or:
– The value val is of the form ([Link] ht).
• Or:
– The value val is of the form ref.i31.
• Or:
– The value val is of the form ([Link] 𝑥).
• Or:
– The value val is of the form ([Link] 𝑥).
• Or:
– The value val is of the form (struct.new_default 𝑥).
• Or:
– The value val is of the form ([Link] 𝑥).
• Or:
– The value val is of the form (array.new_default 𝑥).
• Or:
– The value val is of the form (array.new_fixed 𝑥 𝑛).
• Or:
– The value val is of the form any.convert_extern.
• Or:
– The value val is of the form extern.convert_any.
• Or:
– The value val is of the form ([Link] 𝑥).
– The global 𝐶.globals[𝑥] exists.
– The global 𝐶.globals[𝑥] is of the form (𝜖 𝑡).
• Or:
– The value val is of the form (i𝑁 .binop).
– i𝑁 is contained in [i32; i64].
– binop is contained in [add; sub; mul].
(𝐶 ⊢ instr const)*
𝐶 ⊢ instr * const
i𝑁 ∈ i32 i64 binop ∈ add sub mul
𝐶 ⊢ ([Link] 𝑐nt ) const 𝐶 ⊢ ([Link] 𝑐vt ) const 𝐶 ⊢ (i𝑁 .binop) const

𝐶 ⊢ ([Link] ht) const 𝐶 ⊢ (ref.i31) const 𝐶 ⊢ ([Link] 𝑥) const

𝐶 ⊢ ([Link] 𝑥) const 𝐶 ⊢ (struct.new_default 𝑥) const

𝐶 ⊢ ([Link] 𝑥) const 𝐶 ⊢ (array.new_default 𝑥) const 𝐶 ⊢ (array.new_fixed 𝑥 𝑛) const

𝐶 ⊢ (any.convert_extern) const 𝐶 ⊢ (extern.convert_any) const


𝐶.globals[𝑥] = 𝑡
𝐶 ⊢ ([Link] 𝑥) const

3.4. Instructions 71
WebAssembly Specification, Release 3.0 (2025-11-14)

Note

Currently, constant expressions occurring in globals are further constrained in that contained [Link] in-
structions are only allowed to refer to imported or previously defined globals. Constant expressions occurring
in tables may only have [Link] instructions that refer to imported globals. This is enforced in the validation
rule for modules by constraining the context 𝐶 accordingly.
The definition of constant expression may be extended in future versions of WebAssembly.

3.5 Modules
Modules are valid when all the components they contain are valid. To verify this, most definitions are themselves
classified with a suitable type.

3.5.1 Types
The sequence of types defined in a module is validated incrementally, yielding a sequence of defined types repre-
senting them individually.
The type definition (type rectype) is valid with the defined type sequence dt * if:
• The length of 𝐶.types is equal to 𝑥.
• The defined type sequence dt * is of the form roll*𝑥 (rectype).
• Let 𝐶 ′ be the same context as 𝐶, but with the defined type sequence dt * appended to the field types.
• Under the context 𝐶 ′ , the recursive type rectype is valid for the type index 𝑥.
𝑥 = |𝐶.types| dt * = roll*𝑥 (rectype) 𝐶 ⊕ {types dt * } ⊢ rectype : ok(𝑥)
𝐶 ⊢ type rectype : dt *
The type definition sequence type * is valid with the defined type sequence deftype * if:
• Either:
– The type definition sequence type * is empty.
– The defined type sequence deftype * is empty.
• Or:
*
– The type definition sequence type * is of the form type 1 type ′ .
– The defined type sequence deftype * is of the form dt *1 dt * .
– The type definition type 1 is valid with the defined type sequence dt *1 .
– Let 𝐶 ′ be the same context as 𝐶, but with the defined type sequence dt *1 appended to the field types.
*
– Under the context 𝐶 ′ , the type definition sequence type ′ is valid with the defined type sequence dt * .
𝐶 ⊢ type 1 : dt *1 𝐶 ⊕ {types dt *1 } ⊢ type * : dt *
𝐶⊢𝜖:𝜖 𝐶 ⊢ type 1 type * : dt *1 dt *

3.5.2 Tags
Tags tag are classified by their tag types, which are defined types expanding to function types.
The tag (tag tagtype) is valid with the tag type tagtype ′ if:
• The tag type tagtype is valid.
• The tag type tagtype ′ is clos𝐶 (tagtype).

72 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

𝐶 ⊢ tagtype : ok
𝐶 ⊢ tag tagtype : clos𝐶 (tagtype)

3.5.3 Globals
Globals global are classified by global types.
The global (global globaltype expr ) is valid with the global type globaltype if:
• The global type globaltype is valid.
• The global type globaltype is of the form (mut? 𝑡).
• The expression expr is valid with the value type 𝑡.
• expr is constant.
𝐶 ⊢ globaltype : ok globaltype = mut? 𝑡 𝐶 ⊢ expr : 𝑡 const
𝐶 ⊢ global globaltype expr : globaltype
Sequences of globals are handled incrementally, such that each definition has access to previous definitions.
The global sequence global * is valid with the global type sequence globaltype * if:
• Either:
– The global sequence global * is empty.
– The global type sequence globaltype * is empty.
• Or:
*
– The global sequence global * is of the form global 1 global ′ .
– The global type sequence globaltype * is of the form gt 1 gt * .
– The global global 1 is valid with the global type gt 1 .
– Let 𝐶 ′ be the same context as 𝐶, but with the global type sequence gt 1 appended to the field globals.
*
– Under the context 𝐶 ′ , the global sequence global ′ is valid with the global type sequence gt * .
𝐶 ⊢ global 1 : gt 1 𝐶 ⊕ {globals gt 1 } ⊢ global * : gt *
𝐶⊢𝜖:𝜖 𝐶 ⊢ global 1 global * : gt 1 gt *

3.5.4 Memories
Memories mem are classified by memory types.
The memory (memory memtype) is valid with the memory type memtype if:
• The memory type memtype is valid.
𝐶 ⊢ memtype : ok
𝐶 ⊢ memory memtype : memtype

3.5.5 Tables
Tables table are classified by table types.
The table (table tabletype expr ) is valid with the table type tabletype if:
• The table type tabletype is valid.
• The table type tabletype is of the form (at lim rt).
• The expression expr is valid with the value type rt.
• expr is constant.

3.5. Modules 73
WebAssembly Specification, Release 3.0 (2025-11-14)

𝐶 ⊢ tabletype : ok tabletype = at lim rt 𝐶 ⊢ expr : rt const


𝐶 ⊢ table tabletype expr : tabletype

3.5.6 Functions
Functions func are classified by defined types that expand to function types of the form func 𝑡*1 → 𝑡*2 .
The function (func 𝑥 local * expr ) is valid with the type 𝐶.types[𝑥] if:
• The type 𝐶.types[𝑥] exists.
• The expansion of 𝐶.types[𝑥] is (func 𝑡*1 → 𝑡*2 ).
• For all local in local * :
– The local local is valid with the local type lt.
*
• lt is the concatenation of all such lt.
• Under the context 𝐶 with the field locals appended by (set 𝑡1 )* lt * and the field labels appended by 𝑡*2 and
the field return appended by 𝑡*2 , the expression expr is valid with the result type 𝑡*2 .
𝐶.types[𝑥] ≈ func 𝑡*1 → 𝑡*2 (𝐶 ⊢ local : lt)*
𝐶 ⊕ {locals (set 𝑡1 )* lt * , labels (𝑡*2 ), return (𝑡*2 )} ⊢ expr : 𝑡*2
𝐶 ⊢ func 𝑥 local * expr : 𝐶.types[𝑥]

3.5.7 Locals
Locals local are classified with local types.
The local (local 𝑡) is valid with the local type (init 𝑡) if:
• Either:
– The initialization status init is of the form set.
– A default value for 𝑡 is defined.
• Or:
– The initialization status init is of the form unset.
– A default value for 𝑡 is not defined.
default𝑡 ̸= 𝜖 default𝑡 = 𝜖
𝐶 ⊢ local 𝑡 : set 𝑡 𝐶 ⊢ local 𝑡 : unset 𝑡

Note

For cases where both rules are applicable, the former yields the more permissable type.

3.5.8 Data Segments


Data segments data are classified by the singleton data type, which merely expresses well-formedness.
The memory segment (data 𝑏* datamode) is valid if:
• The data mode datamode is valid.
𝐶 ⊢ datamode : ok
𝐶 ⊢ data 𝑏* datamode : ok
The data mode datamode is valid if:
• Either:
– The data mode datamode is of the form passive.

74 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

• Or:
– The data mode datamode is of the form (active 𝑥 expr ).
– The memory 𝐶.mems[𝑥] exists.
– The memory 𝐶.mems[𝑥] is of the form (at lim page).
– The expression expr is valid with the value type at.
– expr is constant.
𝐶.mems[𝑥] = at lim page 𝐶 ⊢ expr : at const
𝐶 ⊢ passive : ok 𝐶 ⊢ active 𝑥 expr : ok

3.5.9 Element Segments


Element segments elem are classified by their element type.
The table segment (elem elemtype expr * elemmode) is valid with the element type elemtype if:
• The reference type elemtype is valid.
• For all expr in expr * :
– The expression expr is valid with the value type elemtype.
– expr is constant.
• The element mode elemmode is valid with the element type elemtype.
𝐶 ⊢ elemtype : ok (𝐶 ⊢ expr : elemtype const)* 𝐶 ⊢ elemmode : elemtype
𝐶 ⊢ elem elemtype expr * elemmode : elemtype
The element mode elemmode is valid with the element type rt if:
• Either:
– The element mode elemmode is of the form passive.
• Or:
– The element mode elemmode is of the form declare.
• Or:
– The element mode elemmode is of the form (active 𝑥 expr ).
– The table 𝐶.tables[𝑥] exists.
– The table 𝐶.tables[𝑥] is of the form (at lim rt ′ ).
– The reference type rt matches the reference type rt ′ .
– The expression expr is valid with the value type at.
– expr is constant.

𝐶 ⊢ passive : rt 𝐶 ⊢ declare : rt
𝐶.tables[𝑥] = at lim rt ′ 𝐶 ⊢ rt ≤ rt ′ 𝐶 ⊢ expr : at const
𝐶 ⊢ active 𝑥 expr : rt

3.5. Modules 75
WebAssembly Specification, Release 3.0 (2025-11-14)

3.5.10 Start Function


The start function (start 𝑥) is valid if:
• The function 𝐶.funcs[𝑥] exists.
• The expansion of 𝐶.funcs[𝑥] is (func →).
𝐶.funcs[𝑥] ≈ func 𝜖 → 𝜖
𝐶 ⊢ start 𝑥 : ok

3.5.11 Imports
Imports import are classified by external types.
The import (import name 1 name 2 xt) is valid with the external type externtype if:
• The external type xt is valid.
• The external type externtype is clos𝐶 (xt).
𝐶 ⊢ xt : ok
𝐶 ⊢ import name 1 name 2 xt : clos𝐶 (xt)

3.5.12 Exports
Exports export are classified by their external type.
The export (export name externidx ) is valid with the name name and the external type xt if:
• The external index externidx is valid with the external type xt.
𝐶 ⊢ externidx : xt
𝐶 ⊢ export name externidx : name xt

tag 𝑥
The external index (tag 𝑥) is valid with the external type (tag jt) if:
• The tag 𝐶.tags[𝑥] exists.
• The tag 𝐶.tags[𝑥] is of the form jt.
𝐶.tags[𝑥] = jt
𝐶 ⊢ tag 𝑥 : tag jt

global 𝑥
The external index (global 𝑥) is valid with the external type (global gt) if:
• The global 𝐶.globals[𝑥] exists.
• The global 𝐶.globals[𝑥] is of the form gt.
𝐶.globals[𝑥] = gt
𝐶 ⊢ global 𝑥 : global gt

memory 𝑥
The external index (memory 𝑥) is valid with the external type (mem mt) if:
• The memory 𝐶.mems[𝑥] exists.
• The memory 𝐶.mems[𝑥] is of the form mt.
𝐶.mems[𝑥] = mt
𝐶 ⊢ memory 𝑥 : mem mt

76 Chapter 3. Validation
WebAssembly Specification, Release 3.0 (2025-11-14)

table 𝑥
The external index (table 𝑥) is valid with the external type (table tt) if:
• The table 𝐶.tables[𝑥] exists.
• The table 𝐶.tables[𝑥] is of the form tt.
𝐶.tables[𝑥] = tt
𝐶 ⊢ table 𝑥 : table tt

func 𝑥
The external index (func 𝑥) is valid with the external type (func dt) if:
• The function 𝐶.funcs[𝑥] exists.
• The function 𝐶.funcs[𝑥] is of the form dt.
𝐶.funcs[𝑥] = dt
𝐶 ⊢ func 𝑥 : func dt

3.5.13 Modules
Modules are classified by their mapping from the external types of their imports to those of their exports.
A module is entirely closed, that is, its components can only refer to definitions that appear in the module itself.
Consequently, no initial context is required. Instead, the context 𝐶 for validation of the module’s content is con-
structed from the definitions in the module.
The module (module type * import * tag * global * mem * table * func * data * elem * start ? export * ) is valid with
the module type moduletype if:
*
• Under the context {return 𝜖}, the type definition sequence type * is valid with the defined type sequence dt ′ .
• For all import in import * :
*
– Under the context {types dt ′ , return 𝜖}, the import import is valid with the external type xt i .
• xt *i is the concatenation of all such xt i .
• For all tag in tag * :
– Under the context 𝐶 ′ , the tag tag is valid with the tag type jt.
• jt * is the concatenation of all such jt.
• Under the context 𝐶 ′ , the global sequence global * is valid with the global type sequence gt * .
• For all mem in mem * :
– Under the context 𝐶 ′ , the memory mem is valid with the memory type mt.
• mt * is the concatenation of all such mt.
• For all table in table * :
– Under the context 𝐶 ′ , the table table is valid with the table type tt.
• tt * is the concatenation of all such tt.
• For all func in func * :
– The function func is valid with the defined type dt.
• dt * is the concatenation of all such dt.
• For all data in data * :
– The memory segment data is valid.
*
• ok is the concatenation of all such ok .

3.5. Modules 77
WebAssembly Specification, Release 3.0 (2025-11-14)

• For all elem in elem * :


– The table segment elem is valid with the element type rt.
• rt * is the concatenation of all such rt.
• If start is defined, then:
– The start function start is valid.
• For all export in export * :
– The export export is valid with the name nm and the external type xt e .
• nm * is the concatenation of all such nm.
• xt *e is the concatenation of all such xt e .
• nm * disjoint is true.
• The context 𝐶 is of the form 𝐶 ′ with the field tags appended by jt *i jt * and the field globals appended by
gt * and the field mems appended by mt *i mt * and the field tables appended by tt *i tt * and the field datas
appended by ok * and the field elems appended by rt * .
*
• The context 𝐶 ′ is of the form {types dt ′ , globals gt *i , funcs dt *i dt * , return 𝜖, refs 𝑥* }.
• The function index sequence 𝑥* is of the form funcidx(global * mem * table * elem * ).
• The tag type sequence jt *i is of the form tags(xt *i ).
• The global type sequence gt *i is of the form globals(xt *i ).
• The memory type sequence mt *i is of the form mems(xt *i ).
• The table type sequence tt *i is of the form tables(xt *i ).
• The defined type sequence dt *i is of the form funcs(xt *i ).
• The module type moduletype is clos𝐶 (xt *i → xt *e ).
* *
{} ⊢ type * : dt ′ ({types dt ′ } ⊢ import : xt i )*
′ * ′ * *
(𝐶 ⊢ tag : jt) 𝐶 ⊢ global : gt (𝐶 ⊢ mem : mt)*

(𝐶 ′ ⊢ table : tt)* (𝐶 ⊢ func : dt)*
* * *
(𝐶 ⊢ data : ok ) (𝐶 ⊢ elem : rt) (𝐶 ⊢ start : ok) ?
(𝐶 ⊢ export : nm xt e ) nm * disjoint
* * *
𝐶 = 𝐶 ⊕ {tags jt i jt , globals gt , mems mt i mt , tables tt i tt , datas ok , elems rt * }
′ * * * * *
*
𝐶 ′ = {types dt ′ , globals gt *i , funcs dt *i dt * , refs 𝑥* } 𝑥* = funcidx(global * mem * table * elem * )
*
jt i = tags(xt *i ) gt *i = globals(xt *i ) mt *i = mems(xt *i ) tt *i = tables(xt *i ) dt *i = funcs(xt *i )
⊢ module type * import * tag * global * mem * table * func * data * elem * start ? export * : clos𝐶 (xt *i → xt *e )

Note

All functions in a module are mutually recursive. Consequently, the definition of the context 𝐶 in this rule
is recursive: it depends on the outcome of validation of the function, table, memory, and global definitions
contained in the module, which itself depends on 𝐶. However, this recursion is just a specification device. All
types needed to construct 𝐶 can easily be determined from a simple pre-pass over the module that does not
perform any actual validation.
Globals, however, are not recursive but evaluated sequentially, such that each constant expressions only has
access to imported or previously defined globals.

78 Chapter 3. Validation
CHAPTER 4

Execution

4.1 Conventions
WebAssembly code is executed when instantiating a module or invoking an exported function on the resulting
module instance.
Execution behavior is defined in terms of an abstract machine that models the program state. It includes a stack,
which records operand values and control constructs, and an abstract store containing global state.
For each instruction, there is a rule that specifies the effect of its execution on the program state. Furthermore,
there are rules describing the instantiation of a module. As with validation, all rules are given in two equivalent
forms:
1. In prose, describing the execution in intuitive form.
2. In formal notation, describing the rule in mathematical form.18

Note

As with validation, the prose and formal rules are equivalent, so that understanding of the formal notation is
not required to read this specification. The formalism offers a more concise description in notation that is used
widely in programming languages semantics and is readily amenable to mathematical proof.

4.1.1 Prose Notation


Execution is specified by stylised, step-wise rules for each instruction of the abstract syntax. The following con-
ventions are adopted in stating these rules.
• The execution rules implicitly assume a given store 𝑠.
• The execution rules also assume the presence of an implicit stack that is modified by pushing or popping
values, labels, and frames.
• Certain rules require the stack to contain at least one frame. The most recent frame is referred to as the
current frame.
18 The semantics is derived from the following article: Andreas Haas, Andreas Rossberg, Derek Schuff, Ben Titzer, Dan Gohman, Luke

Wagner, Alon Zakai, JF Bastien, Michael Holman. Bringing the Web up to Speed with WebAssembly19 . Proceedings of the 38th ACM
SIGPLAN Conference on Programming Language Design and Implementation (PLDI 2017). ACM 2017.
19 [Link]

79
WebAssembly Specification, Release 3.0 (2025-11-14)

• Both the store and the current frame are mutated by replacing some of their components. Such replacement
is assumed to apply globally.
• The execution of an instruction may trap, in which case the entire computation is aborted and no further
modifications to the store are performed by it. (Other computations can still be initiated afterwards.)
• The execution of an instruction may also end in a jump to a designated target, which defines the next instruc-
tion to execute.
• Execution can enter and exit instruction sequences that form blocks.
• Instruction sequences are implicitly executed in order, unless a trap, jump, or exception occurs.
• In various places the rules contain assertions expressing crucial invariants about the program state.

4.1.2 Formal Notation

Note

This section gives a brief explanation of the notation for specifying execution formally. For the interested reader,
a more thorough introduction can be found in respective text books.20

The formal execution rules use a standard approach for specifying operational semantics, rendering them into
reduction rules. Every rule has the following general form:

configuration ˓→ configuration

A configuration is a syntactic description of a program state. Each rule specifies one step of execution. As long
as there is at most one reduction rule applicable to a given configuration, reduction – and thereby execution – is
deterministic. WebAssembly has only very few exceptions to this, which are noted explicitly in this specification.
For WebAssembly, a configuration typically is a tuple (𝑠; 𝑓 ; instr * ) consisting of the current store 𝑠, the call frame
𝑓 of the current function, and the sequence of instructions that is to be executed. (A more precise definition is
given later.)
To avoid unnecessary clutter, the store 𝑠 and the frame 𝑓 are often combined into a state 𝑧, which is a pair (𝑠; 𝑓 ).
Moreover, 𝑧 is omitted from reduction rules that do not touch them.
There is no separate representation of the stack. Instead, it is conveniently represented as part of the configuration’s
instruction sequence. In particular, values are defined to coincide with const and ref instructions, and a sequence
of such instructions can be interpreted as an operand “stack” that grows to the right.

Note

For example, the reduction rule for the [Link] instruction can be given as follows:

([Link] 𝑛1 ) ([Link] 𝑛2 ) ([Link]) ˓→ ([Link] (𝑛1 + 𝑛2 ) mod 232 )

Per this rule, two const instructions and the add instruction itself are removed from the instruction stream and
replaced with one new const instruction. This can be interpreted as popping two values off the stack and pushing
the result.
When no result is produced, an instruction reduces to the empty sequence:

nop ˓→ 𝜖

Labels and frames are similarly defined to be part of an instruction sequence.


20 For example: Benjamin Pierce. Types and Programming Languages21 . The MIT Press 2002
21 [Link]

80 Chapter 4. Execution
WebAssembly Specification, Release 3.0 (2025-11-14)

The order of reduction is determined by the details of the reduction rules. Usually, the left-most instruction that is
not a constant will be the subject of the next reduction step.
Reduction terminates when no more reduction rules are applicable. Soundness of the WebAssembly type system
guarantees that this is only the case when the original instruction sequence has either been reduced to a sequence
of value instructions, which can be interpreted as the values of the resulting operand stack, or if an exception or
trap occurred.

Note

For example, the following instruction sequence,

(f [Link] 𝑞1 ) (f [Link] 𝑞2 ) (f [Link]) (f [Link] 𝑞3 ) (f [Link]) (f [Link])

terminates after three steps:

˓→ (f [Link] 𝑞1 ) (f [Link] 𝑞4 ) (f [Link] 𝑞3 ) (f [Link]) (f [Link])


˓→ (f [Link] 𝑞1 ) (f [Link] 𝑞5 ) (f [Link])
˓→ (f [Link] 𝑞6 )

where 𝑞4 = −𝑞2 and 𝑞5 = −𝑞2 + 𝑞3 and 𝑞6 = 𝑞1 · (−𝑞2 + 𝑞3 ).

4.2 Runtime Structure


Store, stack, and other runtime structure forming the WebAssembly abstract machine, such as values or module
instances, are made precise in terms of additional auxiliary syntax.

4.2.1 Values
WebAssembly computations manipulate values of either the four basic number types, i.e., integers and floating-
point data of 32 or 64 bit width each, or vectors of 128 bit width, or of reference type.
In most places of the semantics, values of different types can occur. In order to avoid ambiguities, values are
therefore represented with an abstract syntax that makes their type explicit. It is convenient to reuse the same
notation as for the const instructions and [Link] producing them.
References other than null are represented with additional administrative instructions. They either are scalar ref-
erences, containing a 31-bit integer, structure references, pointing to a specific structure address, array references,
pointing to a specific array address, function references, pointing to a specific function address, exception refer-
ences, pointing to a specific exception address, or host references pointing to an uninterpreted form of host address
defined by the embedder. Any of the aformentioned references can furthermore be wrapped up as an external
reference.

val ::= num | vec | ref


num ::= [Link] num numtype
vec ::= [Link] vec vectype
ref ::= addrref
| [Link] heaptype
addrref ::= ref.i31 u31
| [Link] structaddr
| [Link] arrayaddr
| [Link] funcaddr
| [Link] exnaddr
| [Link] hostaddr
| [Link] addrref

4.2. Runtime Structure 81


WebAssembly Specification, Release 3.0 (2025-11-14)

Note

Future versions of WebAssembly may add additional forms of values.

Value types can have an associated default value; it is the respective value 0 for number types, 0 for vector types,
and null for nullable reference types. For other references, no default value is defined, default𝑡 hence is an optional
value val ? .
defaulti𝑁 = (i𝑁 .const 0)
defaultf𝑁 = (f𝑁 .const +0)
defaultv𝑁 = (v𝑁 .const 0)
defaultref null ht = ([Link] ht)
defaultref ht = 𝜖

Convention
• The meta variable 𝑟 ranges over reference values where clear from context.

4.2.2 Results
A result is the outcome of a computation. It is either a sequence of values, a thrown exception, or a trap.

result ::= val * | ([Link] exnaddr ) throw_ref | trap

4.2.3 Store
The store represents all global state that can be manipulated by WebAssembly programs. It consists of the runtime
representation of all instances of functions, tables, memories, globals, tags, element segments, data segments, and
structures, arrays or exceptions that have been allocated during the life time of the abstract machine.
It is an invariant of the semantics that no element or data instance is addressed from anywhere else but the owning
module instances.
Syntactically, the store is defined as a record listing the existing instances of each category:

store ::= {tags taginst *


globals globalinst *
mems meminst *
tables tableinst *
funcs funcinst *
datas datainst *
elems eleminst *
structs structinst *
arrays arrayinst *
exns exninst * }

Note

In practice, implementations may apply techniques like garbage collection or reference counting to remove
objects from the store that are no longer referenced. However, such techniques are not semantically observable,
and hence outside the scope of this specification.

Convention
• The meta variable 𝑠 ranges over stores where clear from context.

82 Chapter 4. Execution
WebAssembly Specification, Release 3.0 (2025-11-14)

4.2.4 Addresses
Function instances, table instances, memory instances, global instances, tag instances, element instances, data
instances and structure, array or exception instances in the store are referenced with abstract addresses. These are
simply indices into the respective store component. In addition, an embedder may supply an uninterpreted set of
host addresses.
addr ::= 0 | 1 | 2 | ...
funcaddr ::= addr
tableaddr ::= addr
memaddr ::= addr
globaladdr ::= addr
tagaddr ::= addr
elemaddr ::= addr
dataaddr ::= addr
structaddr ::= addr
arrayaddr ::= addr
hostaddr ::= addr

An embedder may assign identity to exported store objects corresponding to their addresses, even where this iden-
tity is not observable from within WebAssembly code itself (such as for function instances or immutable globals).

Note

Addresses are dynamic, globally unique references to runtime objects, in contrast to indices, which are static,
module-local references to their original definitions. A memory address memaddr denotes the abstract address
of a memory instance in the store, not an offset inside a memory instance.
There is no specific limit on the number of allocations of store objects, hence logical addresses can be arbitrarily
large natural numbers.

Conventions
• The notation addr(𝐴) denotes the set of addresses from address space addr occurring free in 𝐴. We some-
times reinterpret this set as the list of its elements, without assuming any particular order.

4.2.5 External Addresses


An external address is the runtime address of an entity that can be imported or exported. It is an address denoting
either a function instance, global instance, table instance, memory instance, or tag instance in the shared store.

externaddr ::= tag tagaddr | global globaladdr | mem memaddr | table tableaddr | func funcaddr

4.2.6 Module Instances


A module instance is the runtime representation of a module. It is created by instantiating a module, and collects
runtime representations of all entities that are imported, defined, or exported by the module.

moduleinst ::= {types deftype *


tags tagaddr *
globals globaladdr *
mems memaddr *
tables tableaddr *
funcs funcaddr *
datas dataaddr *
elems elemaddr *
exports exportinst * }

4.2. Runtime Structure 83


WebAssembly Specification, Release 3.0 (2025-11-14)

Each component references runtime instances corresponding to respective declarations from the original module
– whether imported or defined – in the order of their static indices. Function instances, table instances, memory
instances, global instances, and tag instances are denoted by their respective addresses in the store.
It is an invariant of the semantics that all export instances in a given module instance have different names.

Note

All record fields except exports are to be considered private components of a module instance. They are not
accessible to other modules, only to function instances originating from the same module.

4.2.7 Function Instances


A function instance is the runtime representation of a function. It effectively is a closure of the original function
over the runtime module instance of its originating module. The module instance is used to resolve references to
other definitions during execution of the function.

funcinst ::= {type deftype, module moduleinst, code code}


code ::= func | hostfunc

A host function is a function expressed outside WebAssembly but passed to a module as an import. The definition
and behavior of host functions are outside the scope of this specification. For the purpose of this specification, it
is assumed that when invoked, a host function behaves non-deterministically, but within certain constraints that
ensure the integrity of the runtime.

Note

Function instances are immutable, and their identity is not observable by WebAssembly code. However, an
embedder might provide implicit or explicit means for distinguishing their addresses.

4.2.8 Table Instances


A table instance is the runtime representation of a table. It records its type and holds a sequence of reference
values.

tableinst ::= {type tabletype, elem ref * }

Table elements can be mutated through table instructions, the execution of an active element segment, or by external
means provided by the embedder.
It is an invariant of the semantics that all table elements have a type matching the element type of tabletype. It
also is an invariant that the length of the element sequence never exceeds the maximum size of tabletype.

4.2.9 Memory Instances


A memory instance is the runtime representation of a linear memory. It records its type and holds a sequence of
bytes.

meminst ::= {type memtype, bytes byte * }

The length of the sequence always is a multiple of the WebAssembly page size, which is defined to be the constant
65536 – abbreviated 64 Ki.
A memory’s bytes can be mutated through memory instructions, the execution of an active data segment, or by
external means provided by the embedder.
It is an invariant of the semantics that the length of the byte sequence, divided by page size, never exceeds the
maximum size of memtype.

84 Chapter 4. Execution
WebAssembly Specification, Release 3.0 (2025-11-14)

4.2.10 Global Instances


A global instance is the runtime representation of a global variable. It records its type and holds an individual
value.
globalinst ::= {type globaltype, value val }
The value of mutable globals can be mutated through variable instructions or by external means provided by the
embedder.
It is an invariant of the semantics that the value has a type matching the value type of globaltype.

4.2.11 Tag Instances


A tag instance is the runtime representation of a tag definition. It records the defined type of the tag.
taginst ::= {type tagtype}

4.2.12 Element Instances


An element instance is the runtime representation of an element segment. It holds a list of references and its type.
eleminst ::= {type elemtype, elem ref * }
It is an invariant of the semantics that all elements of a segment have a type matching elemtype.

4.2.13 Data Instances


A data instance is the runtime representation of a data segment. It holds a list of bytes.
datainst ::= {bytes byte * }

4.2.14 Export Instances


An export instance is the runtime representation of an export. It defines the export’s name and the associated
external address.
exportinst ::= {name name, addr externaddr }

Conventions
The following auxiliary functions are assumed on sequences of external addresses. They extract addresses of a
specific kind in an order-preserving fashion:
• funcs(xa * ) extracts all function addresses from xa * ,
• tables(xa * ) extracts all table addresses from xa * ,
• mems(xa * ) extracts all memory addresses from xa * ,
• globals(xa * ) extracts all global addresses from xa * ,
• tags(xa * ) extracts all tag addresses from xa * .

4.2.15 Aggregate Instances


A structure instance is the runtime representation of a heap object allocated from a structure type. Likewise,
an array instance is the runtime representation of a heap object allocated from an array type. Both record their
respective defined type and hold a list of the values of their fields.
structinst ::= {type deftype, fields fieldval * }
arrayinst ::= {type deftype, fields fieldval * }
fieldval ::= val | packval
packval ::= [Link] i𝑁

4.2. Runtime Structure 85


WebAssembly Specification, Release 3.0 (2025-11-14)

Conventions
• Conversion of a regular value to a field value is defined as follows:

packvaltype (val ) = val


packpacktype ([Link] 𝑖) = [Link] wrap32,|packtype| (𝑖)

• The inverse conversion of a field value to a regular value is defined as follows:

unpack𝜖valtype (val ) = val


unpacksx
packtype ([Link] 𝑖) = [Link] extendsx
|packtype|,32 (𝑖)

4.2.16 Exception Instances


An exception instance is the runtime representation of an exception produced by a throw instruction. It holds the
address of the respective tag and the argument values.

exninst ::= {tag tagaddr , fields val * }

4.2.17 Stack
Besides the store, most instructions interact with an implicit stack. The stack contains the two kinds of entries:
• Values: the operands of instructions.
• Control Frames: currently active control flow structures.
The latter can in turn be one of the following:
• Labels: active structured control instructions that can be targeted by branches.
• (Call) Frames: the activation records of active function calls.
• Handlers: active exception handlers.

Note

Where clear from context, call frame is abbreviated to just frame.

All these entries can occur on the stack in any order during the execution of a program. Stack entries are described
by abstract syntax as follows.

Note

It is possible to model the WebAssembly semantics using separate stacks for operands, control constructs, and
calls. However, because the stacks are interdependent, additional book keeping about associated stack heights
would be required. For the purpose of this specification, an interleaved representation is simpler.

Values
Values are represented by themselves.

Labels
Labels carry an argument arity 𝑛 and their associated branch target, which is expressed syntactically as an instruc-
tion sequence:

label ::= label𝑛 {instr * }

86 Chapter 4. Execution
WebAssembly Specification, Release 3.0 (2025-11-14)

Intuitively, instr * is the continuation to execute when the branch is taken, in place of the original control construct.

Note

For example, a loop label has the form

label𝑛 {(loop bt . . . )}

When performing a branch to this label, this executes the loop, effectively restarting it from the beginning.
Conversely, a simple block label has the form

label𝑛 {𝜖}

When branching, the empty continuation ends the targeted block, such that execution can proceed with consec-
utive instructions.

Call Frames
Call frames carry the return arity 𝑛 of the respective function, hold the values of its locals (including arguments)
in the order corresponding to their static local indices, and a reference to the function’s own module instance:

callframe ::= frame𝑛 {frame}


frame ::= {locals (val ? )* , module moduleinst}

Locals may be uninitialized, in which case they are empty. Locals are mutated by respective variable instructions.

Exception Handlers
Exception handlers are installed by try_table instructions and record the corresponding list of catch clauses:

handler ::= handler𝑛 {catch * }

The handlers on the stack are searched when an exception is thrown.

Conventions
• The meta variable 𝐿 ranges over labels where clear from context.
• The meta variable 𝑓 ranges over frame states where clear from context.
• The meta variable 𝐻 ranges over exception handlers where clear from context.
• The following auxiliary definition takes a block type and looks up the instruction type that it denotes in the
current frame:
instrtype𝑧 (𝑥) = 𝑡*1 → 𝑡*2 if 𝑧.types[𝑥] ≈ func 𝑡*1 → 𝑡*2
instrtype𝑧 (𝑡? ) = 𝜖 → 𝑡?

4.2.18 Administrative Instructions

Note

This section is only relevant for the formal notation.

4.2. Runtime Structure 87


WebAssembly Specification, Release 3.0 (2025-11-14)

In order to express the reduction of traps, calls, exception handling, and control instructions, the syntax of instruc-
tions is extended to include the following administrative instructions:

instr ::= ...


| addrref
| label𝑛 {instr * } instr *
| frame𝑛 {frame} instr *
| handler𝑛 {catch * } instr *
| trap

An address reference represents an allocated reference value of respective form “on the stack”.
The label, frame, and handler instructions model labels, frames, and active exception handlers, respectively, “on
the stack”. Moreover, the administrative syntax maintains the nesting structure of the original structured control
instruction or function body and their instruction sequences.
The trap instruction represents the occurrence of a trap. Traps are bubbled up through nested instruction sequences,
ultimately reducing the entire program to a single trap instruction, signalling abrupt termination.

Note

For example, the reduction rule for block is:

(block bt instr * ) ˓→ (label𝑛 {𝜖} instr * )

if the block type bt denotes a function type func 𝑡𝑚 1 → 𝑡2 , such that 𝑛 is the block’s result arity. This rule
𝑛

replaces the block with a label instruction, which can be interpreted as “pushing” the label on the stack. When
its end is reached, i.e., the inner instruction sequence has been reduced to the empty sequence – or rather,
a sequence of 𝑛 values representing the results – then the label instruction is eliminated courtesy of its own
reduction rule:

(label𝑛 {instr * } val * ) ˓→ val *

This can be interpreted as removing the label from the stack and only leaving the locally accumulated operand
values. Validation guarantees that 𝑛 matches the number |val * | of resulting values at this point.

Configurations
A configuration describes the current computation. It consists of the computations’s state and the sequence of
instructions left to execute. The state in turn consists of a global store and a current frame referring to the module
instance in which the computation runs, i.e., where the current function originates from.

config ::= state; instr *


state ::= store; frame

Note

The current version of WebAssembly is single-threaded, but configurations with multiple threads may be sup-
ported in the future.

4.3 Numerics
Numeric primitives are defined in a generic manner, by operators indexed over a bit width 𝑁 .
Some operators are non-deterministic, because they can return one of several possible results (such as different NaN
values). Technically, each operator thus returns a set of allowed values. For convenience, deterministic results are
expressed as plain values, which are assumed to be identified with a respective singleton set.

88 Chapter 4. Execution
WebAssembly Specification, Release 3.0 (2025-11-14)

Some operators are partial, because they are not defined on certain inputs. Technically, an empty set of results is
returned for these inputs.
In formal notation, each operator is defined by equational clauses that apply in decreasing order of precedence.
That is, the first clause that is applicable to the given arguments defines the result. In some cases, similar clauses
are combined into one by using the notation ± or ∓. When several of these placeholders occur in a single clause,
then they must be resolved consistently: either the upper sign is chosen for all of them or the lower sign.

Note

For example, the fcopysign operator is defined as follows:

fcopysign𝑁 (±𝑝1 , ±𝑝2 ) = ±𝑝1


fcopysign𝑁 (±𝑝1 , ∓𝑝2 ) = ∓𝑝1

This definition is to be read as a shorthand for the following expansion of each clause into two separate ones:

fcopysign𝑁 (+𝑝1 , +𝑝2 ) = +𝑝1


fcopysign𝑁 (−𝑝1 , −𝑝2 ) = −𝑝1
fcopysign𝑁 (+𝑝1 , −𝑝2 ) = −𝑝1
fcopysign𝑁 (−𝑝1 , +𝑝2 ) = +𝑝1

Numeric operators are lifted to input sequences by applying the operator element-wise, returning a sequence of
results. When there are multiple inputs, they must be of equal length.

𝑜𝑝(𝑐𝑛1 , . . . , 𝑐𝑛𝑘 ) = 𝑜𝑝(𝑐𝑛1 [0], . . . , 𝑐𝑛𝑘 [0]) . . . 𝑜𝑝(𝑐𝑛1 [𝑛 − 1], . . . , 𝑐𝑛𝑘 [𝑛 − 1])

Note

For example, the unary operator fabs, when given a sequence of floating-point values, return a sequence of
floating-point results:

fabs𝑁 (𝑧 𝑛 ) = fabs𝑁 (𝑧[0]) . . . fabs𝑁 (𝑧[𝑛])

The binary operator iadd, when given two sequences of integers of the same length, 𝑛, return a sequence of
integer results:

iadd𝑁 (𝑖𝑛1 , 𝑖𝑛2 ) = iadd𝑁 (𝑖1 [0], 𝑖2 [0]) . . . iadd𝑁 (𝑖1 [𝑛], 𝑖2 [𝑛])

Conventions:
• The meta variable 𝑑 is used to range over single bits.
• The meta variable 𝑝 is used to range over (signless) magnitudes of floating-point values, including nan and
∞.
• The meta variable 𝑞 is used to range over (signless) rational magnitudes, excluding nan or ∞.
• The notation 𝑓 −1 denotes the inverse of a bijective function 𝑓 .
• Truncation of rational values is written trunc(±𝑞), with the usual mathematical definition:

trunc(±𝑞) = ±𝑖 (if 𝑖 ∈ N ∧ +𝑞 − 1 < 𝑖 ≤ +𝑞)

• Saturation of integers is written sat_u𝑁 (𝑖) and sat_s𝑁 (𝑖). The arguments to these two functions range over
arbitrary signed integers.

4.3. Numerics 89
WebAssembly Specification, Release 3.0 (2025-11-14)

– Unsigned saturation, sat_u𝑁 (𝑖) clamps 𝑖 to between 0 and 2𝑁 − 1:

sat_u𝑁 (𝑖) = 0 (if 𝑖 < 0)


sat_u𝑁 (𝑖) = 2𝑁 − 1 (if 𝑖 > 2𝑁 − 1)
sat_u𝑁 (𝑖) = 𝑖 (otherwise)

– Signed saturation, sat_s𝑁 (𝑖) clamps 𝑖 to between −2𝑁 −1 and 2𝑁 −1 − 1:


sat_s𝑁 (𝑖) = −2𝑁 −1 (if 𝑖 < −2𝑁 −1 )
sat_s𝑁 (𝑖) = 2𝑁 −1 − 1 (if 𝑖 > 2𝑁 −1 − 1)
sat_s𝑁 (𝑖) = 𝑖 (otherwise)

4.3.1 Representations
Numbers and numeric vectors have an underlying binary representation as a sequence of bits:

bitsi𝑁 (𝑖) = ibits𝑁 (𝑖)


bitsf𝑁 (𝑧) = fbits𝑁 (𝑧)
bitsv𝑁 (𝑖) = ibits𝑁 (𝑖)

The first case of these applies to representations of both integer value types and packed types.
Each of these functions is a bijection, hence they are invertible.

Integers
Integers are represented as base two unsigned numbers:

ibits𝑁 (𝑖) = 𝑑𝑁 −1 . . . 𝑑0 (𝑖 = 2𝑁 −1 · 𝑑𝑁 −1 + · · · + 20 · 𝑑0 )

Boolean operators like ∧, ∨, or ⊻ are lifted to bit sequences of equal length by applying them pointwise.

Floating-Point
Floating-point values are represented in the respective binary format defined by IEEE 75422 (Section 3.4):

fbits𝑁 (±(1 + 𝑚 · 2−𝑀 ) · 2𝑒 ) = fsign(±) ibits𝐸 (𝑒 + fbias𝑁 ) ibits𝑀 (𝑚)


fbits𝑁 (±(0 + 𝑚 · 2−𝑀 ) · 2𝑒 ) = fsign(±) (0)𝐸 ibits𝑀 (𝑚)
fbits𝑁 (±∞) = fsign(±) (1)𝐸 (0)𝑀
fbits𝑁 (±nan(𝑛)) = fsign(±) (1)𝐸 ibits𝑀 (𝑛)
fbias𝑁 = 2𝐸−1 − 1
fsign(+) = 0
fsign(−) = 1

where 𝑀 = signif(𝑁 ) and 𝐸 = expon(𝑁 ).

Vectors
Numeric vectors of type v𝑁 have the same underlying representation as an i𝑁 . They can also be interpreted as a
sequence of numeric values packed into a v𝑁 with a particular shape 𝑡x𝑀 , provided that 𝑁 = |𝑡| · 𝑀 .

lanes𝑡x𝑀 (𝑐) = 𝑐0 . . . 𝑐𝑀 −1
(where 𝑤 = |𝑡|/8
∧ 𝑏* = bytesi𝑁 (𝑐)
∧ 𝑐𝑖 = bytes−1 *
𝑡 (𝑏 [𝑖 · 𝑤 : 𝑤]))

This function is a bijection on i𝑁 , hence it is invertible.


22 [Link]

90 Chapter 4. Execution
WebAssembly Specification, Release 3.0 (2025-11-14)

Numeric values can be packed into lanes of a specific lane type and vice versa:

packnumtype (𝑐) = 𝑐
packpacktype (𝑐) = wrap|unpack(packtype)|,|packtype| (𝑐)
unpacknumtype (𝑐) = 𝑐
unpackpacktype (𝑐) = extendu|packtype|,|unpack(packtype)| (𝑐)

Storage
When a number is stored into memory, it is converted into a sequence of bytes in little endian23 byte order:

bytes𝑡 (𝑖) = littleendian(bits𝑡 (𝑖))


littleendian(𝜖) = 𝜖
* *
littleendian(𝑑8 𝑑′ ) = littleendian(𝑑′ ) ibits−1 8
8 (𝑑 )

Again these functions are invertible bijections.

4.3.2 Integer Operations


Sign Interpretation
Integer operators are defined on i𝑁 values. Operators that use a signed interpretation convert the value using the
following definition, which takes the two’s complement when the value lies in the upper half of the value range
(i.e., its most significant bit is 1):

signed𝑁 (𝑖) = 𝑖 (0 ≤ 𝑖 < 2𝑁 −1 )


signed𝑁 (𝑖) = 𝑖 − 2𝑁 (2𝑁 −1 ≤ 𝑖 < 2𝑁 )

This function is bijective, and hence invertible.

Boolean Interpretation
The integer result of predicates – i.e., tests and relational operators – is defined with the help of the following
auxiliary function producing the value 1 or 0 depending on a condition.

bool(𝐶) = 1 (if 𝐶)
bool(𝐶) = 0 (otherwise)

iadd𝑁 (𝑖1 , 𝑖2 )
• Return the result of adding 𝑖1 and 𝑖2 modulo 2𝑁 .
iadd𝑁 (𝑖1 , 𝑖2 ) = (𝑖1 + 𝑖2 ) mod 2𝑁

isub𝑁 (𝑖1 , 𝑖2 )
• Return the result of subtracting 𝑖2 from 𝑖1 modulo 2𝑁 .
isub𝑁 (𝑖1 , 𝑖2 ) = (𝑖1 − 𝑖2 + 2𝑁 ) mod 2𝑁

imul𝑁 (𝑖1 , 𝑖2 )
• Return the result of multiplying 𝑖1 and 𝑖2 modulo 2𝑁 .
imul𝑁 (𝑖1 , 𝑖2 ) = (𝑖1 · 𝑖2 ) mod 2𝑁
23 [Link]

4.3. Numerics 91
WebAssembly Specification, Release 3.0 (2025-11-14)

idiv_u𝑁 (𝑖1 , 𝑖2 )
• If 𝑖2 is 0, then the result is undefined.
• Else, return the result of dividing 𝑖1 by 𝑖2 , truncated toward zero.
idiv_u𝑁 (𝑖1 , 0) = {}
idiv_u𝑁 (𝑖1 , 𝑖2 ) = trunc(𝑖1 /𝑖2 )

Note

This operator is partial.

idiv_s𝑁 (𝑖1 , 𝑖2 )
• Let 𝑗1 be the signed interpretation of 𝑖1 .
• Let 𝑗2 be the signed interpretation of 𝑖2 .
• If 𝑗2 is 0, then the result is undefined.
• Else if 𝑗1 divided by 𝑗2 is 2𝑁 −1 , then the result is undefined.
• Else, return the result of dividing 𝑗1 by 𝑗2 , truncated toward zero.
idiv_s𝑁 (𝑖1 , 0) = {}
idiv_s𝑁 (𝑖1 , 𝑖2 ) = {} (if signed𝑁 (𝑖1 )/signed𝑁 (𝑖2 ) = 2𝑁 −1 )
−1
idiv_s𝑁 (𝑖1 , 𝑖2 ) = signed𝑁 (trunc(signed𝑁 (𝑖1 )/signed𝑁 (𝑖2 )))

Note

This operator is partial. Besides division by 0, the result of (−2𝑁 −1 )/(−1) = +2𝑁 −1 is not representable as
an 𝑁 -bit signed integer.

irem_u𝑁 (𝑖1 , 𝑖2 )
• If 𝑖2 is 0, then the result is undefined.
• Else, return the remainder of dividing 𝑖1 by 𝑖2 .
irem_u𝑁 (𝑖1 , 0) = {}
irem_u𝑁 (𝑖1 , 𝑖2 ) = 𝑖1 − 𝑖2 · trunc(𝑖1 /𝑖2 )

Note

This operator is partial.


As long as both operators are defined, it holds that 𝑖1 = 𝑖2 · idiv_u(𝑖1 , 𝑖2 ) + irem_u(𝑖1 , 𝑖2 ).

irem_s𝑁 (𝑖1 , 𝑖2 )
• Let 𝑗1 be the signed interpretation of 𝑖1 .
• Let 𝑗2 be the signed interpretation of 𝑖2 .
• If 𝑖2 is 0, then the result is undefined.
• Else, return the remainder of dividing 𝑗1 by 𝑗2 , with the sign of the dividend 𝑗1 .

92 Chapter 4. Execution
WebAssembly Specification, Release 3.0 (2025-11-14)

irem_s𝑁 (𝑖1 , 0) = {}
irem_s𝑁 (𝑖1 , 𝑖2 ) = signed−1
𝑁 (𝑗1 − 𝑗2 · trunc(𝑗1 /𝑗2 ))
(where 𝑗1 = signed𝑁 (𝑖1 ) ∧ 𝑗2 = signed𝑁 (𝑖2 ))

Note

This operator is partial.


As long as both operators are defined, it holds that 𝑖1 = 𝑖2 · idiv_s(𝑖1 , 𝑖2 ) + irem_s(𝑖1 , 𝑖2 ).

inot𝑁 (𝑖)
• Return the bitwise negation of 𝑖.
inot𝑁 (𝑖) = ibits−1 𝑁
𝑁 (ibits𝑁 (𝑖) ⊻ ibits𝑁 (2 − 1))

irev𝑁 (𝑖)
• Return the bitwise reversal of 𝑖.
irev𝑁 (𝑖) = ibits−1 𝑁
𝑁 ((𝑑 [𝑁 − 𝑖])
𝑖≤𝑁
) (if 𝑑𝑁 = ibits𝑁 (𝑖))

iand𝑁 (𝑖1 , 𝑖2 )
• Return the bitwise conjunction of 𝑖1 and 𝑖2 .
iand𝑁 (𝑖1 , 𝑖2 ) = ibits−1
𝑁 (ibits𝑁 (𝑖1 ) ∧ ibits𝑁 (𝑖2 ))

iandnot𝑁 (𝑖1 , 𝑖2 )
• Return the bitwise conjunction of 𝑖1 and the bitwise negation of 𝑖2 .
iandnot𝑁 (𝑖1 , 𝑖2 ) = iand𝑁 (𝑖1 , inot𝑁 (𝑖2 ))

ior𝑁 (𝑖1 , 𝑖2 )
• Return the bitwise disjunction of 𝑖1 and 𝑖2 .
ior𝑁 (𝑖1 , 𝑖2 ) = ibits−1
𝑁 (ibits𝑁 (𝑖1 ) ∨ ibits𝑁 (𝑖2 ))

ixor𝑁 (𝑖1 , 𝑖2 )
• Return the bitwise exclusive disjunction of 𝑖1 and 𝑖2 .
ixor𝑁 (𝑖1 , 𝑖2 ) = ibits−1
𝑁 (ibits𝑁 (𝑖1 ) ⊻ ibits𝑁 (𝑖2 ))

ishl𝑁 (𝑖1 , 𝑖2 )
• Let 𝑘 be 𝑖2 modulo 𝑁 .
• Return the result of shifting 𝑖1 left by 𝑘 bits, modulo 2𝑁 .
ishl𝑁 (𝑖1 , 𝑖2 ) = ibits−1 𝑁 −𝑘 𝑘
𝑁 (𝑑2 0 ) (if ibits𝑁 (𝑖1 ) = 𝑑𝑘1 𝑑2𝑁 −𝑘 ∧ 𝑘 = 𝑖2 mod 𝑁 )

ishr_u𝑁 (𝑖1 , 𝑖2 )
• Let 𝑘 be 𝑖2 modulo 𝑁 .
• Return the result of shifting 𝑖1 right by 𝑘 bits, extended with 0 bits.
ishr_u𝑁 (𝑖1 , 𝑖2 ) = ibits−1 𝑘 𝑁 −𝑘
𝑁 (0 𝑑1 ) (if ibits𝑁 (𝑖1 ) = 𝑑𝑁
1
−𝑘 𝑘
𝑑2 ∧ 𝑘 = 𝑖2 mod 𝑁 )

4.3. Numerics 93
WebAssembly Specification, Release 3.0 (2025-11-14)

ishr_s𝑁 (𝑖1 , 𝑖2 )
• Let 𝑘 be 𝑖2 modulo 𝑁 .
• Return the result of shifting 𝑖1 right by 𝑘 bits, extended with the most significant bit of the original value.
ishr_s𝑁 (𝑖1 , 𝑖2 ) = ibits−1 𝑘+1 𝑁 −𝑘−1
𝑁 (𝑑0 𝑑1 ) (if ibits𝑁 (𝑖1 ) = 𝑑0 𝑑1𝑁 −𝑘−1 𝑑𝑘2 ∧ 𝑘 = 𝑖2 mod 𝑁 )

irotl𝑁 (𝑖1 , 𝑖2 )
• Let 𝑘 be 𝑖2 modulo 𝑁 .
• Return the result of rotating 𝑖1 left by 𝑘 bits.
irotl𝑁 (𝑖1 , 𝑖2 ) = ibits−1 𝑁 −𝑘 𝑘
𝑁 (𝑑2 𝑑1 ) (if ibits𝑁 (𝑖1 ) = 𝑑𝑘1 𝑑𝑁
2
−𝑘
∧ 𝑘 = 𝑖2 mod 𝑁 )

irotr𝑁 (𝑖1 , 𝑖2 )
• Let 𝑘 be 𝑖2 modulo 𝑁 .
• Return the result of rotating 𝑖1 right by 𝑘 bits.
irotr𝑁 (𝑖1 , 𝑖2 ) = ibits−1 𝑘 𝑁 −𝑘
𝑁 (𝑑2 𝑑1 ) (if ibits𝑁 (𝑖1 ) = 𝑑1𝑁 −𝑘 𝑑𝑘2 ∧ 𝑘 = 𝑖2 mod 𝑁 )

iclz𝑁 (𝑖)
• Return the count of leading zero bits in 𝑖; all bits are considered leading zeros if 𝑖 is 0.
iclz𝑁 (𝑖) = 𝑘 (if ibits𝑁 (𝑖) = 0𝑘 (1 𝑑* )? )

ictz𝑁 (𝑖)
• Return the count of trailing zero bits in 𝑖; all bits are considered trailing zeros if 𝑖 is 0.
ictz𝑁 (𝑖) = 𝑘 (if ibits𝑁 (𝑖) = (𝑑* 1)? 0𝑘 )

ipopcnt𝑁 (𝑖)
• Return the count of non-zero bits in 𝑖.
ipopcnt𝑁 (𝑖) = 𝑘 (if ibits𝑁 (𝑖) = (0* 1)𝑘 0* )

ieqz𝑁 (𝑖)
• Return 1 if 𝑖 is zero, 0 otherwise.
ieqz𝑁 (𝑖) = bool(𝑖 = 0)

inez𝑁 (𝑖)
• Return 0 if 𝑖 is zero, 1 otherwise.
inez𝑁 (𝑖) = bool(𝑖 ̸= 0)

ieq𝑁 (𝑖1 , 𝑖2 )
• Return 1 if 𝑖1 equals 𝑖2 , 0 otherwise.
ieq𝑁 (𝑖1 , 𝑖2 ) = bool(𝑖1 = 𝑖2 )

94 Chapter 4. Execution
WebAssembly Specification, Release 3.0 (2025-11-14)

ine𝑁 (𝑖1 , 𝑖2 )
• Return 1 if 𝑖1 does not equal 𝑖2 , 0 otherwise.
ine𝑁 (𝑖1 , 𝑖2 ) = bool(𝑖1 ̸= 𝑖2 )

ilt_u𝑁 (𝑖1 , 𝑖2 )
• Return 1 if 𝑖1 is less than 𝑖2 , 0 otherwise.
ilt_u𝑁 (𝑖1 , 𝑖2 ) = bool(𝑖1 < 𝑖2 )

ilt_s𝑁 (𝑖1 , 𝑖2 )
• Let 𝑗1 be the signed interpretation of 𝑖1 .
• Let 𝑗2 be the signed interpretation of 𝑖2 .
• Return 1 if 𝑗1 is less than 𝑗2 , 0 otherwise.
ilt_s𝑁 (𝑖1 , 𝑖2 ) = bool(signed𝑁 (𝑖1 ) < signed𝑁 (𝑖2 ))

igt_u𝑁 (𝑖1 , 𝑖2 )
• Return 1 if 𝑖1 is greater than 𝑖2 , 0 otherwise.
igt_u𝑁 (𝑖1 , 𝑖2 ) = bool(𝑖1 > 𝑖2 )

igt_s𝑁 (𝑖1 , 𝑖2 )
• Let 𝑗1 be the signed interpretation of 𝑖1 .
• Let 𝑗2 be the signed interpretation of 𝑖2 .
• Return 1 if 𝑗1 is greater than 𝑗2 , 0 otherwise.
igt_s𝑁 (𝑖1 , 𝑖2 ) = bool(signed𝑁 (𝑖1 ) > signed𝑁 (𝑖2 ))

ile_u𝑁 (𝑖1 , 𝑖2 )
• Return 1 if 𝑖1 is less than or equal to 𝑖2 , 0 otherwise.
ile_u𝑁 (𝑖1 , 𝑖2 ) = bool(𝑖1 ≤ 𝑖2 )

ile_s𝑁 (𝑖1 , 𝑖2 )
• Let 𝑗1 be the signed interpretation of 𝑖1 .
• Let 𝑗2 be the signed interpretation of 𝑖2 .
• Return 1 if 𝑗1 is less than or equal to 𝑗2 , 0 otherwise.
ile_s𝑁 (𝑖1 , 𝑖2 ) = bool(signed𝑁 (𝑖1 ) ≤ signed𝑁 (𝑖2 ))

ige_u𝑁 (𝑖1 , 𝑖2 )
• Return 1 if 𝑖1 is greater than or equal to 𝑖2 , 0 otherwise.
ige_u𝑁 (𝑖1 , 𝑖2 ) = bool(𝑖1 ≥ 𝑖2 )

4.3. Numerics 95
WebAssembly Specification, Release 3.0 (2025-11-14)

ige_s𝑁 (𝑖1 , 𝑖2 )
• Let 𝑗1 be the signed interpretation of 𝑖1 .
• Let 𝑗2 be the signed interpretation of 𝑖2 .
• Return 1 if 𝑗1 is greater than or equal to 𝑗2 , 0 otherwise.
ige_s𝑁 (𝑖1 , 𝑖2 ) = bool(signed𝑁 (𝑖1 ) ≥ signed𝑁 (𝑖2 ))

iextend𝑀 _s𝑁 (𝑖)


• Let 𝑗 be the result of computing wrap𝑁,𝑀 (𝑖).
• Return extends 𝑀,𝑁 (𝑗).
iextend𝑀 _s𝑁 (𝑖) = extends 𝑀,𝑁 (wrap𝑁,𝑀 (𝑖))

ibitselect𝑁 (𝑖1 , 𝑖2 , 𝑖3 )
• Let 𝑗1 be the bitwise conjunction of 𝑖1 and 𝑖3 .
• Let 𝑗3′ be the bitwise negation of 𝑖3 .
• Let 𝑗2 be the bitwise conjunction of 𝑖2 and 𝑗3′ .
• Return the bitwise disjunction of 𝑗1 and 𝑗2 .
ibitselect𝑁 (𝑖1 , 𝑖2 , 𝑖3 ) = ior𝑁 (iand𝑁 (𝑖1 , 𝑖3 ), iand𝑁 (𝑖2 , inot𝑁 (𝑖3 )))

iabs𝑁 (𝑖)
• Let 𝑗 be the signed interpretation of 𝑖.
• If 𝑗 is greater than or equal to 0, then return 𝑖.
• Else return the negation of j, modulo 2𝑁 .
iabs𝑁 (𝑖) = 𝑖 (if signed𝑁 (𝑖) ≥ 0)
iabs𝑁 (𝑖) = −signed𝑁 (𝑖) mod 2𝑁 (otherwise)

ineg𝑁 (𝑖)
• Return the result of negating 𝑖, modulo 2𝑁 .
ineg𝑁 (𝑖) = (2𝑁 − 𝑖) mod 2𝑁

imin_u𝑁 (𝑖1 , 𝑖2 )
• Return 𝑖1 if ilt_u𝑁 (𝑖1 , 𝑖2 ) is 1, return 𝑖2 otherwise.
imin_u𝑁 (𝑖1 , 𝑖2 ) = 𝑖1 (if ilt_u𝑁 (𝑖1 , 𝑖2 ) = 1)
imin_u𝑁 (𝑖1 , 𝑖2 ) = 𝑖2 (otherwise)

imin_s𝑁 (𝑖1 , 𝑖2 )
• Return 𝑖1 if ilt_s𝑁 (𝑖1 , 𝑖2 ) is 1, return 𝑖2 otherwise.
imin_s𝑁 (𝑖1 , 𝑖2 ) = 𝑖1 (if ilt_s𝑁 (𝑖1 , 𝑖2 ) = 1)
imin_s𝑁 (𝑖1 , 𝑖2 ) = 𝑖2 (otherwise)

imax_u𝑁 (𝑖1 , 𝑖2 )
• Return 𝑖1 if igt_u𝑁 (𝑖1 , 𝑖2 ) is 1, return 𝑖2 otherwise.
imax_u𝑁 (𝑖1 , 𝑖2 ) = 𝑖1 (if igt_u𝑁 (𝑖1 , 𝑖2 ) = 1)
imax_u𝑁 (𝑖1 , 𝑖2 ) = 𝑖2 (otherwise)

96 Chapter 4. Execution
WebAssembly Specification, Release 3.0 (2025-11-14)

imax_s𝑁 (𝑖1 , 𝑖2 )
• Return 𝑖1 if igt_s𝑁 (𝑖1 , 𝑖2 ) is 1, return 𝑖2 otherwise.
imax_s𝑁 (𝑖1 , 𝑖2 ) = 𝑖1 (if igt_s𝑁 (𝑖1 , 𝑖2 ) = 1)
imax_s𝑁 (𝑖1 , 𝑖2 ) = 𝑖2 (otherwise)

iadd_sat_u𝑁 (𝑖1 , 𝑖2 )
• Let 𝑖 be the result of adding 𝑖1 and 𝑖2 .
• Return sat_u𝑁 (𝑖).
iadd_sat_u𝑁 (𝑖1 , 𝑖2 ) = sat_u𝑁 (𝑖1 + 𝑖2 )

iadd_sat_s𝑁 (𝑖1 , 𝑖2 )
• Let 𝑗1 be the signed interpretation of 𝑖1
• Let 𝑗2 be the signed interpretation of 𝑖2
• Let 𝑗 be the result of adding 𝑗1 and 𝑗2 .
• Return the value whose signed interpretation is sat_s𝑁 (𝑗).
iadd_sat_s𝑁 (𝑖1 , 𝑖2 ) = signed−1
𝑁 (sat_s𝑁 (signed𝑁 (𝑖1 ) + signed𝑁 (𝑖2 )))

isub_sat_u𝑁 (𝑖1 , 𝑖2 )
• Let 𝑖 be the result of subtracting 𝑖2 from 𝑖1 .
• Return sat_u𝑁 (𝑖).
isub_sat_u𝑁 (𝑖1 , 𝑖2 ) = sat_u𝑁 (𝑖1 − 𝑖2 )

isub_sat_s𝑁 (𝑖1 , 𝑖2 )
• Let 𝑗1 be the signed interpretation of 𝑖1
• Let 𝑗2 be the signed interpretation of 𝑖2
• Let 𝑗 be the result of subtracting 𝑗2 from 𝑗1 .
• Return the value whose signed interpretation is sat_s𝑁 (𝑗).
isub_sat_s𝑁 (𝑖1 , 𝑖2 ) = signed−1
𝑁 (sat_s𝑁 (signed𝑁 (𝑖1 ) − signed𝑁 (𝑖2 )))

iavgr_u𝑁 (𝑖1 , 𝑖2 )
• Let 𝑗 be the result of adding 𝑖1 , 𝑖2 , and 1.
• Return the result of dividing 𝑗 by 2, truncated toward zero.
iavgr_u𝑁 (𝑖1 , 𝑖2 ) = trunc((𝑖1 + 𝑖2 + 1)/2)

iq15mulrsat_s𝑁 (𝑖1 , 𝑖2 )
• Return the whose signed interpretation is the result of sat_s𝑁 (ishr_s𝑁 (𝑖1 · 𝑖2 + 214 , 15)).
iq15mulrsat_s𝑁 (𝑖1 , 𝑖2 ) = signed−1 14
𝑁 (sat_s𝑁 (ishr_s𝑁 (𝑖1 · 𝑖2 + 2 , 15)))

4.3. Numerics 97
WebAssembly Specification, Release 3.0 (2025-11-14)

4.3.3 Floating-Point Operations


Floating-point arithmetic follows the IEEE 75424 standard, with the following qualifications:
• All operators use round-to-nearest ties-to-even, except where otherwise specified. Non-default directed
rounding attributes are not supported.
• Following the recommendation that operators propagate NaN payloads from their operands is permitted but
not required.
• All operators use “non-stop” mode, and floating-point exceptions are not otherwise observable. In particular,
neither alternate floating-point exception handling attributes nor operators on status flags are supported.
There is no observable difference between quiet and signalling NaNs.

Note

Some of these limitations may be lifted in future versions of WebAssembly.

Rounding
Rounding always is round-to-nearest ties-to-even, in correspondence with IEEE 75425 (Section 4.3.1).
An exact floating-point number is a rational number that is exactly representable as a floating-point number of
given bit width 𝑁 .
A limit number for a given floating-point bit width 𝑁 is a positive or negative number whose magnitude is the
smallest power of 2 that is not exactly representable as a floating-point number of width 𝑁 (that magnitude is 2128
for 𝑁 = 32 and 21024 for 𝑁 = 64).
A candidate number is either an exact floating-point number or a positive or negative limit number for the given
bit width 𝑁 .
A candidate pair is a pair 𝑧1 , 𝑧2 of candidate numbers, such that no candidate number exists that lies between the
two.
A real number 𝑟 is converted to a floating-point value of bit width 𝑁 as follows:
• If 𝑟 is 0, then return +0.
• Else if 𝑟 is an exact floating-point number, then return 𝑟.
• Else if 𝑟 greater than or equal to the positive limit, then return +∞.
• Else if 𝑟 is less than or equal to the negative limit, then return −∞.
• Else if 𝑧1 and 𝑧2 are a candidate pair such that 𝑧1 < 𝑟 < 𝑧2 , then:
– If |𝑟 − 𝑧1 | < |𝑟 − 𝑧2 |, then let 𝑧 be 𝑧1 .
– Else if |𝑟 − 𝑧1 | > |𝑟 − 𝑧2 |, then let 𝑧 be 𝑧2 .
– Else if |𝑟 − 𝑧1 | = |𝑟 − 𝑧2 | and the significand of 𝑧1 is even, then let 𝑧 be 𝑧1 .
– Else, let 𝑧 be 𝑧2 .
• If 𝑧 is 0, then:
– If 𝑟 < 0, then return −0.
– Else, return +0.
• Else if 𝑧 is a limit number, then:
– If 𝑟 < 0, then return −∞.
– Else, return +∞.
24 [Link]
25 [Link]

98 Chapter 4. Execution
WebAssembly Specification, Release 3.0 (2025-11-14)

• Else, return 𝑧.
float𝑁 (0) = +0
float𝑁 (𝑟) = 𝑟 (if 𝑟 ∈ exact𝑁 )
float𝑁 (𝑟) = +∞ (if 𝑟 ≥ +limit𝑁 )
float𝑁 (𝑟) = −∞ (if 𝑟 ≤ −limit𝑁 )
float𝑁 (𝑟) = closest𝑁 (𝑟, 𝑧1 , 𝑧2 ) (if 𝑧1 < 𝑟 < 𝑧2 ∧ (𝑧1 , 𝑧2 ) ∈ candidatepair𝑁 )
closest𝑁 (𝑟, 𝑧1 , 𝑧2 ) = rectify𝑁 (𝑟, 𝑧1 ) (if |𝑟 − 𝑧1 | < |𝑟 − 𝑧2 |)
closest𝑁 (𝑟, 𝑧1 , 𝑧2 ) = rectify𝑁 (𝑟, 𝑧2 ) (if |𝑟 − 𝑧1 | > |𝑟 − 𝑧2 |)
closest𝑁 (𝑟, 𝑧1 , 𝑧2 ) = rectify𝑁 (𝑟, 𝑧1 ) (if |𝑟 − 𝑧1 | = |𝑟 − 𝑧2 | ∧ even𝑁 (𝑧1 ))
closest𝑁 (𝑟, 𝑧1 , 𝑧2 ) = rectify𝑁 (𝑟, 𝑧2 ) (if |𝑟 − 𝑧1 | = |𝑟 − 𝑧2 | ∧ even𝑁 (𝑧2 ))
rectify𝑁 (𝑟, ±limit𝑁 ) = ±∞
rectify𝑁 (𝑟, 0) = +0 (𝑟 ≥ 0)
rectify𝑁 (𝑟, 0) = −0 (𝑟 < 0)
rectify𝑁 (𝑟, 𝑧) = 𝑧
where:
exact𝑁 = f 𝑁 ∩Q
expon(𝑁 )−1
limit𝑁 = 22
candidate𝑁 = exact𝑁 ∪ {+limit𝑁 , −limit𝑁 }
candidatepair𝑁 = {(𝑧1 , 𝑧2 ) ∈ candidate2𝑁 | 𝑧1 < 𝑧2 ∧ ∀𝑧 ∈ candidate𝑁 , 𝑧 ≤ 𝑧1 ∨ 𝑧 ≥ 𝑧2 }
even𝑁 ((𝑑 + 𝑚 · 2−𝑀 ) · 2𝑒 ) ⇔ 𝑚 mod 2 = 0
even𝑁 (±limit𝑁 ) ⇔ true

NaN Propagation
When the result of a floating-point operator other than fneg, fabs, or fcopysign is a NaN, then its sign is non-
deterministic and the payload is computed as follows:
• If the payload of all NaN inputs to the operator is canonical (including the case that there are no NaN inputs),
then the payload of the output is canonical as well.
• Otherwise the payload is picked non-deterministically among all arithmetic NaNs; that is, its most significant
bit is 1 and all others are unspecified.
• In the deterministic profile, however, a positive canonical NaNs is reliably produced in the latter case.
The non-deterministic result is expressed by the following auxiliary function producing a set of allowed outputs
from a set of inputs:

nans𝑁 {𝑧 * } = {+nan(canon𝑁 )}
[!DET]
nans𝑁 {𝑧 * } = {+nan(𝑛), −nan(𝑛) | 𝑛 = canon𝑁 } (if {𝑧 * } ⊆ {+nan(canon𝑁 ), −nan(canon𝑁 )}
[!DET]
nans𝑁 {𝑧 * } = {+nan(𝑛), −nan(𝑛) | 𝑛 ≥ canon𝑁 } (if {𝑧 * } ̸⊆ {+nan(canon𝑁 ), −nan(canon𝑁 )}

fadd𝑁 (𝑧1 , 𝑧2 )
• If either 𝑧1 or 𝑧2 is a NaN, then return an element of nans𝑁 {𝑧1 , 𝑧2 }.
• Else if both 𝑧1 and 𝑧2 are infinities of opposite signs, then return an element of nans𝑁 {}.
• Else if both 𝑧1 and 𝑧2 are infinities of equal sign, then return that infinity.
• Else if either 𝑧1 or 𝑧2 is an infinity, then return that infinity.
• Else if both 𝑧1 and 𝑧2 are zeroes of opposite sign, then return positive zero.
• Else if both 𝑧1 and 𝑧2 are zeroes of equal sign, then return that zero.
• Else if either 𝑧1 or 𝑧2 is a zero, then return the other operand.
• Else if both 𝑧1 and 𝑧2 are values with the same magnitude but opposite signs, then return positive zero.
• Else return the result of adding 𝑧1 and 𝑧2 , rounded to the nearest representable value.

4.3. Numerics 99
WebAssembly Specification, Release 3.0 (2025-11-14)

fadd𝑁 (±nan(𝑛), 𝑧2 ) = nans𝑁 {±nan(𝑛), 𝑧2 }


fadd𝑁 (𝑧1 , ±nan(𝑛)) = nans𝑁 {±nan(𝑛), 𝑧1 }
fadd𝑁 (±∞, ∓∞) = nans𝑁 {}
fadd𝑁 (±∞, ±∞) = ±∞
fadd𝑁 (𝑧1 , ±∞) = ±∞
fadd𝑁 (±∞, 𝑧2 ) = ±∞
fadd𝑁 (±0, ∓0) = +0
fadd𝑁 (±0, ±0) = ±0
fadd𝑁 (𝑧1 , ±0) = 𝑧1
fadd𝑁 (±0, 𝑧2 ) = 𝑧2
fadd𝑁 (±𝑞, ∓𝑞) = +0
fadd𝑁 (𝑧1 , 𝑧2 ) = float𝑁 (𝑧1 + 𝑧2 )

fsub𝑁 (𝑧1 , 𝑧2 )
• If either 𝑧1 or 𝑧2 is a NaN, then return an element of nans𝑁 {𝑧1 , 𝑧2 }.
• Else if both 𝑧1 and 𝑧2 are infinities of equal signs, then return an element of nans𝑁 {}.
• Else if both 𝑧1 and 𝑧2 are infinities of opposite sign, then return 𝑧1 .
• Else if 𝑧1 is an infinity, then return that infinity.
• Else if 𝑧2 is an infinity, then return that infinity negated.
• Else if both 𝑧1 and 𝑧2 are zeroes of equal sign, then return positive zero.
• Else if both 𝑧1 and 𝑧2 are zeroes of opposite sign, then return 𝑧1 .
• Else if 𝑧2 is a zero, then return 𝑧1 .
• Else if 𝑧1 is a zero, then return 𝑧2 negated.
• Else if both 𝑧1 and 𝑧2 are the same value, then return positive zero.
• Else return the result of subtracting 𝑧2 from 𝑧1 , rounded to the nearest representable value.
fsub𝑁 (±nan(𝑛), 𝑧2 ) = nans𝑁 {±nan(𝑛), 𝑧2 }
fsub𝑁 (𝑧1 , ±nan(𝑛)) = nans𝑁 {±nan(𝑛), 𝑧1 }
fsub𝑁 (±∞, ±∞) = nans𝑁 {}
fsub𝑁 (±∞, ∓∞) = ±∞
fsub𝑁 (𝑧1 , ±∞) = ∓∞
fsub𝑁 (±∞, 𝑧2 ) = ±∞
fsub𝑁 (±0, ±0) = +0
fsub𝑁 (±0, ∓0) = ±0
fsub𝑁 (𝑧1 , ±0) = 𝑧1
fsub𝑁 (±0, ±𝑞2 ) = ∓𝑞2
fsub𝑁 (±𝑞, ±𝑞) = +0
fsub𝑁 (𝑧1 , 𝑧2 ) = float𝑁 (𝑧1 − 𝑧2 )

Note

Up to the non-determinism regarding NaNs, it always holds that fsub𝑁 (𝑧1 , 𝑧2 ) = fadd𝑁 (𝑧1 , fneg𝑁 (𝑧2 )).

fmul𝑁 (𝑧1 , 𝑧2 )
• If either 𝑧1 or 𝑧2 is a NaN, then return an element of nans𝑁 {𝑧1 , 𝑧2 }.
• Else if one of 𝑧1 and 𝑧2 is a zero and the other an infinity, then return an element of nans𝑁 {}.
• Else if both 𝑧1 and 𝑧2 are infinities of equal sign, then return positive infinity.
• Else if both 𝑧1 and 𝑧2 are infinities of opposite sign, then return negative infinity.
• Else if either 𝑧1 or 𝑧2 is an infinity and the other a value with equal sign, then return positive infinity.

100 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

• Else if either 𝑧1 or 𝑧2 is an infinity and the other a value with opposite sign, then return negative infinity.
• Else if both 𝑧1 and 𝑧2 are zeroes of equal sign, then return positive zero.
• Else if both 𝑧1 and 𝑧2 are zeroes of opposite sign, then return negative zero.
• Else return the result of multiplying 𝑧1 and 𝑧2 , rounded to the nearest representable value.
fmul𝑁 (±nan(𝑛), 𝑧2 ) = nans𝑁 {±nan(𝑛), 𝑧2 }
fmul𝑁 (𝑧1 , ±nan(𝑛)) = nans𝑁 {±nan(𝑛), 𝑧1 }
fmul𝑁 (±∞, ±0) = nans𝑁 {}
fmul𝑁 (±∞, ∓0) = nans𝑁 {}
fmul𝑁 (±0, ±∞) = nans𝑁 {}
fmul𝑁 (±0, ∓∞) = nans𝑁 {}
fmul𝑁 (±∞, ±∞) = +∞
fmul𝑁 (±∞, ∓∞) = −∞
fmul𝑁 (±𝑞1 , ±∞) = +∞
fmul𝑁 (±𝑞1 , ∓∞) = −∞
fmul𝑁 (±∞, ±𝑞2 ) = +∞
fmul𝑁 (±∞, ∓𝑞2 ) = −∞
fmul𝑁 (±0, ±0) = +0
fmul𝑁 (±0, ∓0) = −0
fmul𝑁 (𝑧1 , 𝑧2 ) = float𝑁 (𝑧1 · 𝑧2 )

fdiv𝑁 (𝑧1 , 𝑧2 )
• If either 𝑧1 or 𝑧2 is a NaN, then return an element of nans𝑁 {𝑧1 , 𝑧2 }.
• Else if both 𝑧1 and 𝑧2 are infinities, then return an element of nans𝑁 {}.
• Else if both 𝑧1 and 𝑧2 are zeroes, then return an element of nans𝑁 {𝑧1 , 𝑧2 }.
• Else if 𝑧1 is an infinity and 𝑧2 a value with equal sign, then return positive infinity.
• Else if 𝑧1 is an infinity and 𝑧2 a value with opposite sign, then return negative infinity.
• Else if 𝑧2 is an infinity and 𝑧1 a value with equal sign, then return positive zero.
• Else if 𝑧2 is an infinity and 𝑧1 a value with opposite sign, then return negative zero.
• Else if 𝑧1 is a zero and 𝑧2 a value with equal sign, then return positive zero.
• Else if 𝑧1 is a zero and 𝑧2 a value with opposite sign, then return negative zero.
• Else if 𝑧2 is a zero and 𝑧1 a value with equal sign, then return positive infinity.
• Else if 𝑧2 is a zero and 𝑧1 a value with opposite sign, then return negative infinity.
• Else return the result of dividing 𝑧1 by 𝑧2 , rounded to the nearest representable value.
fdiv𝑁 (±nan(𝑛), 𝑧2 ) = nans𝑁 {±nan(𝑛), 𝑧2 }
fdiv𝑁 (𝑧1 , ±nan(𝑛)) = nans𝑁 {±nan(𝑛), 𝑧1 }
fdiv𝑁 (±∞, ±∞) = nans𝑁 {}
fdiv𝑁 (±∞, ∓∞) = nans𝑁 {}
fdiv𝑁 (±0, ±0) = nans𝑁 {}
fdiv𝑁 (±0, ∓0) = nans𝑁 {}
fdiv𝑁 (±∞, ±𝑞2 ) = +∞
fdiv𝑁 (±∞, ∓𝑞2 ) = −∞
fdiv𝑁 (±𝑞1 , ±∞) = +0
fdiv𝑁 (±𝑞1 , ∓∞) = −0
fdiv𝑁 (±0, ±𝑞2 ) = +0
fdiv𝑁 (±0, ∓𝑞2 ) = −0
fdiv𝑁 (±𝑞1 , ±0) = +∞
fdiv𝑁 (±𝑞1 , ∓0) = −∞
fdiv𝑁 (𝑧1 , 𝑧2 ) = float𝑁 (𝑧1 /𝑧2 )

4.3. Numerics 101


WebAssembly Specification, Release 3.0 (2025-11-14)

fma𝑁 (𝑧1 , 𝑧2 , 𝑧3 )
The function fma is the same as fusedMultiplyAdd defined by IEEE 75426 (Section 5.4.1). It computes (𝑧1 ·𝑧2 )+𝑧3
as if with unbounded range and precision, rounding only once for the final result.
• If either 𝑧1 or 𝑧2 or 𝑧3 is a NaN, return an element of nans𝑁 𝑧1 , 𝑧2 , 𝑧3 .
• Else if either 𝑧1 or 𝑧2 is a zero and the other is an infinity, then return an element of nans𝑁 {}.
• Else if both 𝑧1 or 𝑧2 are infinities of equal sign, and 𝑧3 is a negative infinity, then return an element of
nans𝑁 {}.
• Else if both 𝑧1 or 𝑧2 are infinities of opposite sign, and 𝑧3 is a positive infinity, then return an element of
nans𝑁 {}.
• Else if either 𝑧1 or 𝑧2 is an infinity and the other is a value of the same sign, and 𝑧3 is a negative infinity,
then return an element of nans𝑁 {}.
• Else if either 𝑧1 or 𝑧2 is an infinity and the other is a value of the opposite sign, and 𝑧3 is a positive infinity,
then return an element of nans𝑁 {}.
• Else if both 𝑧1 and 𝑧2 are zeroes of the same sign and 𝑧3 is a zero, then return positive zero.
• Else if both 𝑧1 and 𝑧2 are zeroes of the opposite sign and 𝑧3 is a positive zero, then return positive zero.
• Else if both 𝑧1 and 𝑧2 are zeroes of the opposite sign and 𝑧3 is a negative zero, then return negative zero.
• Else return the result of multiplying 𝑧1 and 𝑧2 , adding 𝑧3 to the intermediate, and the final result ref:rounded
<aux-ieee> to the nearest representable value.
fma𝑁 (±nan(𝑛), 𝑧2 , 𝑧3 ) = nans𝑁 {±nan(𝑛), 𝑧2 , 𝑧3 }
fma𝑁 (𝑧1 , ±nan(𝑛), 𝑧3 ) = nans𝑁 {±nan(𝑛), 𝑧1 , 𝑧3 }
fma𝑁 (𝑧1 , 𝑧2 , ±nan(𝑛)) = nans𝑁 {±nan(𝑛), 𝑧1 , 𝑧2 }
fma𝑁 (±∞, ±0, 𝑧3 ) = nans𝑁 {}
fma𝑁 (±∞, ∓0, 𝑧3 ) = nans𝑁 {}
fma𝑁 (±∞, ±∞, −∞) = nans𝑁 {}
fma𝑁 (±∞, ∓∞, +∞) = nans𝑁 {}
fma𝑁 (±𝑞1 , ±∞, −∞) = nans𝑁 {}
fma𝑁 (±𝑞1 , ∓∞, +∞) = nans𝑁 {}
fma𝑁 (±∞, ±𝑞1 , −∞) = nans𝑁 {}
fma𝑁 (∓∞, ±𝑞1 , +∞) = nans𝑁 {}
fma𝑁 (±0, ±0, ∓0) = +0
fma𝑁 (±0, ±0, ±0) = +0
fma𝑁 (±0, ∓0, +0) = +0
fma𝑁 (±0, ∓0, −0) = −0
fma𝑁 (𝑧1 , 𝑧2 , 𝑧3 ) = float𝑁 (𝑧1 · 𝑧2 + 𝑧3 )

fmin𝑁 (𝑧1 , 𝑧2 )
• If either 𝑧1 or 𝑧2 is a NaN, then return an element of nans𝑁 {𝑧1 , 𝑧2 }.
• Else if either 𝑧1 or 𝑧2 is a negative infinity, then return negative infinity.
• Else if either 𝑧1 or 𝑧2 is a positive infinity, then return the other value.
• Else if both 𝑧1 and 𝑧2 are zeroes of opposite signs, then return negative zero.
• Else return the smaller value of 𝑧1 and 𝑧2 .
26 [Link]

102 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

fmin𝑁 (±nan(𝑛), 𝑧2 ) = nans𝑁 {±nan(𝑛), 𝑧2 }


fmin𝑁 (𝑧1 , ±nan(𝑛)) = nans𝑁 {±nan(𝑛), 𝑧1 }
fmin𝑁 (+∞, 𝑧2 ) = 𝑧2
fmin𝑁 (−∞, 𝑧2 ) = −∞
fmin𝑁 (𝑧1 , +∞) = 𝑧1
fmin𝑁 (𝑧1 , −∞) = −∞
fmin𝑁 (±0, ∓0) = −0
fmin𝑁 (𝑧1 , 𝑧2 ) = 𝑧1 (if 𝑧1 ≤ 𝑧2 )
fmin𝑁 (𝑧1 , 𝑧2 ) = 𝑧2 (if 𝑧2 ≤ 𝑧1 )

fmax𝑁 (𝑧1 , 𝑧2 )
• If either 𝑧1 or 𝑧2 is a NaN, then return an element of nans𝑁 {𝑧1 , 𝑧2 }.
• Else if either 𝑧1 or 𝑧2 is a positive infinity, then return positive infinity.
• Else if either 𝑧1 or 𝑧2 is a negative infinity, then return the other value.
• Else if both 𝑧1 and 𝑧2 are zeroes of opposite signs, then return positive zero.
• Else return the larger value of 𝑧1 and 𝑧2 .
fmax𝑁 (±nan(𝑛), 𝑧2 ) = nans𝑁 {±nan(𝑛), 𝑧2 }
fmax𝑁 (𝑧1 , ±nan(𝑛)) = nans𝑁 {±nan(𝑛), 𝑧1 }
fmax𝑁 (+∞, 𝑧2 ) = +∞
fmax𝑁 (−∞, 𝑧2 ) = 𝑧2
fmax𝑁 (𝑧1 , +∞) = +∞
fmax𝑁 (𝑧1 , −∞) = 𝑧1
fmax𝑁 (±0, ∓0) = +0
fmax𝑁 (𝑧1 , 𝑧2 ) = 𝑧1 (if 𝑧1 ≥ 𝑧2 )
fmax𝑁 (𝑧1 , 𝑧2 ) = 𝑧2 (if 𝑧2 ≥ 𝑧1 )

fcopysign𝑁 (𝑧1 , 𝑧2 )
• If 𝑧1 and 𝑧2 have the same sign, then return 𝑧1 .
• Else return 𝑧1 with negated sign.
fcopysign𝑁 (±𝑝1 , ±𝑝2 ) = ±𝑝1
fcopysign𝑁 (±𝑝1 , ∓𝑝2 ) = ∓𝑝1

fabs𝑁 (𝑧)
• If 𝑧 is a NaN, then return 𝑧 with positive sign.
• Else if 𝑧 is an infinity, then return positive infinity.
• Else if 𝑧 is a zero, then return positive zero.
• Else if 𝑧 is a positive value, then 𝑧.
• Else return 𝑧 negated.
fabs𝑁 (±nan(𝑛)) = +nan(𝑛)
fabs𝑁 (±∞) = +∞
fabs𝑁 (±0) = +0
fabs𝑁 (±𝑞) = +𝑞

fneg𝑁 (𝑧)
• If 𝑧 is a NaN, then return 𝑧 with negated sign.
• Else if 𝑧 is an infinity, then return that infinity negated.
• Else if 𝑧 is a zero, then return that zero negated.
• Else return 𝑧 negated.

4.3. Numerics 103


WebAssembly Specification, Release 3.0 (2025-11-14)

fneg𝑁 (±nan(𝑛)) = ∓nan(𝑛)


fneg𝑁 (±∞) = ∓∞
fneg𝑁 (±0) = ∓0
fneg𝑁 (±𝑞) = ∓𝑞

fsqrt𝑁 (𝑧)
• If 𝑧 is a NaN, then return an element of nans𝑁 {𝑧}.
• Else if 𝑧 is negative infinity, then return an element of nans𝑁 {}.
• Else if 𝑧 is positive infinity, then return positive infinity.
• Else if 𝑧 is a zero, then return that zero.
• Else if 𝑧 has a negative sign, then return an element of nans𝑁 {}.
• Else return the square root of 𝑧.
fsqrt𝑁 (±nan(𝑛)) = nans𝑁 {±nan(𝑛)}
fsqrt𝑁 (−∞) = nans𝑁 {}
fsqrt𝑁 (+∞) = +∞
fsqrt𝑁 (±0) = ±0
fsqrt𝑁 (−𝑞) = nans𝑁 {}
(︀√ )︀
fsqrt𝑁 (+𝑞) = float𝑁 𝑞

fceil𝑁 (𝑧)
• If 𝑧 is a NaN, then return an element of nans𝑁 {𝑧}.
• Else if 𝑧 is an infinity, then return 𝑧.
• Else if 𝑧 is a zero, then return 𝑧.
• Else if 𝑧 is smaller than 0 but greater than −1, then return negative zero.
• Else return the smallest integral value that is not smaller than 𝑧.
fceil𝑁 (±nan(𝑛)) = nans𝑁 {±nan(𝑛)}
fceil𝑁 (±∞) = ±∞
fceil𝑁 (±0) = ±0
fceil𝑁 (−𝑞) = −0 (if −1 < −𝑞 < 0)
fceil𝑁 (±𝑞) = float𝑁 (𝑖) (if ±𝑞 ≤ 𝑖 < ±𝑞 + 1)

ffloor𝑁 (𝑧)
• If 𝑧 is a NaN, then return an element of nans𝑁 {𝑧}.
• Else if 𝑧 is an infinity, then return 𝑧.
• Else if 𝑧 is a zero, then return 𝑧.
• Else if 𝑧 is greater than 0 but smaller than 1, then return positive zero.
• Else return the largest integral value that is not larger than 𝑧.
ffloor𝑁 (±nan(𝑛)) = nans𝑁 {±nan(𝑛)}
ffloor𝑁 (±∞) = ±∞
ffloor𝑁 (±0) = ±0
ffloor𝑁 (+𝑞) = +0 (if 0 < +𝑞 < 1)
ffloor𝑁 (±𝑞) = float𝑁 (𝑖) (if ±𝑞 − 1 < 𝑖 ≤ ±𝑞)

104 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

ftrunc𝑁 (𝑧)
• If 𝑧 is a NaN, then return an element of nans𝑁 {𝑧}.
• Else if 𝑧 is an infinity, then return 𝑧.
• Else if 𝑧 is a zero, then return 𝑧.
• Else if 𝑧 is greater than 0 but smaller than 1, then return positive zero.
• Else if 𝑧 is smaller than 0 but greater than −1, then return negative zero.
• Else return the integral value with the same sign as 𝑧 and the largest magnitude that is not larger than the
magnitude of 𝑧.
ftrunc𝑁 (±nan(𝑛)) = nans𝑁 {±nan(𝑛)}
ftrunc𝑁 (±∞) = ±∞
ftrunc𝑁 (±0) = ±0
ftrunc𝑁 (+𝑞) = +0 (if 0 < +𝑞 < 1)
ftrunc𝑁 (−𝑞) = −0 (if −1 < −𝑞 < 0)
ftrunc𝑁 (±𝑞) = float𝑁 (±𝑖) (if +𝑞 − 1 < 𝑖 ≤ +𝑞)

fnearest𝑁 (𝑧)
• If 𝑧 is a NaN, then return an element of nans𝑁 {𝑧}.
• Else if 𝑧 is an infinity, then return 𝑧.
• Else if 𝑧 is a zero, then return 𝑧.
• Else if 𝑧 is greater than 0 but smaller than or equal to 0.5, then return positive zero.
• Else if 𝑧 is smaller than 0 but greater than or equal to −0.5, then return negative zero.
• Else return the integral value that is nearest to 𝑧; if two values are equally near, return the even one.
fnearest𝑁 (±nan(𝑛)) = nans𝑁 {±nan(𝑛)}
fnearest𝑁 (±∞) = ±∞
fnearest𝑁 (±0) = ±0
fnearest𝑁 (+𝑞) = +0 (if 0 < +𝑞 ≤ 0.5)
fnearest𝑁 (−𝑞) = −0 (if −0.5 ≤ −𝑞 < 0)
fnearest𝑁 (±𝑞) = float𝑁 (±𝑖) (if |𝑖 − 𝑞| < 0.5)
fnearest𝑁 (±𝑞) = float𝑁 (±𝑖) (if |𝑖 − 𝑞| = 0.5 ∧ 𝑖 even)

feq𝑁 (𝑧1 , 𝑧2 )
• If either 𝑧1 or 𝑧2 is a NaN, then return 0.
• Else if both 𝑧1 and 𝑧2 are zeroes, then return 1.
• Else if both 𝑧1 and 𝑧2 are the same value, then return 1.
• Else return 0.
feq𝑁 (±nan(𝑛), 𝑧2 ) = 0
feq𝑁 (𝑧1 , ±nan(𝑛)) = 0
feq𝑁 (±0, ∓0) = 1
feq𝑁 (𝑧1 , 𝑧2 ) = bool(𝑧1 = 𝑧2 )

fne𝑁 (𝑧1 , 𝑧2 )
• If either 𝑧1 or 𝑧2 is a NaN, then return 1.
• Else if both 𝑧1 and 𝑧2 are zeroes, then return 0.
• Else if both 𝑧1 and 𝑧2 are the same value, then return 0.
• Else return 1.

4.3. Numerics 105


WebAssembly Specification, Release 3.0 (2025-11-14)

fne𝑁 (±nan(𝑛), 𝑧2 ) = 1
fne𝑁 (𝑧1 , ±nan(𝑛)) = 1
fne𝑁 (±0, ∓0) = 0
fne𝑁 (𝑧1 , 𝑧2 ) = bool(𝑧1 ̸= 𝑧2 )

flt𝑁 (𝑧1 , 𝑧2 )
• If either 𝑧1 or 𝑧2 is a NaN, then return 0.
• Else if 𝑧1 and 𝑧2 are the same value, then return 0.
• Else if 𝑧1 is positive infinity, then return 0.
• Else if 𝑧1 is negative infinity, then return 1.
• Else if 𝑧2 is positive infinity, then return 1.
• Else if 𝑧2 is negative infinity, then return 0.
• Else if both 𝑧1 and 𝑧2 are zeroes, then return 0.
• Else if 𝑧1 is smaller than 𝑧2 , then return 1.
• Else return 0.
flt𝑁 (±nan(𝑛), 𝑧2 ) = 0
flt𝑁 (𝑧1 , ±nan(𝑛)) = 0
flt𝑁 (𝑧, 𝑧) = 0
flt𝑁 (+∞, 𝑧2 ) = 0
flt𝑁 (−∞, 𝑧2 ) = 1
flt𝑁 (𝑧1 , +∞) = 1
flt𝑁 (𝑧1 , −∞) = 0
flt𝑁 (±0, ∓0) = 0
flt𝑁 (𝑧1 , 𝑧2 ) = bool(𝑧1 < 𝑧2 )

fgt𝑁 (𝑧1 , 𝑧2 )
• If either 𝑧1 or 𝑧2 is a NaN, then return 0.
• Else if 𝑧1 and 𝑧2 are the same value, then return 0.
• Else if 𝑧1 is positive infinity, then return 1.
• Else if 𝑧1 is negative infinity, then return 0.
• Else if 𝑧2 is positive infinity, then return 0.
• Else if 𝑧2 is negative infinity, then return 1.
• Else if both 𝑧1 and 𝑧2 are zeroes, then return 0.
• Else if 𝑧1 is larger than 𝑧2 , then return 1.
• Else return 0.
fgt𝑁 (±nan(𝑛), 𝑧2 ) = 0
fgt𝑁 (𝑧1 , ±nan(𝑛)) = 0
fgt𝑁 (𝑧, 𝑧) = 0
fgt𝑁 (+∞, 𝑧2 ) = 1
fgt𝑁 (−∞, 𝑧2 ) = 0
fgt𝑁 (𝑧1 , +∞) = 0
fgt𝑁 (𝑧1 , −∞) = 1
fgt𝑁 (±0, ∓0) = 0
fgt𝑁 (𝑧1 , 𝑧2 ) = bool(𝑧1 > 𝑧2 )

106 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

fle𝑁 (𝑧1 , 𝑧2 )
• If either 𝑧1 or 𝑧2 is a NaN, then return 0.
• Else if 𝑧1 and 𝑧2 are the same value, then return 1.
• Else if 𝑧1 is positive infinity, then return 0.
• Else if 𝑧1 is negative infinity, then return 1.
• Else if 𝑧2 is positive infinity, then return 1.
• Else if 𝑧2 is negative infinity, then return 0.
• Else if both 𝑧1 and 𝑧2 are zeroes, then return 1.
• Else if 𝑧1 is smaller than or equal to 𝑧2 , then return 1.
• Else return 0.
fle𝑁 (±nan(𝑛), 𝑧2 ) = 0
fle𝑁 (𝑧1 , ±nan(𝑛)) = 0
fle𝑁 (𝑧, 𝑧) = 1
fle𝑁 (+∞, 𝑧2 ) = 0
fle𝑁 (−∞, 𝑧2 ) = 1
fle𝑁 (𝑧1 , +∞) = 1
fle𝑁 (𝑧1 , −∞) = 0
fle𝑁 (±0, ∓0) = 1
fle𝑁 (𝑧1 , 𝑧2 ) = bool(𝑧1 ≤ 𝑧2 )

fge𝑁 (𝑧1 , 𝑧2 )
• If either 𝑧1 or 𝑧2 is a NaN, then return 0.
• Else if 𝑧1 and 𝑧2 are the same value, then return 1.
• Else if 𝑧1 is positive infinity, then return 1.
• Else if 𝑧1 is negative infinity, then return 0.
• Else if 𝑧2 is positive infinity, then return 0.
• Else if 𝑧2 is negative infinity, then return 1.
• Else if both 𝑧1 and 𝑧2 are zeroes, then return 1.
• Else if 𝑧1 is larger than or equal to 𝑧2 , then return 1.
• Else return 0.
fge𝑁 (±nan(𝑛), 𝑧2 ) = 0
fge𝑁 (𝑧1 , ±nan(𝑛)) = 0
fge𝑁 (𝑧, 𝑧) = 1
fge𝑁 (+∞, 𝑧2 ) = 1
fge𝑁 (−∞, 𝑧2 ) = 0
fge𝑁 (𝑧1 , +∞) = 0
fge𝑁 (𝑧1 , −∞) = 1
fge𝑁 (±0, ∓0) = 1
fge𝑁 (𝑧1 , 𝑧2 ) = bool(𝑧1 ≥ 𝑧2 )

fpmin𝑁 (𝑧1 , 𝑧2 )
• If 𝑧2 is less than 𝑧1 then return 𝑧2 .
• Else return 𝑧1 .
fpmin𝑁 (𝑧1 , 𝑧2 ) = 𝑧2 (if flt𝑁 (𝑧2 , 𝑧1 ) = 1)
fpmin𝑁 (𝑧1 , 𝑧2 ) = 𝑧1 (otherwise)

4.3. Numerics 107


WebAssembly Specification, Release 3.0 (2025-11-14)

fpmax𝑁 (𝑧1 , 𝑧2 )
• If 𝑧1 is less than 𝑧2 then return 𝑧2 .
• Else return 𝑧1 .
fpmax𝑁 (𝑧1 , 𝑧2 ) = 𝑧2 (if flt𝑁 (𝑧1 , 𝑧2 ) = 1)
fpmax𝑁 (𝑧1 , 𝑧2 ) = 𝑧1 (otherwise)

4.3.4 Conversions
extendu 𝑀,𝑁 (𝑖)
• Return 𝑖.
extendu 𝑀,𝑁 (𝑖) = 𝑖

Note

In the abstract syntax, unsigned extension just reinterprets the same value.

extends 𝑀,𝑁 (𝑖)


• Let 𝑗 be the signed interpretation of 𝑖 of size 𝑀 .
• Return the two’s complement of 𝑗 relative to size 𝑁 .
extends 𝑀,𝑁 (𝑖) = signed−1
𝑁 (signed𝑀 (𝑖))

wrap𝑀,𝑁 (𝑖)
• Return 𝑖 modulo 2𝑁 .
wrap𝑀,𝑁 (𝑖) = 𝑖 mod 2𝑁

truncu 𝑀,𝑁 (𝑧)


• If 𝑧 is a NaN, then the result is undefined.
• Else if 𝑧 is an infinity, then the result is undefined.
• Else if 𝑧 is a number and trunc(𝑧) is a value within range of the target type, then return that value.
• Else the result is undefined.
truncu 𝑀,𝑁 (±nan(𝑛)) = {}
truncu 𝑀,𝑁 (±∞) = {}
truncu 𝑀,𝑁 (±𝑞) = trunc(±𝑞) (if −1 < trunc(±𝑞) < 2𝑁 )
truncu 𝑀,𝑁 (±𝑞) = {} (otherwise)

Note

This operator is partial. It is not defined for NaNs, infinities, or values for which the result is out of range.

truncs 𝑀,𝑁 (𝑧)


• If 𝑧 is a NaN, then the result is undefined.
• Else if 𝑧 is an infinity, then the result is undefined.
• If 𝑧 is a number and trunc(𝑧) is a value within range of the target type, then return that value.
• Else the result is undefined.

108 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

truncs 𝑀,𝑁 (±nan(𝑛)) = {}


truncs 𝑀,𝑁 (±∞) = {}
truncs 𝑀,𝑁 (±𝑞) = trunc(±𝑞) (if −2𝑁 −1 − 1 < trunc(±𝑞) < 2𝑁 −1 )
truncs 𝑀,𝑁 (±𝑞) = {} (otherwise)

Note

This operator is partial. It is not defined for NaNs, infinities, or values for which the result is out of range.

trunc_sat_u𝑀,𝑁 (𝑧)
• If 𝑧 is a NaN, then return 0.
• Else if 𝑧 is negative infinity, then return 0.
• Else if 𝑧 is positive infinity, then return 2𝑁 − 1.
• Else, return sat_u𝑁 (trunc(𝑧)).
trunc_sat_u𝑀,𝑁 (±nan(𝑛)) = 0
trunc_sat_u𝑀,𝑁 (−∞) = 0
trunc_sat_u𝑀,𝑁 (+∞) = 2𝑁 − 1
trunc_sat_u𝑀,𝑁 (𝑧) = sat_u𝑁 (trunc(𝑧))

trunc_sat_s𝑀,𝑁 (𝑧)
• If 𝑧 is a NaN, then return 0.
• Else if 𝑧 is negative infinity, then return −2𝑁 −1 .
• Else if 𝑧 is positive infinity, then return 2𝑁 −1 − 1.
• Else, return the value whose signed interpretation is sat_s𝑁 (trunc(𝑧)).
trunc_sat_s𝑀,𝑁 (±nan(𝑛)) = 0
trunc_sat_s𝑀,𝑁 (−∞) = −2𝑁 −1
trunc_sat_s𝑀,𝑁 (+∞) = 2𝑁 −1 − 1
trunc_sat_s𝑀,𝑁 (𝑧) = signed−1
𝑁 (sat_s𝑁 (trunc(𝑧)))

promote𝑀,𝑁 (𝑧)
• If 𝑧 is a canonical NaN, then return an element of nans𝑁 {} (i.e., a canonical NaN of size 𝑁 ).
• Else if 𝑧 is a NaN, then return an element of nans𝑁 {±nan(1)} (i.e., any arithmetic NaN of size 𝑁 ).
• Else, return 𝑧.
promote𝑀,𝑁 (±nan(𝑛)) = nans𝑁 {} (if 𝑛 = canon𝑁 )
promote𝑀,𝑁 (±nan(𝑛)) = nans𝑁 {+nan(1)} (otherwise)
promote𝑀,𝑁 (𝑧) = 𝑧

demote𝑀,𝑁 (𝑧)
• If 𝑧 is a canonical NaN, then return an element of nans𝑁 {} (i.e., a canonical NaN of size 𝑁 ).
• Else if 𝑧 is a NaN, then return an element of nans𝑁 {±nan(1)} (i.e., any NaN of size 𝑁 ).
• Else if 𝑧 is an infinity, then return that infinity.
• Else if 𝑧 is a zero, then return that zero.
• Else, return float𝑁 (𝑧).

4.3. Numerics 109


WebAssembly Specification, Release 3.0 (2025-11-14)

demote𝑀,𝑁 (±nan(𝑛)) = nans𝑁 {} (if 𝑛 = canon𝑁 )


demote𝑀,𝑁 (±nan(𝑛)) = nans𝑁 {+nan(1)} (otherwise)
demote𝑀,𝑁 (±∞) = ±∞
demote𝑀,𝑁 (±0) = ±0
demote𝑀,𝑁 (±𝑞) = float𝑁 (±𝑞)

convertu 𝑀,𝑁 (𝑖)


• Return float𝑁 (𝑖).
convertu 𝑀,𝑁 (𝑖) = float𝑁 (𝑖)

converts 𝑀,𝑁 (𝑖)


• Let 𝑗 be the signed interpretation of 𝑖.
• Return float𝑁 (𝑗).
converts 𝑀,𝑁 (𝑖) = float𝑁 (signed𝑀 (𝑖))

reinterpret𝑡1 ,𝑡2 (𝑐)


• Let 𝑑* be the bit sequence bits𝑡1 (𝑐).
• Return the constant 𝑐′ for which bits𝑡2 (𝑐′ ) = 𝑑* .
reinterpret𝑡1 ,𝑡2 (𝑐) = bits−1
𝑡2 (bits𝑡1 (𝑐))

narrows 𝑀,𝑁 (𝑖)


• Let 𝑗 be the signed interpretation of 𝑖 of size 𝑀 .
• Return the value whose signed interpretation is sat_s𝑁 (𝑗).
narrows 𝑀,𝑁 (𝑖) = signed−1
𝑁 (sat_s𝑁 (signed𝑀 (𝑖)))

narrowu 𝑀,𝑁 (𝑖)


• Let 𝑗 be the signed interpretation of 𝑖 of size 𝑀 .
• Return sat_u𝑁 (𝑗).
narrowu 𝑀,𝑁 (𝑖) = sat_u𝑁 (signed𝑀 (𝑖))

4.3.5 Vector Operations


Most vector operations are performed by applying numeric operations lanewise. However, some operators consider
multiple lanes at once.

ivbitmask𝑁 (𝑖𝑚 )
1. For each 𝑖𝑘 in 𝑖𝑚 , let 𝑏𝑘 be the result of computing ilt_s𝑁 (𝑖, 0).
2. Let 𝑏𝑚 be the concatenation of all 𝑏𝑘 .
3. Return the result of computing ibits−1
32 ((0)
32−𝑚 𝑚
𝑏 ).
ivbitmask𝑁 (𝑖𝑚 ) = ibits−1
32 ((0)
32−𝑚
ilt_s𝑁 (𝑖, 0)𝑚 )

110 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

ivswizzle(𝑖𝑛 , 𝑗 𝑛 )
1. For each 𝑗𝑘 in 𝑗 𝑛 , let 𝑟𝑘 be the value ivswizzle_lane(𝑖𝑛 , 𝑗𝑘 ).
2. Let 𝑟𝑛 be the concatenation of all 𝑟𝑘 .
3. Return 𝑟𝑛 .
ivswizzle(𝑖𝑛 , 𝑗 𝑛 ) = ivswizzle_lane(𝑖𝑛 , 𝑗)𝑛
where:
ivswizzle_lane(𝑖𝑛 , 𝑗) = 𝑖𝑛 [𝑗] (if 𝑗 < 𝑛)
ivswizzle_lane(𝑖𝑛 , 𝑗) = 0 (otherwise)

ivshuffle(𝑗 𝑛 , 𝑖𝑛1 , 𝑖𝑛2 )


1. Let 𝑖* ne the concatenation of 𝑖𝑛1 and 𝑖𝑛2 .
2. For each 𝑗𝑘 in 𝑗 𝑛 , let 𝑟𝑘 be 𝑖* [𝑗𝑘 ].
3. Let 𝑟𝑛 be the concatenation of all 𝑟𝑘 .
4. Return 𝑟𝑛 .
ivshuffle(𝑗 𝑛 , 𝑖𝑛1 , 𝑖𝑛2 ) = ((𝑖𝑛1 𝑖𝑛2 )[𝑗])𝑛 (if (𝑗 < 2 · 𝑛)𝑛 )

ivadd_pairwise𝑁 (𝑖2𝑚 )
1. Let (𝑖1 𝑖2 )𝑚 be 𝑖2𝑚 , decomposed into pairwise elements.
2. For each 𝑖1𝑘 in 𝑖𝑚
1 and corresponding 𝑖2𝑘 in 𝑖2 , let 𝑟𝑘 be iadd𝑁 (𝑖1𝑘 , 𝑖2𝑘 ).
𝑚

3. Let 𝑟𝑚 be the concatenation of all 𝑟𝑘 .


4. Return 𝑟𝑚 .
ivadd_pairwise𝑁 (𝑖2𝑚 ) = (iadd𝑁 (𝑖1 , 𝑖2 ))𝑚 (if 𝑖2𝑚 = (𝑖1 𝑖2 )𝑚 )

ivmul𝑁 (𝑖𝑚 𝑚
1 , 𝑖2 )

1. For each 𝑖1𝑘 in 𝑖𝑚


1 and corresponding 𝑖2𝑘 in 𝑖2 , let 𝑟𝑘 be imul𝑁 (𝑖1𝑘 , 𝑖2𝑘 ).
𝑚

2. Let 𝑟𝑚 be the concatenation of all 𝑟𝑘 .


3. Return 𝑟𝑚 .
ivmul𝑁 (𝑖𝑚 𝑚
1 , 𝑖2 ) = (imul𝑁 (𝑖1 , 𝑖2 ))𝑚

ivdot𝑁 (𝑖2𝑚 2𝑚
1 , 𝑖2 )

1. For each 𝑖1𝑘 in 𝑖2𝑚


1 and corresponding 𝑖2𝑘 in 𝑖2 , let 𝑗𝑘 be imul𝑁 (𝑖1𝑘 , 𝑖2𝑘 ).
2𝑚

2. Let 𝑗 2𝑚 be the concatenation of all 𝑗𝑘 .


3. Let (𝑗1 𝑗2 )𝑚 be 𝑗 2𝑚 , decomposed into pairwise elements.
4. For each 𝑖1𝑘 in 𝑖𝑚
1 and corresponding 𝑖2𝑘 in 𝑖2 , let 𝑟𝑘 be iadd𝑁 (𝑖1𝑘 , 𝑖2𝑘 ).
𝑚

5. Let 𝑟𝑚 be the concatenation of all 𝑟𝑘 .


6. Return 𝑟𝑚 .
ivdot𝑁 (𝑖2𝑚 2𝑚
1 , 𝑖2 ) = (iadd𝑁 (𝑗1 , 𝑗2 ))𝑚 (if (imul𝑁 (𝑖1 , 𝑖2 ))2𝑚 = (𝑗1 𝑗2 )𝑚 )

4.3. Numerics 111


WebAssembly Specification, Release 3.0 (2025-11-14)

ivdotsat𝑁 (𝑖𝑚 𝑚
1 , 𝑖2 )

1. For each 𝑖1𝑘 in 𝑖2𝑚


1 and corresponding 𝑖2𝑘 in 𝑖2 , let 𝑗𝑘 be imul𝑁 (𝑖1𝑘 , 𝑖2𝑘 ).
2𝑚

2. Let 𝑗 2𝑚 be the concatenation of all 𝑗𝑘 .


3. Let (𝑗1 𝑗2 )𝑚 be 𝑗 2𝑚 , decomposed into pairwise elements.
4. For each 𝑖1𝑘 in 𝑖𝑚
1 and corresponding 𝑖2𝑘 in 𝑖2 , let 𝑟𝑘 be iadd_sat𝑁 (𝑖1𝑘 , 𝑖2𝑘 ).
𝑚

5. Let 𝑟𝑚 be the concatenation of all 𝑟𝑘 .


6. Return 𝑟𝑚 .
ivdotsat𝑁 (𝑖2𝑚 2𝑚
1 , 𝑖2 ) = (iadd_sat𝑁 (𝑗1 , 𝑗2 ))𝑚 (if (imul𝑁 (𝑖1 , 𝑖2 ))2𝑚 = (𝑗1 𝑗2 )𝑚 )
The previous operators are lifted to operators on arguments of vector type by wrapping them in corresponding lane
projections and injections and intermediate extension operations:

vextunop sh 1 ,sh 2 (𝑐)


extadd_pairwise_sx i𝑁1 x𝑀1 ,i𝑁2 x𝑀2 (𝑐) = lanes−1 *
i𝑁2 x𝑀2 (𝑗 ) (if 𝑖* = lanesi𝑁1 x𝑀1 (𝑐)
*
∧ 𝑖′ = extendsx 𝑁1 ,𝑁2 (𝑖)
*
*
*
∧ 𝑗 = ivadd_pairwise𝑁2 (𝑖′ )

vextbinop sh 1 ,sh 2 (𝑐1 , 𝑐2 )


vextbinop i𝑁1 x𝑀1 ,i𝑁2 x𝑀2 (𝑐1 , 𝑐2 ) = lanes−1 *
i𝑁2 x𝑀2 (𝑗 ) (if 𝑖*1 = lanesi𝑁1 x𝑀1 (𝑐1 )[ℎ : 𝑘]
∧ 𝑖*2 = lanesi𝑁1 x𝑀1 (𝑐2 )[ℎ : 𝑘]
*
∧ 𝑖′1 = extendsx 𝑁1 ,𝑁2 (𝑖1 )
*
′*
∧ 𝑖2 = extend𝑁1 ,𝑁2 (𝑖2 )*
sx
* *
∧ 𝑗 * = 𝑓𝑁2 (𝑖′1 , 𝑖′1 )
where 𝑓 , sx 1 , sx 2 , ℎ, and 𝑘 are instantiated as follows, depending on the operator:

vextbinop 𝑓 sx 1 sx 2 ℎ 𝑘
extmul_low_sx ivmul sx sx 0 𝑀2
extmul_high_sx ivmul sx sx 𝑀2 𝑀2
dot_s ivdot s s 0 𝑀1
relaxed_dot_s ivdotsat s relaxed(𝑅idot )[s, u] 0 𝑀1

Note

Relaxed operations and the paramater 𝑅idot are introduced below.

vextternop sh 1 ,sh 2 (𝑐1 , 𝑐2 , 𝑐3 )


relaxed_dot_add_si𝑁1 x𝑀1 ,i𝑁2 x𝑀2 (𝑐1 , 𝑐2 , 𝑐3 ) = 𝑐 (if 𝑁 = 2 · 𝑁1
∧ 𝑀 = 2 · 𝑀2
∧ 𝑐′ = relaxed_dot_si𝑁1 x𝑀1 ,i𝑁 x𝑀 (𝑐1 , 𝑐2 )
∧ 𝑐′′ = extadd_pairwise_si𝑁 x𝑀,i𝑁2 x𝑀2 (𝑐′ )
∧ 𝑐 ∈ addi𝑁2 x𝑀2 (𝑐′′ , 𝑐3 )

narrow_sx sh 1 ,sh 2 (𝑐1 , 𝑐2 )


narrow_sx i𝑁1 x𝑀1 ,i𝑁2 x𝑀2 (𝑐1 , 𝑐2 ) = lanes−1 *
i𝑁2 x𝑀2 (𝑗 ) (if 𝑖*1 = lanesi𝑁1 x𝑀1 (𝑐1 )
∧ 𝑖*2 = lanesi𝑁1 x𝑀1 (𝑐2 )
*
∧ 𝑖′1 = narrowsx 𝑁1 ,𝑁2 (𝑖1 )
*
′*
∧ 𝑖2 = narrow𝑁1 ,𝑁2 (𝑖2 )*
sx
* *
∧ 𝑗 * = 𝑖′1 ⊕ 𝑖′1

112 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

vcvtop_half ? _zero ?sh 1 ,sh 2 (𝑖)

vcvtop_half ? _zero ?𝑡1 x𝑀1 ,𝑡2 x𝑀2 (𝑖) = 𝑗 (if condition


∧ 𝑐* = lanes𝑡1 x𝑀1 (𝑖)[ℎ : 𝑘]
**
∧ 𝑐′ = ×(vcvtop |𝑡1 |,|𝑡2 | (𝑐)* ⊕ (0)𝑛 )
′* *
∧ 𝑗 ∈ lanes−1
𝑡2 x𝑀2 (𝑐 )

where ℎ, 𝑘, 𝑛, and condition are instantiated as follows, depending on the operator:

half ? zero ? ℎ 𝑘 𝑛 condition


𝜖 𝜖 0 𝑀1 0 (𝑀1 = 𝑀2 )
low 𝜖 0 𝑀2 0 (𝑀1 = 2 · 𝑀2 )
high 𝜖 𝑀2 𝑀2 0 (𝑀1 = 2 · 𝑀2 )
𝜖 zero 0 𝑀1 𝑀1 (2 · 𝑀1 = 𝑀2 )

while ×{𝑥* }𝑁 transforms a sequence of 𝑁 sets of non-deterministic values into a set of non-deterministic se-
quences of 𝑁 values by computing the set product:

×(𝑆1 . . . 𝑆𝑁 ) = {𝑥1 . . . 𝑥𝑁 | 𝑥1 ∈ 𝑆1 ∧ · · · ∧ 𝑥𝑁 ∈ 𝑆𝑁 }

4.3.6 Relaxed Operations


The result of relaxed operators are implementation-dependent, because the set of possible results may depend on
properties of the host environment, such as its hardware. Technically, their behaviour is controlled by a set of global
parameters to the semantics that an implementation can instantiate in different ways. These choices are fixed, that
is, parameters are constant during the execution of any given program.
Every such parameter is an index into a sequence of possible sets of results and must be instantiated to a defined
index. In the deterministic profile, every parameter is prescribed to be 0. This behaviour is expressed by the
following auxiliary function, where 𝑅 is a global parameter selecting one of the allowed outcomes:
[!DET]
relaxed(𝑅)[𝐴0 , . . . , 𝐴𝑛 ] = 𝐴𝑅
relaxed(𝑅)[𝐴0 , . . . , 𝐴𝑛 ] = 𝐴0

Note

Each parameter can be thought of as inducing a family of operations that is fixed to one particular choice by an
implementation. The fixed operation itself can still be non-deterministic or partial.
Implementations are expexted to either choose the behaviour that is the most efficient on the underlying hard-
ware, or the behaviour of the deterministic profile.

frelaxed_madd𝑁 (𝑧1 , 𝑧2 , 𝑧3 )
The implementation-specific behaviour of this operation is determined by the global parameter 𝑅fmadd ∈ {0, 1}.
• Return relaxed(𝑅fmadd )[fadd𝑁 (fmul𝑁 (𝑧1 , 𝑧2 ), 𝑧3 ), fma𝑁 (𝑧1 , 𝑧2 , 𝑧3 )].
frelaxed_madd𝑁 (𝑧1 , 𝑧2 , 𝑧3 ) = relaxed(𝑅fmadd )[fadd𝑁 (fmul𝑁 (𝑧1 , 𝑧2 ), 𝑧3 ), fma𝑁 (𝑧1 , 𝑧2 , 𝑧3 )]

Note

Relaxed multiply-add allows for fused or unfused results, which leads to implementation-dependent rounding
behaviour. In the deterministic profile, the unfused behaviour is used.

4.3. Numerics 113


WebAssembly Specification, Release 3.0 (2025-11-14)

frelaxed_nmadd𝑁 (𝑧1 , 𝑧2 , 𝑧3 )
• Return frelaxed_madd(−𝑧1 , 𝑧2 , 𝑧3 ).
frelaxed_nmadd𝑁 (𝑧1 , 𝑧2 , 𝑧3 ) = frelaxed_madd𝑁 (−𝑧1 , 𝑧2 , 𝑧3 )

Note

This operation is implementation-dependent because frelaxed_madd is implementation-dependent.

frelaxed_min𝑁 (𝑧1 , 𝑧2 )
The implementation-specific behaviour of this operation is determined by the global parameter 𝑅fmin ∈
{0, 1, 2, 3}.
• If 𝑧1 is a NaN, then return relaxed(𝑅fmin )[fmin𝑁 (𝑧1 , 𝑧2 ), nan(𝑛), 𝑧2 , 𝑧2 ].
• If 𝑧2 is a NaN, then return relaxed(𝑅fmin )[fmin𝑁 (𝑧1 , 𝑧2 ), 𝑧1 , nan(𝑛), 𝑧1 ].
• If both 𝑧1 and 𝑧2 are zeroes of opposite sign, then return relaxed(𝑅fmin )[fmin𝑁 (𝑧1 , 𝑧2 ), pm 0, mp 0, -0 ]`.
• Return fmin𝑁 (𝑧1 , 𝑧2 ).
frelaxed_min𝑁 (±nan(𝑛), 𝑧2 ) = relaxed(𝑅fmin )[fmin𝑁 (±nan(𝑛), 𝑧2 ), nan(𝑛), 𝑧2 , 𝑧2 ]
frelaxed_min𝑁 (𝑧1 , ±nan(𝑛)) = relaxed(𝑅fmin )[fmin𝑁 (𝑧1 , ±nan(𝑛)), 𝑧1 , nan(𝑛), 𝑧1 ]
frelaxed_min𝑁 (±0, ∓0) = relaxed(𝑅fmin )[fmin𝑁 (±0, ∓0), ±0, ∓0, −0]
frelaxed_min𝑁 (𝑧1 , 𝑧2 ) = fmin𝑁 (𝑧1 , 𝑧2 ) (otherwise)

Note

Relaxed minimum is implementation-dependent for NaNs and for zeroes with different signs. In the determin-
istic profile, it behaves like regular fmin.

frelaxed_max𝑁 (𝑧1 , 𝑧2 )
The implementation-specific behaviour of this operation is determined by the global parameter 𝑅fmax ∈
{0, 1, 2, 3}.
• If 𝑧1 is a NaN, then return relaxed(𝑅fmax )[fmax𝑁 (𝑧1 , 𝑧2 ), nan(𝑛), 𝑧2 , 𝑧2 ].
• If 𝑧2 is a NaN, then return relaxed(𝑅fmax )[fmax𝑁 (𝑧1 , 𝑧2 ), 𝑧1 , nan(𝑛), 𝑧1 ].
• If both 𝑧1 and 𝑧2 are zeroes of opposite sign, then return relaxed(𝑅fmax )[fmax𝑁 (𝑧1 , 𝑧2 ), pm 0, mp 0, +0 ]`.
• Return fmax𝑁 (𝑧1 , 𝑧2 ).
frelaxed_max𝑁 (±nan(𝑛), 𝑧2 ) = relaxed(𝑅fmax )[fmax𝑁 (±nan(𝑛), 𝑧2 ), nan(𝑛), 𝑧2 , 𝑧2 ]
frelaxed_max𝑁 (𝑧1 , ±nan(𝑛)) = relaxed(𝑅fmax )[fmax𝑁 (𝑧1 , ±nan(𝑛)), 𝑧1 , nan(𝑛), 𝑧1 ]
frelaxed_max𝑁 (±0, ∓0) = relaxed(𝑅fmax )[fmax𝑁 (±0, ∓0), ±0, ∓0, +0]
frelaxed_max𝑁 (𝑧1 , 𝑧2 ) = fmax𝑁 (𝑧1 , 𝑧2 ) (otherwise)

Note

Relaxed maximum is implementation-dependent for NaNs and for zeroes with different signs. In the determin-
istic profile, it behaves like regular fmax.

114 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

irelaxed_q15mulr_s𝑁 (𝑖1 , 𝑖2 )
The implementation-specific behaviour of this operation is determined by the global parameter 𝑅iq15mulr ∈ {0, 1}.
• If both 𝑖1 and 𝑖2 equal (signed−1
𝑁 (−2
𝑁 −1
), then return relaxed(𝑅iq15mulr )[2𝑁 −1 − 1, signed−1
𝑁 (−2
𝑁 −1
)].
• Return iq15mulrsat_s(𝑖1 , 𝑖2 )
irelaxed_q15mulr_s𝑁 (signed−1 𝑁 (−2
𝑁 −1
), signed−1
𝑁 (−2
𝑁 −1
)) = relaxed(𝑅iq15mulr )[2𝑁 −1 − 1, signed−1
𝑁 (−2
𝑁 −1
)]
irelaxed_q15mulr_s𝑁 (𝑖1 , 𝑖2 ) = iq15mulrsat_s(𝑖1 , 𝑖2 )

Note

Relaxed Q15 multiplication is implementation-dependent when the result overflows. In the deterministic pro-
file, it behaves like regular iq15mulrsat_s.

relaxed_trunc𝑢𝑀,𝑁 (𝑧)
The implementation-specific behaviour of this operation is determined by the global parameter 𝑅trunc_u ∈ {0, 1}.
• If 𝑧 is normal or subnormal and trunc(𝑧) is non-negative and less than 2𝑁 , then return truncu 𝑀,𝑁 (𝑧).
• Else, return relaxed(𝑅trunc_u )[trunc_sat_u𝑀,𝑁 (𝑧), R].
relaxed_trunc𝑢𝑀,𝑁 (±𝑞) = truncu 𝑀,𝑁 (±𝑞) (if 0 ≤ trunc(±𝑞) < 2𝑁 )
relaxed_trunc𝑢𝑀,𝑁 (𝑧) = relaxed(𝑅trunc_u )[trunc_sat_u𝑀,𝑁 (𝑧), R] (otherwise)

Note

Relaxed unsigned truncation is non-deterministic for NaNs and out-of-range values. In the deterministic profile,
it behaves like regular trunc_sat_u.

relaxed_trunc𝑠𝑀,𝑁 (𝑧)
The implementation-specific behaviour of this operation is determined by the global parameter 𝑅trunc_s ∈ {0, 1}.
• If 𝑧 is normal or subnormal and trunc(𝑧) is greater than or equal to −2𝑁 −1 and less than 2𝑁 −1 , then return
truncs 𝑀,𝑁 (𝑧).
• Else, return relaxed(𝑅trunc_s )[trunc_sat_s𝑀,𝑁 (𝑧), R].
relaxed_trunc𝑠𝑀,𝑁 (±𝑞) = truncs 𝑀,𝑁 (±𝑞) (if −2𝑁 −1 ≤ trunc(±𝑞) < 2𝑁 −1 )
relaxed_trunc𝑠𝑀,𝑁 (𝑧) = relaxed(𝑅trunc_s )[trunc_sat_s𝑀,𝑁 (𝑧), R] (otherwise)

Note

Relaxed signed truncation is non-deterministic for NaNs and out-of-range values. In the deterministic profile,
it behaves like regular trunc_sat_s.

ivrelaxed_swizzle(𝑖𝑛 , 𝑗 𝑛 )
The implementation-specific behaviour of this operation is determined by the global parameter 𝑅swizzle ∈ {0, 1}.
• For each 𝑗𝑘 in 𝑗 𝑛 , let 𝑟𝑘 be the value ivrelaxed_swizzle_lane(𝑖𝑛 , 𝑗𝑘 ).
• Let 𝑟𝑛 be the concatenation of all 𝑟𝑘 .
• Return 𝑟𝑛 .

4.3. Numerics 115


WebAssembly Specification, Release 3.0 (2025-11-14)

ivrelaxed_swizzle(𝑖𝑛 , 𝑗 𝑛 ) = ivrelaxed_swizzle_lane(𝑖𝑛 , 𝑗)𝑛


where:
ivrelaxed_swizzle_lane(𝑖𝑛 , 𝑗) = 𝑖[𝑗] (if 𝑗 < 16)
ivrelaxed_swizzle_lane(𝑖𝑛 , 𝑗) = 0 (if signed8 (𝑗) < 0)
ivrelaxed_swizzle_lane(𝑖𝑛 , 𝑗) = relaxed(𝑅swizzle )[0, 𝑖𝑛 [𝑗 mod 𝑛]] (otherwise)

Note

Relaxed swizzle is implementation-dependent if the signed interpretation of any of the 8-bit indices in 𝑗 𝑛 is
larger than or equal to 16. In the deterministic profile, it behaves like regular ivswizzle.

relaxed_dot(𝑖1 , 𝑖2 )
The implementation-specific behaviour of this operation is determined by the global parameter 𝑅idot ∈ {0, 1}. It
also affects the behaviour of relaxed_dot_add.
Its definition is part of the definition of vextbinop specified above.

Note

Relaxed dot product is implementation-dependent when the second operand is negative in a signed intepretation.
In the deterministic profile, it behaves like signed dot product.

irelaxed_laneselect𝑁 (𝑖1 , 𝑖2 , 𝑖3 )
The implementation-specific behaviour of this operation is determined by the global parameter 𝑅laneselect ∈ {0, 1}.
• If 𝑖3 is smaller than 2𝑁 −1 , then let 𝑖′3 be the value 0, otherwise 2𝑁 − 1.
• Let 𝑖′′3 be relaxed(𝑅laneselect )[𝑖3 , 𝑖′3 ].
• Return ibitselect𝑁 (𝑖1 , 𝑖2 , 𝑖′′3 ).
irelaxed_laneselect𝑁 (𝑖1 , 𝑖2 , 𝑖3 ) = ibitselect𝑁 (𝑖1 , 𝑖2 , relaxed(𝑅laneselect )[𝑖3 , extends 1,𝑁 (ishr_u𝑁 (𝑖3 , 𝑁 − 1))])

Note

Relaxed lane selection is non-deterministic when the mask mixes set and cleared bits, since the value of the
high bit may or may not be expanded to all bits. In the deterministic profile, it behaves like ibitselect.

4.4 Types
Execution has to check and compare types in a few places, such as executing call_indirect or instantiating modules.
It is an invariant of the semantics that all types occurring during execution are closed.

Note

Runtime type checks generally involve types from multiple modules or types not defined by a module at all,
such that any module-local type indices occurring inside them would not generally be meaningful.

116 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

4.4.1 Instantiation
Any form of type can be instantiated into a closed type inside a module instance by substituting each type index 𝑥
occurring in it with the corresponding defined type [Link][𝑥].
closmoduleinst (𝑡) = 𝑡[:= dt * ] if dt * = [Link]

Note

This is the runtime equivalent to type closure, which is applied at validation time.

4.5 Values
4.5.1 Value Typing
For the purpose of checking argument values against the parameter types of exported functions, values are classified
by value types. The following auxiliary typing rules specify this typing relation relative to a store 𝑆 in which
possibly referenced addresses live.

Numeric Values
The number value ([Link] 𝑐) is valid with the number type nt.

𝑠 ⊢ [Link] 𝑐 : nt

Vector Values
The vector value ([Link] 𝑐) is valid with the vector type vt.

𝑠 ⊢ [Link] 𝑐 : vt

Null References
The reference value ([Link] ht) is valid with the reference type (ref null ht ′ ) if:
• The heap type ht ′ matches the heap type ht.
{} ⊢ ht ′ ≤ ht
𝑠 ⊢ [Link] ht : (ref null ht ′ )

Note

A null reference can be typed with any smaller type. In particular, that allows it to be typed with the least type
in its respective hierarchy. That ensures that the value is compatible with any nullable type in that hierarchy.

Scalar References
The reference value (ref.i31 𝑖) is valid with the reference type (ref i31).

𝑠 ⊢ ref.i31 𝑖 : (ref i31)

Structure References
The reference value ([Link] 𝑎) is valid with the reference type (ref dt) if:
• The structure instance 𝑠.structs[𝑎] exists.
• The defined type 𝑠.structs[𝑎].type is of the form dt.
𝑠.structs[𝑎].type = dt
𝑠 ⊢ [Link] 𝑎 : (ref dt)

4.5. Values 117


WebAssembly Specification, Release 3.0 (2025-11-14)

Array References
The reference value ([Link] 𝑎) is valid with the reference type (ref dt) if:
• The array instance 𝑠.arrays[𝑎] exists.
• The defined type 𝑠.arrays[𝑎].type is of the form dt.
𝑠.arrays[𝑎].type = dt
𝑠 ⊢ [Link] 𝑎 : (ref dt)

Exception References
The reference value ([Link] 𝑎) is valid with the reference type (ref exn) if:
• The exception instance 𝑠.exns[𝑎] exists.
𝑠.exns[𝑎] = exn
𝑠 ⊢ [Link] 𝑎 : (ref exn)

Function References
The reference value ([Link] 𝑎) is valid with the reference type (ref dt) if:
• The function instance 𝑠.funcs[𝑎] exists.
• The defined type 𝑠.funcs[𝑎].type is of the form dt.
𝑠.funcs[𝑎].type = dt
𝑠 ⊢ [Link] 𝑎 : (ref dt)

Host References
The reference value ([Link] 𝑎) is valid with the reference type (ref any).

𝑠 ⊢ [Link] 𝑎 : (ref any)

Note

A bare host reference is considered internalized.

External References
The reference value ([Link] addrref ) is valid with the reference type (ref extern) if:
• The reference value addrref is valid with the reference type (ref any).
𝑠 ⊢ addrref : (ref any)
𝑠 ⊢ [Link] addrref : (ref extern)

Subsumption
The reference value ref is valid with the reference type rt if:
• The reference value ref is valid with the reference type rt ′ .
• The reference type rt ′ matches the reference type rt.
𝑠 ⊢ ref : rt ′ {} ⊢ rt ′ ≤ rt
𝑠 ⊢ ref : rt

118 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

4.5.2 External Typing


For the purpose of checking external address against imports, such values are classified by external types. The
following auxiliary typing rules specify this typing relation relative to a store 𝑆 in which the referenced instances
live.

Functions
The external address (func 𝑎) is valid with the external type (func [Link]) if:
• The function instance 𝑠.funcs[𝑎] exists.
• The function instance 𝑠.funcs[𝑎] is of the form funcinst.
𝑠.funcs[𝑎] = funcinst
𝑠 ⊢ func 𝑎 : func [Link]

Tables
The external address (table 𝑎) is valid with the external type (table [Link]) if:
• The table instance 𝑠.tables[𝑎] exists.
• The table instance 𝑠.tables[𝑎] is of the form tableinst.
𝑠.tables[𝑎] = tableinst
𝑠 ⊢ table 𝑎 : table [Link]

Memories
The external address (mem 𝑎) is valid with the external type (mem [Link]) if:
• The memory instance 𝑠.mems[𝑎] exists.
• The memory instance 𝑠.mems[𝑎] is of the form meminst.
𝑠.mems[𝑎] = meminst
𝑠 ⊢ mem 𝑎 : mem [Link]

Globals
The external address (global 𝑎) is valid with the external type (global [Link]) if:
• The global instance 𝑠.globals[𝑎] exists.
• The global instance 𝑠.globals[𝑎] is of the form globalinst.
𝑠.globals[𝑎] = globalinst
𝑠 ⊢ global 𝑎 : global [Link]

Tags
The external address (tag 𝑎) is valid with the external type (tag [Link]) if:
• The tag instance 𝑠.tags[𝑎] exists.
• The tag instance 𝑠.tags[𝑎] is of the form taginst.
𝑠.tags[𝑎] = taginst
𝑠 ⊢ tag 𝑎 : tag [Link]

4.5. Values 119


WebAssembly Specification, Release 3.0 (2025-11-14)

Subsumption
The external address externaddr is valid with the external type xt if:
• The external address externaddr is valid with the external type xt ′ .
• The external type xt ′ matches the external type xt.
𝑠 ⊢ externaddr : xt ′ {} ⊢ xt ′ ≤ xt
𝑠 ⊢ externaddr : xt

4.6 Instructions
WebAssembly computation is performed by executing individual instructions.

4.6.1 Parametric Instructions


nop
1. Do nothing.
nop ˓→ 𝜖

unreachable
1. Trap.
unreachable ˓→ trap

drop
1. Assert: Due to validation, a value is on the top of the stack.
2. Pop the value val from the stack.
val drop ˓→ 𝜖

select (𝑡* )?
1. Assert: Due to validation, a value of number type i32 is on the top of the stack.
2. Pop the value ([Link] 𝑐) from the stack.
3. Assert: Due to validation, a value is on the top of the stack.
4. Pop the value val 2 from the stack.
5. Assert: Due to validation, a value is on the top of the stack.
6. Pop the value val 1 from the stack.
7. If 𝑐 ̸= 0, then:
a. Push the value val 1 to the stack.
8. Else:
a. Push the value val 2 to the stack.
val 1 val 2 ([Link] 𝑐) (select (𝑡* )? ) ˓→ val 1 if 𝑐 ̸= 0
val 1 val 2 ([Link] 𝑐) (select (𝑡* )? ) ˓→ val 2 if 𝑐 = 0

Note

In future versions of WebAssembly, select may allow more than one value per choice.

120 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

4.6.2 Control Instructions


block bt instr *
1. Let 𝑧 be the current state.
2. Let 𝑡𝑚
1 →localidx * 𝑡𝑛 be the destructuring of instrtype𝑧 (bt).
0 2

3. Assert: Due to validation, localidx *0 = 𝜖.


4. Assert: Due to validation, there are at least 𝑚 values on the top of the stack.
5. Pop the values val 𝑚 from the stack.
6. Let 𝐿 be the label whose arity is 𝑛 and whose continuation is the end of the block.
7. Enter the block val 𝑚 instr * with the label 𝐿.
𝑧; val 𝑚 (block bt instr * ) ˓→ (label𝑛 {𝜖} val 𝑚 instr * ) if instrtype𝑧 (bt) = 𝑡𝑚 𝑛
1 → 𝑡2

loop bt instr *
1. Let 𝑧 be the current state.
2. Let 𝑡𝑚
1 →localidx * 𝑡𝑛 be the destructuring of instrtype𝑧 (bt).
0 2

3. Assert: Due to validation, localidx *0 = 𝜖.


4. Assert: Due to validation, there are at least 𝑚 values on the top of the stack.
5. Pop the values val 𝑚 from the stack.
6. Let 𝐿 be the label whose arity is 𝑚 and whose continuation is the start of the block.
7. Enter the block val 𝑚 instr * with the label 𝐿.
𝑧; val 𝑚 (loop bt instr * ) ˓→ (label𝑚 {loop bt instr * } val 𝑚 instr * ) if instrtype𝑧 (bt) = 𝑡𝑚 𝑛
1 → 𝑡2

if bt instr *1 instr *2
1. Assert: Due to validation, a value of number type i32 is on the top of the stack.
2. Pop the value ([Link] 𝑐) from the stack.
3. If 𝑐 ̸= 0, then:
a. Execute the instruction (block bt instr *1 ).
4. Else:
a. Execute the instruction (block bt instr *2 ).
([Link] 𝑐) (if bt instr *1 else instr *2 ) ˓→ (block bt instr *1 ) if 𝑐 ̸= 0
([Link] 𝑐) (if bt instr *1 else instr *2 ) ˓→ (block bt instr *2 ) if 𝑐 = 0

br 𝑙
1. If the first non-value entry of the stack is a label, then:
a. Let 𝐿 be the topmost label.
b. Let 𝑛 be the arity of 𝐿
c. If 𝑙 = 0, then:
1) Assert: Due to validation, there are at least 𝑛 values on the top of the stack.
2) Pop the values val 𝑛 from the stack.
*
3) Pop all values val ′ from the top of the stack.
4) Pop the label from the stack.

4.6. Instructions 121


WebAssembly Specification, Release 3.0 (2025-11-14)

5) Push the values val 𝑛 to the stack.


6) Jump to the continuation of 𝐿.
d. Else:
1) Pop all values val * from the top of the stack.
2) Pop the label from the stack.
3) Push the values val * to the stack.
4) Execute the instruction (br 𝑙 − 1).
2. Else:
a. Assert: Due to validation, the first non-value entry of the stack is a handler.
b. Pop all values val * from the top of the stack.
c. Pop the handler from the stack.
d. Push the values val * to the stack.
e. Execute the instruction (br 𝑙).
* * *
(label𝑛 {instr ′ } val ′ val 𝑛 (br 𝑙) instr * ) ˓→ val 𝑛 instr ′ if 𝑙 = 0
*
(label𝑛 {instr ′ } val * (br 𝑙) instr * ) ˓→ val * (br 𝑙 − 1) if 𝑙 > 0
(handler𝑛 {catch * } val * (br 𝑙) instr * ) ˓→ val * (br 𝑙)

br_if 𝑙
1. Assert: Due to validation, a value of number type i32 is on the top of the stack.
2. Pop the value ([Link] 𝑐) from the stack.
3. If 𝑐 ̸= 0, then:
a. Execute the instruction (br 𝑙).
4. Else:
a. Do nothing.
([Link] 𝑐) (br_if 𝑙) ˓→ (br 𝑙) if 𝑐 ̸= 0
([Link] 𝑐) (br_if 𝑙) ˓→ 𝜖 if 𝑐 = 0

br_table 𝑙* 𝑙′
1. Assert: Due to validation, a value of number type i32 is on the top of the stack.
2. Pop the value ([Link] 𝑖) from the stack.
3. If 𝑖 < |𝑙* |, then:
a. Execute the instruction (br 𝑙* [𝑖]).
4. Else:
a. Execute the instruction (br 𝑙′ ).
([Link] 𝑖) (br_table 𝑙* 𝑙′ ) ˓→ (br 𝑙* [𝑖]) if 𝑖 < |𝑙* |
([Link] 𝑖) (br_table 𝑙* 𝑙′ ) ˓→ (br 𝑙′ ) if 𝑖 ≥ |𝑙* |

br_on_null 𝑙
1. Assert: Due to validation, a value is on the top of the stack.
2. Pop the value val from the stack.
3. If val is some [Link] heaptype, then:
a. Execute the instruction (br 𝑙).

122 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

4. Else:
a. Push the value val to the stack.
val (br_on_null 𝑙) ˓→ (br 𝑙) if val = [Link] ht
val (br_on_null 𝑙) ˓→ val otherwise

br_on_non_null 𝑙
1. Assert: Due to validation, a value is on the top of the stack.
2. Pop the value val from the stack.
3. If val is some [Link] heaptype, then:
a. Do nothing.
4. Else:
a. Push the value val to the stack.
b. Execute the instruction (br 𝑙).
val (br_on_non_null 𝑙) ˓→ 𝜖 if val = [Link] ht
val (br_on_non_null 𝑙) ˓→ val (br 𝑙) otherwise

br_on_cast 𝑙 rt 1 rt 2
1. Let 𝑓 be the topmost frame.
2. Assert: Due to validation, a reference value is on the top of the stack.
3. Pop the value ref from the stack.
4. Let rt be the type of ref .
5. Push the value ref to the stack.
6. If rt matches clos𝑓.module (rt 2 ), then:
a. Execute the instruction (br 𝑙).
7. Else:
a. Do nothing.
𝑠; 𝑓 ; ref (br_on_cast 𝑙 rt 1 rt 2 ) ˓→ ref (br 𝑙) if 𝑠 ⊢ ref : rt
∧ {} ⊢ rt ≤ clos𝑓.module (rt 2 )
𝑠; 𝑓 ; ref (br_on_cast 𝑙 rt 1 rt 2 ) ˓→ ref otherwise

br_on_cast_fail 𝑙 rt 1 rt 2
1. Let 𝑓 be the topmost frame.
2. Assert: Due to validation, a reference value is on the top of the stack.
3. Pop the value ref from the stack.
4. Let rt be the type of ref .
5. Push the value ref to the stack.
6. If rt matches clos𝑓.module (rt 2 ), then:
a. Do nothing.
7. Else:
a. Execute the instruction (br 𝑙).
𝑠; 𝑓 ; ref (br_on_cast_fail 𝑙 rt 1 rt 2 ) ˓→ ref if 𝑠 ⊢ ref : rt
∧ {} ⊢ rt ≤ clos𝑓.module (rt 2 )
𝑠; 𝑓 ; ref (br_on_cast_fail 𝑙 rt 1 rt 2 ) ˓→ ref (br 𝑙) otherwise

4.6. Instructions 123


WebAssembly Specification, Release 3.0 (2025-11-14)

return
1. If the first non-value entry of the stack is a frame, then:
a. Let 𝑓 be the topmost frame.
b. Let 𝑛 be the arity of 𝑓
c. Assert: Due to validation, there are at least 𝑛 values on the top of the stack.
d. Pop the values val 𝑛 from the stack.
*
e. Pop all values val ′ from the top of the stack.
f. Pop the frame from the stack.
g. Push the values val 𝑛 to the stack.
2. Else if the first non-value entry of the stack is a label, then:
a. Pop all values val * from the top of the stack.
b. Pop the label from the stack.
c. Push the values val * to the stack.
d. Execute the instruction return.
3. Else:
a. Assert: Due to validation, the first non-value entry of the stack is a handler.
b. Pop all values val * from the top of the stack.
c. Pop the handler from the stack.
d. Push the values val * to the stack.
e. Execute the instruction return.
*
(frame𝑛 {𝑓 } val ′ val 𝑛 return instr * ) ˓→ val 𝑛
*
(label𝑛 {instr ′ } val * return instr * ) ˓→ val * return
(handler𝑛 {catch * } val * return instr * ) ˓→ val * return

call 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, 𝑥 < |𝑧.[Link]|.
3. Let 𝑎 be the address 𝑧.[Link][𝑥].
4. Assert: Due to validation, 𝑎 < |𝑧.funcs|.
5. Push the value ([Link] 𝑎) to the stack.
6. Execute the instruction (call_ref 𝑧.funcs[𝑎].type).
𝑧; (call 𝑥) ˓→ ([Link] 𝑎) (call_ref 𝑧.funcs[𝑎].type) if 𝑧.[Link][𝑥] = 𝑎

call_ref 𝑥

Todo

(*) Prose not spliced, for the prose merges the two cases of null and non-null references.

1. Assert: due to validation, a null or function reference is on the top of the stack.
2. Pop the reference value 𝑟 from the stack.
3. If 𝑟 is [Link] ht, then:

124 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

a. Trap.
4. Assert: due to validation, 𝑟 is a function reference.
5. Let [Link] 𝑎 be the reference 𝑟.
6. Invoke the function instance at address 𝑎.
𝑧; ([Link] ht) (call_ref 𝑦) ˓→ trap

Note

The formal rule for calling a non-null function reference is described below.

call_indirect 𝑥 𝑦
1. Execute the instruction ([Link] 𝑥).
2. Execute the instruction ([Link] (ref null 𝑦)).
3. Execute the instruction (call_ref 𝑦).
(call_indirect 𝑥 𝑦) ˓→ ([Link] 𝑥) ([Link] (ref null 𝑦)) (call_ref 𝑦)

return_call 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, 𝑥 < |𝑧.[Link]|.
3. Let 𝑎 be the address 𝑧.[Link][𝑥].
4. Assert: Due to validation, 𝑎 < |𝑧.funcs|.
5. Push the value ([Link] 𝑎) to the stack.
6. Execute the instruction (return_call_ref 𝑧.funcs[𝑎].type).
𝑧; (return_call 𝑥) ˓→ ([Link] 𝑎) (return_call_ref 𝑧.funcs[𝑎].type) if 𝑧.[Link][𝑥] = 𝑎

return_call_ref 𝑦
1. Let 𝑧 be the current state.
2. If the first non-value entry of the stack is a label, then:
a. Pop all values val * from the top of the stack.
b. Pop the label from the stack.
c. Push the values val * to the stack.
d. Execute the instruction (return_call_ref 𝑦).
3. Else if the first non-value entry of the stack is a handler, then:
a. Pop all values val * from the top of the stack.
b. Pop the handler from the stack.
c. Push the values val * to the stack.
d. Execute the instruction (return_call_ref 𝑦).
4. Else:
a. Assert: Due to validation, the first non-value entry of the stack is a frame.
b. Assert: Due to validation, a value is on the top of the stack.

4.6. Instructions 125


WebAssembly Specification, Release 3.0 (2025-11-14)

c. Pop the value val ′′ from the stack.


d. If val ′′ is some [Link] heaptype, then:
1) Trap.
e. Assert: Due to validation, val ′′ is some [Link] funcaddr .
f. Let ([Link] 𝑎) be the destructuring of val ′′ .
g. Assert: Due to validation, 𝑎 < |𝑧.funcs|.
h. Assert: Due to validation, the expansion of 𝑧.funcs[𝑎].type is some func resulttype → resulttype.
i. Let (func 𝑡𝑛1 → 𝑡𝑚
2 ) be the destructuring of the expansion of 𝑧.funcs[𝑎].type.

j. Assert: Due to validation, there are at least 𝑛 values on the top of the stack.
k. Pop the values val 𝑛 from the stack.
*
l. Pop all values val ′ from the top of the stack.
m. Pop the frame from the stack.
n. Push the values val 𝑛 to the stack.
o. Push the value ([Link] 𝑎) to the stack.
p. Execute the instruction (call_ref 𝑦).
*
𝑧; (label𝑘 {instr ′ } val * (return_call_ref 𝑦) instr * ) ˓→ val * (return_call_ref 𝑦)
𝑧; (handler𝑘 {catch * } val * (return_call_ref 𝑦) instr * ) ˓→ val * (return_call_ref 𝑦)
𝑧; (frame𝑘 {𝑓 } val * ([Link] ht) (return_call_ref 𝑦) instr * ) ˓→ trap
*
𝑧; (frame𝑘 {𝑓 } val ′ val 𝑛 ([Link] 𝑎) (return_call_ref 𝑦) instr * ) ˓→ val 𝑛 ([Link] 𝑎) (call_ref 𝑦)
if 𝑧.funcs[𝑎].type ≈ func 𝑡𝑛1 → 𝑡𝑚
2

return_call_indirect 𝑥 𝑦
1. Execute the instruction ([Link] 𝑥).
2. Execute the instruction ([Link] (ref null 𝑦)).
3. Execute the instruction (return_call_ref 𝑦).
(return_call_indirect 𝑥 𝑦) ˓→ ([Link] 𝑥) ([Link] (ref null 𝑦)) (return_call_ref 𝑦)

throw 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, 𝑥 < |𝑧.tags|.
3. Assert: Due to validation, the expansion of 𝑧.tags[𝑥].type is some func resulttype → resulttype.
4. Let (func 𝑡𝑛 → resulttype 0 ) be the destructuring of the expansion of 𝑧.tags[𝑥].type.
5. Assert: Due to validation, resulttype 0 = 𝜖.
6. Let 𝑎 be the length of 𝑧.exns.
7. Assert: Due to validation, there are at least 𝑛 values on the top of the stack.
8. Pop the values val 𝑛 from the stack.
9. Let exn be the exception instance {tag 𝑧.tags[𝑥], fields val 𝑛 }.
10. Append exn to 𝑧.exns.
11. Push the value ([Link] 𝑎) to the stack.
12. Execute the instruction throw_ref.

126 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

𝑧; val 𝑛 (throw 𝑥) ˓→ 𝑧[.exns =⊕ exn]; ([Link] 𝑎) throw_ref if 𝑧.tags[𝑥].type ≈ func 𝑡𝑛 → 𝜖


∧ 𝑎 = |𝑧.exns|
∧ exn = {tag 𝑧.tags[𝑥], fields val 𝑛 }

throw_ref
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value is on the top of the stack.
3. Pop the value val ′ from the stack.
4. If val ′ is some [Link] heaptype, then:
a. Trap.
5. If val ′ is some [Link] exnaddr , then:
a. Let ([Link] 𝑎) be the destructuring of val ′ .
b. Pop all values val * from the top of the stack.
c. If val * ̸= 𝜖, then:
1) Push the value ([Link] 𝑎) to the stack.
2) Execute the instruction throw_ref.
d. Else if the first non-value entry of the stack is a label, then:
1) Pop the label from the stack.
2) Push the value ([Link] 𝑎) to the stack.
3) Execute the instruction throw_ref.
e. Else:
1) If the first non-value entry of the stack is a frame, then:
a) Pop the frame from the stack.
b) Push the value ([Link] 𝑎) to the stack.
c) Execute the instruction throw_ref.
2) Else if the first non-value entry of the stack is not a handler, then:
a) Throw the exception val ′ as a result.
3) Else:
a) Let 𝐻 be the topmost handler.
b) Let 𝑛 be the arity of 𝐻
*
c) Let catch ′′ be the catch handler of 𝐻
*
d) If catch ′′ = 𝜖, then:
1. Pop the handler from the stack.
2. Push the value ([Link] 𝑎) to the stack.
3. Execute the instruction throw_ref.
e) Else if 𝑎 ≥ |𝑧.exns|, then:
* *
1. Let catch 0 catch ′ be catch ′′ .
2. If catch 0 is some catch_all labelidx , then:
a. Let (catch_all 𝑙) be the destructuring of catch 0 .
b. Pop the handler from the stack.

4.6. Instructions 127


WebAssembly Specification, Release 3.0 (2025-11-14)

c. Execute the instruction (br 𝑙).


3. Else if catch 0 is not some catch_all_ref labelidx , then:
* *
a. Let catch catch ′ be catch ′′ .
b. Pop the handler from the stack.
*
c. Let 𝐻 ′ be the handler whose arity is 𝑛 and whose catch handler is catch ′ .
d. Push the handler 𝐻 ′ .
e. Push the value ([Link] 𝑎) to the stack.
f. Execute the instruction throw_ref.
4. Else:
a. Let (catch_all_ref 𝑙) be the destructuring of catch 0 .
b. Pop the handler from the stack.
c. Push the value ([Link] 𝑎) to the stack.
d. Execute the instruction (br 𝑙).
f) Else:
1. Let val * be 𝑧.exns[𝑎].fields.
* *
2. Let catch 0 catch ′ be catch ′′ .
3. If catch 0 is some catch tagidx labelidx , then:
a. Let (catch 𝑥 𝑙) be the destructuring of catch 0 .
b. If 𝑥 < |𝑧.tags| and 𝑧.exns[𝑎].tag = 𝑧.tags[𝑥], then:
1) Pop the handler from the stack.
2) Push the values val * to the stack.
3) Execute the instruction (br 𝑙).
c. Else:
* *
1) Let catch catch ′ be catch ′′ .
2) Pop the handler from the stack.
*
3) Let 𝐻 ′ be the handler whose arity is 𝑛 and whose catch handler is catch ′ .
4) Push the handler 𝐻 ′ .
5) Push the value ([Link] 𝑎) to the stack.
6) Execute the instruction throw_ref.
4. Else if catch 0 is some catch_ref tagidx labelidx , then:
a. Let (catch_ref 𝑥 𝑙) be the destructuring of catch 0 .
b. If 𝑥 ≥ |𝑧.tags| or 𝑧.exns[𝑎].tag ̸= 𝑧.tags[𝑥], then:
* *
1) Let catch catch ′ be catch ′′ .
2) Pop the handler from the stack.
*
3) Let 𝐻 ′ be the handler whose arity is 𝑛 and whose catch handler is catch ′ .
4) Push the handler 𝐻 ′ .
5) Push the value ([Link] 𝑎) to the stack.
6) Execute the instruction throw_ref.
c. Else:

128 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

1) Pop the handler from the stack.


2) Push the values val * to the stack.
3) Push the value ([Link] 𝑎) to the stack.
4) Execute the instruction (br 𝑙).
5. Else:
a. If catch 0 is some catch_all labelidx , then:
1) Let (catch_all 𝑙) be the destructuring of catch 0 .
2) Pop the handler from the stack.
3) Execute the instruction (br 𝑙).
b. Else if catch 0 is not some catch_all_ref labelidx , then:
* *
1) Let catch catch ′ be catch ′′ .
2) Pop the handler from the stack.
*
3) Let 𝐻 be the handler whose arity is 𝑛 and whose catch handler is catch ′ .
4) Push the handler 𝐻.
5) Push the value ([Link] 𝑎) to the stack.
6) Execute the instruction throw_ref.
c. Else:
1) Let (catch_all_ref 𝑙) be the destructuring of catch 0 .
2) Pop the handler from the stack.
3) Push the value ([Link] 𝑎) to the stack.
4) Execute the instruction (br 𝑙).
6. Else:
a. Assert: Due to validation, the first non-value entry of the stack is not a label.
b. Assert: Due to validation, the first non-value entry of the stack is not a frame.
c. Assert: Due to validation, the first non-value entry of the stack is not a handler.
d. Throw the exception val ′ as a result.
𝑧; ([Link] ht) throw_ref ˓→ trap
* *
𝑧; val ([Link] 𝑎) throw_ref instr ˓→ ([Link] 𝑎) throw_ref
if val * ̸= 𝜖 ∨ instr * ̸= 𝜖
*
𝑧; (label𝑛 {instr ′ } ([Link] 𝑎) throw_ref) ˓→ ([Link] 𝑎) throw_ref
𝑧; (frame𝑛 {𝑓 } ([Link] 𝑎) throw_ref) ˓→ ([Link] 𝑎) throw_ref
𝑧; (handler𝑛 {𝜖} ([Link] 𝑎) throw_ref) ˓→ ([Link] 𝑎) throw_ref
′*
𝑧; (handler𝑛 {(catch 𝑥 𝑙) catch } ([Link] 𝑎) throw_ref) ˓→ val * (br 𝑙)
if 𝑧.exns[𝑎].tag = 𝑧.tags[𝑥]
∧ val * = 𝑧.exns[𝑎].fields
′* *
𝑧; (handler𝑛 {(catch_ref 𝑥 𝑙) catch } ([Link] 𝑎) throw_ref) ˓→ val ([Link] 𝑎) (br 𝑙)
if 𝑧.exns[𝑎].tag = 𝑧.tags[𝑥]
∧ val * = 𝑧.exns[𝑎].fields
′*
𝑧; (handler𝑛 {(catch_all 𝑙) catch } ([Link] 𝑎) throw_ref) ˓→ (br 𝑙)
*
𝑧; (handler𝑛 {(catch_all_ref 𝑙) catch ′ } ([Link] 𝑎) throw_ref) ˓→ ([Link] 𝑎) (br 𝑙)
* *
𝑧; (handler𝑛 {catch catch ′ } ([Link] 𝑎) throw_ref) ˓→ (handler𝑛 {catch ′ } ([Link] 𝑎) throw_ref)
otherwise

4.6. Instructions 129


WebAssembly Specification, Release 3.0 (2025-11-14)

try_table bt catch * instr *


1. Let 𝑧 be the current state.
2. Let 𝑡𝑚
1 →localidx * 𝑡𝑛 be the destructuring of instrtype𝑧 (bt).
0 2

3. Assert: Due to validation, localidx *0 = 𝜖.


4. Assert: Due to validation, there are at least 𝑚 values on the top of the stack.
5. Pop the values val 𝑚 from the stack.
6. Let 𝐻 be the handler whose arity is 𝑛 and whose catch handler is catch * .
7. Push the handler 𝐻.
8. Let 𝐿 be the label whose arity is 𝑛 and whose continuation is the end of the block.
9. Enter the block val 𝑚 instr * with the label 𝐿.
𝑧; val 𝑚 (try_table bt catch * instr * ) ˓→ (handler𝑛 {catch * } (label𝑛 {𝜖} val 𝑚 instr * ))
if instrtype𝑧 (bt) = 𝑡𝑚1 → 𝑡2
𝑛

4.6.3 Blocks
The following auxiliary rules define the semantics of executing an instruction sequence that forms a block.

Entering instr * with label 𝐿 and values val *


1. Push 𝐿 to the stack.
2. Push the values val * to the stack.
3. Jump to the start of the instruction sequence instr * .

Note

No formal reduction rule is needed for entering an instruction sequence, because the label 𝐿 is embedded in
the administrative instruction that structured control instructions reduce to directly.

Exiting instr * with label 𝐿


When the end of a block is reached without a jump, exception, or trap aborting it, then the following steps are
performed.
1. Pop all values val * from the top of the stack.
2. Assert: due to validation, the label 𝐿 is now on the top of the stack.
3. Pop the label from the stack.
4. Push val * back to the stack.
5. Jump to the position after the end of the structured control instruction associated with the label 𝐿.
(label𝑛 {instr * } val * ) ˓→ val *

Note

This semantics also applies to the instruction sequence contained in a loop instruction. Therefore, execution of
a loop falls off the end, unless a backwards branch is performed explicitly.

130 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

4.6.4 Exception Handling


The following auxiliary rules define the semantics of entering and exiting try_table blocks.

Entering instr * with label 𝐿 and exception handler 𝐻


1. Push 𝐻 to the stack.
2. Push 𝐿 onto the stack.
3. Jump to the start of the instruction sequence instr * .

Note

No formal reduction rule is needed for entering an exception handler because it is an administrative instruction
that the try_table instruction reduces to directly.

Exiting an exception handler


When the end of a try_table block is reached without a jump, exception, or trap, then the following steps are
performed.
1. Let 𝑚 be the number of values on the top of the stack.
2. Pop the values val 𝑚 from the stack.
3. Assert: due to validation, a handler and a label are now on the top of the stack.
4. Pop the label from the stack.
5. Pop the handler 𝐻 from the stack.
6. Push val 𝑚 back to the stack.
7. Jump to the position after the end of the administrative instruction associated with the handler 𝐻.
(handler𝑛 {catch * } val * ) ˓→ val *

4.6.5 Function Calls


The following auxiliary rules define the semantics of invoking a function instance through one of the call instruc-
tions and returning from it.

Invocation of function reference ([Link] 𝑎)


1. Assert: due to validation, 𝑆.funcs[𝑎] exists.
2. Let 𝑓 be the function instance, 𝑆.funcs[𝑎].
3. Let func [𝑡𝑛1 ] → [𝑡𝑚
2 ] be the composite type expand(f .type).

4. Let func 𝑥 local * instr * be the function 𝑓.code.


5. Assert: due to validation, 𝑛 values are on the top of the stack.
6. Pop the values val 𝑛 from the stack.
7. Let 𝐹 be the frame {module 𝐹.module, locals val 𝑛 (default𝑡 )* }.
8. Push the activation of 𝑓 with arity 𝑚 to the stack.
9. Let 𝐿 be the label whose arity is 𝑚 and whose continuation is the end of the function.
10. Enter the instruction sequence instr * with label 𝐿 and no values.

4.6. Instructions 131


WebAssembly Specification, Release 3.0 (2025-11-14)

𝑧; val 𝑛 ([Link] 𝑎) (call_ref 𝑦) ˓→ (frame𝑚 {𝑓 } (label𝑚 {𝜖} instr * ))


if 𝑧.funcs[𝑎] = fi
∧ fi .type ≈ func 𝑡𝑛1 → 𝑡𝑚
2
∧ fi .code = func 𝑥 (local 𝑡)* (instr * )
∧ 𝑓 = {locals val 𝑛 (default𝑡 )* , module fi .module}

Note

For non-defaultable types, the respective local is left uninitialized by these rules.

Returning from a function


When the end of a function is reached without a jump (including through return), or an exception or trap aborting
it, then the following steps are performed.
1. Let 𝐹 be the current frame.
2. Let 𝑛 be the arity of the activation of 𝐹 .
3. Assert: due to validation, there are 𝑛 values on the top of the stack.
4. Pop the results val 𝑛 from the stack.
5. Assert: due to validation, the frame 𝐹 is now on the top of the stack.
6. Pop the frame from the stack.
7. Push val 𝑛 back to the stack.
8. Jump to the instruction after the original call.
(frame𝑛 {𝑓 } val 𝑛 ) ˓→ val 𝑛

Host Functions
Invoking a host function has non-deterministic behavior. It may either terminate with a trap, an exception, or return
regularly. However, in the latter case, it must consume and produce the right number and types of WebAssembly
values on the stack, according to its function type.
A host function may also modify the store. However, all store modifications must result in an extension of the
original store, i.e., they must only modify mutable contents and must not have instances removed. Furthermore,
the resulting store must be valid, i.e., all data and code in it is well-typed.

𝑆; val 𝑛 ([Link] 𝑎) call_ref ˓→ 𝑆 ′ ; result


if 𝑆.funcs[𝑎] = {type deftype, hostfunc hf }
∧ deftype ≈ func [𝑡𝑛1 ] → [𝑡𝑚 2 ]
∧ (𝑆 ′ ; result) ∈ hf (𝑆; val 𝑛 )
𝑆; val 𝑛 ([Link] 𝑎) call_ref ˓→ 𝑆; val 𝑛 ([Link] 𝑎) call_ref
if 𝑆.funcs[𝑎] = {type deftype, hostfunc hf }
∧ deftype ≈ func [𝑡𝑛1 ] → [𝑡𝑚 2 ]
∧ ⊥ ∈ hf (𝑆; val 𝑛 )

Here, hf (𝑆; val 𝑛 ) denotes the implementation-defined execution of host function hf in current store 𝑆 with argu-
ments val 𝑛 . It yields a set of possible outcomes, where each element is either a pair of a modified store 𝑆 ′ and
a result or the special value ⊥ indicating divergence. A host function is non-deterministic if there is at least one
argument for which the set of outcomes is not singular.
For a WebAssembly implementation to be sound in the presence of host functions, every host function instance
must be valid, which means that it adheres to suitable pre- and post-conditions: under a valid store 𝑆, and given
arguments val 𝑛 matching the ascribed parameter types 𝑡𝑛1 , executing the host function must yield a non-empty set

132 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

of possible outcomes each of which is either divergence or consists of a valid store 𝑆 ′ that is an extension of 𝑆 and
a result matching the ascribed return types 𝑡𝑚
2 . All these notions are made precise in the Appendix.

Note

A host function can call back into WebAssembly by invoking a function exported from a module. However, the
effects of any such call are subsumed by the non-deterministic behavior allowed for the host function.

4.6.6 Variable Instructions


[Link] 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, 𝑧.locals[𝑥] is defined.
3. Let val be 𝑧.locals[𝑥].
4. Push the value val to the stack.
𝑧; ([Link] 𝑥) ˓→ val if 𝑧.locals[𝑥] = val

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value is on the top of the stack.
3. Pop the value val from the stack.
4. Replace 𝑧.locals[𝑥] with val .
𝑧; val ([Link] 𝑥) ˓→ 𝑧[.locals[𝑥] = val ]; 𝜖

[Link] 𝑥
1. Assert: Due to validation, a value is on the top of the stack.
2. Pop the value val from the stack.
3. Push the value val to the stack.
4. Push the value val to the stack.
5. Execute the instruction ([Link] 𝑥).
val ([Link] 𝑥) ˓→ val val ([Link] 𝑥)

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Let val be the value 𝑧.globals[𝑥].value.
3. Push the value val to the stack.
𝑧; ([Link] 𝑥) ˓→ val if 𝑧.globals[𝑥].value = val

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value is on the top of the stack.
3. Pop the value val from the stack.
4. Replace 𝑧.globals[𝑥].value with val .

4.6. Instructions 133


WebAssembly Specification, Release 3.0 (2025-11-14)

𝑧; val ([Link] 𝑥) ˓→ 𝑧[.globals[𝑥].value = val ]; 𝜖

4.6.7 Table Instructions


[Link] 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a number value is on the top of the stack.
3. Pop the value ([Link] 𝑖) from the stack.
4. If 𝑖 ≥ |𝑧.tables[𝑥].elem|, then:
a. Trap.
5. Push the value 𝑧.tables[𝑥].elem[𝑖] to the stack.
𝑧; ([Link] 𝑖) ([Link] 𝑥) ˓→ trap if 𝑖 ≥ |𝑧.tables[𝑥].elem|
𝑧; ([Link] 𝑖) ([Link] 𝑥) ˓→ 𝑧.tables[𝑥].elem[𝑖] if 𝑖 < |𝑧.tables[𝑥].elem|

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a reference value is on the top of the stack.
3. Pop the value ref from the stack.
4. Assert: Due to validation, a number value is on the top of the stack.
5. Pop the value ([Link] 𝑖) from the stack.
6. If 𝑖 ≥ |𝑧.tables[𝑥].elem|, then:
a. Trap.
7. Replace 𝑧.tables[𝑥].refs[𝑖] with ref .
𝑧; ([Link] 𝑖) ref ([Link] 𝑥) ˓→ 𝑧; trap if 𝑖 ≥ |𝑧.tables[𝑥].elem|
𝑧; ([Link] 𝑖) ref ([Link] 𝑥) ˓→ 𝑧[.tables[𝑥].elem[𝑖] = ref ]; 𝜖 if 𝑖 < |𝑧.tables[𝑥].elem|

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Let (at lim rt) be the destructuring of 𝑧.tables[𝑥].type.
3. Let 𝑛 be the length of 𝑧.tables[𝑥].elem.
4. Push the value ([Link] 𝑛) to the stack.
𝑧; ([Link] 𝑥) ˓→ ([Link] 𝑛) if |𝑧.tables[𝑥].elem| = 𝑛
∧ 𝑧.tables[𝑥].type = at lim rt

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a number value is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.
4. Assert: Due to validation, a reference value is on the top of the stack.
5. Pop the value ref from the stack.
6. Either:

134 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

a. Let ti be the table instance growtable(𝑧.tables[𝑥], 𝑛, ref ).


b. Push the value ([Link] |𝑧.tables[𝑥].elem|) to the stack.
c. Replace 𝑧.tables[𝑥] with ti .
7. Or:
a. Push the value ([Link] signed−1
|at| (−1)) to the stack.

𝑧; ref ([Link] 𝑛) ([Link] 𝑥) ˓→ 𝑧[.tables[𝑥] = ti ]; ([Link] |𝑧.tables[𝑥].elem|)


if ti = growtable(𝑧.tables[𝑥], 𝑛, ref )
𝑧; ref ([Link] 𝑛) ([Link] 𝑥) ˓→ 𝑧; ([Link] signed−1 |at| (−1))

Note

The [Link] instruction is non-deterministic. It may either succeed, returning the old table size sz , or fail,
returning −1. Failure must occur if the referenced table instance has a maximum size defined that would be
exceeded. However, failure can occur in other cases as well. In practice, the choice depends on the resources
available to the embedder.

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a number value is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.
4. Assert: Due to validation, a value is on the top of the stack.
5. Pop the value val from the stack.
6. Assert: Due to validation, a value of number type at is on the top of the stack.
7. Pop the value (numtype 0 .const 𝑖) from the stack.
8. If 𝑖 + 𝑛 > |𝑧.tables[𝑥].elem|, then:
a. Trap.
9. If 𝑛 = 0, then:
a. Do nothing.
10. Else:
a. Push the value ([Link] 𝑖) to the stack.
b. Push the value val to the stack.
c. Execute the instruction ([Link] 𝑥).
d. Push the value ([Link] 𝑖 + 1) to the stack.
e. Push the value val to the stack.
f. Push the value ([Link] 𝑛 − 1) to the stack.
g. Execute the instruction ([Link] 𝑥).
𝑧; ([Link] 𝑖) val ([Link] 𝑛) ([Link] 𝑥) ˓→ trap if 𝑖 + 𝑛 > |𝑧.tables[𝑥].elem|
𝑧; ([Link] 𝑖) val ([Link] 𝑛) ([Link] 𝑥) ˓→ 𝜖 otherwise, if 𝑛 = 0
𝑧; ([Link] 𝑖) val ([Link] 𝑛) ([Link] 𝑥) ˓→
([Link] 𝑖) val ([Link] 𝑥) otherwise
([Link] 𝑖 + 1) val ([Link] 𝑛 − 1) ([Link] 𝑥)

4.6. Instructions 135


WebAssembly Specification, Release 3.0 (2025-11-14)

[Link] 𝑥1 𝑥2
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a number value is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.
4. Assert: Due to validation, a number value is on the top of the stack.
5. Pop the value (at 2 .const 𝑖2 ) from the stack.
6. Assert: Due to validation, a number value is on the top of the stack.
7. Pop the value (at 1 .const 𝑖1 ) from the stack.
8. If 𝑖1 + 𝑛 > |𝑧.tables[𝑥1 ].elem|, then:
a. Trap.
9. If 𝑖2 + 𝑛 > |𝑧.tables[𝑥2 ].elem|, then:
a. Trap.
10. If 𝑛 = 0, then:
a. Do nothing.
11. Else:
a. If 𝑖1 ≤ 𝑖2 , then:
1) Push the value (at 1 .const 𝑖1 ) to the stack.
2) Push the value (at 2 .const 𝑖2 ) to the stack.
3) Execute the instruction ([Link] 𝑥2 ).
4) Execute the instruction ([Link] 𝑥1 ).
5) Push the value (at 1 .const 𝑖1 + 1) to the stack.
6) Push the value (at 2 .const 𝑖2 + 1) to the stack.
b. Else:
1) Push the value (at 1 .const 𝑖1 + 𝑛 − 1) to the stack.
2) Push the value (at 2 .const 𝑖2 + 𝑛 − 1) to the stack.
3) Execute the instruction ([Link] 𝑥2 ).
4) Execute the instruction ([Link] 𝑥1 ).
5) Push the value (at 1 .const 𝑖1 ) to the stack.
6) Push the value (at 2 .const 𝑖2 ) to the stack.
c. Push the value ([Link] 𝑛 − 1) to the stack.
d. Execute the instruction ([Link] 𝑥1 𝑥2 ).
𝑧; (at 1 .const 𝑖1 ) (at 2 .const 𝑖2 ) (at ′ .const 𝑛) ([Link] 𝑥1 𝑥2 ) ˓→ trap
if 𝑖1 + 𝑛 > |𝑧.tables[𝑥1 ].elem| ∨ 𝑖2 + 𝑛 > |𝑧.tables[𝑥2 ].elem|
𝑧; (at 1 .const 𝑖1 ) (at 2 .const 𝑖2 ) (at ′ .const 𝑛) ([Link] 𝑥 𝑦) ˓→ 𝜖 otherwise, if 𝑛 = 0
𝑧; (at 1 .const 𝑖1 ) (at 2 .const 𝑖2 ) (at ′ .const 𝑛) ([Link] 𝑥 𝑦) ˓→
(at 1 .const 𝑖1 ) (at 2 .const 𝑖2 ) ([Link] 𝑦) ([Link] 𝑥) otherwise, if 𝑖1 ≤ 𝑖2
(at 1 .const 𝑖1 + 1) (at 2 .const 𝑖2 + 1) (at ′ .const 𝑛 − 1) ([Link] 𝑥 𝑦)
𝑧; (at 1 .const 𝑖1 ) (at 2 .const 𝑖2 ) (at ′ .const 𝑛) ([Link] 𝑥 𝑦) ˓→
(at 1 .const 𝑖1 + 𝑛 − 1) (at 2 .const 𝑖2 + 𝑛 − 1) ([Link] 𝑦) ([Link] 𝑥) otherwise
(at 1 .const 𝑖1 ) (at 2 .const 𝑖2 ) (at ′ .const 𝑛 − 1) ([Link] 𝑥 𝑦)

136 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

[Link] 𝑥 𝑦
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value of number type i32 is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.
4. Assert: Due to validation, a value of number type i32 is on the top of the stack.
5. Pop the value ([Link] 𝑗) from the stack.
6. Assert: Due to validation, a number value is on the top of the stack.
7. Pop the value ([Link] 𝑖) from the stack.
8. If 𝑖 + 𝑛 > |𝑧.tables[𝑥].elem|, then:
a. Trap.
9. If 𝑗 + 𝑛 > |𝑧.elems[𝑦].elem|, then:
a. Trap.
10. If 𝑛 = 0, then:
a. Do nothing.
11. Else:
a. Assert: Due to validation, 𝑗 < |𝑧.elems[𝑦].elem|.
b. Push the value ([Link] 𝑖) to the stack.
c. Push the value 𝑧.elems[𝑦].elem[𝑗] to the stack.
d. Execute the instruction ([Link] 𝑥).
e. Push the value ([Link] 𝑖 + 1) to the stack.
f. Push the value ([Link] 𝑗 + 1) to the stack.
g. Push the value ([Link] 𝑛 − 1) to the stack.
h. Execute the instruction ([Link] 𝑥 𝑦).
𝑧; ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) ([Link] 𝑥 𝑦) ˓→ trap
if 𝑖 + 𝑛 > |𝑧.tables[𝑥].elem| ∨ 𝑗 + 𝑛 > |𝑧.elems[𝑦].elem|
𝑧; ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) ([Link] 𝑥 𝑦) ˓→ 𝜖 otherwise, if 𝑛 = 0
𝑧; ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) ([Link] 𝑥 𝑦) ˓→
([Link] 𝑖) 𝑧.elems[𝑦].elem[𝑗] ([Link] 𝑥) otherwise
([Link] 𝑖 + 1) ([Link] 𝑗 + 1) ([Link] 𝑛 − 1) ([Link] 𝑥 𝑦)

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Replace 𝑧.elems[𝑥].refs with 𝜖.
𝑧; ([Link] 𝑥) ˓→ 𝑧[.elems[𝑥].elem = 𝜖]; 𝜖

4.6.8 Memory Instructions

Note

The alignment [Link] in load and store instructions does not affect the semantics. It is a hint that the
offset ea at which the memory is accessed is intended to satisfy the property ea mod [Link] = 0. A
WebAssembly implementation can use this hint to optimize for the intended use. Unaligned access violating

4.6. Instructions 137


WebAssembly Specification, Release 3.0 (2025-11-14)

that property is still allowed and must succeed regardless of the annotation. However, it may be substantially
slower on some hardware.

[Link] ? 𝑥 ao
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a number value is on the top of the stack.
3. Pop the value ([Link] 𝑖) from the stack.
4. If loadop ? is not defined, then:
a. If 𝑖 + [Link] + |nt|/8 > |𝑧.mems[𝑥].bytes|, then:
1) Trap.
b. Let 𝑐 be the result for which bytesnt (𝑐) = 𝑧.mems[𝑥].bytes[𝑖 + [Link] : |nt|/8].
c. Push the value ([Link] 𝑐) to the stack.
5. Else:
a. Assert: Due to validation, nt is i𝑁 .
b. Let loadop 0 be loadop ? .
c. Let 𝑛_sx be the destructuring of loadop 0 .
d. If 𝑖 + [Link] + 𝑛/8 > |𝑧.mems[𝑥].bytes|, then:
1) Trap.
e. Let 𝑐 be the result for which bytesi𝑛 (𝑐) = 𝑧.mems[𝑥].bytes[𝑖 + [Link] : 𝑛/8].
f. Push the value ([Link] extendsx
𝑛,|nt| (𝑐)) to the stack.

𝑧; ([Link] 𝑖) ([Link] 𝑥 ao) ˓→ trap


if 𝑖 + [Link] + |nt|/8 > |𝑧.mems[𝑥].bytes|
𝑧; ([Link] 𝑖) ([Link] 𝑥 ao) ˓→ ([Link] 𝑐)
if bytesnt (𝑐) = 𝑧.mems[𝑥].bytes[𝑖 + [Link] : |nt|/8]
𝑧; ([Link] 𝑖) (i𝑁 .load𝑛_sx 𝑥 ao) ˓→ trap
if 𝑖 + [Link] + 𝑛/8 > |𝑧.mems[𝑥].bytes|
𝑧; ([Link] 𝑖) (i𝑁 .load𝑛_sx 𝑥 ao) ˓→ (i𝑁 .const extendsx 𝑛,|i𝑁 | (𝑐))
if bytesi𝑛 (𝑐) = 𝑧.mems[𝑥].bytes[𝑖 + [Link] : 𝑛/8]

[Link]𝑀 x𝐾_sx 𝑥 ao
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a number value is on the top of the stack.
3. Pop the value ([Link] 𝑖) from the stack.
4. If 𝑖 + [Link] + 𝑀 · 𝐾/8 > |𝑧.mems[𝑥].bytes|, then:
a. Trap.
5. Let 𝑗 𝐾 be the result for which (bytesi𝑀 (𝑗 𝐾 ) = 𝑧.mems[𝑥].bytes[𝑖 + [Link] + 𝑘 · 𝑀/8 : 𝑀/8])𝑘<𝐾 .
6. Let i𝑁 be the result for which 𝑁 = 𝑀 · 2.
𝐾
7. Let 𝑐 be lanes−1 sx
i𝑁 x𝐾 (extend𝑀,𝑁 (𝑗) ).

8. Push the value ([Link] 𝑐) to the stack.


𝑧; ([Link] 𝑖) ([Link]𝑀 x𝐾_sx 𝑥 ao) ˓→ trap if 𝑖 + [Link] + 𝑀 · 𝐾/8 > |𝑧.mems[𝑥].bytes|
𝑧; ([Link] 𝑖) ([Link]𝑀 x𝐾_sx 𝑥 ao) ˓→ ([Link] 𝑐)
if (bytesi𝑀 (𝑗) = 𝑧.mems[𝑥].bytes[𝑖 + [Link] + 𝑘 · 𝑀/8 : 𝑀/8])𝑘<𝐾
𝐾
∧ 𝑐 = lanes−1 sx
i𝑁 x𝐾 (extend𝑀,𝑁 (𝑗) ) ∧ 𝑁 = 𝑀 · 2

138 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

[Link]𝑁 _splat 𝑥 ao
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a number value is on the top of the stack.
3. Pop the value ([Link] 𝑖) from the stack.
4. If 𝑖 + [Link] + 𝑁/8 > |𝑧.mems[𝑥].bytes|, then:
a. Trap.
5. Let 𝑀 be 128/𝑁 .
6. Let i𝑁 be the result for which |i𝑁 | = 𝑁 .
7. Let 𝑗 be the result for which bytesi𝑁 (𝑗) = 𝑧.mems[𝑥].bytes[𝑖 + [Link] : 𝑁/8].
8. Let 𝑐 be lanes−1 𝑀
i𝑁 x𝑀 (𝑗 ).

9. Push the value ([Link] 𝑐) to the stack.


𝑧; ([Link] 𝑖) ([Link]𝑁 _splat 𝑥 ao) ˓→ trap if 𝑖 + [Link] + 𝑁/8 > |𝑧.mems[𝑥].bytes|
𝑧; ([Link] 𝑖) ([Link]𝑁 _splat 𝑥 ao) ˓→ ([Link] 𝑐)
if bytesi𝑁 (𝑗) = 𝑧.mems[𝑥].bytes[𝑖 + [Link] : 𝑁/8]
∧ 𝑁 = |i𝑁 |
∧ 𝑀 = 128/𝑁
∧ 𝑐 = lanes−1 𝑀
i𝑁 x𝑀 (𝑗 )

[Link]𝑁 _zero 𝑥 ao
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a number value is on the top of the stack.
3. Pop the value ([Link] 𝑖) from the stack.
4. If 𝑖 + [Link] + 𝑁/8 > |𝑧.mems[𝑥].bytes|, then:
a. Trap.
5. Let 𝑗 be the result for which bytesi𝑁 (𝑗) = 𝑧.mems[𝑥].bytes[𝑖 + [Link] : 𝑁/8].
6. Let 𝑐 be extendu𝑁,128 (𝑗).
7. Push the value ([Link] 𝑐) to the stack.
𝑧; ([Link] 𝑖) ([Link]𝑁 _zero 𝑥 ao) ˓→ trap if 𝑖 + [Link] + 𝑁/8 > |𝑧.mems[𝑥].bytes|
𝑧; ([Link] 𝑖) ([Link]𝑁 _zero 𝑥 ao) ˓→ ([Link] 𝑐)
if bytesi𝑁 (𝑗) = 𝑧.mems[𝑥].bytes[𝑖 + [Link] : 𝑁/8]
∧ 𝑐 = extendu𝑁,128 (𝑗)

[Link]𝑁 _lane 𝑥 ao 𝑗
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
3. Pop the value ([Link] 𝑐1 ) from the stack.
4. Assert: Due to validation, a number value is on the top of the stack.
5. Pop the value ([Link] 𝑖) from the stack.
6. If 𝑖 + [Link] + 𝑁/8 > |𝑧.mems[𝑥].bytes|, then:
a. Trap.
7. Let 𝑀 be |v128|/𝑁 .
8. Let i𝑁 be the result for which |i𝑁 | = 𝑁 .

4.6. Instructions 139


WebAssembly Specification, Release 3.0 (2025-11-14)

9. Let 𝑘 be the result for which bytesi𝑁 (𝑘) = 𝑧.mems[𝑥].bytes[𝑖 + [Link] : 𝑁/8].
10. Let 𝑐 be lanes−1
i𝑁 x𝑀 (lanesi𝑁 x𝑀 (𝑐1 )[[𝑗] = 𝑘]).

11. Push the value ([Link] 𝑐) to the stack.


𝑧; ([Link] 𝑖) ([Link] 𝑐1 ) ([Link]𝑁 _lane 𝑥 ao 𝑗) ˓→ trap if 𝑖 + [Link] + 𝑁/8 > |𝑧.mems[𝑥].bytes|
𝑧; ([Link] 𝑖) ([Link] 𝑐1 ) ([Link]𝑁 _lane 𝑥 ao 𝑗) ˓→ ([Link] 𝑐)
if bytesi𝑁 (𝑘) = 𝑧.mems[𝑥].bytes[𝑖 + [Link] : 𝑁/8]
∧ 𝑁 = |i𝑁 |
∧ 𝑀 = |v128|/𝑁
∧ 𝑐 = lanes−1i𝑁 x𝑀 (lanesi𝑁 x𝑀 (𝑐1 )[[𝑗] = 𝑘])

[Link] ? 𝑥 ao
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a number value is on the top of the stack.
3. Pop the value (nt ′ .const 𝑐) from the stack.
4. Assert: Due to validation, a value is on the top of the stack.
5. Pop the value ([Link] 𝑖) from the stack.
6. Assert: Due to validation, nt = nt ′ .
7. If storeop ? is not defined, then:
a. If 𝑖 + [Link] + |nt ′ |/8 > |𝑧.mems[𝑥].bytes|, then:
1) Trap.
b. Let 𝑏* be bytesnt ′ (𝑐).
c. Replace 𝑧.mems[𝑥].bytes[𝑖 + [Link] : |nt ′ |/8] with 𝑏* .
8. Else:
a. Assert: Due to validation, nt ′ is i𝑁 .
b. Let 𝑛 be storeop ? .
c. If 𝑖 + [Link] + 𝑛/8 > |𝑧.mems[𝑥].bytes|, then:
1) Trap.
d. Let 𝑏* be bytesi𝑛 (wrap|nt ′ |,𝑛 (𝑐)).
e. Replace 𝑧.mems[𝑥].bytes[𝑖 + [Link] : 𝑛/8] with 𝑏* .
𝑧; ([Link] 𝑖) ([Link] 𝑐) ([Link] 𝑥 ao) ˓→ 𝑧; trap
if 𝑖 + [Link] + |nt|/8 > |𝑧.mems[𝑥].bytes|
𝑧; ([Link] 𝑖) ([Link] 𝑐) ([Link] 𝑥 ao) ˓→ 𝑧[.mems[𝑥].bytes[𝑖 + [Link] : |nt|/8] = 𝑏* ]; 𝜖
if 𝑏* = bytesnt (𝑐)
𝑧; ([Link] 𝑖) (i𝑁 .const 𝑐) (i𝑁 .store𝑛 𝑥 ao) ˓→ 𝑧; trap
if 𝑖 + [Link] + 𝑛/8 > |𝑧.mems[𝑥].bytes|
𝑧; ([Link] 𝑖) (i𝑁 .const 𝑐) (i𝑁 .store𝑛 𝑥 ao) ˓→ 𝑧[.mems[𝑥].bytes[𝑖 + [Link] : 𝑛/8] = 𝑏* ]; 𝜖
if 𝑏* = bytesi𝑛 (wrap|i𝑁 |,𝑛 (𝑐))
𝑧; ([Link] 𝑖) ([Link] 𝑐) ([Link] 𝑥 ao) ˓→ 𝑧; trap
if 𝑖 + [Link] + |v128|/8 > |𝑧.mems[𝑥].bytes|
𝑧; ([Link] 𝑖) ([Link] 𝑐) ([Link] 𝑥 ao) ˓→ 𝑧[.mems[𝑥].bytes[𝑖 + [Link] : |v128|/8] = 𝑏* ]; 𝜖
if 𝑏* = bytesv128 (𝑐)

140 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

[Link]𝑁 _lane 𝑥 ao 𝑗
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
3. Pop the value ([Link] 𝑐) from the stack.
4. Assert: Due to validation, a number value is on the top of the stack.
5. Pop the value ([Link] 𝑖) from the stack.
6. If 𝑖 + [Link] + 𝑁 > |𝑧.mems[𝑥].bytes|, then:
a. Trap.
7. Let 𝑀 be 128/𝑁 .
8. Let i𝑁 be the result for which |i𝑁 | = 𝑁 .
9. Assert: Due to validation, 𝑗 < |lanesi𝑁 x𝑀 (𝑐)|.
10. Let 𝑏* be bytesi𝑁 (lanesi𝑁 x𝑀 (𝑐)[𝑗]).
11. Replace 𝑧.mems[𝑥].bytes[𝑖 + [Link] : 𝑁/8] with 𝑏* .
𝑧; ([Link] 𝑖) ([Link] 𝑐) ([Link]𝑁 _lane 𝑥 ao 𝑗) ˓→ 𝑧; trap
if 𝑖 + [Link] + 𝑁 > |𝑧.mems[𝑥].bytes|
𝑧; ([Link] 𝑖) ([Link] 𝑐) ([Link]𝑁 _lane 𝑥 ao 𝑗) ˓→ 𝑧[.mems[𝑥].bytes[𝑖 + [Link] : 𝑁/8] = 𝑏* ]; 𝜖
if 𝑁 = |i𝑁 |
∧ 𝑀 = 128/𝑁
∧ 𝑏* = bytesi𝑁 (lanesi𝑁 x𝑀 (𝑐)[𝑗])

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Let (at lim page) be the destructuring of 𝑧.mems[𝑥].type.
3. Let 𝑛 · 64 Ki be the length of 𝑧.mems[𝑥].bytes.
4. Push the value ([Link] 𝑛) to the stack.
𝑧; ([Link] 𝑥) ˓→ ([Link] 𝑛) if 𝑛 · 64 Ki = |𝑧.mems[𝑥].bytes|
∧ 𝑧.mems[𝑥].type = at lim page

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a number value is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.
4. Either:
a. Let mi be the memory instance growmem(𝑧.mems[𝑥], 𝑛).
b. Push the value ([Link] |𝑧.mems[𝑥].bytes|/(64 Ki)) to the stack.
c. Replace 𝑧.mems[𝑥] with mi .
5. Or:
a. Push the value ([Link] signed−1
|at| (−1)) to the stack.

𝑧; ([Link] 𝑛) ([Link] 𝑥) ˓→ 𝑧[.mems[𝑥] = mi ]; ([Link] |𝑧.mems[𝑥].bytes|/64 Ki)


if mi = growmem(𝑧.mems[𝑥], 𝑛)
𝑧; ([Link] 𝑛) ([Link] 𝑥) ˓→ 𝑧; ([Link] signed−1
|at| (−1))

4.6. Instructions 141


WebAssembly Specification, Release 3.0 (2025-11-14)

Note

The [Link] instruction is non-deterministic. It may either succeed, returning the old memory size sz ,
or fail, returning −1. Failure must occur if the referenced memory instance has a maximum size defined that
would be exceeded. However, failure can occur in other cases as well. In practice, the choice depends on the
resources available to the embedder.

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a number value is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.
4. Assert: Due to validation, a value is on the top of the stack.
5. Pop the value val from the stack.
6. Assert: Due to validation, a value of number type at is on the top of the stack.
7. Pop the value (numtype 0 .const 𝑖) from the stack.
8. If 𝑖 + 𝑛 > |𝑧.mems[𝑥].bytes|, then:
a. Trap.
9. If 𝑛 = 0, then:
a. Do nothing.
10. Else:
a. Push the value ([Link] 𝑖) to the stack.
b. Push the value val to the stack.
c. Execute the instruction (i32.store8 𝑥).
d. Push the value ([Link] 𝑖 + 1) to the stack.
e. Push the value val to the stack.
f. Push the value ([Link] 𝑛 − 1) to the stack.
g. Execute the instruction ([Link] 𝑥).
𝑧; ([Link] 𝑖) val ([Link] 𝑛) ([Link] 𝑥) ˓→ trap if 𝑖 + 𝑛 > |𝑧.mems[𝑥].bytes|
𝑧; ([Link] 𝑖) val ([Link] 𝑛) ([Link] 𝑥) ˓→ 𝜖 otherwise, if 𝑛 = 0
𝑧; ([Link] 𝑖) val ([Link] 𝑛) ([Link] 𝑥) ˓→
([Link] 𝑖) val (i32.store8 𝑥) otherwise
([Link] 𝑖 + 1) val ([Link] 𝑛 − 1) ([Link] 𝑥)

[Link] 𝑥1 𝑥2
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a number value is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.
4. Assert: Due to validation, a number value is on the top of the stack.
5. Pop the value (at 2 .const 𝑖2 ) from the stack.
6. Assert: Due to validation, a number value is on the top of the stack.
7. Pop the value (at 1 .const 𝑖1 ) from the stack.
8. If 𝑖1 + 𝑛 > |𝑧.mems[𝑥1 ].bytes|, then:

142 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

a. Trap.
9. If 𝑖2 + 𝑛 > |𝑧.mems[𝑥2 ].bytes|, then:
a. Trap.
10. If 𝑛 = 0, then:
a. Do nothing.
11. Else:
a. If 𝑖1 ≤ 𝑖2 , then:
1) Push the value (at 1 .const 𝑖1 ) to the stack.
2) Push the value (at 2 .const 𝑖2 ) to the stack.
3) Execute the instruction (i32.load8_u 𝑥2 ).
4) Execute the instruction (i32.store8 𝑥1 ).
5) Push the value (at 1 .const 𝑖1 + 1) to the stack.
6) Push the value (at 2 .const 𝑖2 + 1) to the stack.
b. Else:
1) Push the value (at 1 .const 𝑖1 + 𝑛 − 1) to the stack.
2) Push the value (at 2 .const 𝑖2 + 𝑛 − 1) to the stack.
3) Execute the instruction (i32.load8_u 𝑥2 ).
4) Execute the instruction (i32.store8 𝑥1 ).
5) Push the value (at 1 .const 𝑖1 ) to the stack.
6) Push the value (at 2 .const 𝑖2 ) to the stack.
c. Push the value ([Link] 𝑛 − 1) to the stack.
d. Execute the instruction ([Link] 𝑥1 𝑥2 ).
𝑧; (at 1 .const 𝑖1 ) (at 2 .const 𝑖2 ) (at ′ .const 𝑛) ([Link] 𝑥1 𝑥2 ) ˓→ trap
if 𝑖1 + 𝑛 > |𝑧.mems[𝑥1 ].bytes| ∨ 𝑖2 + 𝑛 > |𝑧.mems[𝑥2 ].bytes|
𝑧; (at 1 .const 𝑖1 ) (at 2 .const 𝑖2 ) (at ′ .const 𝑛) ([Link] 𝑥1 𝑥2 ) ˓→ 𝜖 otherwise, if 𝑛 = 0
𝑧; (at 1 .const 𝑖1 ) (at 2 .const 𝑖2 ) (at ′ .const 𝑛) ([Link] 𝑥1 𝑥2 ) ˓→
(at 1 .const 𝑖1 ) (at 2 .const 𝑖2 ) (i32.load8_u 𝑥2 ) (i32.store8 𝑥1 ) otherwise, if 𝑖1 ≤ 𝑖2
(at 1 .const 𝑖1 + 1) (at 2 .const 𝑖2 + 1) (at ′ .const 𝑛 − 1) ([Link] 𝑥1 𝑥2 )
𝑧; (at 1 .const 𝑖1 ) (at 2 .const 𝑖2 ) (at ′ .const 𝑛) ([Link] 𝑥1 𝑥2 ) ˓→
(at 1 .const 𝑖1 + 𝑛 − 1) (at 2 .const 𝑖2 + 𝑛 − 1) (i32.load8_u 𝑥2 ) (i32.store8 𝑥1 ) otherwise
(at 1 .const 𝑖1 ) (at 2 .const 𝑖2 ) (at ′ .const 𝑛 − 1) ([Link] 𝑥1 𝑥2 )

[Link] 𝑥 𝑦
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value of number type i32 is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.
4. Assert: Due to validation, a value of number type i32 is on the top of the stack.
5. Pop the value ([Link] 𝑗) from the stack.
6. Assert: Due to validation, a number value is on the top of the stack.
7. Pop the value ([Link] 𝑖) from the stack.
8. If 𝑖 + 𝑛 > |𝑧.mems[𝑥].bytes|, then:
a. Trap.

4.6. Instructions 143


WebAssembly Specification, Release 3.0 (2025-11-14)

9. If 𝑗 + 𝑛 > |𝑧.datas[𝑦].bytes|, then:


a. Trap.
10. If 𝑛 = 0, then:
a. Do nothing.
11. Else:
a. Assert: Due to validation, 𝑗 < |𝑧.datas[𝑦].bytes|.
b. Push the value ([Link] 𝑖) to the stack.
c. Push the value ([Link] 𝑧.datas[𝑦].bytes[𝑗]) to the stack.
d. Execute the instruction (i32.store8 𝑥).
e. Push the value ([Link] 𝑖 + 1) to the stack.
f. Push the value ([Link] 𝑗 + 1) to the stack.
g. Push the value ([Link] 𝑛 − 1) to the stack.
h. Execute the instruction ([Link] 𝑥 𝑦).
𝑧; ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) ([Link] 𝑥 𝑦) ˓→ trap
if 𝑖 + 𝑛 > |𝑧.mems[𝑥].bytes| ∨ 𝑗 + 𝑛 > |𝑧.datas[𝑦].bytes|
𝑧; ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) ([Link] 𝑥 𝑦) ˓→ 𝜖 otherwise, if 𝑛 = 0
𝑧; ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) ([Link] 𝑥 𝑦) ˓→
([Link] 𝑖) ([Link] 𝑧.datas[𝑦].bytes[𝑗]) (i32.store8 𝑥) otherwise
([Link] 𝑖 + 1) ([Link] 𝑗 + 1) ([Link] 𝑛 − 1) ([Link] 𝑥 𝑦)

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Replace 𝑧.datas[𝑥].bytes with 𝜖.
𝑧; ([Link] 𝑥) ˓→ 𝑧[.datas[𝑥].bytes = 𝜖]; 𝜖

4.6.9 Reference Instructions


[Link] 𝑥
1. Let 𝐹 be the current frame.
2. Assert: due to validation, the defined type 𝐹.[Link][𝑥] exists.
3. Let deftype be the defined type 𝐹.[Link][𝑥].
4. Push the value [Link] deftype to the stack.
𝑧; ([Link] 𝑥) ˓→ ([Link] 𝑧.types[𝑥])

Note

No formal reduction rule is required for the case [Link] absheaptype, since the instruction form is already a
value.

144 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, 𝑥 < |𝑧.[Link]|.
3. Push the value ([Link] 𝑧.[Link][𝑥]) to the stack.
𝑧; ([Link] 𝑥) ˓→ ([Link] 𝑧.[Link][𝑥])

ref.is_null
1. Assert: Due to validation, a reference value is on the top of the stack.
2. Pop the value ref from the stack.
3. If ref is some [Link] heaptype, then:
a. Push the value ([Link] 1) to the stack.
4. Else:
a. Push the value ([Link] 0) to the stack.
ref ref.is_null ˓→ ([Link] 1) if ref = ([Link] ht)
ref ref.is_null ˓→ ([Link] 0) otherwise

ref.as_non_null
1. Assert: Due to validation, a reference value is on the top of the stack.
2. Pop the value ref from the stack.
3. If ref is some [Link] heaptype, then:
a. Trap.
4. Push the value ref to the stack.
ref ref.as_non_null ˓→ trap if ref = ([Link] ht)
ref ref.as_non_null ˓→ ref otherwise

[Link]
1. Assert: Due to validation, a reference value is on the top of the stack.
2. Pop the value ref 2 from the stack.
3. Assert: Due to validation, a reference value is on the top of the stack.
4. Pop the value ref 1 from the stack.
5. If ref 1 is some [Link] heaptype and ref 2 is some [Link] heaptype, then:
a. Push the value ([Link] 1) to the stack.
6. Else if ref 1 = ref 2 , then:
a. Push the value ([Link] 1) to the stack.
7. Else:
a. Push the value ([Link] 0) to the stack.
ref 1 ref 2 [Link] ˓→ ([Link] 1) if ref 1 = ([Link] ht 1 ) ∧ ref 2 = ([Link] ht 2 )
ref 1 ref 2 [Link] ˓→ ([Link] 1) otherwise, if ref 1 = ref 2
ref 1 ref 2 [Link] ˓→ ([Link] 0) otherwise

4.6. Instructions 145


WebAssembly Specification, Release 3.0 (2025-11-14)

[Link] rt
1. Let 𝑓 be the topmost frame.
2. Assert: Due to validation, a reference value is on the top of the stack.
3. Pop the value ref from the stack.
4. Let rt ′ be the type of ref .
5. If rt ′ matches clos𝑓.module (rt), then:
a. Push the value ([Link] 1) to the stack.
6. Else:
a. Push the value ([Link] 0) to the stack.
𝑠; 𝑓 ; ref ([Link] rt) ˓→ ([Link] 1) if 𝑠 ⊢ ref : rt ′
∧ {} ⊢ rt ′ ≤ clos𝑓.module (rt)
𝑠; 𝑓 ; ref ([Link] rt) ˓→ ([Link] 0) otherwise

[Link] rt
1. Let 𝑓 be the topmost frame.
2. Assert: Due to validation, a reference value is on the top of the stack.
3. Pop the value ref from the stack.
4. Let rt ′ be the type of ref .
5. If rt ′ does not match clos𝑓.module (rt), then:
a. Trap.
6. Push the value ref to the stack.
𝑠; 𝑓 ; ref ([Link] rt) ˓→ ref if 𝑠 ⊢ ref : rt ′
∧ {} ⊢ rt ′ ≤ clos𝑓.module (rt)
𝑠; 𝑓 ; ref ([Link] rt) ˓→ trap otherwise

ref.i31
1. Assert: Due to validation, a value of number type i32 is on the top of the stack.
2. Pop the value ([Link] 𝑖) from the stack.
3. Push the value (ref.i31 wrap32,31 (𝑖)) to the stack.
([Link] 𝑖) ref.i31 ˓→ (ref.i31 wrap32,31 (𝑖))

i31.get_sx
1. Assert: Due to validation, a value is on the top of the stack.
2. Pop the value val from the stack.
3. If val is some [Link] heaptype, then:
a. Trap.
4. Assert: Due to validation, val is some ref.i31 u31 .
5. Let (ref.i31 𝑖) be the destructuring of val .
6. Push the value ([Link] extendsx
31,32 (𝑖)) to the stack.

([Link] ht) (i31.get_sx ) ˓→ trap


(ref.i31 𝑖) (i31.get_sx ) ˓→ ([Link] extendsx
31,32 (𝑖))

146 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, the expansion of 𝑧.types[𝑥] is some struct list(fieldtype).
3. Let (struct list 0 ) be the destructuring of the expansion of 𝑧.types[𝑥].
4. Let (mut? zt)𝑛 be list 0 .
5. Let 𝑎 be the length of 𝑧.structs.
6. Assert: Due to validation, there are at least 𝑛 values on the top of the stack.
7. Pop the values val 𝑛 from the stack.
8. Let si be the structure instance {type 𝑧.types[𝑥], fields packzt (val )𝑛 }.
9. Push the value ([Link] 𝑎) to the stack.
10. Append si to 𝑧.structs.
𝑧; val 𝑛 ([Link] 𝑥) ˓→ 𝑧[.structs =⊕ si ]; ([Link] 𝑎) if 𝑧.types[𝑥] ≈ struct (mut? zt)𝑛
∧ 𝑎 = |𝑧.structs|
∧ si = {type 𝑧.types[𝑥], fields (packzt (val ))𝑛 }

struct.new_default 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, the expansion of 𝑧.types[𝑥] is some struct list(fieldtype).
3. Let (struct list 0 ) be the destructuring of the expansion of 𝑧.types[𝑥].
4. Let (mut? zt)* be list 0 .
5. Assert: Due to validation, for all zt in zt * , defaultunpack(zt) is defined.
6. Let val * be the value sequence 𝜖.
7. For each zt in zt * , do:
a. Let val be defaultunpack(zt) .
b. Append val to val * .
8. Assert: Due to validation, |val * | = |zt * |.
9. Push the values val * to the stack.
10. Execute the instruction ([Link] 𝑥).
𝑧; (struct.new_default 𝑥) ˓→ val * ([Link] 𝑥) if 𝑧.types[𝑥] ≈ struct (mut? zt)*
∧ (defaultunpack(zt) = val )*

struct.get_sx ? 𝑥 𝑖
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value is on the top of the stack.
3. Pop the value val from the stack.
4. If val is some [Link] heaptype, then:
a. Trap.
5. Assert: Due to validation, val is some [Link] structaddr .
6. Let ([Link] 𝑎) be the destructuring of val .
7. Assert: Due to validation, 𝑖 < |𝑧.structs[𝑎].fields|.
8. Assert: Due to validation, 𝑎 < |𝑧.structs|.

4.6. Instructions 147


WebAssembly Specification, Release 3.0 (2025-11-14)

9. Assert: Due to validation, the expansion of 𝑧.types[𝑥] is some struct list(fieldtype).


10. Let (struct list 0 ) be the destructuring of the expansion of 𝑧.types[𝑥].
11. Let (mut? zt)* be list 0 .
12. Assert: Due to validation, 𝑖 < |zt * |.
?
13. Push the value unpacksx
zt * [𝑖] (𝑧.structs[𝑎].fields[𝑖]) to the stack.

𝑧; ([Link] ht) (struct.get_sx ? 𝑥 𝑖) ˓→ trap


?
𝑧; ([Link] 𝑎) (struct.get_sx ? 𝑥 𝑖) ˓→ unpacksx zt * [𝑖] (𝑧.structs[𝑎].fields[𝑖])
if 𝑧.types[𝑥] ≈ struct (mut? zt)*

[Link] 𝑥 𝑖
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value is on the top of the stack.
3. Pop the value val from the stack.
4. Assert: Due to validation, a value is on the top of the stack.
5. Pop the value val ′ from the stack.
6. If val ′ is some [Link] heaptype, then:
a. Trap.
7. Assert: Due to validation, val ′ is some [Link] structaddr .
8. Let ([Link] 𝑎) be the destructuring of val ′ .
9. Assert: Due to validation, the expansion of 𝑧.types[𝑥] is some struct list(fieldtype).
10. Let (struct list 0 ) be the destructuring of the expansion of 𝑧.types[𝑥].
11. Let (mut? zt)* be list 0 .
12. Assert: Due to validation, 𝑖 < |zt * |.
13. Replace 𝑧.structs[𝑎].fields[𝑖] with packzt * [𝑖] (val ).
𝑧; ([Link] ht) val ([Link] 𝑥 𝑖) ˓→ 𝑧; trap
𝑧; ([Link] 𝑎) val ([Link] 𝑥 𝑖) ˓→ 𝑧[.structs[𝑎].fields[𝑖] = packzt * [𝑖] (val )]; 𝜖
if 𝑧.types[𝑥] ≈ struct (mut? zt)*

[Link] 𝑥
1. Assert: Due to validation, a value of number type i32 is on the top of the stack.
2. Pop the value ([Link] 𝑛) from the stack.
3. Assert: Due to validation, a value is on the top of the stack.
4. Pop the value val from the stack.
5. Push the values val 𝑛 to the stack.
6. Execute the instruction (array.new_fixed 𝑥 𝑛).
val ([Link] 𝑛) ([Link] 𝑥) ˓→ val 𝑛 (array.new_fixed 𝑥 𝑛)

148 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

array.new_default 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value of number type i32 is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.
4. Assert: Due to validation, the expansion of 𝑧.types[𝑥] is some array fieldtype.
5. Let (array fieldtype 0 ) be the destructuring of the expansion of 𝑧.types[𝑥].
6. Let (mut? zt) be the destructuring of fieldtype 0 .
7. Assert: Due to validation, defaultunpack(zt) is defined.
8. Let val be defaultunpack(zt) .
9. Push the values val 𝑛 to the stack.
10. Execute the instruction (array.new_fixed 𝑥 𝑛).
𝑧; ([Link] 𝑛) (array.new_default 𝑥) ˓→ val 𝑛 (array.new_fixed 𝑥 𝑛) if 𝑧.types[𝑥] ≈ array (mut? zt)
∧ defaultunpack(zt) = val

array.new_fixed 𝑥 𝑛
1. Let 𝑧 be the current state.
2. Assert: Due to validation, the expansion of 𝑧.types[𝑥] is some array fieldtype.
3. Let (array fieldtype 0 ) be the destructuring of the expansion of 𝑧.types[𝑥].
4. Let (mut? zt) be the destructuring of fieldtype 0 .
5. Let 𝑎 be the length of 𝑧.arrays.
6. Assert: Due to validation, there are at least 𝑛 values on the top of the stack.
7. Pop the values val 𝑛 from the stack.
8. Let ai be the array instance {type 𝑧.types[𝑥], fields packzt (val )𝑛 }.
9. Push the value ([Link] 𝑎) to the stack.
10. Append ai to 𝑧.arrays.
𝑧; val 𝑛 (array.new_fixed 𝑥 𝑛) ˓→ 𝑧[.arrays =⊕ ai ]; ([Link] 𝑎)
if 𝑧.types[𝑥] ≈ array (mut? zt)
∧ 𝑎 = |𝑧.arrays| ∧ ai = {type 𝑧.types[𝑥], fields (packzt (val ))𝑛 }

array.new_data 𝑥 𝑦
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value of number type i32 is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.
4. Assert: Due to validation, a value of number type i32 is on the top of the stack.
5. Pop the value ([Link] 𝑖) from the stack.
6. Assert: Due to validation, the expansion of 𝑧.types[𝑥] is some array fieldtype.
7. Let (array fieldtype 0 ) be the destructuring of the expansion of 𝑧.types[𝑥].
8. Let (mut? zt) be the destructuring of fieldtype 0 .
9. If 𝑖 + 𝑛 · |zt|/8 > |𝑧.datas[𝑦].bytes|, then:
a. Trap.

4.6. Instructions 149


WebAssembly Specification, Release 3.0 (2025-11-14)

* *
10. Let byte * be the result for which each byte * has length |zt|/8, and the concatenation of byte * is
𝑧.datas[𝑦].bytes[𝑖 : 𝑛 · |zt|/8].
11. Let 𝑐𝑛 be the result for which (byteszt (𝑐𝑛 ) = byte * )* .
12. Push the values unpack(zt).const unpackzt (𝑐)𝑛 to the stack.
13. Execute the instruction (array.new_fixed 𝑥 𝑛).
𝑧; ([Link] 𝑖) ([Link] 𝑛) (array.new_data 𝑥 𝑦) ˓→ trap
if 𝑧.types[𝑥] ≈ array (mut? zt)
∧ 𝑖 + 𝑛 · |zt|/8 > |𝑧.datas[𝑦].bytes|
𝑧; ([Link] 𝑖) ([Link] 𝑛) (array.new_data 𝑥 𝑦) ˓→ (unpack(zt).const unpackzt (𝑐))𝑛 (array.new_fixed 𝑥 𝑛)
if 𝑧.types[𝑥] ≈ array (mut? zt)
byteszt (𝑐)𝑛 = 𝑧.datas[𝑦].bytes[𝑖 : 𝑛 · |zt|/8]
⨁︀

array.new_elem 𝑥 𝑦
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value of number type i32 is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.
4. Assert: Due to validation, a value of number type i32 is on the top of the stack.
5. Pop the value ([Link] 𝑖) from the stack.
6. If 𝑖 + 𝑛 > |𝑧.elems[𝑦].elem|, then:
a. Trap.
7. Let ref 𝑛 be 𝑧.elems[𝑦].elem[𝑖 : 𝑛].
8. Push the values ref 𝑛 to the stack.
9. Execute the instruction (array.new_fixed 𝑥 𝑛).
𝑧; ([Link] 𝑖) ([Link] 𝑛) (array.new_elem 𝑥 𝑦) ˓→ trap if 𝑖 + 𝑛 > |𝑧.elems[𝑦].elem|
𝑧; ([Link] 𝑖) ([Link] 𝑛) (array.new_elem 𝑥 𝑦) ˓→ ref 𝑛 (array.new_fixed 𝑥 𝑛)
if ref 𝑛 = 𝑧.elems[𝑦].elem[𝑖 : 𝑛]

array.get_sx ? 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value of number type i32 is on the top of the stack.
3. Pop the value ([Link] 𝑖) from the stack.
4. Assert: Due to validation, a value is on the top of the stack.
5. Pop the value val from the stack.
6. If val is some [Link] heaptype, then:
a. Trap.
7. Assert: Due to validation, val is some [Link] arrayaddr .
8. Let ([Link] 𝑎) be the destructuring of val .
9. If 𝑎 < |𝑧.arrays| and 𝑖 ≥ |𝑧.arrays[𝑎].fields|, then:
a. Trap.
10. If 𝑖 < |𝑧.arrays[𝑎].fields| and 𝑎 < |𝑧.arrays|, then:
a. Assert: Due to validation, the expansion of 𝑧.types[𝑥] is some array fieldtype.
b. Let (array fieldtype 0 ) be the destructuring of the expansion of 𝑧.types[𝑥].
c. Let (mut? zt) be the destructuring of fieldtype 0 .

150 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

?
d. Push the value unpacksx
zt (𝑧.arrays[𝑎].fields[𝑖]) to the stack.

𝑧; ([Link] ht) ([Link] 𝑖) (array.get_sx ? 𝑥) ˓→ trap


𝑧; ([Link] 𝑎) ([Link] 𝑖) (array.get_sx ? 𝑥) ˓→ trap if 𝑖 ≥ |𝑧.arrays[𝑎].fields|
?
𝑧; ([Link] 𝑎) ([Link] 𝑖) (array.get_sx ? 𝑥) ˓→ unpacksx zt (𝑧.arrays[𝑎].fields[𝑖])
if 𝑧.types[𝑥] ≈ array (mut? zt)

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value is on the top of the stack.
3. Pop the value val from the stack.
4. Assert: Due to validation, a value of number type i32 is on the top of the stack.
5. Pop the value ([Link] 𝑖) from the stack.
6. Assert: Due to validation, a value is on the top of the stack.
7. Pop the value val ′ from the stack.
8. If val ′ is some [Link] heaptype, then:
a. Trap.
9. Assert: Due to validation, val ′ is some [Link] arrayaddr .
10. Let ([Link] 𝑎) be the destructuring of val ′ .
11. If 𝑎 < |𝑧.arrays| and 𝑖 ≥ |𝑧.arrays[𝑎].fields|, then:
a. Trap.
12. Assert: Due to validation, the expansion of 𝑧.types[𝑥] is some array fieldtype.
13. Let (array fieldtype 0 ) be the destructuring of the expansion of 𝑧.types[𝑥].
14. Let (mut? zt) be the destructuring of fieldtype 0 .
15. Replace 𝑧.arrays[𝑎].fields[𝑖] with packzt (val ).
𝑧; ([Link] ht) ([Link] 𝑖) val ([Link] 𝑥) ˓→ 𝑧; trap
𝑧; ([Link] 𝑎) ([Link] 𝑖) val ([Link] 𝑥) ˓→ 𝑧; trap if 𝑖 ≥ |𝑧.arrays[𝑎].fields|
𝑧; ([Link] 𝑎) ([Link] 𝑖) val ([Link] 𝑥) ˓→ 𝑧[.arrays[𝑎].fields[𝑖] = packzt (val )]; 𝜖
if 𝑧.types[𝑥] ≈ array (mut? zt)

[Link]
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value is on the top of the stack.
3. Pop the value val from the stack.
4. If val is some [Link] heaptype, then:
a. Trap.
5. Assert: Due to validation, val is some [Link] arrayaddr .
6. Let ([Link] 𝑎) be the destructuring of val .
7. Assert: Due to validation, 𝑎 < |𝑧.arrays|.
8. Push the value ([Link] |𝑧.arrays[𝑎].fields|) to the stack.
𝑧; ([Link] ht) [Link] ˓→ trap
𝑧; ([Link] 𝑎) [Link] ˓→ ([Link] |𝑧.arrays[𝑎].fields|)

4.6. Instructions 151


WebAssembly Specification, Release 3.0 (2025-11-14)

[Link] 𝑥
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value of number type i32 is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.
4. Assert: Due to validation, a value is on the top of the stack.
5. Pop the value val from the stack.
6. Assert: Due to validation, a value of number type i32 is on the top of the stack.
7. Pop the value ([Link] 𝑖) from the stack.
8. Assert: Due to validation, a value is on the top of the stack.
9. Pop the value val ′ from the stack.
10. If val ′ is some [Link] heaptype, then:
a. Trap.
11. Assert: Due to validation, val ′ is some [Link] arrayaddr .
12. Let ([Link] 𝑎) be the destructuring of val ′ .
13. If 𝑎 ≥ |𝑧.arrays|, then:
a. Do nothing.
14. Else if 𝑖 + 𝑛 > |𝑧.arrays[𝑎].fields|, then:
a. Trap.
15. If 𝑛 = 0, then:
a. Do nothing.
16. Else:
a. Push the value ([Link] 𝑎) to the stack.
b. Push the value ([Link] 𝑖) to the stack.
c. Push the value val to the stack.
d. Execute the instruction ([Link] 𝑥).
e. Push the value ([Link] 𝑎) to the stack.
f. Push the value ([Link] 𝑖 + 1) to the stack.
g. Push the value val to the stack.
h. Push the value ([Link] 𝑛 − 1) to the stack.
i. Execute the instruction ([Link] 𝑥).
𝑧; ([Link] ht) ([Link] 𝑖) val ([Link] 𝑛) ([Link] 𝑥) ˓→ trap
𝑧; ([Link] 𝑎) ([Link] 𝑖) val ([Link] 𝑛) ([Link] 𝑥) ˓→ trap if 𝑖 + 𝑛 > |𝑧.arrays[𝑎].fields|
𝑧; ([Link] 𝑎) ([Link] 𝑖) val ([Link] 𝑛) ([Link] 𝑥) ˓→ 𝜖 otherwise, if 𝑛 = 0
𝑧; ([Link] 𝑎) ([Link] 𝑖) val ([Link] 𝑛) ([Link] 𝑥) ˓→
([Link] 𝑎) ([Link] 𝑖) val ([Link] 𝑥) otherwise
([Link] 𝑎) ([Link] 𝑖 + 1) val ([Link] 𝑛 − 1) ([Link] 𝑥)

[Link] 𝑥1 𝑥2
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value of number type i32 is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.

152 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

4. Assert: Due to validation, a value of number type i32 is on the top of the stack.
5. Pop the value ([Link] 𝑖2 ) from the stack.
6. Assert: Due to validation, a value is on the top of the stack.
7. Pop the value val from the stack.
8. Assert: Due to validation, a value of number type i32 is on the top of the stack.
9. Pop the value ([Link] 𝑖1 ) from the stack.
10. Assert: Due to validation, a value is on the top of the stack.
11. Pop the value val ′ from the stack.
12. If val ′ is some [Link] heaptype and val is reference value, then:
a. Trap.
13. If val is some [Link] heaptype and val ′ is reference value, then:
a. Trap.
14. If val ′ is some [Link] arrayaddr , then:
a. Let ([Link] 𝑎1 ) be the destructuring of val ′ .
b. If val is some [Link] arrayaddr , then:
1) If 𝑎1 < |𝑧.arrays| and 𝑖1 + 𝑛 > |𝑧.arrays[𝑎1 ].fields|, then:
a) Trap.
2) Let ([Link] 𝑎2 ) be the destructuring of val .
3) If 𝑎2 ≥ |𝑧.arrays|, then:
a) Do nothing.
4) Else if 𝑖2 + 𝑛 > |𝑧.arrays[𝑎2 ].fields|, then:
a) Trap.
5) If 𝑛 = 0, then:
a) Do nothing.
6) Else:
a) Assert: Due to validation, the expansion of 𝑧.types[𝑥2 ] is some array fieldtype.
b) Let (array fieldtype 0 ) be the destructuring of the expansion of 𝑧.types[𝑥2 ].
c) Let (mut? zt 2 ) be the destructuring of fieldtype 0 .
d) Let sx ? be sx (zt 2 ).
e) Push the value ([Link] 𝑎1 ) to the stack.
f) If 𝑖1 ≤ 𝑖2 , then:
1. Push the value ([Link] 𝑖1 ) to the stack.
2. Push the value ([Link] 𝑎2 ) to the stack.
3. Push the value ([Link] 𝑖2 ) to the stack.
4. Execute the instruction (array.get_sx ? 𝑥2 ).
5. Execute the instruction ([Link] 𝑥1 ).
6. Push the value ([Link] 𝑎1 ) to the stack.
7. Push the value ([Link] 𝑖1 + 1) to the stack.
8. Push the value ([Link] 𝑎2 ) to the stack.

4.6. Instructions 153


WebAssembly Specification, Release 3.0 (2025-11-14)

9. Push the value ([Link] 𝑖2 + 1) to the stack.


g) Else:
1. Push the value ([Link] 𝑖1 + 𝑛 − 1) to the stack.
2. Push the value ([Link] 𝑎2 ) to the stack.
3. Push the value ([Link] 𝑖2 + 𝑛 − 1) to the stack.
4. Execute the instruction (array.get_sx ? 𝑥2 ).
5. Execute the instruction ([Link] 𝑥1 ).
6. Push the value ([Link] 𝑎1 ) to the stack.
7. Push the value ([Link] 𝑖1 ) to the stack.
8. Push the value ([Link] 𝑎2 ) to the stack.
9. Push the value ([Link] 𝑖2 ) to the stack.
h) Push the value ([Link] 𝑛 − 1) to the stack.
i) Execute the instruction ([Link] 𝑥1 𝑥2 ).
𝑧; ([Link] ht 1 ) ([Link] 𝑖1 ) ref ([Link] 𝑖2 ) ([Link] 𝑛) ([Link] 𝑥1 𝑥2 ) ˓→ trap
𝑧; ref ([Link] 𝑖1 ) ([Link] ht 2 ) ([Link] 𝑖2 ) ([Link] 𝑛) ([Link] 𝑥1 𝑥2 ) ˓→ trap
𝑧; ([Link] 𝑎1 ) ([Link] 𝑖1 ) ([Link] 𝑎2 ) ([Link] 𝑖2 ) ([Link] 𝑛) ([Link] 𝑥1 𝑥2 ) ˓→ trap
if 𝑖1 + 𝑛 > |𝑧.arrays[𝑎1 ].fields|
𝑧; ([Link] 𝑎1 ) ([Link] 𝑖1 ) ([Link] 𝑎2 ) ([Link] 𝑖2 ) ([Link] 𝑛) ([Link] 𝑥1 𝑥2 ) ˓→ trap
if 𝑖2 + 𝑛 > |𝑧.arrays[𝑎2 ].fields|
𝑧; ([Link] 𝑎1 ) ([Link] 𝑖1 ) ([Link] 𝑎2 ) ([Link] 𝑖2 ) ([Link] 𝑛) ([Link] 𝑥1 𝑥2 ) ˓→ 𝜖
otherwise, if 𝑛 = 0
𝑧; ([Link] 𝑎1 ) ([Link] 𝑖1 ) ([Link] 𝑎2 ) ([Link] 𝑖2 ) ([Link] 𝑛) ([Link] 𝑥1 𝑥2 ) ˓→
([Link] 𝑎1 ) ([Link] 𝑖1 )
([Link] 𝑎2 ) ([Link] 𝑖2 )
(array.get_sx ? 𝑥2 ) ([Link] 𝑥1 )
([Link] 𝑎1 ) ([Link] 𝑖1 + 1) ([Link] 𝑎2 ) ([Link] 𝑖2 + 1) ([Link] 𝑛 − 1) ([Link] 𝑥1 𝑥2 )
otherwise, if 𝑧.types[𝑥2 ] ≈ array (mut? zt 2 )
∧ 𝑖1 ≤ 𝑖2 ∧ sx ? = sx (zt 2 )
𝑧; ([Link] 𝑎1 ) ([Link] 𝑖1 ) ([Link] 𝑎2 ) ([Link] 𝑖2 ) ([Link] 𝑛) ([Link] 𝑥1 𝑥2 ) ˓→
([Link] 𝑎1 ) ([Link] 𝑖1 + 𝑛 − 1)
([Link] 𝑎2 ) ([Link] 𝑖2 + 𝑛 − 1)
(array.get_sx ? 𝑥2 ) ([Link] 𝑥1 )
([Link] 𝑎1 ) ([Link] 𝑖1 ) ([Link] 𝑎2 ) ([Link] 𝑖2 ) ([Link] 𝑛 − 1) ([Link] 𝑥1 𝑥2 )
otherwise, if 𝑧.types[𝑥2 ] ≈ array (mut? zt 2 )
∧ sx ? = sx (zt 2 )
Where:

sx (consttype) = 𝜖
sx (packtype) = s

array.init_data 𝑥 𝑦
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value of number type i32 is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.
4. Assert: Due to validation, a value of number type i32 is on the top of the stack.
5. Pop the value ([Link] 𝑗) from the stack.
6. Assert: Due to validation, a value of number type i32 is on the top of the stack.

154 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

7. Pop the value ([Link] 𝑖) from the stack.


8. Assert: Due to validation, a value is on the top of the stack.
9. Pop the value val from the stack.
10. If val is some [Link] heaptype, then:
a. Trap.
11. Assert: Due to validation, val is some [Link] arrayaddr .
12. Let ([Link] 𝑎) be the destructuring of val .
13. If 𝑎 < |𝑧.arrays| and 𝑖 + 𝑛 > |𝑧.arrays[𝑎].fields|, then:
a. Trap.
14. If the expansion of 𝑧.types[𝑥] is some array fieldtype, then:
a. Let (array fieldtype 0 ) be the destructuring of the expansion of 𝑧.types[𝑥].
b. Let (mut? zt) be the destructuring of fieldtype 0 .
c. If 𝑗 + 𝑛 · |zt|/8 > |𝑧.datas[𝑦].bytes|, then:
1) Trap.
d. If 𝑛 = 0, then:
1) Do nothing.
e. Else:
1) Let 𝑐 be the result for which byteszt (𝑐) = 𝑧.datas[𝑦].bytes[𝑗 : |zt|/8].
2) Push the value ([Link] 𝑎) to the stack.
3) Push the value ([Link] 𝑖) to the stack.
4) Push the value unpack(zt).const unpackzt (𝑐) to the stack.
5) Execute the instruction ([Link] 𝑥).
6) Push the value ([Link] 𝑎) to the stack.
7) Push the value ([Link] 𝑖 + 1) to the stack.
8) Push the value ([Link] 𝑗 + |zt|/8) to the stack.
9) Push the value ([Link] 𝑛 − 1) to the stack.
10) Execute the instruction (array.init_data 𝑥 𝑦).
15. Else if 𝑛 = 0, then:
a. Do nothing.
𝑧; ([Link] ht) ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) (array.init_data 𝑥 𝑦) ˓→ trap
𝑧; ([Link] 𝑎) ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) (array.init_data 𝑥 𝑦) ˓→ trap
if 𝑖 + 𝑛 > |𝑧.arrays[𝑎].fields|
𝑧; ([Link] 𝑎) ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) (array.init_data 𝑥 𝑦) ˓→ trap
if 𝑧.types[𝑥] ≈ array (mut? zt)
∧ 𝑗 + 𝑛 · |zt|/8 > |𝑧.datas[𝑦].bytes|
𝑧; ([Link] 𝑎) ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) (array.init_data 𝑥 𝑦) ˓→ 𝜖
otherwise, if 𝑛 = 0
𝑧; ([Link] 𝑎) ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) (array.init_data 𝑥 𝑦) ˓→
([Link] 𝑎) ([Link] 𝑖) (unpack(zt).const unpackzt (𝑐)) ([Link] 𝑥)
([Link] 𝑎) ([Link] 𝑖 + 1) ([Link] 𝑗 + |zt|/8) ([Link] 𝑛 − 1) (array.init_data 𝑥 𝑦)
otherwise, if 𝑧.types[𝑥] ≈ array (mut? zt)
∧ byteszt (𝑐) = 𝑧.datas[𝑦].bytes[𝑗 : |zt|/8]

4.6. Instructions 155


WebAssembly Specification, Release 3.0 (2025-11-14)

array.init_elem 𝑥 𝑦
1. Let 𝑧 be the current state.
2. Assert: Due to validation, a value of number type i32 is on the top of the stack.
3. Pop the value ([Link] 𝑛) from the stack.
4. Assert: Due to validation, a value of number type i32 is on the top of the stack.
5. Pop the value ([Link] 𝑗) from the stack.
6. Assert: Due to validation, a value of number type i32 is on the top of the stack.
7. Pop the value ([Link] 𝑖) from the stack.
8. Assert: Due to validation, a value is on the top of the stack.
9. Pop the value val from the stack.
10. If val is some [Link] heaptype, then:
a. Trap.
11. Assert: Due to validation, val is some [Link] arrayaddr .
12. Let ([Link] 𝑎) be the destructuring of val .
13. If 𝑎 < |𝑧.arrays| and 𝑖 + 𝑛 > |𝑧.arrays[𝑎].fields|, then:
a. Trap.
14. If 𝑗 + 𝑛 > |𝑧.elems[𝑦].elem|, then:
a. Trap.
15. If 𝑛 = 0, then:
a. Do nothing.
16. Else if 𝑗 < |𝑧.elems[𝑦].elem|, then:
a. Let ref be the reference value 𝑧.elems[𝑦].elem[𝑗].
b. Push the value ([Link] 𝑎) to the stack.
c. Push the value ([Link] 𝑖) to the stack.
d. Push the value ref to the stack.
e. Execute the instruction ([Link] 𝑥).
f. Push the value ([Link] 𝑎) to the stack.
g. Push the value ([Link] 𝑖 + 1) to the stack.
h. Push the value ([Link] 𝑗 + 1) to the stack.
i. Push the value ([Link] 𝑛 − 1) to the stack.
j. Execute the instruction (array.init_elem 𝑥 𝑦).
𝑧; ([Link] ht) ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) (array.init_elem 𝑥 𝑦) ˓→ trap
𝑧; ([Link] 𝑎) ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) (array.init_elem 𝑥 𝑦) ˓→ trap
if 𝑖 + 𝑛 > |𝑧.arrays[𝑎].fields|
𝑧; ([Link] 𝑎) ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) (array.init_elem 𝑥 𝑦) ˓→ trap
if 𝑗 + 𝑛 > |𝑧.elems[𝑦].elem|
𝑧; ([Link] 𝑎) ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) (array.init_elem 𝑥 𝑦) ˓→ 𝜖
otherwise, if 𝑛 = 0
𝑧; ([Link] 𝑎) ([Link] 𝑖) ([Link] 𝑗) ([Link] 𝑛) (array.init_elem 𝑥 𝑦) ˓→
([Link] 𝑎) ([Link] 𝑖) ref ([Link] 𝑥)
([Link] 𝑎) ([Link] 𝑖 + 1) ([Link] 𝑗 + 1) ([Link] 𝑛 − 1) (array.init_elem 𝑥 𝑦)
otherwise, if ref = 𝑧.elems[𝑦].elem[𝑗]

156 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

any.convert_extern
1. Assert: Due to validation, a value is on the top of the stack.
2. Pop the value val from the stack.
3. If val is some [Link] heaptype, then:
a. Push the value ([Link] any) to the stack.
4. If val is some [Link] addrref , then:
a. Let ([Link] addrref ) be the destructuring of val .
b. Push the value addrref to the stack.
([Link] ht) any.convert_extern ˓→ ([Link] any)
([Link] addrref ) any.convert_extern ˓→ addrref

extern.convert_any
1. Assert: Due to validation, a value is on the top of the stack.
2. Pop the value val from the stack.
3. If val is some [Link] heaptype, then:
a. Push the value ([Link] extern) to the stack.
4. If val is address value, then:
a. Push the value ([Link] val ) to the stack.
([Link] ht) extern.convert_any ˓→ ([Link] extern)
addrref extern.convert_any ˓→ ([Link] addrref )

4.6.10 Numeric Instructions


Numeric instructions are defined in terms of the generic numeric operators. The mapping of numeric instructions
to their underlying operators is expressed by the following definition:

op i𝑁 (𝑖1 , . . . , 𝑖𝑘 ) = iop 𝑁 (𝑖1 , . . . , 𝑖𝑘 )


op f𝑁 (𝑧1 , . . . , 𝑧𝑘 ) = fop 𝑁 (𝑧1 , . . . , 𝑧𝑘 )

And for conversion operators:


? ?
cvtop sx
𝑡1 ,𝑡2 (𝑐) = cvtop sx
|𝑡1 |,|𝑡2 | (𝑐)

Where the underlying operators are partial, the corresponding instruction will trap when the result is not defined.
Where the underlying operators are non-deterministic, because they may return one of multiple possible NaN
values, so are the corresponding instructions.

Note

For example, the result of instruction [Link] applied to operands 𝑖1 , 𝑖2 invokes addi32 (𝑖1 , 𝑖2 ), which maps to the
generic iadd32 (𝑖1 , 𝑖2 ) via the above definition. Similarly, i64.trunc_f 32_s applied to 𝑧 invokes truncsf32,i64 (𝑧),
which maps to the generic truncs 32,64 (𝑧).

[Link] 𝑐
1. Push the value ([Link] 𝑐) to the stack.

4.6. Instructions 157


WebAssembly Specification, Release 3.0 (2025-11-14)

Note

No formal reduction rule is required for this instruction, since const instructions already are values.

[Link]
1. Assert: Due to validation, a value of number type nt is on the top of the stack.
2. Pop the value (numtype 0 .const 𝑐1 ) from the stack.
3. If unop nt (𝑐1 ) is empty, then:
a. Trap.
4. Let 𝑐 be an element of unop nt (𝑐1 ).
5. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link]) ˓→ ([Link] 𝑐) if 𝑐 ∈ unop nt (𝑐1 )
([Link] 𝑐1 ) ([Link]) ˓→ trap if unop nt (𝑐1 ) = 𝜖

[Link]
1. Assert: Due to validation, a value of number type nt is on the top of the stack.
2. Pop the value (numtype 0 .const 𝑐2 ) from the stack.
3. Assert: Due to validation, a number value is on the top of the stack.
4. Pop the value (numtype 0 .const 𝑐1 ) from the stack.
5. If binop nt (𝑐1 , 𝑐2 ) is empty, then:
a. Trap.
6. Let 𝑐 be an element of binop nt (𝑐1 , 𝑐2 ).
7. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link] 𝑐2 ) ([Link]) ˓→ ([Link] 𝑐) if 𝑐 ∈ binop nt (𝑐1 , 𝑐2 )
([Link] 𝑐1 ) ([Link] 𝑐2 ) ([Link]) ˓→ trap if binop nt (𝑐1 , 𝑐2 ) = 𝜖

[Link]
1. Assert: Due to validation, a value of number type nt is on the top of the stack.
2. Pop the value (numtype 0 .const 𝑐1 ) from the stack.
3. Let 𝑐 be testop nt (𝑐1 ).
4. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link]) ˓→ ([Link] 𝑐) if 𝑐 = testop nt (𝑐1 )

[Link]
1. Assert: Due to validation, a value of number type nt is on the top of the stack.
2. Pop the value (numtype 0 .const 𝑐2 ) from the stack.
3. Assert: Due to validation, a number value is on the top of the stack.
4. Pop the value (numtype 0 .const 𝑐1 ) from the stack.
5. Let 𝑐 be relop nt (𝑐1 , 𝑐2 ).
6. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link] 𝑐2 ) ([Link]) ˓→ ([Link] 𝑐) if 𝑐 = relop nt (𝑐1 , 𝑐2 )

158 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

nt 2 .cvtop_nt 1
1. Assert: Due to validation, a value of number type nt 1 is on the top of the stack.
2. Pop the value (numtype 0 .const 𝑐1 ) from the stack.
3. If cvtop nt 1 ,nt 2 (𝑐1 ) is empty, then:
a. Trap.
4. Let 𝑐 be an element of cvtop nt 1 ,nt 2 (𝑐1 ).
5. Push the value (nt 2 .const 𝑐) to the stack.
(nt 1 .const 𝑐1 ) (nt 2 .cvtop_nt 1 ) ˓→ (nt 2 .const 𝑐) if 𝑐 ∈ cvtop nt 1 ,nt 2 (𝑐1 )
(nt 1 .const 𝑐1 ) (nt 2 .cvtop_nt 1 ) ˓→ trap if cvtop nt 1 ,nt 2 (𝑐1 ) = 𝜖

4.6.11 Vector Instructions


Vector instructions that operate bitwise are handled as integer operations of respective bit width.

op v𝑁 (𝑖1 , . . . , 𝑖𝑘 ) = iop 𝑁 (𝑖1 , . . . , 𝑖𝑘 )

Most other vector instructions are defined in terms of numeric operators that are applied lane-wise according to
the given shape.

op 𝑡x𝑁 (𝑛1 , . . . , 𝑛𝑘 ) = lanes−1 *


𝑡x𝑁 (op 𝑡 (𝑖1 , . . . , 𝑖𝑘 ) ) (if 𝑖*1 = lanes𝑡x𝑁 (𝑛1 ) ∧ · · · ∧ 𝑖*𝑘 = lanes𝑡x𝑁 (𝑛𝑘 )

Note

For example, the result of instruction [Link] applied to operands 𝑣1 , 𝑣2 invokes addi32x4 (𝑣1 , 𝑣2 ), which
maps to lanes−1 i32x4 (addi32 (𝑖1 , 𝑖2 ) ), where 𝑖1 and 𝑖2 are sequences resulting from invoking lanesi32x4 (𝑣1 ) and
* * *

lanesi32x4 (𝑣2 ) respectively.

For non-deterministic operators this definition is generalized to sets:

op 𝑡x𝑁 (𝑛1 , . . . , 𝑛𝑘 ) = {lanes−1 * * * * *


𝑡x𝑁 (𝑖 ) | 𝑖 ∈ ×(op 𝑡 (𝑖1 , . . . , 𝑖𝑘 ) ) ∧ 𝑖1 = lanes𝑡x𝑁 (𝑛1 ) ∧ · · · ∧ 𝑖𝑘 = lanes𝑡x𝑁 (𝑛𝑘 )}

where ×{𝑥* }𝑁 transforms a sequence of 𝑁 sets of values into a set of sequences of 𝑁 values by computing the
set product:

×(𝑆1 . . . 𝑆𝑁 ) = {𝑥1 . . . 𝑥𝑁 | 𝑥1 ∈ 𝑆1 ∧ · · · ∧ 𝑥𝑁 ∈ 𝑆𝑁 }

The remaining vector operators use individual definitions.

[Link] 𝑐
1. Push the value ([Link] 𝑐) to the stack.

Note

No formal reduction rule is required for this instruction, since const instructions are already values.

[Link]
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐1 ) from the stack.
3. Assert: Due to validation, |vvunop v128 (𝑐1 )| > 0.

4.6. Instructions 159


WebAssembly Specification, Release 3.0 (2025-11-14)

4. Let 𝑐 be an element of vvunop v128 (𝑐1 ).


5. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link]) ˓→ ([Link] 𝑐) if 𝑐 ∈ vvunop v128 (𝑐1 )

[Link]
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐2 ) from the stack.
3. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
4. Pop the value ([Link] 𝑐1 ) from the stack.
5. Assert: Due to validation, |vvbinop v128 (𝑐1 , 𝑐2 )| > 0.
6. Let 𝑐 be an element of vvbinop v128 (𝑐1 , 𝑐2 ).
7. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link] 𝑐2 ) ([Link]) ˓→ ([Link] 𝑐) if 𝑐 ∈ vvbinop v128 (𝑐1 , 𝑐2 )

[Link]
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐3 ) from the stack.
3. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
4. Pop the value ([Link] 𝑐2 ) from the stack.
5. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
6. Pop the value ([Link] 𝑐1 ) from the stack.
7. Assert: Due to validation, |vvternop v128 (𝑐1 , 𝑐2 , 𝑐3 )| > 0.
8. Let 𝑐 be an element of vvternop v128 (𝑐1 , 𝑐2 , 𝑐3 ).
9. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link] 𝑐2 ) ([Link] 𝑐3 ) ([Link]) ˓→ ([Link] 𝑐)
if 𝑐 ∈ vvternop v128 (𝑐1 , 𝑐2 , 𝑐3 )

v128.any_true
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐1 ) from the stack.
3. Let 𝑐 be inez|v128| (𝑐1 ).
4. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) (v128.any_true) ˓→ ([Link] 𝑐) if 𝑐 = inez|v128| (𝑐1 )

[Link]
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐1 ) from the stack.
3. If vunop sh (𝑐1 ) is empty, then:
a. Trap.
4. Let 𝑐 be an element of vunop sh (𝑐1 ).
5. Push the value ([Link] 𝑐) to the stack.

160 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

([Link] 𝑐1 ) ([Link]) ˓→ ([Link] 𝑐) if 𝑐 ∈ vunop sh (𝑐1 )


([Link] 𝑐1 ) ([Link]) ˓→ trap if vunop sh (𝑐1 ) = 𝜖

[Link]
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐2 ) from the stack.
3. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
4. Pop the value ([Link] 𝑐1 ) from the stack.
5. If vbinop sh (𝑐1 , 𝑐2 ) is empty, then:
a. Trap.
6. Let 𝑐 be an element of vbinop sh (𝑐1 , 𝑐2 ).
7. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link] 𝑐2 ) ([Link]) ˓→ ([Link] 𝑐) if 𝑐 ∈ vbinop sh (𝑐1 , 𝑐2 )
([Link] 𝑐1 ) ([Link] 𝑐2 ) ([Link]) ˓→ trap if vbinop sh (𝑐1 , 𝑐2 ) = 𝜖

[Link]
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐3 ) from the stack.
3. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
4. Pop the value ([Link] 𝑐2 ) from the stack.
5. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
6. Pop the value ([Link] 𝑐1 ) from the stack.
7. If vternop sh (𝑐1 , 𝑐2 , 𝑐3 ) is empty, then:
a. Trap.
8. Let 𝑐 be an element of vternop sh (𝑐1 , 𝑐2 , 𝑐3 ).
9. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link] 𝑐2 ) ([Link] 𝑐3 ) ([Link]) ˓→ ([Link] 𝑐) if 𝑐 ∈ vternop sh (𝑐1 , 𝑐2 , 𝑐3 )
([Link] 𝑐1 ) ([Link] 𝑐2 ) ([Link] 𝑐3 ) ([Link]) ˓→ trap if vternop sh (𝑐1 , 𝑐2 , 𝑐3 ) = 𝜖

i𝑁 x𝑀.all_true
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐1 ) from the stack.
3. Let 𝑖* be lanesi𝑁 x𝑀 (𝑐1 ).
4. Let 𝑐 be Π inez𝑁 (𝑖)* .
5. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) (i𝑁 x𝑀.all_true) ˓→ ([Link] 𝑐) if 𝑖* = lanesi𝑁 x𝑀 (𝑐1 )
∧ 𝑐 = Π (inez𝑁 (𝑖)* )

[Link]
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐2 ) from the stack.
3. Assert: Due to validation, a value of vector type v128 is on the top of the stack.

4.6. Instructions 161


WebAssembly Specification, Release 3.0 (2025-11-14)

4. Pop the value ([Link] 𝑐1 ) from the stack.


5. Let 𝑐 be vrelop sh (𝑐1 , 𝑐2 ).
6. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link] 𝑐2 ) ([Link]) ˓→ ([Link] 𝑐) if 𝑐 = vrelop sh (𝑐1 , 𝑐2 )

[Link]
1. Assert: Due to validation, a value of number type i32 is on the top of the stack.
2. Pop the value ([Link] 𝑖) from the stack.
3. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
4. Pop the value ([Link] 𝑐1 ) from the stack.
5. Let 𝑐 be vshiftop sh (𝑐1 , 𝑖).
6. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link] 𝑖) ([Link]) ˓→ ([Link] 𝑐) if 𝑐 = vshiftop sh (𝑐1 , 𝑖)

[Link]
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐1 ) from the stack.
3. Let 𝑐 be bitmasksh (𝑐1 ).
4. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link]) ˓→ ([Link] 𝑐) if 𝑐 = bitmasksh (𝑐1 )

[Link]
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐2 ) from the stack.
3. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
4. Pop the value ([Link] 𝑐1 ) from the stack.
5. Let 𝑐 be swizzlop sh (𝑐1 , 𝑐2 ).
6. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link] 𝑐2 ) ([Link]) ˓→ ([Link] 𝑐) if 𝑐 = swizzlop sh (𝑐1 , 𝑐2 )

[Link] 𝑖*
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐2 ) from the stack.
3. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
4. Pop the value ([Link] 𝑐1 ) from the stack.
5. Let 𝑐 be shufflesh (𝑖* , 𝑐1 , 𝑐2 ).
6. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link] 𝑐2 ) ([Link] 𝑖* ) ˓→ ([Link] 𝑐) if 𝑐 = shufflesh (𝑖* , 𝑐1 , 𝑐2 )

162 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

i𝑁 x𝑀.splat
1. Assert: Due to validation, a value is on the top of the stack.
2. Pop the value (numtype 0 .const 𝑐1 ) from the stack.
3. Assert: Due to validation, numtype 0 = unpack(i𝑁 ).
4. Let 𝑐 be lanes−1 𝑀
i𝑁 x𝑀 (packi𝑁 (𝑐1 ) ).

5. Push the value ([Link] 𝑐) to the stack.


(unpack(i𝑁 ).const 𝑐1 ) (i𝑁 x𝑀.splat) ˓→ ([Link] 𝑐) if 𝑐 = lanes−1 𝑀
i𝑁 x𝑀 (packi𝑁 (𝑐1 ) )

?
lanetypex𝑀.extract_lane_sx ′ 𝑖
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐1 ) from the stack.
?
3. If sx ′ is not defined, then:
a. Assert: Due to validation, lanetype is number type.
b. Assert: Due to validation, 𝑖 < |laneslanetypex𝑀 (𝑐1 )|.
c. Let 𝑐2 be laneslanetypex𝑀 (𝑐1 )[𝑖].
d. Push the value ([Link] 𝑐2 ) to the stack.
4. Else:
a. Assert: Due to validation, lanetype is packed type.
?
b. Let sx be sx ′ .
c. Assert: Due to validation, 𝑖 < |laneslanetypex𝑀 (𝑐1 )|.
d. Let 𝑐2 be extendsx
|lanetype|,32 (laneslanetypex𝑀 (𝑐1 )[𝑖]).

e. Push the value ([Link] 𝑐2 ) to the stack.


([Link] 𝑐1 ) (ntx𝑀.extract_lane 𝑖) ˓→ ([Link] 𝑐2 ) if 𝑐2 = lanesntx𝑀 (𝑐1 )[𝑖]
([Link] 𝑐1 ) (ptx𝑀.extract_lane_sx 𝑖) ˓→ ([Link] 𝑐2 ) if 𝑐2 = extendsx
|pt|,32 (lanesptx𝑀 (𝑐1 )[𝑖])

i𝑁 x𝑀.replace_lane 𝑖
1. Assert: Due to validation, a value is on the top of the stack.
2. Pop the value (numtype 0 .const 𝑐2 ) from the stack.
3. Assert: Due to validation, numtype 0 = unpack(i𝑁 ).
4. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
5. Pop the value ([Link] 𝑐1 ) from the stack.
6. Let 𝑐 be lanes−1
i𝑁 x𝑀 (lanesi𝑁 x𝑀 (𝑐1 )[[𝑖] = packi𝑁 (𝑐2 )]).

7. Push the value ([Link] 𝑐) to the stack.


([Link] 𝑐1 ) (unpack(i𝑁 ).const 𝑐2 ) (i𝑁 x𝑀.replace_lane 𝑖) ˓→ ([Link] 𝑐)
if 𝑐 = lanes−1
i𝑁 x𝑀 (lanesi𝑁 x𝑀 (𝑐1 )[[𝑖] = packi𝑁 (𝑐2 )])

sh 2 .vextunop_sh 1
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐1 ) from the stack.
3. Let 𝑐 be vextunop sh 1 ,sh 2 (𝑐1 ).
4. Push the value ([Link] 𝑐) to the stack.

4.6. Instructions 163


WebAssembly Specification, Release 3.0 (2025-11-14)

([Link] 𝑐1 ) (sh 2 .vextunop_sh 1 ) ˓→ ([Link] 𝑐) if vextunop sh 1 ,sh 2 (𝑐1 ) = 𝑐

sh 2 .vextbinop_sh 1
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐2 ) from the stack.
3. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
4. Pop the value ([Link] 𝑐1 ) from the stack.
5. Let 𝑐 be vextbinop sh 1 ,sh 2 (𝑐1 , 𝑐2 ).
6. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link] 𝑐2 ) (sh 2 .vextbinop_sh 1 ) ˓→ ([Link] 𝑐) if vextbinop sh 1 ,sh 2 (𝑐1 , 𝑐2 ) = 𝑐

sh 2 .vextternop_sh 1
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐3 ) from the stack.
3. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
4. Pop the value ([Link] 𝑐2 ) from the stack.
5. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
6. Pop the value ([Link] 𝑐1 ) from the stack.
7. Let 𝑐 be vextternop sh 1 ,sh 2 (𝑐1 , 𝑐2 , 𝑐3 ).
8. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) ([Link] 𝑐2 ) ([Link] 𝑐3 ) (sh 2 .vextternop_sh 1 ) ˓→ ([Link] 𝑐)
if vextternop sh 1 ,sh 2 (𝑐1 , 𝑐2 , 𝑐3 ) = 𝑐

sh 2 .narrow_sh 1 _sx
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐2 ) from the stack.
3. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
4. Pop the value ([Link] 𝑐1 ) from the stack.
5. Let 𝑐 be narrowsx
sh 1 ,sh 2 (𝑐1 , 𝑐2 ).

6. Push the value ([Link] 𝑐) to the stack.


([Link] 𝑐1 ) ([Link] 𝑐2 ) (sh 2 .narrow_sh 1 _sx ) ˓→ ([Link] 𝑐) if 𝑐 = narrowsx
sh 1 ,sh 2 (𝑐1 , 𝑐2 )

sh 2 .vcvtop_sh 1
1. Assert: Due to validation, a value of vector type v128 is on the top of the stack.
2. Pop the value ([Link] 𝑐1 ) from the stack.
3. Let 𝑐 be vcvtop sh 1 ,sh 2 (vcvtop, 𝑐1 ).
4. Push the value ([Link] 𝑐) to the stack.
([Link] 𝑐1 ) (sh 2 .vcvtop_sh 1 ) ˓→ ([Link] 𝑐) if 𝑐 = vcvtop sh 1 ,sh 2 (vcvtop, 𝑐1 )

164 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

4.6.12 Expressions
An expression is evaluated relative to a current frame pointing to its containing module instance.

eval_expr instr *
1. Execute the sequence instr * .
2. Pop the value val from the stack.
3. Return val .
𝑧; instr * ˓→* 𝑧 ′ ; val * if 𝑧; instr * ˓→* 𝑧 ′ ; val *

Note

Evaluation iterates this reduction rule until reaching a value. Expressions constituting function bodies are
executed during function invocation.

4.7 Modules
For modules, the execution semantics primarily defines instantiation, which allocates instances for a module and
its contained definitions, initializes memories and tables from contained data and element segments, and invokes
the start function if present. It also includes invocation of exported functions.

4.7.1 Allocation
New instances of tags, globals, memories, tables, functions, data segments, and element segments are allocated in
a store 𝑠, as defined by the following auxiliary functions.

Tags
alloctag(𝑠, tagtype)
1. Let taginst be the tag instance {type tagtype}.
2. Let 𝑎 be the length of 𝑠.tags.
3. Append taginst to 𝑠.tags.
4. Return 𝑎.
alloctag(𝑠, tagtype) = (𝑠 ⊕ {tags taginst}, |𝑠.tags|)
if taginst = {type tagtype}

Globals
allocglobal(𝑠, globaltype, val )
1. Let globalinst be the global instance {type globaltype, value val }.
2. Let 𝑎 be the length of 𝑠.globals.
3. Append globalinst to 𝑠.globals.
4. Return 𝑎.
allocglobal(𝑠, globaltype, val ) = (𝑠 ⊕ {globals globalinst}, |𝑠.globals|)
if globalinst = {type globaltype, value val }

4.7. Modules 165


WebAssembly Specification, Release 3.0 (2025-11-14)

Memories
allocmem(𝑠, at [𝑖 .. 𝑗 ? ] page)
1. Let meminst be the memory instance {type (at [𝑖 .. 𝑗 ? ] page), bytes 0x00𝑖·64 Ki }.
2. Let 𝑎 be the length of 𝑠.mems.
3. Append meminst to 𝑠.mems.
4. Return 𝑎.
allocmem(𝑠, at [𝑖 .. 𝑗 ? ] page) = (𝑠 ⊕ {mems meminst}, |𝑠.mems|)
if meminst = {type (at [𝑖 .. 𝑗 ? ] page), bytes (0x00)𝑖·64 Ki }

Tables
alloctable(𝑠, at [𝑖 .. 𝑗 ? ] rt, ref )

1. Let tableinst be the table instance {type (at [𝑖 .. 𝑗 ? ] rt), elem ref 𝑖 }.
2. Let 𝑎 be the length of 𝑠.tables.
3. Append tableinst to 𝑠.tables.
4. Return 𝑎.
alloctable(𝑠, at [𝑖 .. 𝑗 ? ] rt, ref ) = (𝑠 ⊕ {tables tableinst}, |𝑠.tables|)
if tableinst = {type (at [𝑖 .. 𝑗 ? ] rt), elem ref 𝑖 }

Functions
allocfunc(𝑠, deftype, code, moduleinst)
1. Let funcinst be the function instance {type deftype, module moduleinst, code code}.
2. Let 𝑎 be the length of 𝑠.funcs.
3. Append funcinst to 𝑠.funcs.
4. Return 𝑎.
allocfunc(𝑠, deftype, code, moduleinst) = (𝑠 ⊕ {funcs funcinst}, |𝑠.funcs|)
if funcinst = {type deftype, module moduleinst, code code}

Data segments
allocdata(𝑠, ok, byte * )
1. Let datainst be the data instance {bytes byte * }.
2. Let 𝑎 be the length of 𝑠.datas.
3. Append datainst to 𝑠.datas.
4. Return 𝑎.
allocdata(𝑠, ok, byte * ) = (𝑠 ⊕ {datas datainst}, |𝑠.datas|)
if datainst = {bytes byte * }

166 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

Element segments
allocelem(𝑠, elemtype, ref * )
1. Let eleminst be the element instance {type elemtype, elem ref * }.
2. Let 𝑎 be the length of 𝑠.elems.
3. Append eleminst to 𝑠.elems.
4. Return 𝑎.
allocelem(𝑠, elemtype, ref * ) = (𝑠 ⊕ {elems eleminst}, |𝑠.elems|)
if eleminst = {type elemtype, elem ref * }

Growing memories
growmem(meminst, 𝑛)
1. Let {type (at [𝑖 .. 𝑗 ? ] page), bytes 𝑏* } be the destructuring of meminst.
2. Let 𝑖′ be |𝑏* |/(64 Ki) + 𝑛.
3. If (𝑖′ ≤ 𝑗)? , then:
a. Let meminst ′ be the memory instance {type (at [𝑖′ .. 𝑗 ? ] page), bytes 𝑏* 0x00𝑛·64 Ki }.
b. Return meminst ′ .
4. Fail.
growmem(meminst, 𝑛) = meminst ′ if meminst = {type (at [𝑖 .. 𝑗 ? ] page), bytes 𝑏* }
∧ meminst ′ = {type (at [𝑖′ .. 𝑗 ? ] page), bytes 𝑏* (0x00)𝑛·64 Ki }
∧ 𝑖′ = |𝑏* |/(64 Ki) + 𝑛
∧ (𝑖′ ≤ 𝑗)?

Growing tables
growtable(tableinst, 𝑛, 𝑟)
*
1. Let {type (at [𝑖 .. 𝑗 ? ] rt), elem 𝑟′ } be the destructuring of tableinst.
*
2. Let 𝑖′ be |𝑟′ | + 𝑛.
3. If (𝑖′ ≤ 𝑗)? , then:
*
a. Let tableinst ′ be the table instance {type (at [𝑖′ .. 𝑗 ? ] rt), elem 𝑟′ 𝑟𝑛 }.
b. Return tableinst ′ .
4. Fail.
*
growtable(tableinst, 𝑛, 𝑟) = tableinst ′ if tableinst = {type (at [𝑖 .. 𝑗 ? ] rt), elem 𝑟′ }
*
∧ tableinst ′ = {type (at [𝑖′ .. 𝑗 ? ] rt), elem 𝑟′ 𝑟𝑛 }
′ ′*
∧ 𝑖 = |𝑟 | + 𝑛
∧ (𝑖′ ≤ 𝑗)?

Modules
*
allocmodule(𝑠, module, externaddr * , val *g , ref *t , ref *e )
1. Let (module type * import * tag * global * mem * table * func * data * elem * start ? export * ) be the destruc-
turing of module.
2. Let aa *i be tags(externaddr * ).
3. Let ga *i be globals(externaddr * ).

4.7. Modules 167


WebAssembly Specification, Release 3.0 (2025-11-14)

4. Let fa *i be funcs(externaddr * ).
5. Let ma *i be mems(externaddr * ).
6. Let ta *i be tables(externaddr * ).
7. Let fa * be |𝑠.funcs| + 𝑖f for all 𝑖f from 0 to |func * | − 1.
8. Let tagtype * be the tag type sequence 𝜖.
9. For each tag in tag * , do:
a. Let (tag tagtype) be the destructuring of tag.
b. Append tagtype to tagtype * .
*
10. Let byte * be the byte sequence sequence 𝜖.
11. For each data in data * , do:
a. Let (data byte * datamode) be the destructuring of data.
*
b. Append byte * to byte * .
12. Let globaltype * be the global type sequence 𝜖.
13. For each global in global * , do:
a. Let (global globaltype expr g ) be the destructuring of global .
b. Append globaltype to globaltype * .
14. Let tabletype * be the table type sequence 𝜖.
15. For each table in table * , do:
a. Let (table tabletype expr t ) be the destructuring of table.
b. Append tabletype to tabletype * .
16. Let memtype * be the memory type sequence 𝜖.
17. For each mem in mem * , do:
a. Let (memory memtype) be the destructuring of mem.
b. Append memtype to memtype * .
18. Let dt * be alloctype* (type * ).
19. Let elemtype * be the reference type sequence 𝜖.
20. For each elem in elem * , do:
a. Let (elem elemtype expr *e elemmode) be the destructuring of elem.
b. Append elemtype to elemtype * .
21. Let expr *f be the expression sequence 𝜖.
*
22. Let local * be the local sequence sequence 𝜖.
23. Let 𝑥* be the type index sequence 𝜖.
24. For each func in func * , do:
a. Let (func 𝑥 local * expr f ) be the destructuring of func.
b. Append expr f to expr *f .
*
c. Append local * to local * .
d. Append 𝑥 to 𝑥* .
25. Let aa * be 𝜖.
26. For each tagtype in tagtype * , do:

168 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

a. Let aa be the tag address alloctag(𝑠, tagtype[:= dt * ]).


b. Append aa to aa * .
27. Let ga * be 𝜖.
28. For each globaltype in globaltype * and val g in val *g , do:
a. Let ga be the global address allocglobal(𝑠, globaltype[:= dt * ], val g ).
b. Append ga to ga * .
29. Let ma * be 𝜖.
30. For each memtype in memtype * , do:
a. Let ma be the memory address allocmem(𝑠, memtype[:= dt * ]).
b. Append ma to ma * .
31. Let ta * be 𝜖.
32. For each tabletype in tabletype * and ref t in ref *t , do:
a. Let ta be the table address alloctable(𝑠, tabletype[:= dt * ], ref t ).
b. Append ta to ta * .
33. Let xi * be 𝜖.
34. For each export in export * , do:
a. Let xi be the export instance allocexport(moduleinst, export).
b. Append xi to xi * .
35. Let da * be 𝜖.
*
36. For each byte * in byte * , do:
a. Let da be the data address allocdata(𝑠, ok, byte * ).
b. Append da to da * .
37. Let ea * be 𝜖.
*
38. For each elemtype in elemtype * and ref *e in ref *e , do:
a. Let ea be the elem address allocelem(𝑠, elemtype[:= dt * ], ref *e ).
b. Append ea to ea * .
39. Let moduleinst be the module instance {types dt * , tags aa *i aa * , globals ga *i ga * , mems ma *i ma * ,
tables ta *i ta * , funcs fa *i fa * , datas da * , elems ea * , exports xi * }.
40. Let funcaddr *0 be 𝜖.
*
41. For each expr f in expr *f and local * in local * and 𝑥 in 𝑥* , do:
a. Let funcaddr 0 be the function address allocfunc(𝑠, dt * [𝑥], func 𝑥 local * expr f , moduleinst).
b. Append funcaddr 0 to funcaddr *0 .
42. Assert: Due to validation, funcaddr *0 = fa * .
43. Return moduleinst.

4.7. Modules 169


WebAssembly Specification, Release 3.0 (2025-11-14)

allocmodule(𝑠, module, externaddr * , val *g , ref *t , (ref *e )* ) = (𝑠7 , moduleinst)


if module = module type * import * tag * global * mem * table * func * data * elem * start ? export *
∧ tag * = (tag tagtype)*
∧ global * = (global globaltype expr g )*
∧ mem * = (memory memtype)*
∧ table * = (table tabletype expr t )*
∧ func * = (func 𝑥 local * expr f )*
∧ data * = (data byte * datamode)*
∧ elem * = (elem elemtype expr *e elemmode)*
∧ aa *i = tags(externaddr * )
∧ ga *i = globals(externaddr * )
∧ ma *i = mems(externaddr * )
∧ ta *i = tables(externaddr * )
∧ fa *i = funcs(externaddr * )
∧ dt * = alloctype* (type * )
*
∧ fa * = (|𝑠.funcs| + 𝑖f )𝑖f <|func |
*
∧ (𝑠1 , aa * ) = alloctag* (𝑠, tagtype[:= dt * ] )
*
∧ (𝑠2 , ga ) = allocglobal (𝑠1 , globaltype[:= dt * ] , val *g )
* *
* * * *
∧ (𝑠3 , ma ) = allocmem (𝑠2 , memtype[:= dt ] )
*
∧ (𝑠4 , ta * ) = alloctable* (𝑠3 , tabletype[:= dt * ] , ref *t )
* * |data * | * *
∧ (𝑠5 , da ) = allocdata (𝑠4 , ok , (byte ) )
*
∧ (𝑠6 , ea * ) = allocelem* (𝑠5 , elemtype[:= dt * ] , (ref *e )* )
*
∧ (𝑠7 , fa ) = allocfunc (𝑠6 , dt [𝑥]* , (func 𝑥 local * expr f )* , moduleinst |func | )
* * *

∧ xi * = allocexport ({tags aa *i aa * , globals ga *i ga * , mems ma *i ma * , tables ta *i ta * , funcs fa *i fa * }, export * )


*

∧ moduleinst = {types dt * ,
tags aa *i aa * , globals ga *i ga * ,
mems ma *i ma * ,
tables ta *i ta * , funcs fa *i fa * , datas da * ,
elems ea * , exports xi * }
Here, the notation allocx* is shorthand for multiple allocations of object kind 𝑋, defined as follows:

allocX* (𝑠, 𝜖, 𝜖) = (𝑠, 𝜖)


* * *
allocX* (𝑠, 𝑋 𝑋 ′ , 𝑌 𝑌 ′ ) = (𝑠2 , 𝑎 𝑎′ ) if (𝑠1 , 𝑎) = allocX(𝑋, 𝑌, 𝑠, 𝑋, 𝑌 )
* * *
∧ (𝑠2 , 𝑎′ ) = allocX* (𝑠1 , 𝑋 ′ , 𝑌 ′ )

For types, however, allocation is defined in terms of rolling and substitution of all preceding types to produce a list
of closed defined types:

*
alloctype* (type ′′ )
*
1. If type ′′ = 𝜖, then:
a. Return 𝜖.
* *
2. Let type ′ type be type ′′ .
3. Let (type rectype) be the destructuring of type.
* *
4. Let deftype ′ be alloctype* (type ′ ).
*
5. Let 𝑥 be the length of deftype ′ .
*
6. Let deftype * be roll*𝑥 (rectype)[:= deftype ′ ].
*
7. Return deftype ′ deftype * .
alloctype* (𝜖) = 𝜖
* * * *
alloctype* (type ′ type) = deftype ′ deftype * if deftype ′ = alloctype* (type ′ )
∧ type = type rectype
*
∧ deftype * = roll*𝑥 (rectype)[:= deftype ′ ]
*
∧ 𝑥 = |deftype ′ |
Finally, export instances are produced with the help of the following definition:

170 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

allocexport(moduleinst, export name externidx )


1. If externidx is some tag tagidx , then:
a. Let (tag 𝑥) be the destructuring of externidx .
b. Return {name name, addr (tag [Link][𝑥])}.
2. If externidx is some global globalidx , then:
a. Let (global 𝑥) be the destructuring of externidx .
b. Return {name name, addr (global [Link][𝑥])}.
3. If externidx is some memory memidx , then:
a. Let (memory 𝑥) be the destructuring of externidx .
b. Return {name name, addr (mem [Link][𝑥])}.
4. If externidx is some table tableidx , then:
a. Let (table 𝑥) be the destructuring of externidx .
b. Return {name name, addr (table [Link][𝑥])}.
5. Assert: Due to validation, externidx is some func funcidx .
6. Let (func 𝑥) be the destructuring of externidx .
7. Return {name name, addr (func [Link][𝑥])}.
allocexport(moduleinst, export name (tag 𝑥)) = {name name, addr (tag [Link][𝑥])}
allocexport(moduleinst, export name (global 𝑥)) = {name name, addr (global [Link][𝑥])}
allocexport(moduleinst, export name (memory 𝑥)) = {name name, addr (mem [Link][𝑥])}
allocexport(moduleinst, export name (table 𝑥)) = {name name, addr (table [Link][𝑥])}
allocexport(moduleinst, export name (func 𝑥)) = {name name, addr (func [Link][𝑥])}

Note

The definition of module allocation is mutually recursive with the allocation of its associated functions, because
the resulting module instance is passed to the allocators as an argument, in order to form the necessary closures.
In an implementation, this recursion is easily unraveled by mutating one or the other in a secondary step.

4.7.2 Instantiation
Given a store 𝑠, a module is instantiated with a list of external addresses externaddr * supplying the required
imports as follows.
Instantiation checks that the module is valid and the provided imports match the declared types, and may fail with
an error otherwise. Instantiation can also result in an exception or trap when initializing a table or memory from
an active segment or when executing the start function. It is up to the embedder to define how such conditions are
reported.

instantiate(𝑠, module, externaddr * )


1. If module is not valid, then:
a. Fail.
2. Let xt *i → xt *e be the destructuring of the type of module.
3. Let (module type * import * tag * global * mem * table * func * data * elem * start ? export * ) be the destruc-
turing of module.
4. If |externaddr * | =
̸ |xt *i |, then:
a. Fail.

4.7. Modules 171


WebAssembly Specification, Release 3.0 (2025-11-14)

5. For all externaddr in externaddr * , and corresponding xt i in xt *i :


a. If externaddr is not valid with type xt i , then:
1) Fail.
*
6. Let instr *d be the concatenation of rundata𝑖d (data * [𝑖d ])𝑖d <|data | .
*
7. Let instr *e be the concatenation of runelem𝑖e (elem * [𝑖e ])𝑖e <|elem | .
8. Let moduleinst 0 be the module instance {types alloctype* (type * ), globals globals(externaddr * ),
*
funcs funcs(externaddr * ) (|𝑠.funcs| + 𝑖f )𝑖f <|func | }.
9. Let expr *t be the expression sequence 𝜖.
10. For each table in table * , do:
a. Let (table tabletype expr t ) be the destructuring of table.
b. Append expr t to expr *t .
11. Let expr *g be the expression sequence 𝜖.
12. Let globaltype * be the global type sequence 𝜖.
13. For each global in global * , do:
a. Let (global globaltype expr g ) be the destructuring of global .
b. Append expr g to expr *g .
c. Append globaltype to globaltype * .
14. Let expr *e * be the expression sequence sequence 𝜖.
15. For each elem in elem * , do:
a. Let (elem reftype expr *e elemmode) be the destructuring of elem.
b. Append expr *e to expr *e * .
16. Let 𝑧 be the state (𝑠, {module moduleinst 0 }).
17. Let 𝐹 be the frame 𝑧.frame.
18. Push the frame 𝐹 .
19. Let val *g be evalglobal* (𝑧, globaltype * , expr *g ).
20. Let ref *t be the reference value sequence 𝜖.
21. For each expr t in expr *t , do:
a. Let ref t be the result of evaluating expr t with state 𝑧.
b. Append ref t to ref *t .
*
22. Let ref *e be the reference value sequence sequence 𝜖.
23. For each expr *e in expr *e * , do:
a. Let ref *e be the reference value sequence 𝜖.
b. For each expr e in expr *e , do:
1) Let ref e be the result of evaluating expr e with state 𝑧.
2) Append ref e to ref *e .
*
c. Append ref *e to ref *e .
24. Pop the frame from the stack.
*
25. Let moduleinst be allocmodule(𝑠, module, externaddr * , val *g , ref *t , ref *e ).
26. Let 𝐹 ′ be the frame {module moduleinst}.

172 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

27. Push the frame 𝐹 ′ .


28. Execute the sequence instr *e .
29. Execute the sequence instr *d .
30. If start ? is defined, then:
a. Let (start 𝑥) be start ? .
b. Let instr s be the instruction (call 𝑥).
c. Execute the instruction instr s .
31. Pop the frame from the stack.
32. Return moduleinst.
instantiate(𝑠, module, externaddr * ) = 𝑠′ ; {module moduleinst}; instr *e instr *d instr ?s
if ⊢ module : xt *i → xt *e
∧ (𝑠 ⊢ externaddr : xt i )*
∧ module = module type * import * tag * global * mem * table * func * data * elem * start ? export *
∧ global * = (global globaltype expr g )*
∧ table * = (table tabletype expr t )*
∧ data * = (data byte * datamode)*
∧ elem * = (elem reftype expr *e elemmode)*
∧ start ? = (start 𝑥)?
∧ moduleinst 0 = {types alloctype* (type * ),
globals globals(externaddr * ),
*
funcs funcs(externaddr * ) (|𝑠.funcs| + 𝑖f )𝑖f <|func | }
∧ 𝑧 = 𝑠; {module moduleinst 0 }
∧ (𝑧 ′ , val *g ) = evalglobal* (𝑧, globaltype * , expr *g )
∧ (𝑧 ′ ; expr t ˓→* 𝑧 ′ ; ref t )*
*
∧ (𝑧 ′ ; expr e ˓→* 𝑧 ′ ; ref e )*
∧ (𝑠 , moduleinst) = allocmodule(𝑠, module, externaddr * , val *g , ref *t , (ref *e )* )

*
∧ instr *d = rundata𝑖d (data * [𝑖d ])𝑖d <|data |
⨁︀
*
∧ instr *e = runelem𝑖e (elem * [𝑖e ])𝑖e <|elem |
⨁︀
? ?
∧ instr s = (call 𝑥)
where:

*
evalglobal* (𝑧, globaltype * , expr ′′ )
*
1. If expr ′′ = 𝜖, then:
a. Assert: Due to validation, globaltype * = 𝜖.
b. Return 𝜖.
2. Else:
* *
a. Let expr expr ′ be expr ′′ .
b. Assert: Due to validation, |globaltype * | ≥ 1.
*
c. Let gt gt ′ be globaltype * .
d. Let (𝑠, 𝑓 ) be the destructuring of 𝑧.
e. Let val be the result of evaluating expr with state 𝑧.
f. Let 𝑎 be allocglobal(𝑠, gt, val ).
g. Append 𝑎 to 𝑓.[Link].
* * *
h. Let val ′ be evalglobal* ((𝑠, 𝑓 ), gt ′ , expr ′ ).
*
i. Return val val ′ .

4.7. Modules 173


WebAssembly Specification, Release 3.0 (2025-11-14)

evalglobal* (𝑧, 𝜖, 𝜖) = (𝑧, 𝜖)


* * *
evalglobal* (𝑧, gt gt ′ , expr expr ′ ) = (𝑧 ′ , val val ′ )
if 𝑧; expr ˓→* 𝑧; val
∧ 𝑧 = 𝑠; 𝑓
∧ (𝑠′ , 𝑎) = allocglobal(𝑠, gt, val )
* * *
∧ (𝑧 ′ , val ′ ) = evalglobal* ((𝑠′ ; 𝑓 [.[Link] =⊕ 𝑎]), gt ′ , expr ′ )

rundata𝑥 (data 𝑏𝑛 datamode)


1. If datamode = passive, then:
a. Return 𝜖.
2. Assert: Due to validation, datamode is some active memidx expr .
3. Let (active 𝑦 instr * ) be the destructuring of datamode.
4. Return instr * ([Link] 0) ([Link] 𝑛) ([Link] 𝑦 𝑥) ([Link] 𝑥).

runelem𝑥 (elem rt 𝑒𝑛 elemmode)


1. If elemmode = passive, then:
a. Return 𝜖.
2. If elemmode = declare, then:
a. Return ([Link] 𝑥).
3. Assert: Due to validation, elemmode is some active tableidx expr .
4. Let (active 𝑦 instr * ) be the destructuring of elemmode.
5. Return instr * ([Link] 0) ([Link] 𝑛) ([Link] 𝑦 𝑥) ([Link] 𝑥).
rundata𝑥 (data 𝑏𝑛 (passive)) = 𝜖
rundata𝑥 (data 𝑏𝑛 (active 𝑦 instr * )) =
instr * ([Link] 0) ([Link] 𝑛) ([Link] 𝑦 𝑥) ([Link] 𝑥)
runelem𝑥 (elem rt 𝑒𝑛 (passive)) = 𝜖
runelem𝑥 (elem rt 𝑒𝑛 (declare)) = ([Link] 𝑥)
runelem𝑥 (elem rt 𝑒𝑛 (active 𝑦 instr * )) =
instr * ([Link] 0) ([Link] 𝑛) ([Link] 𝑦 𝑥) ([Link] 𝑥)

Note

Checking import types assumes that the module instance has already been allocated to compute the respective
closed defined types. However, this forward reference merely is a way to simplify the specification. In practice,
implementations will likely allocate or canonicalize types beforehand, when compiling a module, in a stage
before instantiation and before imports are checked.
Similarly, module allocation and the evaluation of global and table initializers as well as element segments
*
are mutually recursive because the global initialization values val *g , ref t , and element segment contents ref *e
are passed to the module allocator while depending on the module instance moduleinst and store 𝑠′ returned
by allocation. Again, this recursion is just a specification device. In practice, the initialization values can be
determined beforehand by staging module allocation such that first, the module’s own function instances are
pre-allocated in the store, then the initializer expressions are evaluated in order, allocating globals on the way,
then the rest of the module instance is allocated, and finally the new function instances’ module fields are set to
that module instance. This is possible because validation ensures that initialization expressions cannot actually
call a function, only take their reference.
All failure conditions are checked before any observable mutation of the store takes place. Store mutation is
not atomic; it happens in individual steps that may be interleaved with other threads.
Evaluation of constant expressions does not affect the store.

174 Chapter 4. Execution


WebAssembly Specification, Release 3.0 (2025-11-14)

4.7.3 Invocation
Once a module has been instantiated, any exported function can be invoked externally via its function address
funcaddr in the store 𝑠 and an appropriate list val * of argument values.
Invocation may fail with an error if the arguments do not fit the function type. Invocation can also result in an
exception or trap. It is up to the embedder to define how such conditions are reported.

Note

If the embedder API performs type checks itself, either statically or dynamically, before performing an invoca-
tion, then no failure other than traps or exceptions can occur.

invoke(𝑠, funcaddr , val * )


1. Assert: Due to validation, the expansion of 𝑠.funcs[funcaddr ].type is some func resulttype → resulttype.
2. Let (func 𝑡*1 → 𝑡*2 ) be the destructuring of the expansion of 𝑠.funcs[funcaddr ].type.
̸ |val * |, then:
3. If |𝑡*1 | =
a. Fail.
4. For all 𝑡1 in 𝑡*1 , and corresponding val in val * :
a. If val is not valid with type 𝑡1 , then:
1) Fail.
5. Let 𝑘 be the length of 𝑡*2 .
6. Let 𝐹 be the frame {module {}} whose arity is 𝑘.
7. Push the frame 𝐹 .
8. Push the values val * to the stack.
9. Push the value ([Link] funcaddr ) to the stack.
10. Execute the instruction (call_ref 𝑠.funcs[funcaddr ].type).
𝑘
11. Pop the values val ′ from the stack.
12. Pop the frame from the stack.
𝑘
13. Return val ′ .
invoke(𝑠, funcaddr , val * ) = 𝑠; {module {}}; val * ([Link] funcaddr ) (call_ref 𝑠.funcs[funcaddr ].type)
if 𝑠.funcs[funcaddr ].type ≈ func 𝑡*1 → 𝑡*2
∧ (𝑠 ⊢ val : 𝑡1 )*

4.7. Modules 175


WebAssembly Specification, Release 3.0 (2025-11-14)

176 Chapter 4. Execution


CHAPTER 5

Binary Format

5.1 Conventions
The binary format for WebAssembly modules is a dense linear encoding of their abstract syntax.28
The format is defined by an attribute grammar whose only terminal symbols are bytes. A byte sequence is a
well-formed encoding of a module if and only if it is generated by the grammar.
Each production of this grammar has exactly one synthesized attribute: the abstract syntax that the respective byte
sequence encodes. Thus, the attribute grammar implicitly defines a decoding function (i.e., a parsing function for
the binary format).
Except for a few exceptions, the binary grammar closely mirrors the grammar of the abstract syntax.

Note

Some phrases of abstract syntax have multiple possible encodings in the binary format. For example, numbers
may be encoded as if they had optional leading zeros. Implementations of decoders must support all possible
alternatives; implementations of encoders can pick any allowed encoding.

The recommended extension for files containing WebAssembly modules in binary format is “.wasm” and the rec-
ommended Media Type27 is “application/wasm”.

5.1.1 Grammar
The following conventions are adopted in defining grammar rules for the binary format. They mirror the conven-
tions used for abstract syntax. In order to distinguish symbols of the binary syntax from symbols of the abstract
syntax, typewriter font is adopted for the former.
• Terminal symbols are bytes expressed in hexadecimal notation: 0x0F.
• Nonterminal symbols are written in typewriter font: valtype, instr.
• 𝐵 𝑛 is a sequence of 𝑛 ≥ 0 iterations of 𝐵.
• 𝐵 * is a possibly empty sequence of iterations of 𝐵. (This is a shorthand for 𝐵 𝑛 used where 𝑛 is not relevant.)
28 Additional encoding layers – for example, introducing compression – may be defined on top of the basic representation defined here.

However, such layers are outside the scope of the current specification.
27 [Link]

177
WebAssembly Specification, Release 3.0 (2025-11-14)

• 𝐵 ? is an optional occurrence of 𝐵. (This is a shorthand for 𝐵 𝑛 where 𝑛 ≤ 1.)


• 𝑥:𝐵 denotes the same language as the nonterminal 𝐵, but also binds the variable 𝑥 to the attribute synthesized
for 𝐵. A pattern may also be used instead of a variable, e.g., 7:𝐵.
• Productions are written sym ::= 𝐵1 ⇒ 𝐴1 | . . . | 𝐵𝑛 ⇒ 𝐴𝑛 , where each 𝐴𝑖 is the attribute that is syn-
thesized for sym in the given case, usually from attribute variables bound in 𝐵𝑖 .
• Large productions may be split into multiple definitions, indicated by ending the first one with explicit el-
lipses, sym ::= 𝐵1 , and starting continuations with ellipses, sym ::= . . . | 𝐵2 .
• Some productions are augmented by side conditions in parentheses, which restrict the applicability of the
production. They provide a shorthand for a combinatorial expansion of the production into many separate
cases.
• If the same meta variable or non-terminal symbol appears multiple times in a production (in the syntax or
in an attribute), then all those occurrences must have the same instantiation. (This is a shorthand for a side
condition requiring multiple different variables to be equal.)

Note

For example, the binary grammar for number types is given as follows:

numtype ::= 0x7C ⇒ f 64


| 0x7D ⇒ f 32
| 0x7E ⇒ i64
| 0x7F ⇒ i32

Consequently, the byte 0x7F encodes the type i32, 0x7E encodes the type i64, and so forth. No other byte value
is allowed as the encoding of a number type.
The binary grammar for limits is defined as follows:

limits ::= 0x00 𝑛:u64 ⇒ (i32, [𝑛 .. 𝜖])


| 0x01 𝑛:u64 𝑚:u64 ⇒ (i32, [𝑛 .. 𝑚])
| 0x04 𝑛:u64 ⇒ (i64, [𝑛 .. 𝜖])
| 0x05 𝑛:u64 𝑚:u64 ⇒ (i64, [𝑛 .. 𝑚])

That is, a limits pair is encoded as either the byte 0x00 followed by the encoding of a u64 value, or the byte 0x01
followed by two such encodings. The variables 𝑛 and 𝑚 name the attributes of the respective u64 nonterminals,
which in this case are the actual unsigned integers those decode into. The attribute of the complete production
then is the abstract syntax for the limit, expressed in terms of the former values.

5.1.2 Auxiliary Notation


When dealing with binary encodings the following notation is also used:
• 𝜖 denotes the empty byte sequence.
• ||B|| is the length of the byte sequence generated from the production B in a derivation.

5.1.3 Lists
Lists are encoded with their u32 length followed by the encoding of their element sequence.

list(X) ::= 𝑛:u32 (el :X)𝑛 ⇒ el 𝑛

178 Chapter 5. Binary Format


WebAssembly Specification, Release 3.0 (2025-11-14)

5.2 Values
5.2.1 Bytes
Bytes encode themselves.

byte ::= 0x00 | . . . | 0xFF

5.2.2 Integers
All integers are encoded using the LEB12829 variable-length integer encoding, in either unsigned or signed variant.
Unsigned integers are encoded in unsigned LEB12830 format. As an additional constraint, the total number of
bytes encoding a u𝑁 value must not exceed ceil(𝑁/7) bytes.

u𝑁 ::= 𝑛:byte ⇒ 𝑛 if 𝑛 < 27 ∧ 𝑛 < 2𝑁


| 𝑛:byte 𝑚:u(𝑁 − 7) ⇒ 2 · 𝑚 + (𝑛 − 2 ) if 𝑛 ≥ 27 ∧ 𝑁 > 7
7 7

Signed integers are encoded in signed LEB12831 format, which uses a two’s complement representation. As an
additional constraint, the total number of bytes encoding an s𝑁 value must not exceed ceil(𝑁/7) bytes.

s𝑁 ::= 𝑛:byte ⇒ 𝑛 if 𝑛 < 26 ∧ 𝑛 < 2𝑁 −1


| 𝑛:byte ⇒ 𝑛 − 27 if 26 ≤ 𝑛 < 27 ∧ 𝑛 ≥ 27 − 2𝑁 −1
| 𝑛:byte 𝑖:u(𝑁 − 7) ⇒ 27 · 𝑖 + (𝑛 − 27 ) if 𝑛 ≥ 27 ∧ 𝑁 > 7

Uninterpreted integers are encoded as signed integers.

i𝑁 ::= 𝑖:s𝑁 ⇒ signed−1


𝑁 (𝑖)

Note

The side conditions 𝑁 > 7 in the productions for non-terminal bytes of the u𝑁 and s𝑁 encodings restrict the
encoding’s length. However, “trailing zeros” are still allowed within these bounds. For example, 0x03 and
0x83 0x00 are both well-formed encodings for the value 3 as a u8 . Similarly, either of 0x7E and 0xFE 0x7F
and 0xFE 0xFF 0x7F are well-formed encodings of the value −2 as an s16 .
The side conditions on the value 𝑛 of terminal bytes further enforce that any unused bits in these bytes must be 0
for positive values and 1 for negative ones. For example, 0x83 0x10 is malformed as a u8 encoding. Similarly,
both 0x83 0x3E and 0xFF 0x7B are malformed as s8 encodings.

5.2.3 Floating-Point
Floating-point values are encoded directly by their IEEE 75432 (Section 3.4) bit pattern in little endian33 byte order:

f𝑁 ::= 𝑏* :byte𝑁/8 ⇒ bytes−1 *


f𝑁 (𝑏 )

29 [Link]
30 [Link]
31 [Link]
32 [Link]
33 [Link]

5.2. Values 179


WebAssembly Specification, Release 3.0 (2025-11-14)

5.2.4 Names
Names are encoded as a list of bytes containing the Unicode34 (Section 3.9) UTF-8 encoding of the name’s character
sequence.

name ::= 𝑏* :list(byte) ⇒ name if utf 8(name) = 𝑏*

The auxiliary utf 8 function expressing this encoding is defined as follows:

utf 8(ch * ) = utf 8(ch)*


⨁︀
utf 8(ch) = 𝑏 if ch < U+80
∧ ch = 𝑏
utf 8(ch) = 𝑏1 𝑏2 if U+80 ≤ ch < U+0800
∧ ch = 26 · (𝑏1 − 0xC0) + cont(𝑏2 )
utf 8(ch) = 𝑏1 𝑏2 𝑏3 if U+0800 ≤ ch < U+D800 ∨ U+E000 ≤ ch < U+10000
∧ ch = 212 · (𝑏1 − 0xE0) + 26 · cont(𝑏2 ) + cont(𝑏3 )
utf 8(ch) = 𝑏1 𝑏2 𝑏3 𝑏4 if U+10000 ≤ ch < U+11000
∧ ch = 218 · (𝑏1 − 0xF0) + 212 · cont(𝑏2 ) + 26 · cont(𝑏3 ) + cont(𝑏4 )

where cont(𝑏) = 𝑏 − 0x80 if (0x80 < 𝑏 < 0xC0)

Note

Unlike in some other formats, name strings are not 0-terminated.

5.3 Types

Note

In some places, possible types include both type constructors or types denoted by type indices. Thus, the
binary format for type constructors corresponds to the encodings of small negative s𝑁 values, such that they
can unambiguously occur in the same place as (positive) type indices.

5.3.1 Number Types


Number types are encoded by a single byte.

numtype ::= 0x7C ⇒ f 64


| 0x7D ⇒ f 32
| 0x7E ⇒ i64
| 0x7F ⇒ i32

5.3.2 Vector Types


Vector types are also encoded by a single byte.

vectype ::= 0x7B ⇒ v128

34 [Link]

180 Chapter 5. Binary Format


WebAssembly Specification, Release 3.0 (2025-11-14)

5.3.3 Heap Types


Heap types are encoded as either a single byte, or as a type index encoded as a positive signed integer.
absheaptype ::= 0x69 ⇒ exn
| 0x6A ⇒ array
| 0x6B ⇒ struct
| 0x6C ⇒ i31
| 0x6D ⇒ eq
| 0x6E ⇒ any
| 0x6F ⇒ extern
| 0x70 ⇒ func
| 0x71 ⇒ none
| 0x72 ⇒ noextern
| 0x73 ⇒ nofunc
| 0x74 ⇒ noexn
heaptype ::= ht:absheaptype ⇒ ht
| 𝑥:s33 ⇒ 𝑥 if 𝑥 ≥ 0

Note

The heap type bot cannot occur in a module.

5.3.4 Reference Types


Reference types are either encoded by a single byte followed by a heap type, or, as a short form, directly as an
abstract heap type.
reftype ::= 0x63 ht:heaptype ⇒ ref null ht
| 0x64 ht:heaptype ⇒ ref ht
| ht:absheaptype ⇒ ref null ht

5.3.5 Value Types


Value types are encoded with their respective encoding as a number type, vector type, or reference type.
valtype ::= nt:numtype ⇒ nt
| vt:vectype ⇒ vt
| rt:reftype ⇒ rt

Note

The value type bot cannot occur in a module.


Value types can occur in contexts where type indices are also allowed, such as in the case of block types. Thus,
the binary format for types corresponds to the signed LEB12835 encoding of small negative s𝑁 values, so that
they can coexist with (positive) type indices in the future.

5.3.6 Result Types


Result types are encoded by the respective lists of value types.

resulttype ::= 𝑡* :list(valtype) ⇒ 𝑡*

35 [Link]

5.3. Types 181


WebAssembly Specification, Release 3.0 (2025-11-14)

5.3.7 Composite Types


Composite types are encoded by a distinct byte followed by a type encoding of the respective form.

mut ::= 0x00 ⇒ 𝜖


| 0x01 ⇒ mut
comptype ::= 0x5E ft:fieldtype ⇒ array ft
| 0x5F ft * :list(fieldtype) ⇒ struct ft *
| 0x60 𝑡*1 :resulttype 𝑡*2 :resulttype ⇒ func 𝑡*1 → 𝑡*2
fieldtype ::= zt:storagetype mut? :mut ⇒ mut? zt
storagetype ::= 𝑡:valtype ⇒ 𝑡
| pt:packtype ⇒ pt
packtype ::= 0x77 ⇒ i16
| 0x78 ⇒ i8

5.3.8 Recursive Types


Recursive types are encoded by the byte 0x4E followed by a list of sub types. Additional shorthands are recognized
for unary recursions and sub types without super types.

rectype ::= 0x4E st * :list(subtype) ⇒ rec st *


| st:subtype ⇒ rec st
subtype ::= 0x4F 𝑥* :list(typeidx) ct:comptype ⇒ sub final 𝑥* ct
| 0x50 𝑥* :list(typeidx) ct:comptype ⇒ sub 𝑥* ct
| ct:comptype ⇒ sub final 𝜖 ct

5.3.9 Limits
Limits are encoded with a preceding flag indicating whether a maximum is present, and a flag for the address type.

limits ::= 0x00 𝑛:u64 ⇒ (i32, [𝑛 .. 𝜖])


| 0x01 𝑛:u64 𝑚:u64 ⇒ (i32, [𝑛 .. 𝑚])
| 0x04 𝑛:u64 ⇒ (i64, [𝑛 .. 𝜖])
| 0x05 𝑛:u64 𝑚:u64 ⇒ (i64, [𝑛 .. 𝑚])

5.3.10 Tag Types


Tag types are encoded by a type index denoting a function type.

tagtype ::= 0x00 𝑥:typeidx ⇒ 𝑥

Note

In future versions of WebAssembly, the preceding zero byte may encode additional attributes.

5.3.11 Global Types


Global types are encoded by their value type and a flag for their mutability.

globaltype ::= 𝑡:valtype mut? :mut ⇒ mut? 𝑡

182 Chapter 5. Binary Format


WebAssembly Specification, Release 3.0 (2025-11-14)

5.3.12 Memory Types


Memory types are encoded with their limits.

memtype ::= (at, lim):limits ⇒ at lim page

5.3.13 Table Types


Table types are encoded with their limits and the encoding of their element reference type.

tabletype ::= rt:reftype (at, lim):limits ⇒ at lim rt

5.3.14 External Types


External types are encoded by a distiguishing byte followed by an encoding of the respective form of type.

externtype ::= 0x00 𝑥:typeidx ⇒ func 𝑥


| 0x01 tt:tabletype ⇒ table tt
| 0x02 mt:memtype ⇒ mem mt
| 0x03 gt:globaltype ⇒ global gt
| 0x04 jt:tagtype ⇒ tag jt

5.4 Instructions
Instructions are encoded by opcodes. Each opcode is represented by a single byte, and is followed by the instruc-
tion’s immediate arguments, where present. The only exception are structured control instructions, which consist
of several opcodes bracketing their nested instruction sequences.

Note

The byte codes chosen to encode instructions are historical and do not follow a consistent pattern. In this section,
instructions are hence not presented in opcode order, but instead grouped consistently with other sections in
this document. An instruction index ordered by opcode can be found in the Appendix.
Gaps in the byte code ranges are reserved for future extensions.

5.4.1 Parametric Instructions


Parametric instructions are represented by single byte codes, possibly followed by a type annotation.

instr ::= 0x00 ⇒ unreachable


| 0x01 ⇒ nop
| 0x1A ⇒ drop
| 0x1B ⇒ select
| 0x1C 𝑡* :list(valtype) ⇒ select 𝑡*

5.4.2 Control Instructions


Control instructions have varying encodings. For structured instructions, the instruction sequences forming nested
blocks are delimited with explicit opcodes for end and else.

5.4. Instructions 183


WebAssembly Specification, Release 3.0 (2025-11-14)

Block types are encoded in special compressed form, by either the byte 0x40 indicating the empty type, as a single
value type, or as a type index encoded as a positive signed integer.

blocktype ::= 0x40 ⇒ 𝜖


| 𝑡:valtype ⇒ 𝑡
| 𝑖:s33 ⇒ 𝑖
instr ::= ...
| 0x02 bt:blocktype (in:instr)* 0x0B ⇒ block bt in *
| 0x03 bt:blocktype (in:instr)* 0x0B ⇒ loop bt in *
| 0x04 bt:blocktype (in:instr)* 0x0B ⇒ if bt in * else 𝜖
| 0x04 bt:blocktype (in 1 :instr)* ⇒ if bt in *1 else in *2
0x05 (in 2 :instr)* 0x0B
| 0x08 𝑥:tagidx ⇒ throw 𝑥
| 0x0A ⇒ throw_ref
| 0x0C 𝑙:labelidx ⇒ br 𝑙
| 0x0D 𝑙:labelidx ⇒ br_if 𝑙
| 0x0E 𝑙* :list(labelidx) 𝑙𝑛 :labelidx ⇒ br_table 𝑙* 𝑙𝑛
| 0x0F ⇒ return
| 0x10 𝑥:funcidx ⇒ call 𝑥
| 0x11 𝑦:typeidx 𝑥:tableidx ⇒ call_indirect 𝑥 𝑦
| 0x12 𝑥:funcidx ⇒ return_call 𝑥
| 0x13 𝑦:typeidx 𝑥:tableidx ⇒ return_call_indirect 𝑥 𝑦
| 0x14 𝑥:typeidx ⇒ call_ref 𝑥
| 0x15 𝑥:typeidx ⇒ return_call_ref 𝑥
| 0x1F bt:blocktype 𝑐* :list(catch) (in:instr)* 0x0B ⇒ try_table bt 𝑐* in *
| 0xD5 𝑙:labelidx ⇒ br_on_null 𝑙
| 0xD6 𝑙:labelidx ⇒ br_on_non_null 𝑙
| 0xFB 24:u32 (null?1 , null?2 ):castop ⇒ br_on_cast 𝑙 (ref null?1 ht 1 ) (ref null?2 ht 2 )
𝑙:labelidx ht 1 :heaptype ht 2 :heaptype
| 0xFB 25:u32 (null?1 , null?2 ):castop ⇒ br_on_cast_fail 𝑙 (ref null?1 ht 1 ) (ref null?2 h
𝑙:labelidx ht 1 :heaptype ht 2 :heaptype
catch ::= 0x00 𝑥:tagidx 𝑙:labelidx ⇒ catch 𝑥 𝑙
| 0x01 𝑥:tagidx 𝑙:labelidx ⇒ catch_ref 𝑥 𝑙
| 0x02 𝑙:labelidx ⇒ catch_all 𝑙
| 0x03 𝑙:labelidx ⇒ catch_all_ref 𝑙
castop ::= 0x00 ⇒ (𝜖, 𝜖)
| 0x01 ⇒ (null, 𝜖)
| 0x02 ⇒ (𝜖, null)
| 0x03 ⇒ (null, null)

Note

The else opcode 0x05 in the encoding of an if instruction can be omitted if the following instruction sequence
is empty.
Unlike any other occurrence, the type index in a block type is encoded as a positive signed integer, so that its
signed LEB128 bit pattern cannot collide with the encoding of value types or the special code 0x40, which
correspond to the LEB128 encoding of negative integers. To avoid any loss in the range of allowed indices, it
is treated as a 33 bit signed integer.

5.4.3 Variable Instructions


Variable instructions are represented by byte codes followed by the encoding of the respective index.

184 Chapter 5. Binary Format


WebAssembly Specification, Release 3.0 (2025-11-14)

instr ::= ...


| 0x20 𝑥:localidx ⇒ [Link] 𝑥
| 0x21 𝑥:localidx ⇒ [Link] 𝑥
| 0x22 𝑥:localidx ⇒ [Link] 𝑥
| 0x23 𝑥:globalidx ⇒ [Link] 𝑥
| 0x24 𝑥:globalidx ⇒ [Link] 𝑥

5.4.4 Table Instructions


Table instructions are represented either by a single byte or a one byte prefix followed by a variable-length unsigned
integer.

instr ::= ...


| 0x25 𝑥:tableidx ⇒ [Link] 𝑥
| 0x26 𝑥:tableidx ⇒ [Link] 𝑥
| 0xFC 12:u32 𝑦:elemidx 𝑥:tableidx ⇒ [Link] 𝑥 𝑦
| 0xFC 13:u32 𝑥:elemidx ⇒ [Link] 𝑥
| 0xFC 14:u32 𝑥1 :tableidx 𝑥2 :tableidx ⇒ [Link] 𝑥1 𝑥2
| 0xFC 15:u32 𝑥:tableidx ⇒ [Link] 𝑥
| 0xFC 16:u32 𝑥:tableidx ⇒ [Link] 𝑥
| 0xFC 17:u32 𝑥:tableidx ⇒ [Link] 𝑥

5.4.5 Memory Instructions


Each variant of memory instruction is encoded with a different byte code. Loads and stores are followed by the
encoding of their memarg immediate, which includes the memory index if bit 6 of the flags field containing
alignment is set; the memory index defaults to 0 otherwise.

5.4. Instructions 185


WebAssembly Specification, Release 3.0 (2025-11-14)

memarg ::= 𝑛:u32 𝑚:u64 ⇒ (0, {align 𝑛, offset 𝑚}) if 𝑛 < 26


| 𝑛:u32 𝑥:memidx 𝑚:u64 ⇒ (𝑥, {align (𝑛 − 2 ), offset 𝑚}) if 26 ≤ 𝑛 < 27
6

instr ::= ...


| 0x28 (𝑥, ao):memarg ⇒ [Link] 𝑥 ao
| 0x29 (𝑥, ao):memarg ⇒ [Link] 𝑥 ao
| 0x2A (𝑥, ao):memarg ⇒ f [Link] 𝑥 ao
| 0x2B (𝑥, ao):memarg ⇒ f [Link] 𝑥 ao
| 0x2C (𝑥, ao):memarg ⇒ i32.load8_s 𝑥 ao
| 0x2D (𝑥, ao):memarg ⇒ i32.load8_u 𝑥 ao
| 0x2E (𝑥, ao):memarg ⇒ i32.load16_s 𝑥 ao
| 0x2F (𝑥, ao):memarg ⇒ i32.load16_u 𝑥 ao
| 0x30 (𝑥, ao):memarg ⇒ i64.load8_s 𝑥 ao
| 0x31 (𝑥, ao):memarg ⇒ i64.load8_u 𝑥 ao
| 0x32 (𝑥, ao):memarg ⇒ i64.load16_s 𝑥 ao
| 0x33 (𝑥, ao):memarg ⇒ i64.load16_u 𝑥 ao
| 0x34 (𝑥, ao):memarg ⇒ i64.load32_s 𝑥 ao
| 0x35 (𝑥, ao):memarg ⇒ i64.load32_u 𝑥 ao
| 0x36 (𝑥, ao):memarg ⇒ [Link] 𝑥 ao
| 0x37 (𝑥, ao):memarg ⇒ [Link] 𝑥 ao
| 0x38 (𝑥, ao):memarg ⇒ f [Link] 𝑥 ao
| 0x39 (𝑥, ao):memarg ⇒ f [Link] 𝑥 ao
| 0x3A (𝑥, ao):memarg ⇒ i32.store8 𝑥 ao
| 0x3B (𝑥, ao):memarg ⇒ i32.store16 𝑥 ao
| 0x3C (𝑥, ao):memarg ⇒ i64.store8 𝑥 ao
| 0x3D (𝑥, ao):memarg ⇒ i64.store16 𝑥 ao
| 0x3E (𝑥, ao):memarg ⇒ i64.store32 𝑥 ao
| 0x3F 𝑥:memidx ⇒ [Link] 𝑥
| 0x40 𝑥:memidx ⇒ [Link] 𝑥
| 0xFC 8:u32 𝑦:dataidx 𝑥:memidx ⇒ [Link] 𝑥 𝑦
| 0xFC 9:u32 𝑥:dataidx ⇒ [Link] 𝑥
| 0xFC 10:u32 𝑥1 :memidx 𝑥2 :memidx ⇒ [Link] 𝑥1 𝑥2
| 0xFC 11:u32 𝑥:memidx ⇒ [Link] 𝑥

5.4.6 Reference Instructions


Generic reference instructions are represented by single byte codes, others use prefixes and type operands.

instr ::= ...


| 0xD0 ht:heaptype ⇒ [Link] ht
| 0xD1 ⇒ ref.is_null
| 0xD2 𝑥:funcidx ⇒ [Link] 𝑥
| 0xD3 ⇒ [Link]
| 0xD4 ⇒ ref.as_non_null
| 0xFB 20:u32 ht:heaptype ⇒ [Link] (ref ht)
| 0xFB 21:u32 ht:heaptype ⇒ [Link] (ref null ht)
| 0xFB 22:u32 ht:heaptype ⇒ [Link] (ref ht)
| 0xFB 23:u32 ht:heaptype ⇒ [Link] (ref null ht)

5.4.7 Aggregate Instructions


Aggregate instructions all use a prefix.

186 Chapter 5. Binary Format


WebAssembly Specification, Release 3.0 (2025-11-14)

instr ::= ...


| 0xFB 0:u32 𝑥:typeidx ⇒ [Link] 𝑥
| 0xFB 1:u32 𝑥:typeidx ⇒ struct.new_default 𝑥
| 0xFB 2:u32 𝑥:typeidx 𝑖:u32 ⇒ [Link] 𝑥 𝑖
| 0xFB 3:u32 𝑥:typeidx 𝑖:u32 ⇒ struct.get_s 𝑥 𝑖
| 0xFB 4:u32 𝑥:typeidx 𝑖:u32 ⇒ struct.get_u 𝑥 𝑖
| 0xFB 5:u32 𝑥:typeidx 𝑖:u32 ⇒ [Link] 𝑥 𝑖
| 0xFB 6:u32 𝑥:typeidx ⇒ [Link] 𝑥
| 0xFB 7:u32 𝑥:typeidx ⇒ array.new_default 𝑥
| 0xFB 8:u32 𝑥:typeidx 𝑛:u32 ⇒ array.new_fixed 𝑥 𝑛
| 0xFB 9:u32 𝑥:typeidx 𝑦:dataidx ⇒ array.new_data 𝑥 𝑦
| 0xFB 10:u32 𝑥:typeidx 𝑦:elemidx ⇒ array.new_elem 𝑥 𝑦
| 0xFB 11:u32 𝑥:typeidx ⇒ [Link] 𝑥
| 0xFB 12:u32 𝑥:typeidx ⇒ array.get_s 𝑥
| 0xFB 13:u32 𝑥:typeidx ⇒ array.get_u 𝑥
| 0xFB 14:u32 𝑥:typeidx ⇒ [Link] 𝑥
| 0xFB 15:u32 ⇒ [Link]
| 0xFB 16:u32 𝑥:typeidx ⇒ [Link] 𝑥
| 0xFB 17:u32 𝑥1 :typeidx 𝑥2 :typeidx ⇒ [Link] 𝑥1 𝑥2
| 0xFB 18:u32 𝑥:typeidx 𝑦:dataidx ⇒ array.init_data 𝑥 𝑦
| 0xFB 19:u32 𝑥:typeidx 𝑦:elemidx ⇒ array.init_elem 𝑥 𝑦
| 0xFB 26:u32 ⇒ any.convert_extern
| 0xFB 27:u32 ⇒ extern.convert_any
| 0xFB 28:u32 ⇒ ref.i31
| 0xFB 29:u32 ⇒ i31.get_s
| 0xFB 30:u32 ⇒ i31.get_u

5.4.8 Numeric Instructions


All variants of numeric instructions are represented by separate byte codes.
The const instructions are followed by the respective literal.

instr ::= ...


| 0x41 𝑛:u32 ⇒ [Link] 𝑛
| 0x42 𝑛:u64 ⇒ [Link] 𝑛
| 0x43 𝑝:f32 ⇒ f [Link] 𝑝
| 0x44 𝑝:f64 ⇒ f [Link] 𝑝

All other numeric instructions are plain opcodes without any immediates.

5.4. Instructions 187


WebAssembly Specification, Release 3.0 (2025-11-14)

instr ::= ...


| 0x45 ⇒ [Link]
| 0x46 ⇒ [Link]
| 0x47 ⇒ [Link]
| 0x48 ⇒ i32.lt_s
| 0x49 ⇒ i32.lt_u
| 0x4A ⇒ i32.gt_s
| 0x4B ⇒ i32.gt_u
| 0x4C ⇒ i32.le_s
| 0x4D ⇒ i32.le_u
| 0x4E ⇒ i32.ge_s
| 0x4F ⇒ i32.ge_u
| 0x50 ⇒ [Link]
| 0x51 ⇒ [Link]
| 0x52 ⇒ [Link]
| 0x53 ⇒ i64.lt_s
| 0x54 ⇒ i64.lt_u
| 0x55 ⇒ i64.gt_s
| 0x56 ⇒ i64.gt_u
| 0x57 ⇒ i64.le_s
| 0x58 ⇒ i64.le_u
| 0x59 ⇒ i64.ge_s
| 0x5A ⇒ i64.ge_u

instr ::= ...


| 0x5B ⇒ f [Link]
| 0x5C ⇒ f [Link]
| 0x5D ⇒ f [Link]
| 0x5E ⇒ f [Link]
| 0x5F ⇒ f [Link]
| 0x60 ⇒ f [Link]
| 0x61 ⇒ f [Link]
| 0x62 ⇒ f [Link]
| 0x63 ⇒ f [Link]
| 0x64 ⇒ f [Link]
| 0x65 ⇒ f [Link]
| 0x66 ⇒ f [Link]

188 Chapter 5. Binary Format


WebAssembly Specification, Release 3.0 (2025-11-14)

instr ::= ...


| 0x67 ⇒ [Link]
| 0x68 ⇒ [Link]
| 0x69 ⇒ [Link]
| 0x6A ⇒ [Link]
| 0x6B ⇒ [Link]
| 0x6C ⇒ [Link]
| 0x6D ⇒ i32.div_s
| 0x6E ⇒ i32.div_u
| 0x6F ⇒ i32.rem_s
| 0x70 ⇒ i32.rem_u
| 0x71 ⇒ [Link]
| 0x72 ⇒ [Link]
| 0x73 ⇒ [Link]
| 0x74 ⇒ [Link]
| 0x75 ⇒ i32.shr_s
| 0x76 ⇒ i32.shr_u
| 0x77 ⇒ [Link]
| 0x78 ⇒ [Link]
| 0x79 ⇒ [Link]
| 0x7A ⇒ [Link]
| 0x7B ⇒ [Link]
| 0x7C ⇒ [Link]
| 0x7D ⇒ [Link]
| 0x7E ⇒ [Link]
| 0x7F ⇒ i64.div_s
| 0x80 ⇒ i64.div_u
| 0x81 ⇒ i64.rem_s
| 0x82 ⇒ i64.rem_u
| 0x83 ⇒ [Link]
| 0x84 ⇒ [Link]
| 0x85 ⇒ [Link]
| 0x86 ⇒ [Link]
| 0x87 ⇒ i64.shr_s
| 0x88 ⇒ i64.shr_u
| 0x89 ⇒ [Link]
| 0x8A ⇒ [Link]

5.4. Instructions 189


WebAssembly Specification, Release 3.0 (2025-11-14)

instr ::= ...


| 0x8B ⇒ f [Link]
| 0x8C ⇒ f [Link]
| 0x8D ⇒ f [Link]
| 0x8E ⇒ f [Link]
| 0x8F ⇒ f [Link]
| 0x90 ⇒ f [Link]
| 0x91 ⇒ f [Link]
| 0x92 ⇒ f [Link]
| 0x93 ⇒ f [Link]
| 0x94 ⇒ f [Link]
| 0x95 ⇒ f [Link]
| 0x96 ⇒ f [Link]
| 0x97 ⇒ f [Link]
| 0x98 ⇒ f [Link]
| 0x99 ⇒ f [Link]
| 0x9A ⇒ f [Link]
| 0x9B ⇒ f [Link]
| 0x9C ⇒ f [Link]
| 0x9D ⇒ f [Link]
| 0x9E ⇒ f [Link]
| 0x9F ⇒ f [Link]
| 0xA0 ⇒ f [Link]
| 0xA1 ⇒ f [Link]
| 0xA2 ⇒ f [Link]
| 0xA3 ⇒ f [Link]
| 0xA4 ⇒ f [Link]
| 0xA5 ⇒ f [Link]
| 0xA6 ⇒ f [Link]

instr ::= ...


| 0xA7 ⇒ i32.wrap_i64
| 0xA8 ⇒ i32.trunc_s_f 32
| 0xA9 ⇒ i32.trunc_u_f 32
| 0xAA ⇒ i32.trunc_s_f 64
| 0xAB ⇒ i32.trunc_u_f 64
| 0xAC ⇒ i64.extend_s_i32
| 0xAD ⇒ i64.extend_u_i32
| 0xAE ⇒ i64.trunc_s_f 32
| 0xAF ⇒ i64.trunc_u_f 32
| 0xB0 ⇒ i64.trunc_s_f 64
| 0xB1 ⇒ i64.trunc_u_f 64
| 0xB2 ⇒ f 32.convert_s_i32
| 0xB3 ⇒ f 32.convert_u_i32
| 0xB4 ⇒ f 32.convert_s_i64
| 0xB5 ⇒ f 32.convert_u_i64
| 0xB6 ⇒ f 32.demote_f 64
| 0xB7 ⇒ f 64.convert_s_i32
| 0xB8 ⇒ f 64.convert_u_i32
| 0xB9 ⇒ f 64.convert_s_i64
| 0xBA ⇒ f 64.convert_u_i64
| 0xBB ⇒ f 64.promote_f 32
| 0xBC ⇒ i32.reinterpret_f 32
| 0xBD ⇒ i64.reinterpret_f 64
| 0xBE ⇒ f 32.reinterpret_i32
| 0xBF ⇒ f 64.reinterpret_i64

190 Chapter 5. Binary Format


WebAssembly Specification, Release 3.0 (2025-11-14)

instr ::= ...


| 0xC0 ⇒ i32.extend8_s
| 0xC1 ⇒ i32.extend16_s
| 0xC2 ⇒ i64.extend8_s
| 0xC3 ⇒ i64.extend16_s
| 0xC4 ⇒ i64.extend32_s
The saturating truncation instructions all have a one byte prefix, whereas the actual opcode is encoded by a variable-
length unsigned integer.

instr ::= ...


| 0xFC 0:u32 ⇒ i32.trunc_sat_s_f 32
| 0xFC 1:u32 ⇒ i32.trunc_sat_u_f 32
| 0xFC 2:u32 ⇒ i32.trunc_sat_s_f 64
| 0xFC 3:u32 ⇒ i32.trunc_sat_u_f 64
| 0xFC 4:u32 ⇒ i64.trunc_sat_s_f 32
| 0xFC 5:u32 ⇒ i64.trunc_sat_u_f 32
| 0xFC 6:u32 ⇒ i64.trunc_sat_s_f 64
| 0xFC 7:u32 ⇒ i64.trunc_sat_u_f 64

5.4.9 Vector Instructions


All variants of vector instructions are represented by separate byte codes. They all have a one byte prefix, whereas
the actual opcode is encoded by a variable-length unsigned integer.
Vector loads and stores are followed by the encoding of their memarg immediate.

laneidx ::= 𝑙:byte ⇒ 𝑙


instr ::= ...
| 0xFD 0:u32 (𝑥, ao):memarg ⇒ [Link] 𝑥 ao
| 0xFD 1:u32 (𝑥, ao):memarg ⇒ v128.load8x8_s 𝑥 ao
| 0xFD 2:u32 (𝑥, ao):memarg ⇒ v128.load8x8_u 𝑥 ao
| 0xFD 3:u32 (𝑥, ao):memarg ⇒ v128.load16x4_s 𝑥 ao
| 0xFD 4:u32 (𝑥, ao):memarg ⇒ v128.load16x4_u 𝑥 ao
| 0xFD 5:u32 (𝑥, ao):memarg ⇒ v128.load32x2_s 𝑥 ao
| 0xFD 6:u32 (𝑥, ao):memarg ⇒ v128.load32x2_u 𝑥 ao
| 0xFD 7:u32 (𝑥, ao):memarg ⇒ v128.load8_splat 𝑥 ao
| 0xFD 8:u32 (𝑥, ao):memarg ⇒ v128.load16_splat 𝑥 ao
| 0xFD 9:u32 (𝑥, ao):memarg ⇒ v128.load32_splat 𝑥 ao
| 0xFD 10:u32 (𝑥, ao):memarg ⇒ v128.load64_splat 𝑥 ao
| 0xFD 11:u32 (𝑥, ao):memarg ⇒ [Link] 𝑥 ao
| 0xFD 84:u32 (𝑥, ao):memarg 𝑖:laneidx ⇒ v128.load8_lane 𝑥 ao 𝑖
| 0xFD 85:u32 (𝑥, ao):memarg 𝑖:laneidx ⇒ v128.load16_lane 𝑥 ao 𝑖
| 0xFD 86:u32 (𝑥, ao):memarg 𝑖:laneidx ⇒ v128.load32_lane 𝑥 ao 𝑖
| 0xFD 87:u32 (𝑥, ao):memarg 𝑖:laneidx ⇒ v128.load64_lane 𝑥 ao 𝑖
| 0xFD 88:u32 (𝑥, ao):memarg 𝑖:laneidx ⇒ v128.store8_lane 𝑥 ao 𝑖
| 0xFD 89:u32 (𝑥, ao):memarg 𝑖:laneidx ⇒ v128.store16_lane 𝑥 ao 𝑖
| 0xFD 90:u32 (𝑥, ao):memarg 𝑖:laneidx ⇒ v128.store32_lane 𝑥 ao 𝑖
| 0xFD 91:u32 (𝑥, ao):memarg 𝑖:laneidx ⇒ v128.store64_lane 𝑥 ao 𝑖
| 0xFD 92:u32 (𝑥, ao):memarg ⇒ v128.load32_zero 𝑥 ao
| 0xFD 93:u32 (𝑥, ao):memarg ⇒ v128.load64_zero 𝑥 ao

The const instruction for vectors is followed by 16 immediate bytes, which are converted into an u128 in
littleendian byte order:

instr ::= . . .
| 0xFD 12:u32 (𝑏:byte)16 ⇒ [Link] bytes−1 16
i128 ((𝑏) )

5.4. Instructions 191


WebAssembly Specification, Release 3.0 (2025-11-14)

The shuffle instruction is also followed by the encoding of 16 laneidx immediates.

instr ::= ...


| 0xFD 13:u32 (𝑙:laneidx)16 ⇒ [Link] 𝑙16
| 0xFD 14:u32 ⇒ [Link]
| 0xFD 256:u32 ⇒ i8x16.relaxed_swizzle

Lane instructions are followed by the encoding of a laneidx immediate.

instr ::= ...


| 0xFD 21:u32 𝑙:laneidx ⇒ i8x16.extract_lane_s 𝑙
| 0xFD 22:u32 𝑙:laneidx ⇒ i8x16.extract_lane_u 𝑙
| 0xFD 23:u32 𝑙:laneidx ⇒ i8x16.replace_lane 𝑙
| 0xFD 24:u32 𝑙:laneidx ⇒ i16x8.extract_lane_s 𝑙
| 0xFD 25:u32 𝑙:laneidx ⇒ i16x8.extract_lane_u 𝑙
| 0xFD 26:u32 𝑙:laneidx ⇒ i16x8.replace_lane 𝑙
| 0xFD 27:u32 𝑙:laneidx ⇒ i32x4.extract_lane 𝑙
| 0xFD 28:u32 𝑙:laneidx ⇒ i32x4.replace_lane 𝑙
| 0xFD 29:u32 𝑙:laneidx ⇒ i64x2.extract_lane 𝑙
| 0xFD 30:u32 𝑙:laneidx ⇒ i64x2.replace_lane 𝑙
| 0xFD 31:u32 𝑙:laneidx ⇒ f 32x4.extract_lane 𝑙
| 0xFD 32:u32 𝑙:laneidx ⇒ f 32x4.replace_lane 𝑙
| 0xFD 33:u32 𝑙:laneidx ⇒ f 64x2.extract_lane 𝑙
| 0xFD 34:u32 𝑙:laneidx ⇒ f 64x2.replace_lane 𝑙

All other vector instructions are plain opcodes without any immediates.

instr ::= ...


| 0xFD 15:u32 ⇒ [Link]
| 0xFD 16:u32 ⇒ [Link]
| 0xFD 17:u32 ⇒ [Link]
| 0xFD 18:u32 ⇒ [Link]
| 0xFD 19:u32 ⇒ f [Link]
| 0xFD 20:u32 ⇒ f [Link]

192 Chapter 5. Binary Format


WebAssembly Specification, Release 3.0 (2025-11-14)

instr ::= ...


| 0xFD 35:u32 ⇒ [Link]
| 0xFD 36:u32 ⇒ [Link]
| 0xFD 37:u32 ⇒ i8x16.lt_s
| 0xFD 38:u32 ⇒ i8x16.lt_u
| 0xFD 39:u32 ⇒ i8x16.gt_s
| 0xFD 40:u32 ⇒ i8x16.gt_u
| 0xFD 41:u32 ⇒ i8x16.le_s
| 0xFD 42:u32 ⇒ i8x16.le_u
| 0xFD 43:u32 ⇒ i8x16.ge_s
| 0xFD 44:u32 ⇒ i8x16.ge_u
| 0xFD 45:u32 ⇒ [Link]
| 0xFD 46:u32 ⇒ [Link]
| 0xFD 47:u32 ⇒ i16x8.lt_s
| 0xFD 48:u32 ⇒ i16x8.lt_u
| 0xFD 49:u32 ⇒ i16x8.gt_s
| 0xFD 50:u32 ⇒ i16x8.gt_u
| 0xFD 51:u32 ⇒ i16x8.le_s
| 0xFD 52:u32 ⇒ i16x8.le_u
| 0xFD 53:u32 ⇒ i16x8.ge_s
| 0xFD 54:u32 ⇒ i16x8.ge_u
| 0xFD 55:u32 ⇒ [Link]
| 0xFD 56:u32 ⇒ [Link]
| 0xFD 57:u32 ⇒ i32x4.lt_s
| 0xFD 58:u32 ⇒ i32x4.lt_u
| 0xFD 59:u32 ⇒ i32x4.gt_s
| 0xFD 60:u32 ⇒ i32x4.gt_u
| 0xFD 61:u32 ⇒ i32x4.le_s
| 0xFD 62:u32 ⇒ i32x4.le_u
| 0xFD 63:u32 ⇒ i32x4.ge_s
| 0xFD 64:u32 ⇒ i32x4.ge_u
| 0xFD 214:u32 ⇒ [Link]
| 0xFD 215:u32 ⇒ [Link]
| 0xFD 216:u32 ⇒ i64x2.lt_s
| 0xFD 217:u32 ⇒ i64x2.gt_s
| 0xFD 218:u32 ⇒ i64x2.le_s
| 0xFD 219:u32 ⇒ i64x2.ge_s

instr ::= ...


| 0xFD 65:u32 ⇒ f [Link]
| 0xFD 66:u32 ⇒ f [Link]
| 0xFD 67:u32 ⇒ f [Link]
| 0xFD 68:u32 ⇒ f [Link]
| 0xFD 69:u32 ⇒ f [Link]
| 0xFD 70:u32 ⇒ f [Link]
| 0xFD 71:u32 ⇒ f [Link]
| 0xFD 72:u32 ⇒ f [Link]
| 0xFD 73:u32 ⇒ f [Link]
| 0xFD 74:u32 ⇒ f [Link]
| 0xFD 75:u32 ⇒ f [Link]
| 0xFD 76:u32 ⇒ f [Link]

5.4. Instructions 193


WebAssembly Specification, Release 3.0 (2025-11-14)

instr ::= ...


| 0xFD 77:u32 ⇒ [Link]
| 0xFD 78:u32 ⇒ [Link]
| 0xFD 79:u32 ⇒ [Link]
| 0xFD 80:u32 ⇒ [Link]
| 0xFD 81:u32 ⇒ [Link]
| 0xFD 82:u32 ⇒ [Link]
| 0xFD 83:u32 ⇒ v128.any_true

instr ::= ...


| 0xFD 96:u32 ⇒ [Link]
| 0xFD 97:u32 ⇒ [Link]
| 0xFD 98:u32 ⇒ [Link]
| 0xFD 99:u32 ⇒ i8x16.all_true
| 0xFD 100:u32 ⇒ [Link]
| 0xFD 101:u32 ⇒ i8x16.narrow_i16x8_s
| 0xFD 102:u32 ⇒ i8x16.narrow_i16x8_u
| 0xFD 107:u32 ⇒ [Link]
| 0xFD 108:u32 ⇒ i8x16.shr_s
| 0xFD 109:u32 ⇒ i8x16.shr_u
| 0xFD 110:u32 ⇒ [Link]
| 0xFD 111:u32 ⇒ i8x16.add_sat_s
| 0xFD 112:u32 ⇒ i8x16.add_sat_u
| 0xFD 113:u32 ⇒ [Link]
| 0xFD 114:u32 ⇒ i8x16.sub_sat_s
| 0xFD 115:u32 ⇒ i8x16.sub_sat_u
| 0xFD 118:u32 ⇒ i8x16.min_s
| 0xFD 119:u32 ⇒ i8x16.min_u
| 0xFD 120:u32 ⇒ i8x16.max_s
| 0xFD 121:u32 ⇒ i8x16.max_u
| 0xFD 123:u32 ⇒ i8x16.avgr_u

194 Chapter 5. Binary Format


WebAssembly Specification, Release 3.0 (2025-11-14)

instr ::= ...


| 0xFD 124:u32 ⇒ i16x8.extadd_pairwise_s_i8x16
| 0xFD 125:u32 ⇒ i16x8.extadd_pairwise_u_i8x16
| 0xFD 128:u32 ⇒ [Link]
| 0xFD 129:u32 ⇒ [Link]
| 0xFD 131:u32 ⇒ i16x8.all_true
| 0xFD 132:u32 ⇒ [Link]
| 0xFD 133:u32 ⇒ i16x8.narrow_i32x4_s
| 0xFD 134:u32 ⇒ i16x8.narrow_i32x4_u
| 0xFD 135:u32 ⇒ i16x8.extend_low_s_i8x16
| 0xFD 136:u32 ⇒ i16x8.extend_high_s_i8x16
| 0xFD 137:u32 ⇒ i16x8.extend_low_u_i8x16
| 0xFD 138:u32 ⇒ i16x8.extend_high_u_i8x16
| 0xFD 139:u32 ⇒ [Link]
| 0xFD 140:u32 ⇒ i16x8.shr_s
| 0xFD 141:u32 ⇒ i16x8.shr_u
| 0xFD 130:u32 ⇒ i16x8.q15mulr_sat_s
| 0xFD 142:u32 ⇒ [Link]
| 0xFD 143:u32 ⇒ i16x8.add_sat_s
| 0xFD 144:u32 ⇒ i16x8.add_sat_u
| 0xFD 145:u32 ⇒ [Link]
| 0xFD 146:u32 ⇒ i16x8.sub_sat_s
| 0xFD 147:u32 ⇒ i16x8.sub_sat_u
| 0xFD 149:u32 ⇒ [Link]
| 0xFD 150:u32 ⇒ i16x8.min_s
| 0xFD 151:u32 ⇒ i16x8.min_u
| 0xFD 152:u32 ⇒ i16x8.max_s
| 0xFD 153:u32 ⇒ i16x8.max_u
| 0xFD 155:u32 ⇒ i16x8.avgr_u
| 0xFD 273:u32 ⇒ i16x8.relaxed_q15mulr_s
| 0xFD 156:u32 ⇒ i16x8.extmul_low_s_i8x16
| 0xFD 157:u32 ⇒ i16x8.extmul_high_s_i8x16
| 0xFD 158:u32 ⇒ i16x8.extmul_low_u_i8x16
| 0xFD 159:u32 ⇒ i16x8.extmul_high_u_i8x16
| 0xFD 274:u32 ⇒ i16x8.relaxed_dot_s_i8x16

5.4. Instructions 195


WebAssembly Specification, Release 3.0 (2025-11-14)

instr ::= ...


| 0xFD 126:u32 ⇒ i32x4.extadd_pairwise_s_i16x8
| 0xFD 127:u32 ⇒ i32x4.extadd_pairwise_u_i16x8
| 0xFD 160:u32 ⇒ [Link]
| 0xFD 161:u32 ⇒ [Link]
| 0xFD 163:u32 ⇒ i32x4.all_true
| 0xFD 164:u32 ⇒ [Link]
| 0xFD 167:u32 ⇒ i32x4.extend_low_s_i16x8
| 0xFD 168:u32 ⇒ i32x4.extend_high_s_i16x8
| 0xFD 169:u32 ⇒ i32x4.extend_low_u_i16x8
| 0xFD 170:u32 ⇒ i32x4.extend_high_u_i16x8
| 0xFD 171:u32 ⇒ [Link]
| 0xFD 172:u32 ⇒ i32x4.shr_s
| 0xFD 173:u32 ⇒ i32x4.shr_u
| 0xFD 174:u32 ⇒ [Link]
| 0xFD 177:u32 ⇒ [Link]
| 0xFD 181:u32 ⇒ [Link]
| 0xFD 182:u32 ⇒ i32x4.min_s
| 0xFD 183:u32 ⇒ i32x4.min_u
| 0xFD 184:u32 ⇒ i32x4.max_s
| 0xFD 185:u32 ⇒ i32x4.max_u
| 0xFD 186:u32 ⇒ i32x4.dot_s_i16x8
| 0xFD 188:u32 ⇒ i32x4.extmul_low_s_i16x8
| 0xFD 189:u32 ⇒ i32x4.extmul_high_s_i16x8
| 0xFD 190:u32 ⇒ i32x4.extmul_low_u_i16x8
| 0xFD 191:u32 ⇒ i32x4.extmul_high_u_i16x8
| 0xFD 275:u32 ⇒ i32x4.relaxed_dot_add_s_i16x8
instr ::= ...
| 0xFD 192:u32 ⇒ [Link]
| 0xFD 193:u32 ⇒ [Link]
| 0xFD 195:u32 ⇒ i64x2.all_true
| 0xFD 196:u32 ⇒ [Link]
| 0xFD 199:u32 ⇒ i64x2.extend_low_s_i32x4
| 0xFD 200:u32 ⇒ i64x2.extend_high_s_i32x4
| 0xFD 201:u32 ⇒ i64x2.extend_low_u_i32x4
| 0xFD 202:u32 ⇒ i64x2.extend_high_u_i32x4
| 0xFD 203:u32 ⇒ [Link]
| 0xFD 204:u32 ⇒ i64x2.shr_s
| 0xFD 205:u32 ⇒ i64x2.shr_u
| 0xFD 206:u32 ⇒ [Link]
| 0xFD 209:u32 ⇒ [Link]
| 0xFD 213:u32 ⇒ [Link]
| 0xFD 220:u32 ⇒ i64x2.extmul_low_s_i32x4
| 0xFD 221:u32 ⇒ i64x2.extmul_high_s_i32x4
| 0xFD 222:u32 ⇒ i64x2.extmul_low_u_i32x4
| 0xFD 223:u32 ⇒ i64x2.extmul_high_u_i32x4

196 Chapter 5. Binary Format


WebAssembly Specification, Release 3.0 (2025-11-14)

instr ::= ...


| 0xFD 103:u32 ⇒ f [Link]
| 0xFD 104:u32 ⇒ f [Link]
| 0xFD 105:u32 ⇒ f [Link]
| 0xFD 106:u32 ⇒ f [Link]
| 0xFD 224:u32 ⇒ f [Link]
| 0xFD 225:u32 ⇒ f [Link]
| 0xFD 227:u32 ⇒ f [Link]
| 0xFD 228:u32 ⇒ f [Link]
| 0xFD 229:u32 ⇒ f [Link]
| 0xFD 230:u32 ⇒ f [Link]
| 0xFD 231:u32 ⇒ f [Link]
| 0xFD 232:u32 ⇒ f [Link]
| 0xFD 233:u32 ⇒ f [Link]
| 0xFD 234:u32 ⇒ f [Link]
| 0xFD 235:u32 ⇒ f [Link]
| 0xFD 269:u32 ⇒ f 32x4.relaxed_min
| 0xFD 270:u32 ⇒ f 32x4.relaxed_max
| 0xFD 261:u32 ⇒ f 32x4.relaxed_madd
| 0xFD 262:u32 ⇒ f 32x4.relaxed_nmadd

instr ::= ...


| 0xFD 116:u32 ⇒ f [Link]
| 0xFD 117:u32 ⇒ f [Link]
| 0xFD 122:u32 ⇒ f [Link]
| 0xFD 148:u32 ⇒ f [Link]
| 0xFD 236:u32 ⇒ f [Link]
| 0xFD 237:u32 ⇒ f [Link]
| 0xFD 239:u32 ⇒ f [Link]
| 0xFD 240:u32 ⇒ f [Link]
| 0xFD 241:u32 ⇒ f [Link]
| 0xFD 242:u32 ⇒ f [Link]
| 0xFD 243:u32 ⇒ f [Link]
| 0xFD 244:u32 ⇒ f [Link]
| 0xFD 245:u32 ⇒ f [Link]
| 0xFD 246:u32 ⇒ f [Link]
| 0xFD 247:u32 ⇒ f [Link]
| 0xFD 271:u32 ⇒ f 64x2.relaxed_min
| 0xFD 272:u32 ⇒ f 64x2.relaxed_max
| 0xFD 263:u32 ⇒ f 64x2.relaxed_madd
| 0xFD 264:u32 ⇒ f 64x2.relaxed_nmadd
| 0xFD 265:u32 ⇒ i8x16.relaxed_laneselect
| 0xFD 266:u32 ⇒ i16x8.relaxed_laneselect
| 0xFD 267:u32 ⇒ i32x4.relaxed_laneselect
| 0xFD 268:u32 ⇒ i64x2.relaxed_laneselect

5.4. Instructions 197


WebAssembly Specification, Release 3.0 (2025-11-14)

instr ::= ...


| 0xFD 94:u32 ⇒ f 32x4.demote_zero_f 64x2
| 0xFD 95:u32 ⇒ f 64x2.promote_low_f 32x4
| 0xFD 248:u32 ⇒ i32x4.trunc_sat_s_f 32x4
| 0xFD 249:u32 ⇒ i32x4.trunc_sat_u_f 32x4
| 0xFD 250:u32 ⇒ f 32x4.convert_s_i32x4
| 0xFD 251:u32 ⇒ f 32x4.convert_u_i32x4
| 0xFD 252:u32 ⇒ i32x4.trunc_sat_s_zero_f 64x2
| 0xFD 253:u32 ⇒ i32x4.trunc_sat_u_zero_f 64x2
| 0xFD 254:u32 ⇒ f 64x2.convert_low_s_i32x4
| 0xFD 255:u32 ⇒ f 64x2.convert_low_u_i32x4
| 0xFD 257:u32 ⇒ i32x4.relaxed_trunc_s_f 32x4
| 0xFD 258:u32 ⇒ i32x4.relaxed_trunc_u_f 32x4
| 0xFD 259:u32 ⇒ i32x4.relaxed_trunc_s_zero_f 64x2
| 0xFD 260:u32 ⇒ i32x4.relaxed_trunc_u_zero_f 64x2

5.4.10 Expressions
Expressions are encoded by their instruction sequence terminated with an explicit 0x0B opcode for end.

expr ::= (in:instr)* 0x0B ⇒ in *

5.5 Modules
The binary encoding of modules is organized into sections. Most sections correspond to one component of a
module record, except that function definitions are split into two sections, separating their type declarations in the
function section from their bodies in the code section.

Note

This separation enables parallel and streaming compilation of the functions in a module.

5.5.1 Indices
All basic indices are encoded with their respective value.

typeidx ::= 𝑥:u32 ⇒ 𝑥


funcidx ::= 𝑥:u32 ⇒ 𝑥
tableidx ::= 𝑥:u32 ⇒ 𝑥
memidx ::= 𝑥:u32 ⇒ 𝑥
globalidx ::= 𝑥:u32 ⇒ 𝑥
tagidx ::= 𝑥:u32 ⇒ 𝑥
elemidx ::= 𝑥:u32 ⇒ 𝑥
dataidx ::= 𝑥:u32 ⇒ 𝑥
localidx ::= 𝑥:u32 ⇒ 𝑥
labelidx ::= 𝑙:u32 ⇒ 𝑙

External indices are encoded by a distiguishing byte followed by an encoding of their respective value.

externidx ::= 0x00 𝑥:funcidx ⇒ func 𝑥


| 0x01 𝑥:tableidx ⇒ table 𝑥
| 0x02 𝑥:memidx ⇒ memory 𝑥
| 0x03 𝑥:globalidx ⇒ global 𝑥
| 0x04 𝑥:tagidx ⇒ tag 𝑥

198 Chapter 5. Binary Format


WebAssembly Specification, Release 3.0 (2025-11-14)

5.5.2 Sections
Each section consists of
• a one-byte section id,
• the u32 length of the contents, in bytes,
• the actual contents, whose structure is dependent on the section id.
Every section is optional; an omitted section is equivalent to the section being present with empty contents.
The following parameterized grammar rule defines the generic structure of a section with id 𝑁 and contents de-
scribed by the grammar X.

section𝑁 (X) ::= 𝑁 :byte len:u32 en * :X ⇒ en * if len = ||X||


| 𝜖 ⇒ 𝜖

For most sections, the contents X encodes a list. In these cases, the empty result 𝜖 is interpreted as the empty list.

Note

Other than for unknown custom sections, the size is not required for decoding, but can be used to skip sections
when navigating through a binary. The module is malformed if the size does not match the length of the binary
contents X.

The following section ids are used:

Id Section
0 custom section
1 type section
2 import section
3 function section
4 table section
5 memory section
6 global section
7 export section
8 start section
9 element section
10 code section
11 data section
12 data count section
13 tag section

Note

Section ids do not always correspond to the order of sections in the encoding of a module.

5.5.3 Custom Section


Custom sections have the id 0. They are intended to be used for debugging information or third-party extensions,
and are ignored by the WebAssembly semantics. Their contents consist of a name further identifying the custom
section, followed by an uninterpreted sequence of bytes for custom use.

customsec ::= section0 (custom)


custom ::= name byte*

5.5. Modules 199


WebAssembly Specification, Release 3.0 (2025-11-14)

Note

If an implementation interprets the data of a custom section, then errors in that data, or the placement of the
section, must not invalidate the module.

5.5.4 Type Section


The type section has the id 1. It decodes into the list of recursive types of a module.
typesec ::= ty * :section1 (list(type)) ⇒ ty *
type ::= qt:rectype ⇒ type qt

5.5.5 Import Section


The import section has the id 2. It decodes into the list of imports of a module.
importsec ::= im * :section2 (list(import)) ⇒ im *
import ::= nm 1 :name nm 2 :name xt:externtype ⇒ import nm 1 nm 2 xt

5.5.6 Function Section


The function section has the id 3. It decodes into a list of type indices that classify the functions defined by a
module. The bodies of the respective functions are encoded separately in the code section.

funcsec ::= 𝑥* :section3 (list(typeidx)) ⇒ 𝑥*

5.5.7 Table Section


The table section has the id 4. It decodes into the list of tables defined by a module.
tablesec ::= tab * :section4 (list(table)) ⇒ tab *
table ::= tt:tabletype ⇒ table tt ([Link] ht) if tt = at lim (ref null? ht)
| 0x40 0x00 tt:tabletype 𝑒:expr ⇒ table tt 𝑒

Note

The encoding of a table type cannot start with byte 0x40, hence decoding is unambiguous. The zero byte
following it is reserved for future extensions.

5.5.8 Memory Section


The memory section has the id 5. It decodes into the list of memories defined by a module.
memsec ::= mem * :section5 (list(mem)) ⇒ mem *
mem ::= mt:memtype ⇒ memory mt

5.5.9 Global Section


The global section has the id 6. It decodes into the list of globals defined by a module.
globalsec ::= glob * :section6 (list(global)) ⇒ glob *
global ::= gt:globaltype 𝑒:expr ⇒ global gt 𝑒

200 Chapter 5. Binary Format


WebAssembly Specification, Release 3.0 (2025-11-14)

5.5.10 Export Section


The export section has the id 7. It decodes into the list of exports of a module.

exportsec ::= ex * :section7 (list(export)) ⇒ ex *


export ::= nm:name xx :externidx ⇒ export nm xx

5.5.11 Start Section


The start section has the id 8. It decodes into the optional start function of a module.

startsec ::= start ? :section8 (start) ⇒ start ?


start ::= 𝑥:funcidx ⇒ (start 𝑥)

5.5.12 Element Section


The element section has the id 9. It decodes into the list of element segments defined by a module.

elemsec ::= elem * :section9 (list(elem)) ⇒ elem *


elemkind ::= 0x00 ⇒ ref null func
elem ::= 0:u32 𝑒𝑜 :expr 𝑦 * :list(funcidx) ⇒
elem (ref func) ([Link] 𝑦)* (active 0 𝑒𝑜 )
| 1:u32 rt:elemkind 𝑦 * :list(funcidx) ⇒
elem rt ([Link] 𝑦)* passive
| 2:u32 𝑥:tableidx 𝑒:expr rt:elemkind 𝑦 * :list(funcidx) ⇒
elem rt ([Link] 𝑦)* (active 𝑥 𝑒)
| 3:u32 rt:elemkind 𝑦 * :list(funcidx) ⇒
elem rt ([Link] 𝑦)* declare
| 4:u32 𝑒o :expr 𝑒* :list(expr) ⇒
elem (ref null func) 𝑒* (active 0 𝑒o )
| 5:u32 rt:reftype 𝑒* :list(expr) ⇒
elem rt 𝑒* passive
| 6:u32 𝑥:tableidx 𝑒o :expr 𝑒* :list(expr) ⇒
elem (ref null func) 𝑒* (active 𝑥 𝑒o )
| 7:u32 rt:reftype 𝑒* :list(expr) ⇒
elem rt 𝑒* declare

Note

The initial integer can be interpreted as a bitfield. Bit 0 distinguishes a passive or declarative segment from
an active segment, bit 1 indicates the presence of an explicit table index for an active segment and otherwise
distinguishes passive from declarative segments, bit 2 indicates the use of element type and element expressions
instead of element kind and element indices.
Additional element kinds may be added in future versions of WebAssembly.

5.5.13 Code Section


The code section has the id 10. It decodes into the list of code entries that are pairs of lists of locals and expressions.
They represent the body of the functions defined by a module. The types of the respective functions are encoded
separately in the function section.
The encoding of each code entry consists of
• the u32 length of the function code in bytes,
• the actual function code, which in turn consists of

5.5. Modules 201


WebAssembly Specification, Release 3.0 (2025-11-14)

– the declaration of locals,


– the function body as an expression.
Local declarations are compressed into a list whose entries consist of
• a u32 count,
• a value type,
denoting count locals of the same value type.

codesec ::= code * :section10 (list(code)) ⇒ code *


code ::= len:u32 code:func ⇒ code if len
⨁︀ = ||func||
* * *
loc * :list(locals) 𝑒:expr ( loc * , 𝑒) if | loc * | < 232
⨁︀
func ::= ⇒
locals ::= 𝑛:u32 𝑡:valtype ⇒ (local 𝑡)𝑛

Here, code ranges over pairs (local * , expr ). Any code for which the length of the resulting sequence is out of
bounds of the maximum size of a list is malformed.

Note

Like with sections, the code size is not needed for decoding, but can be used to skip functions when navigating
through a binary. The module is malformed if a size does not match the length of the respective function code.

5.5.14 Data Section


The data section has the id 11. It decodes into the list of data segments defined by a module.

datasec ::= data * :section11 (list(data)) ⇒ data *


data ::= 0:u32 𝑒:expr 𝑏* :list(byte) ⇒ data 𝑏* (active 0 𝑒)
| 1:u32 𝑏* :list(byte) ⇒ data 𝑏* passive
| 2:u32 𝑥:memidx 𝑒:expr 𝑏* :list(byte) ⇒ data 𝑏* (active 𝑥 𝑒)

Note

The initial integer can be interpreted as a bitfield. Bit 0 indicates a passive segment, bit 1 indicates the presence
of an explicit memory index for an active segment.

5.5.15 Data Count Section


The data count section has the id 12. It decodes into an optional u32 count that represents the number of data
segments in the data section. If this count does not match the length of the data segment list, the module is
malformed.
datacntsec ::= 𝑛? :section12 (datacnt) ⇒ 𝑛?
datacnt ::= 𝑛:u32 ⇒ 𝑛

Note

The data count section is used to simplify single-pass validation. Since the data section occurs after the code
section, the [Link] and [Link] instructions would not be able to check whether the data segment index
is valid until the data section is read. The data count section occurs before the code section, so a single-pass
validator can use this count instead of deferring validation.

202 Chapter 5. Binary Format


WebAssembly Specification, Release 3.0 (2025-11-14)

5.5.16 Tag Section


The tag section has the id 13. It decodes into the list of tags defined by a module.

tagsec ::= tag * :section13 (list(tag)) ⇒ tag *


tag ::= jt:tagtype ⇒ tag jt

5.5.17 Modules
The encoding of a module starts with a preamble containing a 4-byte magic number (the string ‘∖0asm’) and a
version field. The current version of the WebAssembly binary format is 1.
The preamble is followed by a sequence of sections. Custom sections may be inserted at any place in this sequence,
while other sections must occur at most once and in the prescribed order. All sections can be empty.
The lengths of lists produced by the (possibly empty) function and code section must match up.
Similarly, the optional data count must match the length of the data segment list. Furthermore, it must be present
if any data index occurs in the code section.

magic ::= 0x00 0x61 0x73 0x6D


version ::= 0x01 0x00 0x00 0x00
module ::= magic version ⇒
customsec* type * :typesec
customsec* import * :importsec
customsec* typeidx * :funcsec
customsec* table * :tablesec
customsec* mem * :memsec
customsec* tag * :tagsec
customsec* global * :globalsec
customsec* export * :exportsec
customsec* start ? :startsec
customsec* elem * :elemsec
customsec* 𝑛? :datacntsec
customsec* (local * , expr )* :codesec
customsec* data * :datasec
customsec*
module type * import * tag * global * mem * table * func * data * elem * start ? export *
if (𝑛 = |data * |)?
∧ (𝑛? ̸= 𝜖 ∨ dataidx(func * ) = 𝜖)
∧ (func = func typeidx local * expr )*

Note

The version of the WebAssembly binary format may increase in the future if backward-incompatible changes
have to be made to the format. However, such changes are expected to occur very infrequently, if ever. The
binary format is intended to be extensible, such that future features can be added without incrementing its
version.

5.5. Modules 203


WebAssembly Specification, Release 3.0 (2025-11-14)

204 Chapter 5. Binary Format


CHAPTER 6

Text Format

6.1 Conventions
The textual format for WebAssembly modules is a rendering of their abstract syntax into S-expressions36 .
Like the binary format, the text format is defined by an attribute grammar. A text string is a well-formed description
of a module if and only if it is generated by the grammar. Each production of this grammar has at most one
synthesized attribute: the abstract syntax that the respective character sequence expresses. Thus, the attribute
grammar implicitly defines a parsing function. Some productions also take a context as an inherited attribute that
records bound identifiers.
Except for a few exceptions, the core of the text grammar closely mirrors the grammar of the abstract syntax.
However, it also defines a number of abbreviations that are “syntactic sugar” over the core syntax.
The recommended extension for files containing WebAssembly modules in text format is “.wat”. Files with this
extension are assumed to be encoded in UTF-8, as per Unicode37 (Section 2.5).

6.1.1 Grammar
The following conventions are adopted in defining grammar rules of the text format. They mirror the conventions
used for abstract syntax and for the binary format. In order to distinguish symbols of the textual syntax from
symbols of the abstract syntax, typewriter font is adopted for the former.
• Terminal symbols are either literal strings of characters enclosed in quotes or expressed as Unicode38 scalar
values: ‘module’, U+0A. (All characters written literally are unambiguously drawn from the 7-bit ASCII39
subset of Unicode.)
• Nonterminal symbols are written in typewriter font: valtype, instr.
• 𝑇 𝑛 is a sequence of 𝑛 ≥ 0 iterations of 𝑇 .
• 𝑇 * is a possibly empty sequence of iterations of 𝑇 . (This is a shorthand for 𝑇 𝑛 used where 𝑛 is not relevant.)
• 𝑇 + is a possibly empty sequence of iterations of 𝑇 . (This is a shorthand for 𝑇 𝑛 used where 𝑛 is not relevant.)
• 𝑇 ? is an optional occurrence of 𝑇 . (This is a shorthand for 𝑇 𝑛 where 𝑛 ≤ 1.)
36 [Link]
37 [Link]
38 [Link]
39 [Link]

205
WebAssembly Specification, Release 3.0 (2025-11-14)

• 𝑥:𝑇 denotes the same language as the nonterminal 𝑇 , but also binds the variable 𝑥 to the attribute synthesized
for 𝑇 . A pattern may also be used instead of a variable, e.g., 7:𝑇 .
• Productions are written sym ::= 𝑇1 ⇒ 𝐴1 | . . . | 𝑇𝑛 ⇒ 𝐴𝑛 , where each 𝐴𝑖 is the attribute that is syn-
thesized for sym in the given case, usually from attribute variables bound in 𝑇𝑖 .
• Large productions may be split into multiple definitions, indicated by ending the first one with explicit el-
lipses, sym ::= 𝐵1 , and starting continuations with ellipses, sym ::= . . . | 𝐵2 .
• Some productions are augmented by side conditions in parentheses, which restrict the applicability of the
production. They provide a shorthand for a combinatorial expansion of the production into many separate
cases.
• If the same meta variable or non-terminal symbol appears multiple times in a production (in the syntax or in
an attribute), then all those occurrences must have the same instantiation.
• A distinction is made between lexical and syntactic productions. For the latter, arbitrary white space is
allowed in any place where the grammar contains spaces. The productions defining lexical syntax and the
syntax of values are considered lexical, all others are syntactic.

Note

For example, the textual grammar for number types is given as follows:

numtype ::= ‘i32’ ⇒ i32


| ‘i64’ ⇒ i64
| ‘f32’ ⇒ f 32
| ‘f64’ ⇒ f 64

The textual grammar for limits is defined as follows:

limits ::= 𝑛:u64 ⇒ [𝑛 .. 𝜖]


| 𝑛:u64 𝑚:u64 ⇒ [𝑛 .. 𝑚]

The variables 𝑛 and 𝑚 name the attributes of the respective u64 nonterminals, which in this case are the actual
unsigned integers those parse into. The attribute of the complete production then is the abstract syntax for the
limit, expressed in terms of the former values.

6.1.2 Abbreviations
In addition to the core grammar, which corresponds directly to the abstract syntax, the textual syntax also defines
a number of abbreviations that can be used for convenience and readability.
Abbreviations are defined by rewrite rules specifying their expansion into the core syntax:

sym ::= abbreviated syntax ≡ expanded syntax

These expansions are assumed to be applied, recursively and in order of appearance, before applying the core
grammar rules to construct the abstract syntax.

6.1.3 Contexts
The text format allows the use of symbolic identifiers in place of indices. To resolve these identifiers into concrete
indices, some grammar productions are indexed by an identifier context 𝐼 as a synthesized attribute that records
the declared identifiers in each index space. In addition, the context records the types defined in the module, so
that parameter indices can be computed for functions.

206 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

It is convenient to define identifier contexts as records 𝐼 with abstract syntax as follows:

𝐼 ::= {types (name ? )*


tags (name ? )*
globals (name ? )*
mems (name ? )*
tables (name ? )*
funcs (name ? )*
datas (name ? )*
elems (name ? )*
locals (name ? )*
labels (name ? )*
fields ((name ? )* )*
typedefs (deftype ? )* }

For each index space, such a context contains the list of names assigned to the defined indices, which were denoted
by the corresponding identifiers. Unnamed indices are associated with empty (𝜖) entries in these lists. Fields have
dependent name spaces, and hence a separate list of field identifiers per type.
In addition, the field typedefs records the defined type associated with each type index. They are needed to look
up the number of parameters of function types when used in a function definition, in order to produce the correct
indices for locals.
An identifier context is well-formed if no index space contains duplicate identifiers. For fields, names need only
be unique within a single type.

Conventions
To avoid unnecessary clutter, empty components are omitted when writing out identifier contexts. For example,
the record {} is shorthand for an identifier context whose components are all empty.

6.1.4 Lists
Lists are written as plain sequences, but with a restriction on the length of these sequence.

list(X) ::= (el :X)* ⇒ el * if |el * | < 232

6.2 Lexical Format


6.2.1 Characters
The text format assigns meaning to source text, which consists of a sequence of characters. Characters are assumed
to be represented as valid Unicode40 (Section 2.4) scalar values.

source ::= char*


char ::= U+00 | . . . | U+D7FF | U+E000 | . . . | U+10FFFF

Note

While source text may contain any Unicode character in comments or string literals, the rest of the grammar is
formed exclusively from the characters supported by the 7-bit ASCII41 subset of Unicode.

40 [Link]
41 [Link]

6.2. Lexical Format 207


WebAssembly Specification, Release 3.0 (2025-11-14)

6.2.2 Tokens
The character stream in the source text is divided, from left to right, into a sequence of tokens, as defined by the
following grammar.

token ::= keyword | u | s | f | string | id | ‘(’ | ‘)’ | reserved


keyword ::= (‘a’ | . . . | ‘z’) idchar*
reserved ::= (idchar | string | ‘,’ | ‘;’ | ‘[’ | ‘]’ | ‘{’ | ‘}’)+

Tokens are formed from the input character stream according to the longest match rule. That is, the next token
always consists of the longest possible sequence of characters that is recognized by the above lexical grammar.
Tokens can be separated by white space, but except for strings, they cannot themselves contain whitespace.
Keyword tokens always start with a lower-case letter. The set of keywords is defined implicitly: only those tokens
are defined to be keywords that occur as a terminal symbol in literal form, such as ‘keyword’, in a syntactic
production of this chapter.
Any token that does not fall into any of the other categories is considered reserved, and cannot occur in source text.

Note

The effect of defining the set of reserved tokens is that all tokens must be separated by either parentheses, white
space, or comments. For example, ‘0$x’ is a single reserved token, as is ‘’’a’’’’b’’’. Consequently, they are
not recognized as two separate tokens ‘0’ and ‘$x’, or ‘’’a’’’ and ‘’’b’’’, respectively, but instead disallowed.
This property of tokenization is not affected by the fact that the definition of reserved tokens overlaps with other
token classes.

6.2.3 White Space


White space is any sequence of literal space characters, formatting characters, comments, or annotations. The
allowed formatting characters correspond to a subset of the ASCII42 format effectors, namely, horizontal tabulation
(U+09), line feed (U+0A), and carriage return (U+0D).

space ::= (‘ ’ | format | comment | annot)*


format ::= newline | U+09
newline ::= U+0A | U+0D | U+0D U+0A

The only relevance of white space is to separate tokens. It is otherwise ignored.

6.2.4 Comments
A comment can either be a line comment, started with a double semicolon ‘;;’ and extending to the end of the line,
or a block comment, enclosed in delimiters ‘(;’ . . . ‘;)’. Block comments can be nested.

comment ::= linecomment | blockcomment


linecomment ::= ‘;;’ linechar* (newline | eof)
linechar ::= 𝑐:char if 𝑐 ̸= U+0A ∧ 𝑐 ̸= U+0D
blockcomment ::= ‘(;’ blockchar* ‘;)’
blockchar ::= 𝑐:char if 𝑐 ̸= ‘;’ ∧ 𝑐 ̸= ‘(’
| ‘;’+ 𝑐:char if 𝑐 ̸= ‘;’ ∧ 𝑐 ̸= ‘)’
| ‘(’+ 𝑐:char if 𝑐 ̸= ‘;’ ∧ 𝑐 ̸= ‘(’
| blockcomment

Here, the pseudo token eof indicates the end of the input. The look-ahead restrictions on the productions for
blockchar disambiguate the grammar such that only well-bracketed uses of block comment delimiters are allowed.

42 [Link]

208 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

Note

Any formatting and control characters are allowed inside comments.

6.2.5 Annotations
An annotation is a bracketed token sequence headed by an annotation id of the form ‘@id’ or ‘@’’...’’’. No
space is allowed between the opening parenthesis and this id. Annotations are intended to be used for third-party
extensions; they can appear anywhere in a program but are ignored by the WebAssembly semantics itself, which
treats them as white space.
Annotations can contain other parenthesized token sequences (including nested annotations), as long as they are
well-nested. String literals and comments occurring in an annotation must also be properly nested and closed.
annot ::= ‘(@’ annotid (space | token)* ‘)’
annotid ::= idchar+ | name

Note

The annotation id is meant to be an identifier categorising the extension, and plays a role similar to the name of a
custom section. By convention, annotations corresponding to a custom section should use the custom section’s
name as an id.
Implementations are expected to ignore annotations with ids that they do not recognize. On the other hand,
they may impose restrictions on annotations that they do recognize, e.g., requiring a specific structure by super-
imposing a more concrete grammar. It is up to an implementation how it deals with errors in such annotations.

6.3 Values
The grammar productions in this section define lexical syntax, hence no white space is allowed.

6.3.1 Integers
All integers can be written in either decimal or hexadecimal notation. In both cases, digits can optionally be
separated by underscores.
sign ::= 𝜖 ⇒ +1 | ‘+’ ⇒ +1 | ‘-’ ⇒ −1
digit ::= ‘0’ ⇒ 0 | . . . | ‘9’ ⇒ 9
hexdigit ::= 𝑑:digit ⇒ 𝑑
| ‘A’ ⇒ 10 | . . . | ‘F’ ⇒ 15
| ‘a’ ⇒ 10 | . . . | ‘f’ ⇒ 15
num ::= 𝑑:digit ⇒ 𝑑
| 𝑛:num ‘_’? 𝑑:digit ⇒ 10 𝑛 + 𝑑
hexnum ::= ℎ:hexdigit ⇒ ℎ
| 𝑛:hexnum ‘_’? ℎ:hexdigit ⇒ 16 𝑛 + ℎ
The allowed syntax for integer literals depends on size and signedness. Moreover, their value must lie within the
range of the respective type.
u𝑁 ::= 𝑛:num ⇒ 𝑛 if 𝑛 < 2𝑁
| ‘0x’ 𝑛:hexnum ⇒ 𝑛 if 𝑛 < 2𝑁
s𝑁 ::= 𝑠:sign 𝑛:u𝑁 ⇒ 𝑠·𝑛 if −2𝑁 −1 ≤ 𝑠 · 𝑛 < 2𝑁 −1
Uninterpreted integers can be written as either signed or unsigned, and are normalized to unsigned in the abstract
syntax.
i𝑁 ::= 𝑛:u𝑁 ⇒ 𝑛
| 𝑖:s𝑁 ⇒ signed−1
𝑁 (𝑖)

6.3. Values 209


WebAssembly Specification, Release 3.0 (2025-11-14)

6.3.2 Floating-Point
Floating-point values can be represented in either decimal or hexadecimal notation.

frac ::= 𝑑:digit ⇒ 𝑑/10


| 𝑑:digit ‘_’? 𝑝:frac ⇒ (𝑑 + 𝑝/10)/10
hexfrac ::= ℎ:hexdigit ⇒ ℎ/16
| ℎ:hexdigit ‘_’? 𝑝:hexfrac ⇒ (ℎ + 𝑝/16)/16
mant ::= 𝑝:num ‘.’? ⇒ 𝑝
| 𝑝:num ‘.’ 𝑞:frac ⇒ 𝑝+𝑞
hexmant ::= 𝑝:hexnum ‘.’? ⇒ 𝑝
| 𝑝:hexnum ‘.’ 𝑞:hexfrac ⇒ 𝑝+𝑞
float ::= 𝑝:mant (‘E’ | ‘e’) 𝑠:sign 𝑒:num ⇒ 𝑝 · 10𝑠·𝑒
hexfloat ::= ‘0x’ 𝑝:hexmant (‘P’ | ‘p’) 𝑠:sign 𝑒:num ⇒ 𝑝 · 2𝑠·𝑒

The value of a literal must not lie outside the representable range of the corresponding IEEE 75443 type (that is, a
numeric value must not overflow to ±∞), but it may be rounded to the nearest representable value.

Note

Rounding can be prevented by using hexadecimal notation with no more significant bits than supported by the
required type.

Floating-point values may also be written as constants for infinity or canonical NaN (not a number). Furthermore,
arbitrary NaN values may be expressed by providing an explicit payload value.

f𝑁 ::= (+1):sign 𝑞:f𝑁 mag ⇒ +𝑞


| (−1):sign 𝑞:f𝑁 mag ⇒ −𝑞
f𝑁 mag ::= 𝑞:float ⇒ float𝑁 (𝑞) if float𝑁 (𝑞) ̸= ∞
| 𝑞:hexfloat ⇒ float𝑁 (𝑞) if float𝑁 (𝑞) ̸= ∞
| ‘inf’ ⇒ ∞
| ‘nan’ ⇒ nan(canon𝑁 )
| ‘nan:0x’ 𝑛:hexnum ⇒ nan(𝑛) if 1 ≤ 𝑛 < 2signif(𝑁 )

6.3.3 Strings
Strings denote sequences of bytes that can represent both textual and binary data. They are enclosed in quotation
marks and may contain any character other than ASCII44 control characters, quotation marks (‘’’’), or backslash
(‘∖’), except when expressed with an escape sequence.
⨁︀ * *
string ::= ‘’’’ (𝑏* :stringelem)* ‘’’’ if | 𝑏* * | < 232
⨁︀
⇒ 𝑏
stringelem ::= 𝑐:stringchar ⇒ utf 8(𝑐)
| ‘∖’ ℎ1 :hexdigit ℎ2 :hexdigit ⇒ 16 ℎ1 + ℎ2
43 [Link]
44 [Link]

210 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

Each character in a string literal represents the byte sequence corresponding to its UTF-8 Unicode45 (Section 2.5)
encoding, except for hexadecimal escape sequences ‘∖hh’, which represent raw bytes of the respective value.

stringchar ::= 𝑐:char ⇒ 𝑐 if 𝑐 ≥ U+20 ∧ 𝑐 ̸= U+7F ∧ 𝑐 ̸= ‘’’’ ∧ 𝑐 ̸= ‘∖’


| ‘∖t’ ⇒ U+09
| ‘∖n’ ⇒ U+0A
| ‘∖r’ ⇒ U+0D
| ‘∖’’’ ⇒ U+22
| ‘∖’’ ⇒ U+27
| ‘∖∖’ ⇒ U+5C
| ‘∖u{’ 𝑛:hexnum ‘}’ ⇒ 𝑛 if 𝑛 < 0xD800 ∨ 0xE800 ≤ 𝑛 < 0x110000

6.3.4 Names
Names are strings denoting a literal character sequence. A name string must form a valid UTF-8 encoding as
defined by Unicode46 (Section 2.5) and is interpreted as a string of Unicode scalar values.

name ::= 𝑏* :string ⇒ 𝑐* if 𝑏* = utf 8(𝑐* )

Note

Presuming the source text is itself encoded correctly, strings that do not contain any uses of hexadecimal byte
escapes are always valid names.

6.3.5 Identifiers
Indices can be given in both numeric and symbolic form. Symbolic identifiers that stand in lieu of indices start with
‘$’, followed by eiter a sequence of printable ASCII47 characters that does not contain a space, quotation mark,
comma, semicolon, or bracket, or by a quoted name.

id ::= ‘$’ 𝑐* :idchar+ ⇒ 𝑐*


| ‘$’ 𝑐* :name ⇒ 𝑐* if |𝑐* | > 0
idchar ::= ‘0’ | . . . | ‘9’
| ‘A’ | . . . | ‘Z’
| ‘a’ | . . . | ‘z’
| ‘!’ | ‘#’ | ‘$’ | ‘%’ | ‘&’ | ‘’’ | ‘*’ | ‘+’ | ‘-’ | ‘.’ | ‘/’
| ‘:’ | ‘<’ | ‘=’ | ‘>’ | ‘?’ | ‘@’ | ‘∖’ | ‘ ^ ’ | ‘_’ | ‘ ` ’ | ‘|’ | ‘ ~ ’

Note

The value of an identifier character is the Unicode codepoint denoting it.

Conventions
The expansion rules of some abbreviations require insertion of a fresh identifier. That may be any syntactically
valid identifier that does not already occur in the given source text.
45 [Link]
46 [Link]
47 [Link]

6.3. Values 211


WebAssembly Specification, Release 3.0 (2025-11-14)

6.4 Types
6.4.1 Number Types
numtype ::= ‘i32’ ⇒ i32
| ‘i64’ ⇒ i64
| ‘f32’ ⇒ f 32
| ‘f64’ ⇒ f 64

6.4.2 Vector Types


vectype ::= ‘v128’ ⇒ v128

6.4.3 Heap Types


absheaptype ::= ‘any’ ⇒ any
| ‘eq’ ⇒ eq
| ‘i31’ ⇒ i31
| ‘struct’ ⇒ struct
| ‘array’ ⇒ array
| ‘none’ ⇒ none
| ‘func’ ⇒ func
| ‘nofunc’ ⇒ nofunc
| ‘exn’ ⇒ exn
| ‘noexn’ ⇒ noexn
| ‘extern’ ⇒ extern
| ‘noextern’ ⇒ noextern
heaptype𝐼 ::= ht:absheaptype ⇒ ht
| 𝑥:typeidx𝐼 ⇒ 𝑥

6.4.4 Reference Types


null ::= ‘null’ ⇒ null
reftype𝐼 ::= ‘(’ ‘ref’ null :null ht:heaptype𝐼 ‘)’ ⇒
? ?
ref null? ht

Abbreviations
There are shorthands for references to abstract heap types.

reftype𝐼 ::= ...


| ‘anyref’ ≡ ‘(’ ‘ref’ ‘null’ ‘any’ ‘)’
| ‘eqref’ ≡ ‘(’ ‘ref’ ‘null’ ‘eq’ ‘)’
| ‘i31ref’ ≡ ‘(’ ‘ref’ ‘null’ ‘i31’ ‘)’
| ‘structref’ ≡ ‘(’ ‘ref’ ‘null’ ‘struct’ ‘)’
| ‘arrayref’ ≡ ‘(’ ‘ref’ ‘null’ ‘array’ ‘)’
| ‘nullref’ ≡ ‘(’ ‘ref’ ‘null’ ‘none’ ‘)’
| ‘funcref’ ≡ ‘(’ ‘ref’ ‘null’ ‘func’ ‘)’
| ‘nullfuncref’ ≡ ‘(’ ‘ref’ ‘null’ ‘nofunc’ ‘)’
| ‘exnref’ ≡ ‘(’ ‘ref’ ‘null’ ‘exn’ ‘)’
| ‘nullexnref’ ≡ ‘(’ ‘ref’ ‘null’ ‘noexn’ ‘)’
| ‘externref’ ≡ ‘(’ ‘ref’ ‘null’ ‘extern’ ‘)’
| ‘nullexternref’ ≡ ‘(’ ‘ref’ ‘null’ ‘noextern’ ‘)’

212 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

6.4.5 Value Types


valtype𝐼 ::= nt:numtype ⇒ nt
| vt:vectype ⇒ vt
| rt:reftype𝐼 ⇒ rt

6.4.6 Composite Types


Composite types are parsed into their respective abstract representation, paired with the local identifier context
generated by their bound field or parameter identifiers:
comptype𝐼 ::= ‘(’ ‘struct’ (ft, id ? )* :list(field𝐼 ) ‘)’ ⇒ (struct ft * , {fields (id ? )* })
| ‘(’ ‘array’ ft:fieldtype𝐼 ‘)’ ⇒ (array ft, {})
| ‘(’ ‘func’ (𝑡1 , id ? )* :list(param𝐼 ) 𝑡*2 :list(result𝐼 ) ‘)’ ⇒ (func 𝑡*1 → 𝑡*2 , {})
field𝐼 ::= ‘(’ ‘field’ id ? :id? ft:fieldtype𝐼 ‘)’ ⇒ (ft, id ? )
param𝐼 ::= ‘(’ ‘param’ id ? :id? 𝑡:valtype𝐼 ‘)’ ⇒ (𝑡, id ? )
result𝐼 ::= ‘(’ ‘result’ 𝑡:valtype𝐼 ‘)’ ⇒ 𝑡
fieldtype𝐼 ::= zt:storagetype𝐼 ⇒ zt
| ‘(’ ‘mut’ zt:storagetype𝐼 ‘)’ ⇒ mut zt
storagetype𝐼 ::= 𝑡:valtype𝐼 ⇒ 𝑡
| pt:packtype ⇒ pt
packtype ::= ‘i8’ ⇒ i8
| ‘i16’ ⇒ i16

Note

The optional identifier names for parameters in a function type only have documentation purpose. They cannot
be referenced from anywhere.

Abbreviations
Multiple anonymous structure fields or parameters or multiple results may be combined into a single declaration:
field𝐼 ::= . . . | ‘(’ ‘field’ fieldtype*𝐼 ‘)’ ≡ (‘(’ ‘field’ fieldtype𝐼 ‘)’)*
param𝐼 ::= . . . | ‘(’ ‘param’ valtype*𝐼 ‘)’ ≡ (‘(’ ‘param’ valtype𝐼 ‘)’)*
result𝐼 ::= . . . | ‘(’ ‘result’ valtype*𝐼 ‘)’ ≡ (‘(’ ‘param’ valtype𝐼 ‘)’)*

6.4.7 Recursive Types


Recursive types are parsed into their respective abstract representation, paired with the identifier context generated
by their bound identifiers:
final ::= ‘final’ ⇒ final
subtype𝐼 ::= ‘(’ ‘sub’ fin :final 𝑥 :list(typeidx𝐼 ) (ct, 𝐼 ):comptype𝐼 ‘)’ ⇒
? ? * ′
(sub fin ? 𝑥* ct, 𝐼 ′ )
typedef𝐼 ::= ‘(’ ‘type’ id ? :id? (st, 𝐼 ′ ):subtype𝐼 ‘)’ ⇒ (st, 𝐼 ′ ⊕ {types (id ? )})
⨁︀ *
rectype𝐼 ::= ‘(’ ‘rec’ (st, 𝐼 ′ )* :list(typedef𝐼 ) ‘)’ ⇒ (rec st * , 𝐼 ′ )

Abbreviations
Final sub types with no super-types can omit the ‘sub’ keyword and its arguments:
subtype𝐼 ::= . . . | comptype𝐼 ≡ ‘(’ ‘sub’ ‘final’ comptype𝐼 ‘)’
Similarly, singular recursive types can omit the ‘rec’ keyword:
rectype𝐼 ::= . . . | typedef𝐼 ≡ ‘(’ ‘rec’ typedef𝐼 ‘)’

6.4. Types 213


WebAssembly Specification, Release 3.0 (2025-11-14)

6.4.8 Address Types


addrtype ::= ‘i32’ ⇒ i32
| ‘i64’ ⇒ i64

Abbreviations
The address type can be omitted, in which case it defaults i32:

addrtype ::= . . . | 𝜖 ≡ ‘i32’

6.4.9 Limits
limits ::= 𝑛:u64 ⇒ [𝑛 .. 𝜖]
| 𝑛:u64 𝑚:u64 ⇒ [𝑛 .. 𝑚]

6.4.10 Tag Types


tagtype𝐼 ::= (𝑥, 𝐼 ′ ):typeuse𝐼 ⇒ 𝑥

6.4.11 Global Types


globaltype𝐼 ::= 𝑡:valtype𝐼 ⇒ 𝑡
| ‘(’ ‘mut’ 𝑡:valtype𝐼 ‘)’ ⇒ mut 𝑡

6.4.12 Memory Types


memtype𝐼 ::= at:addrtype lim:limits ⇒ at lim page

6.4.13 Table Types


tabletype𝐼 ::= at:addrtype lim:limits rt:reftype𝐼 ⇒ at lim rt

6.4.14 External Types


externtype𝐼 ::= ‘(’ ‘tag’ id ? :id? jt:tagtype𝐼 ‘)’ ⇒ (tag jt, {tags (id ? )})
| ‘(’ ‘global’ id ? :id? gt:globaltype𝐼 ‘)’ ⇒ (global gt, {globals (id ? )})
| ‘(’ ‘memory’ id ? :id? mt:memtype𝐼 ‘)’ ⇒ (mem mt, {mems (id ? )})
| ‘(’ ‘table’ id ? :id? tt:tabletype𝐼 ‘)’ ⇒ (table tt, {tables (id ? )})
| ‘(’ ‘func’ id ? :id? (𝑥, 𝐼 ′ ):typeuse𝐼 ‘)’ ⇒ (func 𝑥, {funcs (id ? )})

214 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

6.4.15 Type Uses


A type use is a reference to a type definition. Where it is required to reference a function type, it may optionally
be augmented by explicit inlined parameter and result declarations. That allows binding symbolic identifiers to
name the local indices of parameters. If inline declarations are given, then their types must match the referenced
function type.
typeuse𝐼 ::= ‘(’ ‘type’ 𝑥:typeidx𝐼 ‘)’ ⇒ (𝑥, 𝐼 ′ )
if 𝐼.typedefs[𝑥] = (rec st * ).𝑖
∧ st * [𝑖] = sub final (func 𝑡*1 → 𝑡*2 )
*
∧ 𝐼 ′ = {locals (𝜖)|𝑡1 | }
| ‘(’ ‘type’ 𝑥:typeidx𝐼 ‘)’ (𝑡1 , id ? )* :param*𝐼 𝑡*2 :result*𝐼 ⇒ (𝑥, 𝐼 ′ )
if 𝐼.typedefs[𝑥] = (rec st * ).𝑖
∧ st * [𝑖] = sub final (func 𝑡*1 → 𝑡*2 )
∧ 𝐼 ′ = {locals (id ? )* }
∧ ⊢ 𝐼 ′ : ok

Note

If inline declarations are given, their types must be syntactically equal to the types from the indexed definition;
possible type substitutions from other definitions that might make them equal are not taken into account. This
is to simplify syntactic pre-processing.

The synthesized attribute of a typeuse is a pair consisting of both the used type index and the local identifier
context containing possible parameter identifiers.

Note

Both productions overlap for the case that the function type is func 𝜖 → 𝜖. However, in that case, they also
produce the same results, so that the choice is immaterial.
The well-formedness condition on 𝐼 ′ ensures that the parameters do not contain duplicate identifiers.

Abbreviations
A type use may also be replaced entirely by inline parameter and result declarations. In that case, a type index is
automatically inserted:

typeuse𝐼 ::= . . . | (𝑡1 , id ? )* :param*𝐼 𝑡*2 :result*𝐼 ≡ ‘(’ ‘type’ 𝑥:typeidx𝐼 ‘)’ param*𝐼 result*𝐼
if 𝐼.typedefs[𝑥] = (rec (sub final (func 𝑡*1 → 𝑡*2 ))).0
∧ (𝐼.typedefs[𝑖] ̸= (rec (sub final (func 𝑡*1 → 𝑡*2 ))).0)𝑖<𝑥
where 𝑥 is the smallest existing type index whose recursive type definition parses into a singular, final function
type with the same parameters and results. If no such index exists, then a new recursive type of the same form is
inserted at the end of the module.
Abbreviations are expanded in the order they appear, such that previously inserted type definitions are reused by
consecutive expansions.

6.5 Instructions
Instructions are syntactically distinguished into plain and structured instructions.
instr𝐼 ::= in:plaininstr𝐼 ⇒ in
| in:blockinstr𝐼 ⇒ in
instrs𝐼 ::= in * :instr*𝐼 ⇒ in *
In addition, as a syntactic abbreviation, instructions can be written as S-expressions in folded form, to group them
visually.

6.5. Instructions 215


WebAssembly Specification, Release 3.0 (2025-11-14)

6.5.1 Labels
Structured control instructions can be annotated with a symbolic label identifier. They are the only symbolic
identifiers that can be bound locally in an instruction sequence. The following grammar handles the corresponding
update to the identifier context by composing the context with an additional label entry.

label𝐼 ::= 𝜖 ⇒ (𝜖, {labels 𝜖} ⊕ 𝐼)


| id :id ⇒ (id , {labels id } ⊕ 𝐼) if id ∈
/ 𝐼.labels
| id :id ⇒ (id , {labels id } ⊕ 𝐼[.labels[𝑥] = 𝜖]) if id = 𝐼.labels[𝑥]

Note

The new label entry is inserted at the beginning of the label list in the identifier context. This effectively shifts
all existing labels up by one, mirroring the fact that control instructions are indexed relatively not absolutely.
If a label with the same name already exists, then it is shadowed and the earlier label becomes inaccessible.

6.5.2 Parametric Instructions


plaininstr𝐼 ::= ‘unreachable’ ⇒ unreachable
| ‘nop’ ⇒ nop
| ‘drop’ ⇒ drop
| ‘select’ (𝑡* :result*𝐼 )? ⇒ select (𝑡* )?

6.5.3 Control Instructions


Structured control instructions can bind an optional symbolic label identifier. The same label identifier may op-
tionally be repeated after the corresponding ‘end’ or ‘else’ keywords, to indicate the matching delimiters.
Their block type is given as a type use, analogous to the type of functions. However, the special case of a type use
that is syntactically empty or consists of only a single result is not regarded as an abbreviation for an inline function

216 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

type, but is parsed directly into an optional value type.


blocktype𝐼 ::= 𝑡? :result?𝐼 ⇒ 𝑡?
| (𝑥, 𝐼 ′ ):typeuse𝐼 ⇒ 𝑥
if 𝐼 ′ = {locals (𝜖)* }
blockinstr𝐼 ::= ‘block’ (id ? , 𝐼 ′ ):label𝐼 bt:blocktype𝐼 ⇒ block bt in *
in * :instrs𝐼 ′
?
‘end’ id ′ :id?
? ?
if id ′ = 𝜖 ∨ id ′ = id ?
| ‘loop’ (id ? , 𝐼 ′ ):label𝐼 bt:blocktype𝐼 ⇒ loop bt in *
in * :instrs𝐼 ′
?
‘end’ id ′ :id?
? ?
if id ′ = 𝜖 ∨ id ′ = id ?
| ‘if’ (id ? , 𝐼 ′ ):label𝐼 bt:blocktype𝐼 ⇒ if bt in *1 else in *2
in *1 :instrs𝐼 ′
‘else’ id ?1 :id?
in *2 :instrs𝐼 ′
‘end’ id ?2 :id?
if (id ?1 = 𝜖 ∨ id ?1 = id ? ) ∧ (id ?2 = 𝜖 ∨ id ?2 = id ? )
| ‘try_table’ (id ? , 𝐼 ′ ):label𝐼 bt:blocktype𝐼 ⇒ try_table bt 𝑐* in *
𝑐* :catch*𝐼
in * :instrs𝐼 ′
?
‘end’ id ′ :id?
? ?
if id ′ = 𝜖 ∨ id ′ = id ?
catch𝐼 ::= ‘(’ ‘catch’ 𝑥:tagidx𝐼 𝑙:labelidx𝐼 ‘)’ ⇒ catch 𝑥 𝑙
| ‘(’ ‘catch_ref’ 𝑥:tagidx𝐼 𝑙:labelidx𝐼 ‘)’ ⇒ catch_ref 𝑥 𝑙
| ‘(’ ‘catch_all’ 𝑙:labelidx𝐼 ‘)’ ⇒ catch_all 𝑙
| ‘(’ ‘catch_all_ref’ 𝑙:labelidx𝐼 ‘)’ ⇒ catch_all_ref 𝑙

Note

The side condition stating that the identifier context 𝐼 ′ must only contain unnamed entries in the rule for
typeuse block types enforces that no identifier can be bound in any param declaration for a block type.

All other control instruction are represented verbatim.

Note

The side condition stating that the identifier context 𝐼 ′ must only contain unnamed entries in the rule for
call_indirect enforces that no identifier can be bound in any param declaration appearing in the type anno-
tation.

Abbreviations
The ‘else’ keyword of an ‘if’ instruction can be omitted if the following instruction sequence is empty.
blockinstr𝐼 ::= . . .
| ‘if’ label𝐼 blocktype𝐼 instrs𝐼 ‘end’ id? ≡
‘if’ label𝐼 blocktype𝐼 instrs𝐼 ‘else’ ‘end’ id?
Also, for backwards compatibility, the table index to ‘call_indirect’ and ‘return_call_indirect’ can be
omitted, defaulting to 0.
plaininstr𝐼 ::= . . .
| ‘call_indirect’ typeuse𝐼 ≡ ‘call_indirect’ ‘0’ typeuse𝐼
| ‘return_call_indirect’ typeuse𝐼 ≡ ‘return_call_indirect’ ‘0’ typeuse𝐼

6.5. Instructions 217


WebAssembly Specification, Release 3.0 (2025-11-14)

6.5.4 Variable Instructions


plaininstr𝐼 ::= ...
| ‘[Link]’ 𝑥:localidx𝐼 ⇒ [Link] 𝑥
| ‘[Link]’ 𝑥:localidx𝐼 ⇒ [Link] 𝑥
| ‘[Link]’ 𝑥:localidx𝐼 ⇒ [Link] 𝑥
| ‘[Link]’ 𝑥:globalidx𝐼 ⇒ [Link] 𝑥
| ‘[Link]’ 𝑥:globalidx𝐼 ⇒ [Link] 𝑥

6.5.5 Table Instructions


plaininstr𝐼 ::= ...
| ‘[Link]’ 𝑥:tableidx𝐼 ⇒ [Link] 𝑥
| ‘[Link]’ 𝑥:tableidx𝐼 ⇒ [Link] 𝑥
| ‘[Link]’ 𝑥:tableidx𝐼 ⇒ [Link] 𝑥
| ‘[Link]’ 𝑥:tableidx𝐼 ⇒ [Link] 𝑥
| ‘[Link]’ 𝑥:tableidx𝐼 ⇒ [Link] 𝑥
| ‘[Link]’ 𝑥1 :tableidx𝐼 𝑥2 :tableidx𝐼 ⇒ [Link] 𝑥1 𝑥2
| ‘[Link]’ 𝑥:tableidx𝐼 𝑦:elemidx𝐼 ⇒ [Link] 𝑥 𝑦
| ‘[Link]’ 𝑥:elemidx𝐼 ⇒ [Link] 𝑥

Abbreviations
For backwards compatibility, all table indices may be omitted from table instructions, defaulting to 0.

plaininstr𝐼 ::= ...


| ‘[Link]’ ≡ ‘[Link]’ ‘0’
| ‘[Link]’ ≡ ‘[Link]’ ‘0’
| ‘[Link]’ ≡ ‘[Link]’ ‘0’
| ‘[Link]’ ≡ ‘[Link]’ ‘0’
| ‘[Link]’ ≡ ‘[Link]’ ‘0’
| ‘[Link]’ ≡ ‘[Link]’ ‘0’ ‘0’
| ‘[Link]’ elemidx𝐼 ≡ ‘[Link]’ ‘0’ elemidx𝐼

6.5.6 Memory Instructions


The offset and alignment immediates to memory instructions are optional. The offset defaults to 0, the alignment
to the storage size of the respective memory access, which is its natural alignment. Lexically, an offset or align

218 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

phrase is considered a single keyword token, so no white space is allowed around the ‘=’.
memarg𝑁 ::= 𝑛:offset 𝑚:align𝑁 ⇒ {align 𝑛, offset 𝑚}
offset ::= ‘offset=’ 𝑛:u64 ⇒ 𝑛
| 𝜖 ⇒ 0
align𝑁 ::= ‘align=’ 𝑚:u64 ⇒ 𝑚 if 𝑚 = 2𝑛
| 𝜖 ⇒ 𝑁
laneidx ::= 𝑖:u8 ⇒ 𝑖
plaininstr𝐼 ::= ...
| ‘[Link]’ 𝑥:memidx𝐼 ao:memarg4 ⇒ [Link] 𝑥 ao
| ‘[Link]’ 𝑥:memidx𝐼 ao:memarg8 ⇒ [Link] 𝑥 ao
| ‘[Link]’ 𝑥:memidx𝐼 ao:memarg4 ⇒ f [Link] 𝑥 ao
| ‘[Link]’ 𝑥:memidx𝐼 ao:memarg8 ⇒ f [Link] 𝑥 ao
| ‘i32.load8_s’ 𝑥:memidx𝐼 ao:memarg1 ⇒ i32.load8_s 𝑥 ao
| ‘i32.load8_u’ 𝑥:memidx𝐼 ao:memarg1 ⇒ i32.load8_u 𝑥 ao
| ‘i32.load16_s’ 𝑥:memidx𝐼 ao:memarg2 ⇒ i32.load16_s 𝑥 ao
| ‘i32.load16_u’ 𝑥:memidx𝐼 ao:memarg2 ⇒ i32.load16_u 𝑥 ao
| ‘i64.load8_s’ 𝑥:memidx𝐼 ao:memarg1 ⇒ i64.load8_s 𝑥 ao
| ‘i64.load8_u’ 𝑥:memidx𝐼 ao:memarg1 ⇒ i64.load8_u 𝑥 ao
| ‘i64.load16_s’ 𝑥:memidx𝐼 ao:memarg2 ⇒ i64.load16_s 𝑥 ao
| ‘i64.load16_u’ 𝑥:memidx𝐼 ao:memarg2 ⇒ i64.load16_u 𝑥 ao
| ‘i64.load32_s’ 𝑥:memidx𝐼 ao:memarg4 ⇒ i64.load32_s 𝑥 ao
| ‘i64.load32_u’ 𝑥:memidx𝐼 ao:memarg4 ⇒ i64.load32_u 𝑥 ao
| ‘[Link]’ 𝑥:memidx𝐼 ao:memarg16 ⇒ [Link] 𝑥 ao
| ‘v128.load8x8_s’ 𝑥:memidx𝐼 ao:memarg8 ⇒ v128.load8x8_s 𝑥 ao
| ‘v128.load8x8_u’ 𝑥:memidx𝐼 ao:memarg8 ⇒ v128.load8x8_u 𝑥 ao
| ‘v128.load16x4_s’ 𝑥:memidx𝐼 ao:memarg8 ⇒ v128.load16x4_s 𝑥 ao
| ‘v128.load16x4_u’ 𝑥:memidx𝐼 ao:memarg8 ⇒ v128.load16x4_u 𝑥 ao
| ‘v128.load32x2_s’ 𝑥:memidx𝐼 ao:memarg8 ⇒ v128.load32x2_s 𝑥 ao
| ‘v128.load32x2_u’ 𝑥:memidx𝐼 ao:memarg8 ⇒ v128.load32x2_u 𝑥 ao
| ‘v128.load8_splat’ 𝑥:memidx𝐼 ao:memarg1 ⇒ v128.load8_splat 𝑥 ao
| ‘v128.load16_splat’ 𝑥:memidx𝐼 ao:memarg2 ⇒ v128.load16_splat 𝑥 ao
| ‘v128.load32_splat’ 𝑥:memidx𝐼 ao:memarg4 ⇒ v128.load32_splat 𝑥 ao
| ‘v128.load64_splat’ 𝑥:memidx𝐼 ao:memarg8 ⇒ v128.load64_splat 𝑥 ao
| ‘v128.load32_zero’ 𝑥:memidx𝐼 ao:memarg4 ⇒ v128.load32_zero 𝑥 ao
| ‘v128.load64_zero’ 𝑥:memidx𝐼 ao:memarg8 ⇒ v128.load64_zero 𝑥 ao
| ‘v128.load8_lane’ 𝑥:memidx𝐼 ao:memarg1 𝑖:laneidx ⇒ v128.load8_lane 𝑥 ao 𝑖
| ‘v128.load16_lane’ 𝑥:memidx𝐼 ao:memarg2 𝑖:laneidx ⇒ v128.load16_lane 𝑥 ao 𝑖
| ‘v128.load32_lane’ 𝑥:memidx𝐼 ao:memarg4 𝑖:laneidx ⇒ v128.load32_lane 𝑥 ao 𝑖
| ‘v128.load64_lane’ 𝑥:memidx𝐼 ao:memarg8 𝑖:laneidx ⇒ v128.load64_lane 𝑥 ao 𝑖
| ‘[Link]’ 𝑥:memidx𝐼 ao:memarg4 ⇒ [Link] 𝑥 ao
| ‘[Link]’ 𝑥:memidx𝐼 ao:memarg8 ⇒ [Link] 𝑥 ao
| ‘[Link]’ 𝑥:memidx𝐼 ao:memarg4 ⇒ f [Link] 𝑥 ao
| ‘[Link]’ 𝑥:memidx𝐼 ao:memarg8 ⇒ f [Link] 𝑥 ao
| ‘i32.store8’ 𝑥:memidx𝐼 ao:memarg1 ⇒ i32.store8 𝑥 ao
| ‘i32.store16’ 𝑥:memidx𝐼 ao:memarg2 ⇒ i32.store16 𝑥 ao
| ‘i64.store8’ 𝑥:memidx𝐼 ao:memarg1 ⇒ i64.store8 𝑥 ao
| ‘i64.store16’ 𝑥:memidx𝐼 ao:memarg2 ⇒ i64.store16 𝑥 ao
| ‘i64.store32’ 𝑥:memidx𝐼 ao:memarg4 ⇒ i64.store32 𝑥 ao
| ‘[Link]’ 𝑥:memidx𝐼 ao:memarg16 ⇒ [Link] 𝑥 ao
| ‘v128.store8_lane’ 𝑥:memidx𝐼 ao:memarg1 𝑖:laneidx ⇒ v128.store8_lane 𝑥 ao 𝑖
| ‘v128.store16_lane’ 𝑥:memidx𝐼 ao:memarg2 𝑖:laneidx ⇒ v128.store16_lane 𝑥 ao 𝑖
| ‘v128.store32_lane’ 𝑥:memidx𝐼 ao:memarg4 𝑖:laneidx ⇒ v128.store32_lane 𝑥 ao 𝑖
| ‘v128.store64_lane’ 𝑥:memidx𝐼 ao:memarg8 𝑖:laneidx ⇒ v128.store64_lane 𝑥 ao 𝑖
| ‘[Link]’ 𝑥:memidx𝐼 ⇒ [Link] 𝑥
| ‘[Link]’ 𝑥:memidx𝐼 ⇒ [Link] 𝑥
| ‘[Link]’ 𝑥:memidx𝐼 ⇒ [Link] 𝑥
| ‘[Link]’ 𝑥1 :memidx𝐼 𝑥2 :memidx𝐼 ⇒ [Link] 𝑥1 𝑥2
| ‘[Link]’ 𝑥:memidx𝐼 𝑦:dataidx𝐼 ⇒ [Link] 𝑥 𝑦
| ‘[Link]’ 𝑥:dataidx𝐼 ⇒ [Link] 𝑥
6.5. Instructions 219
WebAssembly Specification, Release 3.0 (2025-11-14)

Abbreviations
As an abbreviation, the memory index can be omitted in all memory instructions, defaulting to 0.

plaininstr𝐼 ::= ...


| ‘[Link]’ memarg4 ≡ ‘[Link]’ ‘0’ memarg4
| ‘[Link]’ memarg8 ≡ ‘[Link]’ ‘0’ memarg8
| ‘[Link]’ memarg4 ≡ ‘[Link]’ ‘0’ memarg4
| ‘[Link]’ memarg8 ≡ ‘[Link]’ ‘0’ memarg8
| ‘i32.load8_s’ memarg1 ≡ ‘i32.load8_s’ ‘0’ memarg1
| ‘i32.load8_u’ memarg1 ≡ ‘i32.load8_u’ ‘0’ memarg1
| ‘i32.load16_s’ memarg2 ≡ ‘i32.load16_s’ ‘0’ memarg2
| ‘i32.load16_u’ memarg2 ≡ ‘i32.load16_u’ ‘0’ memarg2
| ‘i64.load8_s’ memarg1 ≡ ‘i64.load8_s’ ‘0’ memarg1
| ‘i64.load8_u’ memarg1 ≡ ‘i64.load8_u’ ‘0’ memarg1
| ‘i64.load16_s’ memarg2 ≡ ‘i64.load16_s’ ‘0’ memarg2
| ‘i64.load16_u’ memarg2 ≡ ‘i64.load16_u’ ‘0’ memarg2
| ‘i64.load32_s’ memarg4 ≡ ‘i64.load32_s’ ‘0’ memarg4
| ‘i64.load32_u’ memarg4 ≡ ‘i64.load32_u’ ‘0’ memarg4
| ‘[Link]’ memarg16 ≡ ‘[Link]’ ‘0’ memarg16
| ‘v128.load8x8_s’ memarg8 ≡ ‘v128.load8x8_s’ ‘0’ memarg8
| ‘v128.load8x8_u’ memarg8 ≡ ‘v128.load8x8_u’ ‘0’ memarg8
| ‘v128.load16x4_s’ memarg8 ≡ ‘v128.load16x4_s’ ‘0’ memarg8
| ‘v128.load16x4_u’ memarg8 ≡ ‘v128.load16x4_u’ ‘0’ memarg8
| ‘v128.load32x2_s’ memarg8 ≡ ‘v128.load32x2_s’ ‘0’ memarg8
| ‘v128.load32x2_u’ memarg8 ≡ ‘v128.load32x2_u’ ‘0’ memarg8
| ‘v128.load8_splat’ memarg1 ≡ ‘v128.load8_splat’ ‘0’ memarg1
| ‘v128.load16_splat’ memarg2 ≡ ‘v128.load16_splat’ ‘0’ memarg2
| ‘v128.load32_splat’ memarg4 ≡ ‘v128.load32_splat’ ‘0’ memarg4
| ‘v128.load64_splat’ memarg8 ≡ ‘v128.load64_splat’ ‘0’ memarg8
| ‘v128.load32_zero’ memarg4 ≡ ‘v128.load32_zero’ ‘0’ memarg4
| ‘v128.load64_zero’ memarg8 ≡ ‘v128.load64_zero’ ‘0’ memarg8
| ‘v128.load8_lane’ memarg1 laneidx ≡ ‘v128.load8_lane’ ‘0’ memarg1 laneidx
| ‘v128.load16_lane’ memarg2 laneidx ≡ ‘v128.load16_lane’ ‘0’ memarg2 laneidx
| ‘v128.load32_lane’ memarg4 laneidx ≡ ‘v128.load32_lane’ ‘0’ memarg4 laneidx
| ‘v128.load64_lane’ memarg8 laneidx ≡ ‘v128.load64_lane’ ‘0’ memarg8 laneidx
| ‘[Link]’ memarg4 ≡ ‘[Link]’ ‘0’ memarg4
| ‘[Link]’ memarg8 ≡ ‘[Link]’ ‘0’ memarg8
| ‘[Link]’ memarg4 ≡ ‘[Link]’ ‘0’ memarg4
| ‘[Link]’ memarg8 ≡ ‘[Link]’ ‘0’ memarg8
| ‘i32.store8’ memarg1 ≡ ‘i32.store8’ ‘0’ memarg1
| ‘i32.store16’ memarg2 ≡ ‘i32.store16’ ‘0’ memarg2
| ‘i64.store8’ memarg1 ≡ ‘i64.store8’ ‘0’ memarg1
| ‘i64.store16’ memarg2 ≡ ‘i64.store16’ ‘0’ memarg2
| ‘i64.store32’ memarg4 ≡ ‘i64.store32’ ‘0’ memarg4
| ‘[Link]’ memarg16 ≡ ‘[Link]’ ‘0’ memarg16
| ‘v128.store8_lane’ memarg1 laneidx ≡ ‘v128.store8_lane’ ‘0’ memarg1 laneidx
| ‘v128.store16_lane’ memarg2 laneidx ≡ ‘v128.store16_lane’ ‘0’ memarg1 laneidx
| ‘v128.store32_lane’ memarg4 laneidx ≡ ‘v128.store32_lane’ ‘0’ memarg1 laneidx
| ‘v128.store64_lane’ memarg8 laneidx ≡ ‘v128.store64_lane’ ‘0’ memarg1 laneidx
| ‘[Link]’ ≡ ‘[Link]’ ‘0’
| ‘[Link]’ ≡ ‘[Link]’ ‘0’
| ‘[Link]’ ≡ ‘[Link]’ ‘0’
| ‘[Link]’ ≡ ‘[Link]’ ‘0’ ‘0’
| ‘[Link]’ dataidx𝐼 ≡ ‘[Link]’ ‘0’ dataidx𝐼

220 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

6.5.7 Reference Instructions


plaininstr𝐼 ::= ...
| ‘[Link]’ ht:heaptype𝐼 ⇒ [Link] ht
| ‘[Link]’ 𝑥:funcidx𝐼 ⇒ [Link] 𝑥
| ‘ref.is_null’ ⇒ ref.is_null
| ‘ref.as_non_null’ ⇒ ref.as_non_null
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ rt:reftype𝐼 ⇒ [Link] rt
| ‘[Link]’ rt:reftype𝐼 ⇒ [Link] rt

6.5.8 Aggregate Instructions


plaininstr𝐼 ::= ...
| ‘ref.i31’ ⇒ ref.i31
| ‘i31.get_s’ ⇒ i31.get_s
| ‘i31.get_u’ ⇒ i31.get_u
| ‘[Link]’ 𝑥:typeidx𝐼 ⇒ [Link] 𝑥
| ‘struct.new_default’ 𝑥:typeidx𝐼 ⇒ struct.new_default 𝑥
| ‘[Link]’ 𝑥:typeidx𝐼 𝑖:fieldidx𝐼,𝑥 ⇒ [Link] 𝑥 𝑖
| ‘struct.get_s’ 𝑥:typeidx𝐼 𝑖:fieldidx𝐼,𝑥 ⇒ struct.get_s 𝑥 𝑖
| ‘struct.get_u’ 𝑥:typeidx𝐼 𝑖:fieldidx𝐼,𝑥 ⇒ struct.get_u 𝑥 𝑖
| ‘[Link]’ 𝑥:typeidx𝐼 𝑖:fieldidx𝐼,𝑥 ⇒ [Link] 𝑥 𝑖
| ‘[Link]’ 𝑥:typeidx𝐼 ⇒ [Link] 𝑥
| ‘array.new_default’ 𝑥:typeidx𝐼 ⇒ array.new_default 𝑥
| ‘array.new_fixed’ 𝑥:typeidx𝐼 𝑛:u32 ⇒ array.new_fixed 𝑥 𝑛
| ‘array.new_data’ 𝑥:typeidx𝐼 𝑦:dataidx𝐼 ⇒ array.new_data 𝑥 𝑦
| ‘array.new_elem’ 𝑥:typeidx𝐼 𝑦:elemidx𝐼 ⇒ array.new_elem 𝑥 𝑦
| ‘[Link]’ 𝑥:typeidx𝐼 ⇒ [Link] 𝑥
| ‘array.get_s’ 𝑥:typeidx𝐼 ⇒ array.get_s 𝑥
| ‘array.get_u’ 𝑥:typeidx𝐼 ⇒ array.get_u 𝑥
| ‘[Link]’ 𝑥:typeidx𝐼 ⇒ [Link] 𝑥
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ 𝑥:typeidx𝐼 ⇒ [Link] 𝑥
| ‘[Link]’ 𝑥1 :typeidx𝐼 𝑥2 :typeidx𝐼 ⇒ [Link] 𝑥1 𝑥2
| ‘array.init_data’ 𝑥:typeidx𝐼 𝑦:dataidx𝐼 ⇒ array.init_data 𝑥 𝑦
| ‘array.init_elem’ 𝑥:typeidx𝐼 𝑦:elemidx𝐼 ⇒ array.init_elem 𝑥 𝑦
| ‘any.convert_extern’ ⇒ any.convert_extern
| ‘extern.convert_any’ ⇒ extern.convert_any

6.5.9 Numeric Instructions


plaininstr𝐼 ::= ...
| ‘[Link]’ 𝑐:i32 ⇒ [Link] 𝑐
| ‘[Link]’ 𝑐:i64 ⇒ [Link] 𝑐
| ‘[Link]’ 𝑐:f32 ⇒ f [Link] 𝑐
| ‘[Link]’ 𝑐:f64 ⇒ f [Link] 𝑐

6.5. Instructions 221


WebAssembly Specification, Release 3.0 (2025-11-14)

plaininstr𝐼 ::= ...


| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i32.lt_s’ ⇒ i32.lt_s
| ‘i32.lt_u’ ⇒ i32.lt_u
| ‘i32.gt_s’ ⇒ i32.gt_s
| ‘i32.gt_u’ ⇒ i32.gt_u
| ‘i32.le_s’ ⇒ i32.le_s
| ‘i32.le_u’ ⇒ i32.le_u
| ‘i32.ge_s’ ⇒ i32.ge_s
| ‘i32.ge_u’ ⇒ i32.ge_u
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i32.extend8_s’ ⇒ i32.extend8_s
| ‘i32.extend16_s’ ⇒ i32.extend16_s
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i32.div_s’ ⇒ i32.div_s
| ‘i32.div_u’ ⇒ i32.div_u
| ‘i32.rem_s’ ⇒ i32.rem_s
| ‘i32.rem_u’ ⇒ i32.rem_u
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i32.shr_s’ ⇒ i32.shr_s
| ‘i32.shr_u’ ⇒ i32.shr_u
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]

222 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

plaininstr𝐼 ::= ...


| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i64.lt_s’ ⇒ i64.lt_s
| ‘i64.lt_u’ ⇒ i64.lt_u
| ‘i64.gt_s’ ⇒ i64.gt_s
| ‘i64.gt_u’ ⇒ i64.gt_u
| ‘i64.le_s’ ⇒ i64.le_s
| ‘i64.le_u’ ⇒ i64.le_u
| ‘i64.ge_s’ ⇒ i64.ge_s
| ‘i64.ge_u’ ⇒ i64.ge_u
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i64.extend8_s’ ⇒ i64.extend8_s
| ‘i64.extend16_s’ ⇒ i64.extend16_s
| ‘i64.extend32_s’ ⇒ i64.extend32_s
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i64.div_s’ ⇒ i64.div_s
| ‘i64.div_u’ ⇒ i64.div_u
| ‘i64.rem_s’ ⇒ i64.rem_s
| ‘i64.rem_u’ ⇒ i64.rem_u
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i64.shr_s’ ⇒ i64.shr_s
| ‘i64.shr_u’ ⇒ i64.shr_u
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
plaininstr𝐼 ::= ...
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]

6.5. Instructions 223


WebAssembly Specification, Release 3.0 (2025-11-14)

plaininstr𝐼 ::= ...


| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]

plaininstr𝐼 ::= ...


| ‘i32.wrap_i64’ ⇒ i32.wrap_i64
| ‘i32.trunc_f32_s’ ⇒ i32.trunc_s_f 32
| ‘i32.trunc_f32_u’ ⇒ i32.trunc_u_f 32
| ‘i32.trunc_f64_s’ ⇒ i32.trunc_s_f 64
| ‘i32.trunc_f64_u’ ⇒ i32.trunc_u_f 64
| ‘i32.trunc_sat_f32_s’ ⇒ i32.trunc_sat_s_f 32
| ‘i32.trunc_sat_f32_u’ ⇒ i32.trunc_sat_u_f 32
| ‘i32.trunc_sat_f64_s’ ⇒ i32.trunc_sat_s_f 64
| ‘i32.trunc_sat_f64_u’ ⇒ i32.trunc_sat_u_f 64
| ‘i64.extend_i64_s’ ⇒ i64.extend_s_i64
| ‘i64.extend_i64_u’ ⇒ i64.extend_u_i64
| ‘i64.trunc_f32_s’ ⇒ i64.trunc_s_f 32
| ‘i64.trunc_f32_u’ ⇒ i64.trunc_u_f 32
| ‘i64.trunc_f64_s’ ⇒ i64.trunc_s_f 64
| ‘i64.trunc_f64_u’ ⇒ i64.trunc_u_f 64
| ‘i64.trunc_sat_f32_s’ ⇒ i64.trunc_sat_s_f 32
| ‘i64.trunc_sat_f32_u’ ⇒ i64.trunc_sat_u_f 32
| ‘i64.trunc_sat_f64_s’ ⇒ i64.trunc_sat_s_f 64
| ‘i64.trunc_sat_f64_u’ ⇒ i64.trunc_sat_u_f 64
| ‘f32.demote_f64’ ⇒ f 32.demote_f 64
| ‘f32.convert_i32_s’ ⇒ f 32.convert_s_i32
| ‘f32.convert_i32_u’ ⇒ f 32.convert_u_i32
| ‘f32.convert_i64_s’ ⇒ f 32.convert_s_i64
| ‘f32.convert_i64_u’ ⇒ f 32.convert_u_i64
| ‘f64.promote_f32’ ⇒ f 64.promote_f 32
| ‘f64.convert_i32_s’ ⇒ f 64.convert_s_i32
| ‘f64.convert_i32_u’ ⇒ f 64.convert_u_i32
| ‘f64.convert_i64_s’ ⇒ f 64.convert_s_i64
| ‘f64.convert_i64_u’ ⇒ f 64.convert_u_i64
| ‘i32.reinterpret_f32’ ⇒ i32.reinterpret_f 32
| ‘i64.reinterpret_f64’ ⇒ i64.reinterpret_f 64
| ‘f32.reinterpret_i32’ ⇒ f 32.reinterpret_i32
| ‘f64.reinterpret_i64’ ⇒ f 64.reinterpret_i64

224 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

6.5.10 Vector Instructions


Vector constant instructions have a mandatory shape descriptor, which determines how the following values are
parsed.

plaininstr𝐼 ::= ...


‘[Link]’ ‘i8x16’ 𝑐* :i816 [Link] bytes−1 *
⨁︀
| ⇒ i128 (⨁︀ bytesi8 (𝑐) )
−1
| ‘[Link]’ ‘i16x8’ 𝑐* :i168 ⇒ [Link] bytesi128 ( bytesi16 (𝑐)* )
‘[Link]’ ‘i32x4’ 𝑐* :i324 [Link] bytes−1 *
⨁︀
| ⇒ i128 (⨁︀ bytesi32 (𝑐) )
−1
| ‘[Link]’ ‘i64x2’ 𝑐* :i642 ⇒ [Link] bytesi128 ( bytesi64 (𝑐)* )
‘[Link]’ ‘f32x4’ 𝑐* :f324 [Link] bytes−1 *
⨁︀
| ⇒ i128 (⨁︀ bytesf32 (𝑐) )
−1
| ‘[Link]’ ‘f64x2’ 𝑐* :f642 ⇒ [Link] bytesi128 ( bytesf64 (𝑐) ) *

plaininstr𝐼 ::= ...


| ‘[Link]’ 𝑖* :laneidx16 ⇒ [Link] 𝑖*
| ‘[Link]’ ⇒ [Link]
| ‘i8x16.relaxed_swizzle’ ⇒ i8x16.relaxed_swizzle
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘i8x16.extract_lane_s’ 𝑖:laneidx ⇒ i8x16.extract_lane_s 𝑖
| ‘i8x16.extract_lane_u’ 𝑖:laneidx ⇒ i8x16.extract_lane_u 𝑖
| ‘i16x8.extract_lane_s’ 𝑖:laneidx ⇒ i16x8.extract_lane_s 𝑖
| ‘i16x8.extract_lane_u’ 𝑖:laneidx ⇒ i16x8.extract_lane_u 𝑖
| ‘i32x4.extract_lane’ 𝑖:laneidx ⇒ i32x4.extract_lane 𝑖
| ‘i64x2.extract_lane’ 𝑖:laneidx ⇒ i64x2.extract_lane 𝑖
| ‘f32x4.extract_lane’ 𝑖:laneidx ⇒ f 32x4.extract_lane 𝑖
| ‘f64x2.extract_lane’ 𝑖:laneidx ⇒ f 64x2.extract_lane 𝑖
| ‘i8x16.replace_lane’ 𝑖:laneidx ⇒ i8x16.replace_lane 𝑖
| ‘i16x8.replace_lane’ 𝑖:laneidx ⇒ i16x8.replace_lane 𝑖
| ‘i32x4.replace_lane’ 𝑖:laneidx ⇒ i32x4.replace_lane 𝑖
| ‘i64x2.replace_lane’ 𝑖:laneidx ⇒ i64x2.replace_lane 𝑖
| ‘f32x4.replace_lane’ 𝑖:laneidx ⇒ f 32x4.replace_lane 𝑖
| ‘f64x2.replace_lane’ 𝑖:laneidx ⇒ f 64x2.replace_lane 𝑖

plaininstr𝐼 ::= ...


| ‘v128.any_true’ ⇒ v128.any_true
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]

6.5. Instructions 225


WebAssembly Specification, Release 3.0 (2025-11-14)

plaininstr𝐼 ::= ...


| ‘i8x16.all_true’ ⇒ i8x16.all_true
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i8x16.lt_s’ ⇒ i8x16.lt_s
| ‘i8x16.lt_u’ ⇒ i8x16.lt_u
| ‘i8x16.gt_s’ ⇒ i8x16.gt_s
| ‘i8x16.gt_u’ ⇒ i8x16.gt_u
| ‘i8x16.le_s’ ⇒ i8x16.le_s
| ‘i8x16.le_u’ ⇒ i8x16.le_u
| ‘i8x16.ge_s’ ⇒ i8x16.ge_s
| ‘i8x16.ge_u’ ⇒ i8x16.ge_u
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i8x16.add_sat_s’ ⇒ i8x16.add_sat_s
| ‘i8x16.add_sat_u’ ⇒ i8x16.add_sat_u
| ‘[Link]’ ⇒ [Link]
| ‘i8x16.sub_sat_s’ ⇒ i8x16.sub_sat_s
| ‘i8x16.sub_sat_u’ ⇒ i8x16.sub_sat_u
| ‘i8x16.min_s’ ⇒ i8x16.min_s
| ‘i8x16.min_u’ ⇒ i8x16.min_u
| ‘i8x16.max_s’ ⇒ i8x16.max_s
| ‘i8x16.max_u’ ⇒ i8x16.max_u
| ‘i8x16.avgr_u’ ⇒ i8x16.avgr_u
| ‘i8x16.relaxed_laneselect’ ⇒ i8x16.relaxed_laneselect
| ‘[Link]’ ⇒ [Link]
| ‘i8x16.shr_s’ ⇒ i8x16.shr_s
| ‘i8x16.shr_u’ ⇒ i8x16.shr_u
| ‘[Link]’ ⇒ [Link]
| ‘i8x16.narrow_i16x8_s’ ⇒ i8x16.narrow_i16x8_s
| ‘i8x16.narrow_i16x8_u’ ⇒ i8x16.narrow_i16x8_u

226 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

plaininstr𝐼 ::= ...


| ‘i16x8.all_true’ ⇒ i16x8.all_true
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i16x8.lt_s’ ⇒ i16x8.lt_s
| ‘i16x8.lt_u’ ⇒ i16x8.lt_u
| ‘i16x8.gt_s’ ⇒ i16x8.gt_s
| ‘i16x8.gt_u’ ⇒ i16x8.gt_u
| ‘i16x8.le_s’ ⇒ i16x8.le_s
| ‘i16x8.le_u’ ⇒ i16x8.le_u
| ‘i16x8.ge_s’ ⇒ i16x8.ge_s
| ‘i16x8.ge_u’ ⇒ i16x8.ge_u
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i16x8.add_sat_s’ ⇒ i16x8.add_sat_s
| ‘i16x8.add_sat_u’ ⇒ i16x8.add_sat_u
| ‘[Link]’ ⇒ [Link]
| ‘i16x8.sub_sat_s’ ⇒ i16x8.sub_sat_s
| ‘i16x8.sub_sat_u’ ⇒ i16x8.sub_sat_u
| ‘[Link]’ ⇒ [Link]
| ‘i16x8.min_s’ ⇒ i16x8.min_s
| ‘i16x8.min_u’ ⇒ i16x8.min_u
| ‘i16x8.max_s’ ⇒ i16x8.max_s
| ‘i16x8.max_u’ ⇒ i16x8.max_u
| ‘i16x8.avgr_u’ ⇒ i16x8.avgr_u
| ‘i16x8.q15mulr_sat_s’ ⇒ i16x8.q15mulr_sat_s
| ‘i16x8.relaxed_q15mulr_s’ ⇒ i16x8.relaxed_q15mulr_s
| ‘i16x8.relaxed_laneselect’ ⇒ i16x8.relaxed_laneselect
| ‘[Link]’ ⇒ [Link]
| ‘i16x8.shr_s’ ⇒ i16x8.shr_s
| ‘i16x8.shr_u’ ⇒ i16x8.shr_u
| ‘[Link]’ ⇒ [Link]
| ‘i16x8.narrow_i32x4_s’ ⇒ i16x8.narrow_i32x4_s
| ‘i16x8.narrow_i32x4_u’ ⇒ i16x8.narrow_i32x4_u

6.5. Instructions 227


WebAssembly Specification, Release 3.0 (2025-11-14)

plaininstr𝐼 ::= ...


| ‘i32x4.all_true’ ⇒ i32x4.all_true
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i32x4.lt_s’ ⇒ i32x4.lt_s
| ‘i32x4.lt_u’ ⇒ i32x4.lt_u
| ‘i32x4.gt_s’ ⇒ i32x4.gt_s
| ‘i32x4.gt_u’ ⇒ i32x4.gt_u
| ‘i32x4.le_s’ ⇒ i32x4.le_s
| ‘i32x4.le_u’ ⇒ i32x4.le_u
| ‘i32x4.ge_s’ ⇒ i32x4.ge_s
| ‘i32x4.ge_u’ ⇒ i32x4.ge_u
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i32x4.min_s’ ⇒ i32x4.min_s
| ‘i32x4.min_u’ ⇒ i32x4.min_u
| ‘i32x4.max_s’ ⇒ i32x4.max_s
| ‘i32x4.max_u’ ⇒ i32x4.max_u
| ‘i32x4.relaxed_laneselect’ ⇒ i32x4.relaxed_laneselect
| ‘[Link]’ ⇒ [Link]
| ‘i32x4.shr_s’ ⇒ i32x4.shr_s
| ‘i32x4.shr_u’ ⇒ i32x4.shr_u
| ‘[Link]’ ⇒ [Link]
plaininstr𝐼 ::= ...
| ‘i64x2.all_true’ ⇒ i64x2.all_true
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i64x2.lt_s’ ⇒ i64x2.lt_s
| ‘i64x2.gt_s’ ⇒ i64x2.gt_s
| ‘i64x2.le_s’ ⇒ i64x2.le_s
| ‘i64x2.ge_s’ ⇒ i64x2.ge_s
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘[Link]’ ⇒ [Link]
| ‘i64x2.relaxed_laneselect’ ⇒ i64x2.relaxed_laneselect
| ‘[Link]’ ⇒ [Link]
| ‘i64x2.shr_s’ ⇒ i64x2.shr_s
| ‘i64x2.shr_u’ ⇒ i64x2.shr_u
| ‘[Link]’ ⇒ [Link]

228 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

plaininstr𝐼 ::= ...


| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘f32x4.relaxed_min’ ⇒ f 32x4.relaxed_min
| ‘f32x4.relaxed_max’ ⇒ f 32x4.relaxed_max
| ‘f32x4.relaxed_madd’ ⇒ f 32x4.relaxed_madd
| ‘f32x4.relaxed_nmadd’ ⇒ f 32x4.relaxed_nmadd
plaininstr𝐼 ::= ...
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘[Link]’ ⇒ f [Link]
| ‘f64x2.relaxed_min’ ⇒ f 64x2.relaxed_min
| ‘f64x2.relaxed_max’ ⇒ f 64x2.relaxed_max
| ‘f64x2.relaxed_madd’ ⇒ f 64x2.relaxed_madd
| ‘f64x2.relaxed_nmadd’ ⇒ f 64x2.relaxed_nmadd

6.5. Instructions 229


WebAssembly Specification, Release 3.0 (2025-11-14)

plaininstr𝐼 ::= ...


| ‘i16x8.extend_low_i8x16_s’ ⇒ i16x8.extend_low_s_i8x16
| ‘i16x8.extend_low_i8x16_u’ ⇒ i16x8.extend_low_u_i8x16
| ‘i16x8.extend_high_i8x16_s’ ⇒ i16x8.extend_high_s_i8x16
| ‘i16x8.extend_high_i8x16_u’ ⇒ i16x8.extend_high_u_i8x16
| ‘i32x4.extend_low_i16x8_s’ ⇒ i32x4.extend_low_s_i16x8
| ‘i32x4.extend_low_i16x8_u’ ⇒ i32x4.extend_low_u_i16x8
| ‘i32x4.extend_high_i16x8_s’ ⇒ i32x4.extend_high_s_i16x8
| ‘i32x4.extend_high_i16x8_u’ ⇒ i32x4.extend_high_u_i16x8
| ‘i32x4.trunc_sat_f32x4_s’ ⇒ i32x4.trunc_sat_s_f 32x4
| ‘i32x4.trunc_sat_f32x4_u’ ⇒ i32x4.trunc_sat_u_f 32x4
| ‘i32x4.trunc_sat_f64x2_s_zero’ ⇒ i32x4.trunc_sat_s_zero_f 64x2
| ‘i32x4.trunc_sat_f64x2_u_zero’ ⇒ i32x4.trunc_sat_u_zero_f 64x2
| ‘i32x4.relaxed_trunc_f32x4_s’ ⇒ i32x4.relaxed_trunc_s_f 32x4
| ‘i32x4.relaxed_trunc_f32x4_u’ ⇒ i32x4.relaxed_trunc_u_f 32x4
| ‘i32x4.relaxed_trunc_f64x2_s_zero’ ⇒ i32x4.relaxed_trunc_s_zero_f 64x2
| ‘i32x4.relaxed_trunc_f64x2_u_zero’ ⇒ i32x4.relaxed_trunc_u_zero_f 64x2
| ‘i64x2.extend_low_i32x4_s’ ⇒ i64x2.extend_low_s_i32x4
| ‘i64x2.extend_low_i32x4_u’ ⇒ i64x2.extend_low_u_i32x4
| ‘i64x2.extend_high_i32x4_s’ ⇒ i64x2.extend_high_s_i32x4
| ‘i64x2.extend_high_i32x4_u’ ⇒ i64x2.extend_high_u_i32x4
| ‘f32x4.demote_f64x2_zero’ ⇒ f 32x4.demote_zero_f 64x2
| ‘f32x4.convert_i32x4_s’ ⇒ f 32x4.convert_s_i32x4
| ‘f32x4.convert_i32x4_u’ ⇒ f 32x4.convert_u_i32x4
| ‘f64x2.promote_low_f32x4’ ⇒ f 64x2.promote_low_f 32x4
| ‘f64x2.convert_low_i32x4_s’ ⇒ f 64x2.convert_low_s_i32x4
| ‘f64x2.convert_low_i32x4_u’ ⇒ f 64x2.convert_low_u_i32x4
plaininstr𝐼 ::= ...
| ‘i16x8.extadd_pairwise_i8x16_s’ ⇒ i16x8.extadd_pairwise_s_i8x16
| ‘i16x8.extadd_pairwise_i8x16_u’ ⇒ i16x8.extadd_pairwise_u_i8x16
| ‘i16x8.extmul_low_i8x16_s’ ⇒ i16x8.extmul_low_s_i8x16
| ‘i16x8.extmul_low_i8x16_u’ ⇒ i16x8.extmul_low_u_i8x16
| ‘i16x8.extmul_high_i8x16_s’ ⇒ i16x8.extmul_high_s_i8x16
| ‘i16x8.extmul_high_i8x16_u’ ⇒ i16x8.extmul_high_u_i8x16
| ‘i32x4.extadd_pairwise_i16x8_s’ ⇒ i32x4.extadd_pairwise_s_i16x8
| ‘i32x4.extadd_pairwise_i16x8_u’ ⇒ i32x4.extadd_pairwise_u_i16x8
| ‘i32x4.extmul_low_i16x8_s’ ⇒ i32x4.extmul_low_s_i16x8
| ‘i32x4.extmul_low_i16x8_u’ ⇒ i32x4.extmul_low_u_i16x8
| ‘i32x4.extmul_high_i16x8_s’ ⇒ i32x4.extmul_high_s_i16x8
| ‘i32x4.extmul_high_i16x8_u’ ⇒ i32x4.extmul_high_u_i16x8
| ‘i32x4.dot_i16x8_s’ ⇒ i32x4.dot_s_i16x8
| ‘i64x2.extmul_low_i32x4_s’ ⇒ i64x2.extmul_low_s_i32x4
| ‘i64x2.extmul_low_i32x4_u’ ⇒ i64x2.extmul_low_u_i32x4
| ‘i64x2.extmul_high_i32x4_s’ ⇒ i64x2.extmul_high_s_i32x4
| ‘i64x2.extmul_high_i32x4_u’ ⇒ i64x2.extmul_high_u_i32x4

6.5.11 Folded Instructions


Instructions can be written as S-expressions by grouping them into folded form. In that notation, an instruction is
wrapped in parentheses and optionally includes nested folded instructions to indicate its operands.
In the case of block instructions, the folded form omits the ‘end’ delimiter. For if instructions, both branches have
to be wrapped into nested S-expressions, headed by the keywords ‘then’ and ‘else’.
The set of all phrases defined by the following abbreviations recursively forms the auxiliary syntactic class

230 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

foldedinstr. Such a folded instruction can appear anywhere a regular instruction can.
foldedinstr𝐼 ::= ‘(’ plaininstr𝐼 instrs𝐼 ‘)’ ≡
instrs𝐼 plaininstr𝐼
| ‘(’ ‘block’ label𝐼 blocktype𝐼 instrs𝐼 ′ ‘)’ ≡
‘block’ label𝐼 blocktype𝐼 instrs𝐼 ′ ‘end’
| ‘(’ ‘loop’ label𝐼 blocktype𝐼 instrs𝐼 ′ ‘)’ ≡
‘loop’ label𝐼 blocktype𝐼 instrs𝐼 ′ ‘end’
| ‘(’ ‘if’ label𝐼 blocktype𝐼 foldedinstr*𝐼 ≡
‘(’ ‘then’ in *1 :instrs𝐼 ′ ‘)’ (‘(’ ‘else’ in *2 :instrs𝐼 ′ ‘)’)? ‘)’
foldedinstr*𝐼 ‘if’ label𝐼 blocktype𝐼 in *1 :instrs𝐼 ′ (‘else’ in *2 :instrs𝐼 ′ )? ‘end’
| ‘(’ ‘try_table’ label𝐼 blocktype𝐼 catch*𝐼 instrs𝐼 ′ ‘)’ ≡
‘try_table’ label𝐼 blocktype𝐼 catch*𝐼 instrs𝐼 ′ ‘end’

Note

For example, the instruction sequence

([Link] $x) ([Link] 2) [Link] ([Link] 3) [Link]

can be folded into

([Link] ([Link] ([Link] $x) ([Link] 2)) ([Link] 3))

Folded instructions are solely syntactic sugar, no additional syntactic or type-based checking is implied.

6.5.12 Expressions
Expressions are written as instruction sequences.

expr𝐼 ::= in * :instrs𝐼 ⇒ in *

6.6 Modules
Modules consist of a sequence of declarations. The grammar rules for each declaration construct produce a pair,
consisting of not just the abstract syntax representing the respective declaration, but also an identifier context
recording the new symbolic identifiers bound by the construct, for use in the remainder of the module.

6.6.1 Indices
Indices can be given either in raw numeric form or as symbolic identifiers when bound by a respective construct.
Such identifiers are looked up in the suitable space of the identifier context 𝐼.
idxids ::= 𝑥:u32 ⇒ 𝑥
| id :id ⇒ 𝑥 if ids[𝑥] = id
typeidx𝐼 ::= idx𝐼.types
tagidx𝐼 ::= idx𝐼.tags
globalidx𝐼 ::= idx𝐼.globals
memidx𝐼 ::= idx𝐼.mems
tableidx𝐼 ::= idx𝐼.tables
funcidx𝐼 ::= idx𝐼.funcs
dataidx𝐼 ::= idx𝐼.datas
elemidx𝐼 ::= idx𝐼.elems
localidx𝐼 ::= idx𝐼.locals
labelidx𝐼 ::= idx𝐼.labels
fieldidx𝐼,𝑥 ::= idx𝐼.fields[𝑥]

6.6. Modules 231


WebAssembly Specification, Release 3.0 (2025-11-14)

6.6.2 Types
A type definition consists of a recursive type. The identifier context produced for the local bindings is further
extended with the respective sequence of defined types that the recursive type generates.

type𝐼 ::= (qt, 𝐼 ′ ):rectype𝐼 ⇒ (type qt, 𝐼 ′ ⊕ 𝐼 ′′ ) if qt = rec st 𝑛


∧ 𝐼 ′′ = {typedefs (qt.𝑖)𝑖<𝑛 }

6.6.3 Tags
A tag definition can bind a symbolic tag identifier.

tag𝐼 ::= ‘(’ ‘tag’ id ? :id? jt:tagtype𝐼 ‘)’ ⇒ (tag jt, {tags (id ? )})

Abbreviations
Tags can be defined as imports or exports inline:

import𝐼 ::= . . .
| ‘(’ ‘tag’ id? ‘(’ ‘import’ name2 ‘)’ tagtype𝐼 ‘)’ ≡
‘(’ ‘import’ name2 ‘(’ ‘tag’ id? tagtype𝐼 ‘)’ ‘)’
export𝐼 ::= ‘(’ ‘tag’ id ? :id? ‘(’ ‘export’ name ‘)’ . . . ‘)’ ≡
‘(’ ‘tag’ id ′ :id . . . ‘)’
‘(’ ‘export’ name ‘(’ ‘tag’ id ‘)’ ‘)’
if id ? = id ′ ∨ id ? = 𝜖 ∧ id ′ ∈
/ 𝐼.tags

Note

The latter abbreviation can be applied repeatedly, if “. . .” contains additional export clauses. Consequently, a
memory declaration can contain any number of exports, possibly followed by an import.

6.6.4 Globals
Global definitions can bind a symbolic global identifier.

global𝐼 ::= ‘(’ ‘global’ id ? :id? gt:globaltype𝐼 𝑒:expr𝐼 ‘)’ ⇒ (global gt 𝑒, {globals (id ? )})

Abbreviations
Globals can be defined as imports or exports inline:

import𝐼 ::= . . .
| ‘(’ ‘global’ id? ‘(’ ‘import’ name2 ‘)’ globaltype𝐼 ‘)’ ≡
‘(’ ‘import’ name2 ‘(’ ‘global’ id? globaltype𝐼 ‘)’ ‘)’
export𝐼 ::= ‘(’ ‘global’ id ? :id? ‘(’ ‘export’ name ‘)’ . . . ‘)’ ≡
‘(’ ‘global’ id ′ :id . . . ‘)’
‘(’ ‘export’ name ‘(’ ‘global’ id ‘)’ ‘)’
if id ? = id ′ ∨ id ? = 𝜖 ∧ id ′ ∈
/ 𝐼.globals

232 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

Note

The latter abbreviation can be applied repeatedly, if “. . .” contains additional export clauses. Consequently, a
global declaration can contain any number of exports, possibly followed by an import.

6.6.5 Memories
Memory definitions can bind a symbolic memory identifier.

mem𝐼 ::= ‘(’ ‘memory’ id ? :id? mt:memtype𝐼 ‘)’ ⇒ (memory mt, {mems (id ? )})

Abbreviations
A data segment can be given inline with a memory definition, in which case its offset is 0 and the limits of the
memory type are inferred from the length of the data, rounded up to page size:

mem𝐼 ::= ‘(’ ‘memory’ id ? :id? at ? :addrtype? ‘(’ ‘data’ 𝑏* :datastring ‘)’ ‘)’ ≡
‘(’ ‘memory’ id ′ :id at ? :addrtype? 𝑛:u64 𝑛:u64 ‘)’
‘(’ ‘data’ ‘(’ ‘memory’ id ′ :id ‘)’ ‘(’ at ′ :addrtype ‘.const’ ‘0’ ‘)’ datastring ‘)’
if id ? = id ′ ∨ id ? = 𝜖 ∧ id ′ ∈
/ 𝐼.mems
∧ at ? = at ′ ∨ at ? = 𝜖 ∧ at ′ = i32
∧ 𝑛 = ceil(|𝑏* |/64 · Ki)

Memories can be defined as imports or exports inline:

import𝐼 ::= ...


| ‘(’ ‘memory’ id? ‘(’ ‘import’ name2 ‘)’ memtype𝐼 ‘)’ ≡
‘(’ ‘import’ name2 ‘(’ ‘memory’ id? memtype𝐼 ‘)’ ‘)’
export𝐼 ::= ‘(’ ‘memory’ id ? :id? ‘(’ ‘export’ name ‘)’ . . . ‘)’ ≡
‘(’ ‘memory’ id ′ :id . . . ‘)’
‘(’ ‘export’ name ‘(’ ‘memory’ id ‘)’ ‘)’
if id ? = id ′ ∨ id ? = 𝜖 ∧ id ′ ∈
/ 𝐼.mems

Note

The latter abbreviation can be applied repeatedly, if “. . .” contains additional export clauses. Consequently, a
memory declaration can contain any number of exports, possibly followed by an import.

6.6.6 Tables
Table definitions can bind a symbolic table identifier.

table𝐼 ::= ‘(’ ‘table’ id ? :id? tt:tabletype𝐼 𝑒:expr𝐼 ‘)’ ⇒ (table tt 𝑒, {tables (id ? )})

Abbreviations
A table’s initialization expression can be omitted, in which case it defaults to [Link]:

table𝐼 ::= . . .
| ‘(’ ‘table’ id? tt:tabletype𝐼 ‘)’ ≡
‘(’ ‘table’ id? tt:tabletype𝐼 ‘(’ ‘[Link]’ ht:heaptype𝐼 ‘)’ ‘)’
if tt = at lim (ref null? ht)

6.6. Modules 233


WebAssembly Specification, Release 3.0 (2025-11-14)

An element segment can be given inline with a table definition, in which case its offset is 0 and the limits of the
table type are inferred from the length of the given segment:

table𝐼 ::= ‘(’ ‘table’ id ? :id? at ? :addrtype? reftype𝐼 ‘(’ ‘elem’ (rt, 𝑒* ):elemlist𝐼 ‘)’ ‘)’ ≡
‘(’ ‘table’ id ′ :id at ? :addrtype? 𝑛:u64 𝑛:u64 reftype𝐼 ‘)’
‘(’ ‘elem’ ‘(’ ‘table’ id ′ :id ‘)’ ‘(’ at ′ :addrtype ‘.const’ ‘0’ ‘)’ elemlist𝐼 ‘)’
if id ? = id ′ ∨ id ? = 𝜖 ∧ id ′ ∈/ 𝐼.tables
? ′ ? ′
∧ at = at ∨ at = 𝜖 ∧ at = i32
∧ 𝑛 = |𝑒* |

Tables can be defined as imports or exports inline:

import𝐼 ::= . . .
| ‘(’ ‘table’ id? ‘(’ ‘import’ name2 ‘)’ tabletype𝐼 ‘)’ ≡
‘(’ ‘import’ name2 ‘(’ ‘table’ id? tabletype𝐼 ‘)’ ‘)’
export𝐼 ::= ‘(’ ‘table’ id ? :id? ‘(’ ‘export’ name ‘)’ . . . ‘)’ ≡
‘(’ ‘table’ id ′ :id . . . ‘)’
‘(’ ‘export’ name ‘(’ ‘table’ id ‘)’ ‘)’
if id ? = id ′ ∨ id ? = 𝜖 ∧ id ′ ∈
/ 𝐼.tables

Note

The latter abbreviation can be applied repeatedly, if “. . .” contains additional export clauses. Consequently, a
table declaration can contain any number of exports, possibly followed by an import.

6.6.7 Functions
Function definitions can bind a symbolic function identifier, and local identifiers for its parameters and locals.

func𝐼 ::= ‘(’ ‘func’ id ? :id? (𝑥, 𝐼 1 ):typeuse𝐼 ((loc * , 𝐼 2 ):local𝐼 )* 𝑒:expr𝐼 ′ ‘)’ ⇒
*
(func 𝑥 ( loc * ) 𝑒, {funcs ?
⨁︀
⨁︀ * (id )})
if 𝐼 = 𝐼 ⊕ 𝐼 1 ⊕

𝐼2
∧ ⊢ 𝐼 ′ : ok

local𝐼 ::= ‘(’ ‘local’ id ? :id? 𝑡:valtype𝐼 ‘)’ ⇒


(local 𝑡, {locals (id ? )})

Note

The well-formedness condition on 𝐼 ′ ensures that parameters and locals do not contain duplicate identifiers.

Abbreviations
Multiple anonymous locals may be combined into a single declaration:

local𝐼 ::= . . . | ‘(’ ‘local’ 𝑡:valtype*𝐼 ‘)’ ≡ (‘(’ ‘local’ 𝑡:valtype𝐼 ‘)’)*

Functions can be defined as imports or exports inline:

import𝐼 ::= . . .
| ‘(’ ‘func’ id? ‘(’ ‘import’ name2 ‘)’ typeuse𝐼 ‘)’ ≡
‘(’ ‘import’ name2 ‘(’ ‘func’ id? typeuse𝐼 ‘)’ ‘)’
export𝐼 ::= ‘(’ ‘func’ id ? :id? ‘(’ ‘export’ name ‘)’ . . . ‘)’ ≡
‘(’ ‘func’ id ′ :id . . . ‘)’
‘(’ ‘export’ name ‘(’ ‘func’ id ‘)’ ‘)’
if id ? = id ′ ∨ id ? = 𝜖 ∧ id ′ ∈
/ 𝐼.funcs

234 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

Note

The latter abbreviation can be applied repeatedly, if “. . .” contains additional export clauses. Consequently, a
function declaration can contain any number of exports, possibly followed by an import.

6.6.8 Data Segments


Data segments allow for an optional memory index to identify the memory to initialize. The data is written as a
string, which may be split up into a possibly empty sequence of individual string literals.

data𝐼 ::= ‘(’ ‘data’ id ? :id? 𝑏* :datastring ‘)’ ⇒


(data 𝑏* passive, {datas (id ? )})
| ‘(’ ‘data’ id ? :id? 𝑥:memuse𝐼 𝑒:offset𝐼 𝑏* :datastring ‘)’ ⇒
(data 𝑏* (active 𝑥 𝑒), {datas (id ? )})
datastring ::= 𝑏* * :string* 𝑏* *
⨁︀

memuse𝐼 ::= ‘(’ ‘memory’ 𝑥:memidx𝐼 ‘)’ ⇒ 𝑥
offset𝐼 ::= ‘(’ ‘offset’ 𝑒:expr𝐼 ‘)’ ⇒ 𝑒

Note

In the current version of WebAssembly, the only valid memory index is 0 or a symbolic memory identifier
resolving to the same value.

Abbreviations
As an abbreviation, a single folded instruction may occur in place of the offset of an active segment:

offset𝐼 ::= . . . | foldedinstr𝐼 ≡ ‘(’ ‘offset’ foldedinstr𝐼 ‘)’

Also, a memory use can be omitted, defaulting to 0.

memuse𝐼 ::= ... | 𝜖 ≡ ‘(’ ‘memory’ ‘0’ ‘)’

As another abbreviation, data segments may also be specified inline with memory definitions; see the respective
section.

6.6.9 Element Segments


Element segments allow for an optional table index to identify the table to initialize.

elem𝐼 ::= ‘(’ ‘elem’ id ? :id? (rt, 𝑒* ):elemlist𝐼 ‘)’ ⇒


(elem rt 𝑒* passive, {elems (id ? )})
| ‘(’ ‘elem’ id ? :id? 𝑥:tableuse𝐼 𝑒′ :offset𝐼 (rt, 𝑒* ):elemlist𝐼 ‘)’ ⇒
(elem rt 𝑒* (active 𝑥 𝑒′ ), {elems (id ? )})
| ‘(’ ‘elem’ id ? :id? ‘declare’ (rt, 𝑒* ):elemlist𝐼 ‘)’ ⇒
(elem rt 𝑒* declare, {elems (id ? )})
elemlist𝐼 ::= rt:reftype𝐼 𝑒* :list(expr𝐼 ) ⇒ (rt, 𝑒* )
elemexpr𝐼 ::= ‘(’ ‘item’ 𝑒:expr𝐼 ‘)’ ⇒ 𝑒
tableuse𝐼 ::= ‘(’ ‘table’ 𝑥:tableidx𝐼 ‘)’ ⇒ 𝑥

Abbreviations
As an abbreviation, a single folded instruction may occur in place of the offset of an active element segment or as
an element expression:

elemexpr𝐼 ::= . . . | foldedinstr𝐼 ≡ ‘(’ ‘item’ foldedinstr𝐼 ‘)’

6.6. Modules 235


WebAssembly Specification, Release 3.0 (2025-11-14)

Also, the element list may be written as just a sequence of function indices:

elemlist𝐼 ::= . . . | ‘func’ 𝑥* :funcidx*𝐼 ≡ ‘(’ ‘ref’ ‘func’ ‘)’ (‘(’ ‘[Link]’ funcidx𝐼 ‘)’)*

A table use can be omitted, defaulting to 0.

tableuse𝐼 ::= . . . | 𝜖 ≡ ‘(’ ‘table’ ‘0’ ‘)’

Furthermore, for backwards compatibility with earlier versions of WebAssembly, if the table use is omitted, the
‘func’ keyword can be omitted as well.

elem𝐼 ::= ...


| ‘(’ ‘elem’ 𝑒′ :offset𝐼 list(funcidx𝐼 ) ‘)’ ≡
‘(’ ‘elem’ 𝑒′ :offset𝐼 ‘func’ list(funcidx𝐼 ) ‘)’

As yet another abbreviation, element segments may also be specified inline with table definitions; see the respective
section.

6.6.10 Start Function


A start function is defined in terms of its index.

start𝐼 ::= ‘(’ ‘start’ 𝑥:funcidx𝐼 ‘)’ ⇒ (start 𝑥, {})

Note

At most one start function may occur in a module, which is ensured by a suitable side condition on the module
grammar.

6.6.11 Imports
The external type in imports can bind a symbolic tag, global, memory, or function identifier.

import𝐼 ::= ‘(’ ‘import’ nm 1 :name nm 2 :name (xt, 𝐼 ′ ):externtype𝐼 ‘)’ ⇒ (import nm 1 nm 2 xt, 𝐼 ′ )

Abbreviations
As an abbreviation, imports may also be specified inline with tag, global, memory, table, or function definitions;
see the respective sections.

6.6.12 Exports
The syntax for exports mirrors their abstract syntax directly.

export𝐼 ::= ‘(’ ‘export’ nm:name xx :externidx𝐼 ‘)’ ⇒ (export nm xx , {})


externidx𝐼 ::= ‘(’ ‘tag’ 𝑥:tagidx𝐼 ‘)’ ⇒ tag 𝑥
| ‘(’ ‘global’ 𝑥:globalidx𝐼 ‘)’ ⇒ global 𝑥
| ‘(’ ‘memory’ 𝑥:memidx𝐼 ‘)’ ⇒ memory 𝑥
| ‘(’ ‘table’ 𝑥:tableidx𝐼 ‘)’ ⇒ table 𝑥
| ‘(’ ‘func’ 𝑥:funcidx𝐼 ‘)’ ⇒ func 𝑥

Abbreviations
As an abbreviation, exports may also be specified inline with tag, global, memory, table, or function definitions;
see the respective sections.

236 Chapter 6. Text Format


WebAssembly Specification, Release 3.0 (2025-11-14)

6.6.13 Modules
A module consists of a sequence of declarations that can occur in any order.

decl ::= type | import | tag | global | mem | table | func | data | elem | start | export

All declarations and their respective bound identifiers scope over the entire module, including the text preceding
them. A module itself may optionally bind an identifier that names the module. The name serves a documentary
role only.

Note

Tools may include the module name in the name section of the binary format.

decl𝐼 ::= type𝐼 | import𝐼 | tag𝐼 | global𝐼 | mem𝐼 | table𝐼


| func𝐼 | data𝐼 | elem𝐼 | start𝐼 | export𝐼

module ::= ‘(’ ‘module’ id? (decl , 𝐼)* :decl*𝐼 ′ ‘)’ ⇒


module type⨁︀ *
import * tag * global * mem * table * func * data * elem * start ? export *
if 𝐼 ′ = 𝐼*
∧ ⊢ 𝐼 ′ : ok
∧ type * = types(decl * )
∧ import * = imports(decl * )
∧ tag * = tags(decl * )
∧ global * = globals(decl * )
∧ mem * = mems(decl * )
∧ table * = tables(decl * )
∧ func * = funcs(decl * )
∧ data * = datas(decl * )
∧ elem * = elems(decl * )
∧ start ? = starts(decl * )
∧ export * = exports(decl * )
∧ ordered(decl * )
where types(decl * ), imports(decl * ), tags(decl * ), etc., extract the sequence of types, imports, tags, etc., contained
in decl * , respectively. The auxiliary predicate ordered checks that no imports occur after the first definition of a
tag, global, memory, table, or function in a sequence of declarations:

* *
ordered(decl ′ ) = true if imports(decl ′ ) = 𝜖
* *
ordered(decl 1 import decl 2 ) =
imports(decl *1 ) = 𝜖 ∧ tags(decl *1 ) = 𝜖 ∧ globals(decl *1 ) = 𝜖 ∧ mems(decl *1 ) = 𝜖 ∧ tables(decl *1 ) = 𝜖 ∧ funcs(decl *1 ) = 𝜖

Abbreviations
In a source file, the toplevel ‘(’ ‘module’ decldots ‘)’ surrounding the module body may be omitted.

module ::= . . . | decl*𝐼 ≡ ‘(’ ‘module’ decl*𝐼 ‘)’

6.6. Modules 237


WebAssembly Specification, Release 3.0 (2025-11-14)

238 Chapter 6. Text Format


CHAPTER 7

Appendix

7.1 Embedding
A WebAssembly implementation will typically be embedded into a host environment. An embedder implements
the connection between such a host environment and the WebAssembly semantics as defined in the main body of
this specification. An embedder is expected to interact with the semantics in well-defined ways.
This section defines a suitable interface to the WebAssembly semantics in the form of entry points through which
an embedder can access it. The interface is intended to be complete, in the sense that an embedder does not need
to reference other functional parts of the WebAssembly specification directly.

Note

On the other hand, an embedder does not need to provide the host environment with access to all functionality
defined in this interface. For example, an implementation may not support parsing of the text format.

7.1.1 Types
In the description of the embedder interface, syntactic classes from the abstract syntax and the runtime’s abstract
machine are used as names for variables that range over the possible objects from that class. Hence, these syntactic
classes can also be interpreted as types.
For numeric parameters, notation like 𝑖 : u64 is used to specify a symbolic name in addition to the respective value
range.

7.1.2 Booleans
Interface operation that are predicates return Boolean values:

bool ::= false | true

7.1.3 Exceptions and Errors


Invoking an exported function may throw or propagate exceptions, expressed by an auxiliary syntactic class:

exception ::= exception exnaddr

The exception address 𝑒𝑥𝑛𝑎𝑑𝑑𝑟 identifies the exception thrown.

239
WebAssembly Specification, Release 3.0 (2025-11-14)

Failure of an interface operation is also indicated by an auxiliary syntactic class:


error ::= error

In addition to the error conditions specified explicitly in this section, such as invalid arguments or exceptions and
traps resulting from execution, implementations may also return errors when specific implementation limitations
are reached.

Note

Errors are abstract and unspecific with this definition. Implementations can refine it to carry suitable classifi-
cations and diagnostic messages.

7.1.4 Pre- and Post-Conditions


Some operations state pre-conditions about their arguments or post-conditions about their results. It is the embed-
der’s responsibility to meet the pre-conditions. If it does, the post conditions are guaranteed by the semantics.
In addition to pre- and post-conditions explicitly stated with each operation, the specification adopts the following
conventions for runtime objects (store, moduleinst, addresses):
• Every runtime object passed as a parameter must be valid per an implicit pre-condition.
• Every runtime object returned as a result is valid per an implicit post-condition.

Note

As long as an embedder treats runtime objects as abstract and only creates and manipulates them through the
interface defined here, all implicit pre-conditions are automatically met.

7.1.5 Store
store_init() : store
1. Return the empty store.
store_init() = {}

7.1.6 Modules
module_decode(byte * ) : module | error
1. If there exists a derivation for the byte sequence byte * as a module according to the binary grammar for
modules, yielding a module 𝑚, then return 𝑚.
2. Else, return error.
*
module_decode(𝑏* ) = 𝑚 (if module =⇒ 𝑚:𝑏* )
module_decode(𝑏* ) = error (otherwise)

module_parse(char * ) : module | error


1. If there exists a derivation for the source char * as a module according to the text grammar for modules,
yielding a module 𝑚, then return 𝑚.
2. Else, return error.
*
module_parse(𝑐* ) = 𝑚 (if module =⇒ 𝑚:𝑐* )
module_parse(𝑐* ) = error (otherwise)

240 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

module_validate(module) : error ?
1. If module is valid, then return nothing.
2. Else, return error.
*
module_validate(𝑚) = 𝜖 (if ⊢ 𝑚 : externtype * → externtype ′ )
module_validate(𝑚) = error (otherwise)

module_instantiate(store, module, externaddr * ) : (store, moduleinst | exception | error )


1. Try instantiating module in store with external addresses externaddr * as imports:
a. If it succeeds with a module instance moduleinst, then let result be moduleinst.
b. Else, let result be error.
2. Return the new store paired with result.
module_instantiate(𝑆, 𝑚, ev * ) = (𝑆 ′ , 𝐹.module) (if instantiate(𝑆, 𝑚, ev * ) ˓→ * 𝑆 ′ ; 𝐹 ; 𝜖)
module_instantiate(𝑆, 𝑚, ev * ) = (𝑆 ′ , error) (otherwise, if instantiate(𝑆, 𝑚, ev * ) ˓→ * 𝑆 ′ ; 𝐹 ; result)

Note

The store may be modified even in case of an error.

module_imports(module) : (name, name, externtype)*


1. Pre-condition: module is valid with the external import types externtype * and external export types
*
externtype ′ .
2. Let import * be the imports of module.
3. Assert: the length of import * equals the length of externtype * .
4. For each import 𝑖 in import * and corresponding externtype 𝑖 in externtype * , do:
a. Let import nm 𝑖1 nm 𝑖2 xt 𝑖 be the deconstruction of import 𝑖 .
b. Let result 𝑖 be the triple (nm 𝑖1 , nm 𝑖2 , externtype 𝑖 ).
5. Return the concatenation of all result 𝑖 , in index order.
6. Post-condition: each externtype 𝑖 is valid under the empty context.

module_imports(𝑚) = (nm 1 , nm 2 , externtype)*


*
(if (import nm 1 nm 2 xt * )* ∈ 𝑚 ∧ ⊢ 𝑚 : externtype * → externtype ′ )

module_exports(module) : (name, externtype)*


1. Pre-condition: module is valid with the external import types externtype * and external export types
*
externtype ′ .
2. Let export * be the exports of module.
*
3. Assert: the length of export * equals the length of externtype ′ .
*
4. For each export 𝑖 in export * and corresponding externtype ′𝑖 in externtype ′ , do:
a. Let export nm 𝑖 externidx 𝑖 be the deconstruction of export 𝑖 .
b. Let result 𝑖 be the pair (nm 𝑖 , externtype ′𝑖 ).
5. Return the concatenation of all result 𝑖 , in index order.

7.1. Embedding 241


WebAssembly Specification, Release 3.0 (2025-11-14)

6. Post-condition: each externtype ′𝑖 is valid under the empty context.

module_exports(𝑚) = (
𝑚𝑎𝑡ℎ𝑖𝑡𝑛𝑚, externtype ′ )*
*
(if (export nm xt * )* ∈ 𝑚 ∧ ⊢ 𝑚 : externtype * → externtype ′ )

7.1.7 Module Instances


instance_export(moduleinst, name) : externaddr | error
1. Assert: due to validity of the module instance moduleinst, all its export names are different.
2. If there exists an exportinst 𝑖 in [Link] such that name exportinst 𝑖 .name equals name, then:
a. Return the external address exportinst 𝑖 .addr.
3. Else, return error.

instance_export(𝑚, name) = 𝑚.exports[𝑖].addr (if 𝑚.exports[𝑖].name = name)


instance_export(𝑚, name) = error (otherwise)

7.1.8 Functions
func_alloc(store, deftype, hostfunc) : (store, funcaddr )
1. Pre-condition: the defined type deftype is valid under the empty context and expands to a function type.
2. Let funcaddr be the result of allocating a host function in store with defined type deftype, host function
code hostfunc and an empty module instance.
3. Return the new store paired with funcaddr .
func_alloc(𝑆, dt, code) = (𝑆 ′ , a) (if allocfunc(𝑆, dt, code, {}) = 𝑆 ′ , a)

Note

This operation assumes that hostfunc satisfies the pre- and post-conditions required for a function instance with
type deftype.
Regular (non-host) function instances can only be created indirectly through module instantiation.

func_type(store, funcaddr ) : deftype


1. Let deftype be the definedn type 𝑆.funcs[𝑎].type.
2. Return deftype.
3. Post-condition: the returned defined type is valid and expands to a function type.
func_type(𝑆, 𝑎) = 𝑆.funcs[𝑎].type

func_invoke(store, funcaddr , val * ) : (store, val * | exception | error )


1. Try invoking the function funcaddr in store with values val * as arguments:
* *
a. If it succeeds with values val ′ as results, then let result be val ′ .
b. Else if the outcome is an exception with a thrown exception [Link] exnaddr as the result, then let result be
exception exnaddr

242 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

c. Else it has trapped, hence let result be error.


2. Return the new store paired with result.

* *
func_invoke(𝑆, 𝑎, 𝑣 * ) = (𝑆 ′ , 𝑣 ′ ) (if invoke(𝑆, 𝑎, 𝑣 * ) ˓→ * 𝑆 ′ ; 𝐹 ; 𝑣 ′ )
func_invoke(𝑆, 𝑎, 𝑣 * ) = (𝑆 ′ , exception 𝑎′ ) (if invoke(𝑆, 𝑎, 𝑣 * ) ˓→ * 𝑆 ′ ; 𝐹 ; ([Link] 𝑎′ ) throw_ref
func_invoke(𝑆, 𝑎, 𝑣 * ) = (𝑆 ′ , error) (if invoke(𝑆, 𝑎, 𝑣 * ) ˓→ * 𝑆 ′ ; 𝐹 ; trap)

Note

The store may be modified even in case of an error.

7.1.9 Tables
table_alloc(store, tabletype, ref ) : (store, tableaddr )
1. Pre-condition: the tabletype is valid under the empty context.
2. Let tableaddr be the result of allocating a table in store with table type tabletype and initialization value
ref .
3. Return the new store paired with tableaddr .
table_alloc(𝑆, tt, 𝑟) = (𝑆 ′ , a) (if alloctable(𝑆, tt, 𝑟) = 𝑆 ′ , a)

table_type(store, tableaddr ) : tabletype


1. Return 𝑆.tables[𝑎].type.
2. Post-condition: the returned table type is valid under the empty context.
table_type(𝑆, 𝑎) = 𝑆.tables[𝑎].type

table_read(store, tableaddr , 𝑖 : u64 ) : ref | error


1. Let ti be the table instance [Link][tableaddr ].
2. If 𝑖 is larger than or equal to the length of ti .elem, then return error.
3. Else, return the reference value ti .elem[𝑖].
table_read(𝑆, 𝑎, 𝑖) = 𝑟 (if 𝑆.tables[𝑎].elem[𝑖] = 𝑟)
table_read(𝑆, 𝑎, 𝑖) = error (otherwise)

table_write(store, tableaddr , 𝑖 : u64 , ref ) : store | error


1. Let ti be the table instance [Link][tableaddr ].
2. If 𝑖 is larger than or equal to the length of ti .elem, then return error.
3. Replace ti .elem[𝑖] with the reference value ref .
4. Return the updated store.
table_write(𝑆, 𝑎, 𝑖, 𝑟) = 𝑆′ (if 𝑆 ′ = 𝑆 with tables[𝑎].elem[𝑖] = 𝑟)
table_write(𝑆, 𝑎, 𝑖, 𝑟) = error (otherwise)

table_size(store, tableaddr ) : u64


1. Return the length of [Link][tableaddr ].elem.

table_size(𝑆, 𝑎) = 𝑛 (if |𝑆.tables[𝑎].elem| = 𝑛)

7.1. Embedding 243


WebAssembly Specification, Release 3.0 (2025-11-14)

table_grow(store, tableaddr , 𝑛 : u64 , ref ) : store | error


1. Try growing the table instance [Link][tableaddr ] by 𝑛 elements with initialization value ref :
a. If it succeeds, return the updated store.
b. Else, return error.

table_grow(𝑆, 𝑎, 𝑛, 𝑟) = 𝑆′ (if 𝑆 ′ = 𝑆 with tables[𝑎] = growtable(𝑆.tables[𝑎], 𝑛, 𝑟))


table_grow(𝑆, 𝑎, 𝑛, 𝑟) = error (otherwise)

7.1.10 Memories
mem_alloc(store, memtype) : (store, memaddr )
1. Pre-condition: the memtype is valid under the empty context.
2. Let memaddr be the result of allocating a memory in store with memory type memtype.
3. Return the new store paired with memaddr .
mem_alloc(𝑆, mt) = (𝑆 ′ , a) (if allocmem(𝑆, mt) = 𝑆 ′ , a)

mem_type(store, memaddr ) : memtype


1. Return 𝑆.mems[𝑎].type.
2. Post-condition: the returned memory type is valid under the empty context.
mem_type(𝑆, 𝑎) = 𝑆.mems[𝑎].type

mem_read(store, memaddr , 𝑖 : u64 ) : byte | error


1. Let mi be the memory instance [Link][memaddr ].
2. If 𝑖 is larger than or equal to the length of mi .bytes, then return error.
3. Else, return the byte mi .bytes[𝑖].
mem_read(𝑆, 𝑎, 𝑖) = 𝑏 (if 𝑆.mems[𝑎].bytes[𝑖] = 𝑏)
mem_read(𝑆, 𝑎, 𝑖) = error (otherwise)

mem_write(store, memaddr , 𝑖 : u64 , byte) : store | error


1. Let mi be the memory instance [Link][memaddr ].
2. If 𝑖 is larger than or equal to the length of mi .bytes, then return error.
3. Replace mi .bytes[𝑖] with byte.
4. Return the updated store.
mem_write(𝑆, 𝑎, 𝑖, 𝑏) = 𝑆′ (if 𝑆 ′ = 𝑆 with mems[𝑎].bytes[𝑖] = 𝑏)
mem_write(𝑆, 𝑎, 𝑖, 𝑏) = error (otherwise)

mem_size(store, memaddr ) : u64


1. Return the length of [Link][memaddr ].bytes divided by the page size.

mem_size(𝑆, 𝑎) = 𝑛 (if |𝑆.mems[𝑎].bytes| = 𝑛 · 64 Ki)

244 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

mem_grow(store, memaddr , 𝑛 : u64 ) : store | error


1. Try growing the memory instance [Link][memaddr ] by 𝑛 pages:
a. If it succeeds, return the updated store.
b. Else, return error.

mem_grow(𝑆, 𝑎, 𝑛) = 𝑆′ (if 𝑆 ′ = 𝑆 with mems[𝑎] = growmem(𝑆.mems[𝑎], 𝑛))


mem_grow(𝑆, 𝑎, 𝑛) = error (otherwise)

7.1.11 Tags
tag_alloc(store, tagtype) : (store, tagaddr )
1. Pre-condition: 𝑡𝑎𝑔𝑡𝑦𝑝𝑒 is valid.
2. Let tagaddr be the result of allocating a tag in store with tag type tagtype.
3. Return the new store paired with tagaddr .
tag_alloc(𝑆, tt) = (𝑆 ′ , a) (if alloctag(𝑆, tt) = 𝑆 ′ , a)

tag_type(store, tagaddr ) : tagtype


1. Return 𝑆.tags[𝑎].type.
2. Post-condition: the returned tag type is valid.
tag_type(𝑆, 𝑎) = 𝑆.tags[𝑎].type

7.1.12 Exceptions
exn_alloc(store, tagaddr , val * ) : (store, exnaddr )
1. Pre-condition: tagaddr is an allocated tag address.
2. Let exnaddr be the result of allocating an exception instance in store with tag address tagaddr and initial-
ization values val * .
3. Return the new store paired with exnaddr .
exn_alloc(𝑆, tagaddr , val * ) = (𝑆 ⊕ {exns exninst}, |𝑆.exns|) (if exninst = {tag tagaddr , fields val * }

exn_tag(store, exnaddr ) : tagaddr


1. Let exninst be the exception instance [Link][exnaddr ].
2. Return the tag address [Link].
exn_tag(𝑆, 𝑎) = [Link] (if exninst = 𝑆.exns[𝑎])

exn_read(store, exnaddr ) : val *


1. Let exninst be the exception instance [Link][exnaddr ].
2. Return the values [Link].
exn_read(𝑆, 𝑎) = [Link] (if exninst = 𝑆.exns[𝑎])

7.1. Embedding 245


WebAssembly Specification, Release 3.0 (2025-11-14)

7.1.13 Globals
global_alloc(store, globaltype, val ) : (store, globaladdr )
1. Pre-condition: the globaltype is valid under the empty context.
2. Let globaladdr be the result of allocating a global in store with global type globaltype and initialization
value val .
3. Return the new store paired with globaladdr .
global_alloc(𝑆, gt, 𝑣) = (𝑆 ′ , a) (if allocglobal(𝑆, gt, 𝑣) = 𝑆 ′ , a)

global_type(store, globaladdr ) : globaltype


1. Return 𝑆.globals[𝑎].type.
2. Post-condition: the returned global type is valid under the empty context.
global_type(𝑆, 𝑎) = 𝑆.globals[𝑎].type

global_read(store, globaladdr ) : val


1. Let gi be the global instance [Link][globaladdr ].
2. Return the value gi .value.
global_read(𝑆, 𝑎) = 𝑣 (if 𝑆.globals[𝑎].value = 𝑣)

global_write(store, globaladdr , val ) : store | error


1. Let gi be the global instance [Link][globaladdr ].
2. Let mut 𝑡 be the structure of the global type gi .type.
3. If mut is empty, then return error.
4. Replace gi .value with the value val .
5. Return the updated store.

global_write(𝑆, 𝑎, 𝑣) = 𝑆 ′ (if 𝑆.globals[𝑎].type = mut 𝑡 ∧ 𝑆 ′ = 𝑆 with globals[𝑎].value = 𝑣)


global_write(𝑆, 𝑎, 𝑣) = error (otherwise)

7.1.14 Values
ref_type(store, ref ) : reftype
1. Pre-condition: the reference ref is valid under store 𝑆.
2. Return the reference type 𝑡 with which ref is valid.
3. Post-condition: the returned reference type is valid under the empty context.
ref_type(𝑆, 𝑟) = 𝑡 (if 𝑆 ⊢ 𝑟 : 𝑡)

Note

In future versions of WebAssembly, not all references may carry precise type information at run time. In such
cases, this function may return a less precise supertype.

246 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

val_default(valtype) : val
1. If default𝑣𝑎𝑙𝑡𝑦𝑝𝑒 is not defined, then return error.
1. Else, return the value default𝑣𝑎𝑙𝑡𝑦𝑝𝑒 .
val_default(𝑡) = 𝑣 (if default𝑡 = 𝑣)
val_default(𝑡) = error (if default𝑡 = 𝜖)

7.1.15 Matching
match_valtype(valtype 1 , valtype 2 ) : bool
1. Pre-condition: the value types valtype 1 and valtype 2 are valid under the empty context.
2. If valtype 1 matches valtype 2 , then return true.
3. Else, return false.
match_reftype(𝑡1 , 𝑡2 ) = true (if ⊢ 𝑡1 ≤ 𝑡2 )
match_reftype(𝑡1 , 𝑡2 ) = false (otherwise)

match_externtype(externtype 1 , externtype 2 ) : bool


1. Pre-condition: the extern types externtype 1 and externtype 2 are valid under the empty context.
2. If externtype 1 matches externtype 2 , then return true.
3. Else, return false.
match_externtype(et 1 , et 2 ) = true (if ⊢ et 1 ≤ et 2 )
match_externtype(et 1 , et 2 ) = false (otherwise)

7.2 Profiles
To enable the use of WebAssembly in as many environments as possible, profiles specify coherent language subsets
that fit constraints imposed by common classes of host environments. A host platform can thereby decide to support
the language only under a restricted profile, or even the intersection of multiple profiles.

7.2.1 Conventions
A profile modification is specified by decorating selected rules in the main body of this specification with a profile
annotation that defines them as conditional on the choice of profile.
For that purpose, every profile defines a profile marker, an alphanumeric short-hand like ABC. A profile annotation
of the form [!ABC XYZ] on a rule indicates that this rule is excluded for either of the profiles whose marker is ABC
or XYZ.
There are two ways of subsetting the language in a profile:
• Syntactic, by omitting a feature, in which case certain constructs are removed from the syntax altogether.
• Semantic, by restricting a feature, in which case certain constructs are still present but some behaviours are
ruled out.

Syntax Annotations
To omit a construct from a profile syntactically, respective productions in the grammar of the abstract syntax are
annotated with an associated profile marker. This is defined to have the following implications:
1. Any production in the binary or textual syntax that produces abstract syntax with a marked construct is
omitted by extension.
2. Any validation or execution rule that handles a marked construct is omitted by extension.

7.2. Profiles 247


WebAssembly Specification, Release 3.0 (2025-11-14)

The overall effect is that the respective construct is no longer part of the language under a respective profile.

Note

For example, a “busy” profile marked BUSY could rule out the nop instruction by marking the production for
it in the abstract syntax as follows:

instr ::= . . .
[!BUSY]
| nop
| unreachable

A rule may be annotated by multiple markers, which could be the case if a construct is in the intersection of
multiple features.

Semantics Annotations
To restrict certain behaviours in a profile, individual validation or reduction rules or auxiliary definitions are an-
notated with an associated marker.
This has the consequence that the respective rule is no longer applicable under the given profile.

Note

For example, an “infinite” profile marked INF could define that growing memory never fails:

𝑆; 𝐹 ; ([Link] 𝑛) [Link] 𝑥 ˓→ 𝑆 ′ ; 𝐹 ; ([Link] sz )


(if 𝐹.[Link][𝑥] = 𝑎
∧ sz = |𝑆.mems[𝑎].datas|/64 Ki
∧ 𝑆 ′ = 𝑆 with mems[𝑎] = growmem(𝑆.mems[𝑎], 𝑛))
[!INF]
𝑆; 𝐹 ; ([Link] 𝑛) [Link] 𝑥 ˓→ 𝑆; 𝐹 ; ([Link] signed−1
32 (−1))

Properties
All profiles are defined such that the following properties are preserved:
• All profiles represent syntactic and semantic subsets of the full profile, i.e., they do not add syntax or alter
behaviour.
• All profiles are mutually compatible, i.e., no two profiles subset semantic behaviour in inconsistent or am-
biguous ways, and any intersection of profiles preserves the properties described here.
• Profiles do not violate soundness, i.e., all configurations valid under that profile still have well-defined exe-
cution behaviour.

Note

Tools are generally expected to handle and produce code for the full profile by default. In particular, producers
should not generate code that depends on specific profiles. Instead, all code should preserve correctness when
executed under the full profile.
Moreover, profiles should be considered static and fixed for a given platform or ecosystem. Runtime condition-
ing on the “current” profile is not intended and should be avoided.

7.2.2 Defined Profiles

248 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Note

The number of defined profiles is expected to remain small in the future. Profiles are intended for broad and
permanent use cases only. In particular, profiles are not intended for language versioning.

Full Profile (FUL)


The full profile contains the complete language and all possible behaviours. It imposes no restrictions, i.e., all rules
and definitions are active. All other profiles define sub-languages of this profile.

Deterministic Profile (DET)


The deterministic profile excludes all rules marked [!DET]
. It defines a sub-language that does not exhibit any
incidental non-deterministic behaviour:
• All NaN values generated by floating-point instructions are canonical and positive.
• All relaxed vector instructions have a fixed behaviour that does not depend on the implementation.
Even under this profile, the [Link] and [Link] instructions technically remain non-deterministic, in
order to be able to indicate resource exhaustion.

Note

In future versions of WebAssembly, new non-deterministic behaviour may be added to the language, such that
the deterministic profile will induce additional restrictions.

7.3 Implementation Limitations


Implementations typically impose additional restrictions on a number of aspects of a WebAssembly module or
execution. These may stem from:
• physical resource limits,
• constraints imposed by the embedder or its environment,
• limitations of selected implementation strategies.
This section lists allowed limitations. Where restrictions take the form of numeric limits, no minimum requirements
are given, nor are the limits assumed to be concrete, fixed numbers. However, it is expected that all implementations
have “reasonably” large limits to enable common applications.

Note

A conforming implementation is not allowed to leave out individual features. However, designated subsets of
WebAssembly may be specified in the future.

7.3.1 Syntactic Limits


Structure
An implementation may impose restrictions on the following dimensions of a module:
• the number of types in a module
• the number of functions in a module, including imports
• the number of tables in a module, including imports
• the number of memories in a module, including imports

7.3. Implementation Limitations 249


WebAssembly Specification, Release 3.0 (2025-11-14)

• the number of globals in a module, including imports


• the number of tags in a module, including imports
• the number of element segments in a module
• the number of data segments in a module
• the number of imports to a module
• the number of exports from a module
• the number of sub types in a recursive type
• the subtyping depth of a sub type
• the number of fields in a structure type
• the number of parameters in a function type
• the number of results in a function type
• the number of parameters in a block type
• the number of results in a block type
• the number of locals in a function
• the number of instructions in a function body
• the number of instructions in a structured control instruction
• the number of structured control instructions in a function
• the nesting depth of structured control instructions
• the number of label indices in a br_table instruction
• the number of instructions in a constant expression
• the length of the array in a array.new_fixed instruction
• the length of an element segment
• the length of a data segment
• the length of a name
• the range of characters in a name
If the limits of an implementation are exceeded for a given module, then the implementation may reject the vali-
dation, compilation, or instantiation of that module with an embedder-specific error.

Note

The last item allows embedders that operate in limited environments without support for Unicode48 to limit the
names of imports and exports to common subsets like ASCII49 .

Binary Format
For a module given in binary format, additional limitations may be imposed on the following dimensions:
• the size of a module
• the size of any section
• the size of an individual function’s code
• the size of a structured control instruction
48 [Link]
49 [Link]

250 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

• the size of an individual constant expression’s instruction sequence


• the number of sections

Text Format
For a module given in text format, additional limitations may be imposed on the following dimensions:
• the size of the source text
• the size of any syntactic element
• the size of an individual token
• the nesting depth of folded instructions
• the length of symbolic identifiers
• the range of literal characters allowed in the source text

7.3.2 Validation
An implementation may defer validation of individual functions until they are first invoked.
If a function turns out to be invalid, then the invocation, and every consecutive call to the same function, results in
a trap.

Note

This is to allow implementations to use interpretation or just-in-time compilation for functions. The function
must still be fully validated before execution of its body begins.

7.3.3 Execution
Restrictions on the following dimensions may be imposed during execution of a WebAssembly program:
• the number of allocated module instances
• the number of allocated function instances
• the number of allocated table instances
• the number of allocated memory instances
• the number of allocated global instances
• the number of allocated tag instances
• the number of allocated structure instances
• the number of allocated array instances
• the number of allocated exception instances
• the size of a table instance
• the size of a memory instance
• the size of an array instance
• the number of frames on the stack
• the number of labels on the stack
• the number of values on the stack

7.3. Implementation Limitations 251


WebAssembly Specification, Release 3.0 (2025-11-14)

If the runtime limits of an implementation are exceeded during execution of a computation, then it may terminate
that computation and report an embedder-specific error to the invoking code.
Some of the above limits may already be verified during instantiation, in which case an implementation may report
exceedance in the same manner as for syntactic limits.

Note

Concrete limits are usually not fixed but may be dependent on specifics, interdependent, vary over time, or
depend on other implementation- or embedder-specific situations or events.

7.4 Type Soundness


The type system of WebAssembly is sound, implying both type safety and memory safety with respect to the We-
bAssembly semantics. For example:
• All types declared and derived during validation are respected at run time; e.g., every local or global variable
will only contain type-correct values, every instruction will only be applied to operands of the expected type,
and every function invocation always evaluates to a result of the right type (if it does not diverge, throw an
exception, or trap).
• No memory location will be read or written except those explicitly defined by the program, i.e., as a local, a
global, an element in a table, or a location within a linear memory.
• There is no undefined behavior, i.e., the execution rules cover all possible cases that can occur in a valid
program, and the rules are mutually consistent.
Soundness also is instrumental in ensuring additional properties, most notably, encapsulation of function and
module scopes: no locals can be accessed outside their own function and no module components can be accessed
outside their own module unless they are explicitly exported or imported.
The typing rules defining WebAssembly validation only cover the static components of a WebAssembly program.
In order to state and prove soundness precisely, the typing rules must be extended to the dynamic components of
the abstract runtime, that is, the store, configurations, and administrative instructions.50

7.4.1 Contexts
In order to check rolled up recursive types, the context is locally extended with an additional component that records
the sub type corresponding to each recursive type index within the current recursive type:

𝐶 ::= { . . . , recs subtype * }

7.4.2 Types
Well-formedness for extended type forms is defined as follows.

Heap Type bot


• The heap type is valid.

𝐶 ⊢ bot : ok
50 The formalization and theorems are derived from the following article: Andreas Haas, Andreas Rossberg, Derek Schuff, Ben Titzer, Dan
Gohman, Luke Wagner, Alon Zakai, JF Bastien, Michael Holman. Bringing the Web up to Speed with WebAssembly51 . Proceedings of the
38th ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI 2017). ACM 2017.
51 [Link]

252 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Heap Type rec 𝑖


• The recursive type index 𝑖 must exist in 𝐶.recs.
• Then the heap type is valid.
𝐶.recs[𝑖] = subtype
𝐶 ⊢ rec 𝑖 : ok

Value Type bot


• The value type is valid.

𝐶 ⊢ bot : ok

Recursive Types rec subtype *


• Let 𝐶 ′ be the current context 𝐶, but where recs is subtype * .
• There must be a type index 𝑥, such that for each sub type subtype 𝑖 in subtype * :
– Under the context 𝐶 ′ , the sub type subtype 𝑖 must be valid for type index 𝑥 + 𝑖 and recursive type index
𝑖.
• Then the recursive type is valid for the type index 𝑥.
𝐶, recs subtype * ⊢ rec subtype * : ok(𝑥, 0)
𝐶 ⊢ rec subtype * : ok(𝑥)
*
𝐶 ⊢ subtype : ok(𝑥, 𝑖) 𝐶 ⊢ rec subtype ′ : ok(𝑥 + 1, 𝑖 + 1)
𝐶 ⊢ rec 𝜖 : ok(𝑥, 𝑖) 𝐶 ⊢ rec subtype subtype ′ * : ok(𝑥, 𝑖)

Note

These rules are a generalisation of the ones previously given.

Sub types sub final? ht * comptype


• The composite type comptype must be valid.
• The sequence ht * may be no longer than 1.
• For every heap type ht 𝑘 in ht * :
– The heap type ht 𝑘 must be ordered before a type index 𝑥 and recursive type index a 𝑖, meaning:
∗ Either ht 𝑘 is a defined type.
∗ Or ht 𝑘 is a type index 𝑦𝑘 that is smaller than 𝑥.
∗ Or ht 𝑘 is a recursive type index rec 𝑗𝑘 where 𝑗𝑘 is smaller than 𝑖.
– Let sub type subtype 𝑘 be the unrolling of the heap type ht 𝑘 , meaning:
∗ Either ht 𝑘 is a defined type deftype 𝑘 , then subtype 𝑘 must be the unrolling of deftype 𝑘 .
∗ Or ht 𝑘 is a type index 𝑦𝑘 , then subtype 𝑘 must be the unrolling of the defined type 𝐶.types[𝑦𝑘 ].
∗ Or ht 𝑘 is a recursive type index rec 𝑗𝑘 , then subtype 𝑘 must be 𝐶.recs[𝑗𝑘 ].
– The sub type subtype 𝑘 must not contain final.
– Let comptype ′𝑘 be the composite type in subtype 𝑘 .
– The composite type comptype must match comptype ′𝑘 .
• Then the sub type is valid for the type index 𝑥 and recursive type index 𝑖.

7.4. Type Soundness 253


WebAssembly Specification, Release 3.0 (2025-11-14)

*
|ht * | ≤ 1 (ht ≺ 𝑥, 𝑖)* (unroll𝐶 (ht) = sub ht ′ comptype ′ )*
𝐶 ⊢ comptype : ok (𝐶 ⊢ comptype ≤ comptype ′ )*
𝐶 ⊢ sub final? ht * comptype : ok(𝑥, 𝑖)
where:
(deftype ≺ 𝑥, 𝑖) = true
(𝑦 ≺ 𝑥, 𝑖) = 𝑦<𝑥
(rec 𝑗 ≺ 𝑥, 𝑖) = 𝑗<𝑖

unroll𝐶 (deftype) = unroll(deftype)


unroll𝐶 (𝑦) = unroll(𝐶.types[𝑦])
unroll𝐶 (rec 𝑗) = 𝐶.recs[𝑗]

Note

This rule is a generalisation of the ones previously given, which only allowed type indices as supertypes.

Defined types rectype.𝑖


The defined type (rectype.𝑖) is valid if:
• The recursive type rectype is valid for the type index 𝑥.
• The recursive type rectype is of the form (rec subtype 𝑛 ).
• 𝑖 is less than 𝑛.
𝐶 ⊢ rectype : ok(𝑥) rectype = rec subtype 𝑛 𝑖<𝑛
𝐶 ⊢ rectype.𝑖 : ok

7.4.3 Subtyping
In a rolled-up recursive type, a recursive type indices rec 𝑖 matches another heap type ht if:
*
• Let sub final? ht ′ comptype be the sub type 𝐶.recs[𝑖].
*
• The heap type ht is contained in ht ′ .
𝐶.recs[𝑖] = sub final? (ht *1 ht ht *2 ) comptype
𝐶 ⊢ rec 𝑖 ≤ ht

Note

This rule is only invoked when checking validity of rolled-up recursive types.

7.4.4 Results
Results can be classified by result types as follows.

Results val *
• For each value val 𝑖 in val * :
– The value val 𝑖 is valid with some value type 𝑡𝑖 .
• Let 𝑡* be the concatenation of all 𝑡𝑖 .
• Then the result is valid with result type [𝑡* ].
(𝑆 ⊢ val : 𝑡)*
𝑆 ⊢ val * : [𝑡* ]

254 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Results ([Link] 𝑎) throw_ref


• The value [Link] 𝑎 must be valid.
• Then the result is valid with result type [𝑡* ], for any valid closed result types.
𝑆 ⊢ [Link] 𝑎 : ref exn ⊢ [𝑡* ] : ok
𝑆 ⊢ ([Link] 𝑎) throw_ref : [𝑡′ * ]

Results trap
• The result is valid with result type [𝑡* ], for any valid closed result types.
⊢ [𝑡* ] : ok
𝑆 ⊢ trap : [𝑡* ]

7.4.5 Store Validity


The following typing rules specify when a runtime store 𝑆 is valid. A valid store must consist of tag, global,
memory, table, function, data, element, structure, array, exception, and module instances that are themselves valid,
relative to 𝑆.
To that end, each kind of instance is classified by a respective tag, global, memory, table, function, or element,
type, or just ok in the case of data structures, arrays, or exceptions. Module instances are classified by module
contexts, which are regular contexts repurposed as module types describing the index spaces defined by a module.

Store 𝑆
• Each tag instance taginst 𝑖 in 𝑆.tags must be valid with some tag type tagtype 𝑖 .
• Each global instance globalinst 𝑖 in 𝑆.globals must be valid with some global type globaltype 𝑖 .
• Each memory instance meminst 𝑖 in 𝑆.mems must be valid with some memory type memtype 𝑖 .
• Each table instance tableinst 𝑖 in 𝑆.tables must be valid with some table type tabletype 𝑖 .
• Each function instance funcinst 𝑖 in 𝑆.funcs must be valid with some defined type deftype 𝑖 .
• Each data instance datainst 𝑖 in 𝑆.datas must be valid.
• Each element instance eleminst 𝑖 in 𝑆.elems must be valid with some reference type reftype 𝑖 .
• Each structure instance structinst 𝑖 in 𝑆.structs must be valid.
• Each array instance arrayinst 𝑖 in 𝑆.arrays must be valid.
• Each exception instance exninst 𝑖 in 𝑆.exns must be valid.
• No reference to a bound structure address must be reachable from itself through a path consisting only of
indirections through immutable structure, or array fields or fields of exception instances.
• No reference to a bound array address must be reachable from itself through a path consisting only of indi-
rections through immutable structure or array fields or fields of exception instances.
• No reference to a bound exception address must be reachable from itself through a path consisting only of
indirections through immutable structure or array fields or fields of exception instances.
• Then the store is valid.

7.4. Type Soundness 255


WebAssembly Specification, Release 3.0 (2025-11-14)

(𝑆 ⊢ taginst : tagtype)* (𝑆 ⊢ globalinst : globaltype)*


*
(𝑆 ⊢ meminst : memtype) (𝑆 ⊢ tableinst : tabletype)*
*
(𝑆 ⊢ funcinst : deftype) (𝑆 ⊢ datainst : ok)* (𝑆 ⊢ eleminst : reftype)*
* *
(𝑆 ⊢ structinst : ok) (𝑆 ⊢ arrayinst : ok) (𝑆 ⊢ exninst : ok)*
𝑆 = {tags taginst , globals globalinst , mems meminst , tables tableinst * , funcs funcinst * ,
* * *

datas datainst * , elems eleminst * , structs structinst * , arrays arrayinst * , exns exninst * }
(𝑆.structs[𝑎s ] = structinst)* (([Link] 𝑎s ) ̸≫+𝑆 ([Link] 𝑎s ))
*
* + *
(𝑆.arrays[𝑎a ] = arrayinst) (([Link] 𝑎a ) ̸≫𝑆 ([Link] 𝑎a ))
(𝑆.exns[𝑎e ] = exninst)* (([Link] 𝑎e ) ̸≫+ 𝑆 ([Link] 𝑎e ))
*

⊢ 𝑆 : ok
where val 1 ≫+
𝑆 val 2 denotes the transitive closure of the following immutable reachability relation on values:

([Link] 𝑎) ≫𝑆 𝑆.structs[𝑎].fields[𝑖] if expand(𝑆.structs[𝑎].type) = struct ft 𝑖1 st ft *2


([Link] 𝑎) ≫𝑆 𝑆.arrays[𝑎].fields[𝑖] if expand(𝑆.arrays[𝑎].type) = array st
([Link] 𝑎) ≫𝑆 𝑆.exns[𝑎].fields[𝑖]
([Link] ref ) ≫𝑆 ref

Note

The constraint on reachability through immutable fields prevents the presence of cyclic data structures that can
not be constructed in the language. Cycles can only be formed using mutation.

Tag Instances {type tagtype}


• The tag type tagtype must be valid under the empty context.
• Then the tag instance is valid with tag type tagtype.
⊢ tagtype : ok
𝑆 ⊢ {type tagtype} : tagtype

Global Instances {type mut 𝑡, value val }


• The global type mut 𝑡 must be valid under the empty context.
• The value val must be valid with some value type 𝑡′ .
• The value type 𝑡′ must match the value type 𝑡.
• Then the global instance is valid with global type mut 𝑡.
⊢ mut 𝑡 : ok 𝑆 ⊢ val : 𝑡′ ⊢ 𝑡′ ≤ 𝑡
𝑆 ⊢ {type mut 𝑡, value val } : mut 𝑡

Memory Instances {type (addrtype limits), bytes 𝑏* }


• The memory type addrtype limits must be valid under the empty context.
• Let limits be [𝑛 .. 𝑚].
• The length of 𝑏* must equal 𝑚 multiplied by the page size 64 Ki.
• Then the memory instance is valid with memory type addrtype limits.
⊢ addrtype [𝑛 .. 𝑚] : ok |𝑏* | = 𝑛 · 64 Ki
𝑆 ⊢ {type (addrtype [𝑛 .. 𝑚]), bytes 𝑏* } : addrtype [𝑛 .. 𝑚]

256 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Table Instances {type (addrtype limits 𝑡), elem ref * }


• The table type addrtype limits 𝑡 must be valid under the empty context.
• Let limits be [𝑛 .. 𝑚].
• The length of ref * must equal 𝑛.
• For each reference ref 𝑖 in the table’s elements ref 𝑛 :
– The reference ref 𝑖 must be valid with some reference type 𝑡′𝑖 .
– The reference type 𝑡′𝑖 must match the reference type 𝑡.
• Then the table instance is valid with table type addrtype limits 𝑡.
⊢ addrtype [𝑛 .. 𝑚] 𝑡 : ok |ref * | = 𝑛 (𝑆 ⊢ ref : 𝑡′ )* (⊢ 𝑡′ ≤ 𝑡)*
*
𝑆 ⊢ {type (addrtype [𝑛 .. 𝑚] 𝑡), elem ref } : addrtype [𝑛 .. 𝑚] 𝑡

Function Instances {type deftype, module moduleinst, code func}


• The defined type deftype must be valid under an empty context.
• The module instance moduleinst must be valid with some context 𝐶.
• Under context 𝐶:
– The function func must be valid with some defined type deftype ′ .
– The defined type deftype ′ must match deftype.
• Then the function instance is valid with defined type deftype.
⊢ deftype : ok 𝑆 ⊢ moduleinst : 𝐶
𝐶 ⊢ func : deftype ′ 𝐶 ⊢ deftype ′ ≤ deftype
𝑆 ⊢ {type deftype, module moduleinst, code func} : deftype

Host Function Instances {type deftype, hostfunc hf }


• The defined type deftype must be valid under an empty context.
• The expansion of defined type deftype must be some function type func [𝑡*1 ] → [𝑡*2 ].
• For every valid store 𝑆1 extending 𝑆 and every sequence val * of values whose types coincide with 𝑡*1 :
– Executing hf in store 𝑆1 with arguments val * has a non-empty set of possible outcomes.
– For every element 𝑅 of this set:
∗ Either 𝑅 must be ⊥ (i.e., divergence).
∗ Or 𝑅 consists of a valid store 𝑆2 extending 𝑆1 and a result result whose type coincides with [𝑡*2 ].
• Then the function instance is valid with defined type deftype.
∀𝑆1 , val * , ⊢ 𝑆1 : ok ∧ ⊢ 𝑆 ⪯ 𝑆1 ∧ 𝑆1 ⊢ val * : [𝑡*1 ] =⇒
hf (𝑆1 ; val * ) ⊃ ∅ ∧
⊢ deftype : ok ∀𝑅 ∈ hf (𝑆1 ; val * ), 𝑅 = ⊥ ∨
* *
deftype ≈ func [𝑡1 ] → [𝑡2 ] ∃𝑆2 , result, ⊢ 𝑆2 : ok ∧ ⊢ 𝑆1 ⪯ 𝑆2 ∧ 𝑆2 ⊢ result : [𝑡*2 ] ∧ 𝑅 = (𝑆2 ; result)
𝑆 ⊢ {type deftype, hostfunc hf } : deftype

Note

This rule states that, if appropriate pre-conditions about store and arguments are satisfied, then executing the
host function must satisfy appropriate post-conditions about store and results. The post-conditions match the
ones in the execution rule for invoking host functions.

7.4. Type Soundness 257


WebAssembly Specification, Release 3.0 (2025-11-14)

Any store under which the function is invoked is assumed to be an extension of the current store. That way, the
function itself is able to make sufficient assumptions about future stores.

Data Instances {bytes 𝑏* }


• The data instance is valid.

𝑆 ⊢ {bytes 𝑏* } : ok

Element Instances {type 𝑡, elem ref * }


• The reference type 𝑡 must be valid under the empty context.
• For each reference ref 𝑖 in the elements ref 𝑛 :
– The reference ref 𝑖 must be valid with some reference type 𝑡′𝑖 .
– The reference type 𝑡′𝑖 must match the reference type 𝑡.
• Then the element instance is valid with reference type 𝑡.
⊢ 𝑡 : ok (𝑆 ⊢ ref : 𝑡′ )* (⊢ 𝑡′ ≤ 𝑡)*
𝑆 ⊢ {type 𝑡, elem ref * } : 𝑡

Structure Instances {type deftype, fields fieldval * }


• The defined type deftype must be valid under the empty context.
• The expansion of deftype must be a structure type struct fieldtype * .
• The length of the sequence of field values fieldval * must be the same as the length of the sequence of field
types fieldtype * .
• For each field value fieldval 𝑖 in fieldval * and corresponding field type fieldtype 𝑖 in fieldtype * :
– Let fieldtype 𝑖 be mut storagetype 𝑖 .
– The field value fieldval 𝑖 must be valid with storage type storagetype 𝑖 .
• Then the structure instance is valid.
⊢ dt : ok expand(dt) = struct (mut st)* (𝑆 ⊢ fv : st)*
𝑆 ⊢ {type dt, fields fv * } : ok

Array Instances {type deftype, fields fieldval * }


• The defined type deftype must be valid under the empty context.
• The expansion of deftype must be an array type array fieldtype.
• Let fieldtype be mut storagetype.
• For each field value fieldval 𝑖 in fieldval * :
– The field value fieldval 𝑖 must be valid with storage type storagetype.
• Then the array instance is valid.
⊢ dt : ok expand(dt) = array (mut st) (𝑆 ⊢ fv : st)*
𝑆 ⊢ {type dt, fields fv * } : ok

258 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Field Values fieldval


• If fieldval is a value val , then:
– The value val must be valid with value type 𝑡.
– Then the field value is valid with value type 𝑡.
• Else, fieldval is a packed value packval :
– Let [Link] 𝑖 be the field value fieldval .
– Then the field value is valid with packed type packtype.

𝑆 ⊢ [Link] 𝑖 : pt

Exception Instances {tag 𝑎, fields val * }


• The store entry 𝑆.tags[𝑎] must exist.
*
• The expansion of the tag type 𝑆.tags[𝑎].type must be some function type func [𝑡* ] → [𝑡′ ].
*
• The result type [𝑡′ ] must be empty.
• The sequence val 𝑎 𝑠𝑡 of values must have the same length as the sequence 𝑡* of value types.
• For each value val 𝑖 in val 𝑎 𝑠𝑡 and corresponding value type 𝑡𝑖 in 𝑡* , the value val 𝑖 must be valid with type
𝑡𝑖 .
• Then the exception instance is valid.
𝑆.tags[𝑎].type ≈ func [𝑡* ] → [] (𝑆 ⊢ val : 𝑡)*
𝑆 ⊢ {tag 𝑎, fields val * } : ok

Export Instances {name name, addr externaddr }


• The external address externaddr must be valid with some external type externtype.
• Then the export instance is valid.
𝑆 ⊢ externaddr : externtype
𝑆 ⊢ {name name, addr externaddr } : ok

Module Instances moduleinst


• Each defined type deftype 𝑖 in [Link] must be valid under the empty context.
• For each tag address tagaddr 𝑖 in [Link], the external address tag tagaddr 𝑖 must be valid with
some external type tag tagtype 𝑖 .
• For each global address globaladdr 𝑖 in [Link], the external address global globaladdr 𝑖 must be
valid with some external type global globaltype 𝑖 .
• For each memory address memaddr 𝑖 in [Link], the external address mem memaddr 𝑖 must be
valid with some external type mem memtype 𝑖 .
• For each table address tableaddr 𝑖 in [Link], the external address table tableaddr 𝑖 must be valid
with some external type table tabletype 𝑖 .
• For each function address funcaddr 𝑖 in [Link], the external address func funcaddr 𝑖 must be
valid with some external type func deftype F𝑖 .
• For each data address dataaddr 𝑖 in [Link], the data instance 𝑆.datas[dataaddr 𝑖 ] must be valid
with ok 𝑖 .

7.4. Type Soundness 259


WebAssembly Specification, Release 3.0 (2025-11-14)

• For each element address elemaddr 𝑖 in [Link], the element instance 𝑆.elems[elemaddr 𝑖 ] must
be valid with some reference type reftype 𝑖 .
• Each export instance exportinst 𝑖 in [Link] must be valid.
• For each export instance exportinst 𝑖 in [Link], the name exportinst 𝑖 .name must be different
from any other name occurring in [Link].
• Let deftype * be the concatenation of all deftype 𝑖 in order.
• Let tagtype * be the concatenation of all tagtype 𝑖 in order.
• Let globaltype * be the concatenation of all globaltype 𝑖 in order.
• Let memtype * be the concatenation of all memtype 𝑖 in order.
• Let tabletype * be the concatenation of all tabletype 𝑖 in order.
• Let deftype *F be the concatenation of all deftype F𝑖 in order.
• Let reftype * be the concatenation of all reftype 𝑖 in order.
• Let ok * be the concatenation of all ok 𝑖 in order.
• Let 𝑚 be the length of [Link].
• Let 𝑥* be the sequence of function indices from 0 to 𝑚 − 1.
• Then the module instance is valid with context {types deftype * , tags tagtype * , globals globaltype * ,
mems memtype * , tables tabletype * , funcs deftype *F , datas ok * , elems reftype * , refs 𝑥* }.

(⊢ deftype : ok)* (𝑆 ⊢ tag tagaddr : tag tagtype)*


(𝑆 ⊢ global globaladdr : global globaltype)* (𝑆 ⊢ func funcaddr : func deftype F )*
*
(𝑆 ⊢ mem memaddr : mem memtype) (𝑆 ⊢ table tableaddr : table tabletype)*
*
(𝑆 ⊢ 𝑆.datas[dataaddr ] : ok ) (𝑆 ⊢ 𝑆.elems[elemaddr ] : reftype)*
(𝑆 ⊢ exportinst : ok) *
([Link])* disjoint
*
𝑆 ⊢ {types deftype ,
tags tagaddr * ,
globals globaladdr * ,
mems memaddr * ,
tables tableaddr * ,
funcs funcaddr * ,
datas dataaddr * ,
elems elemaddr * ,
exports exportinst * } : {types deftype * ,
tags tagtype * ,
globals globaltype * ,
mems memtype * ,
tables tabletype * ,
funcs deftype *F ,
datas ok * ,
elems reftype * ,
refs 0 . . . (|funcaddr * | − 1) }

7.4.6 Configuration Validity


To relate the WebAssembly type system to its execution semantics, the typing rules for instructions must be ex-
tended to configurations 𝑆; 𝑇 , which relates the store to execution threads.
Configurations and threads are classified by their result type. In addition to the store 𝑆, threads are typed under a
return type resulttype ? , which controls whether and with which type a return instruction is allowed. This type is
absent (𝜖) except for instruction sequences inside an administrative frame instruction.

260 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Finally, frames are classified with frame contexts, which extend the module contexts of a frame’s associated module
instance with the locals that the frame contains.

Configurations 𝑆; 𝑇
• The store 𝑆 must be valid.
• Under no allowed return type, the thread 𝑇 must be valid with some result type [𝑡* ].
• Then the configuration is valid with the result type [𝑡* ].
⊢ 𝑆 : ok 𝑆; 𝜖 ⊢ 𝑇 : [𝑡* ]
⊢ 𝑆; 𝑇 : [𝑡* ]

Threads 𝐹 ; instr *
• Let resulttype ? be the current allowed return type.
• The frame 𝐹 must be valid with a context 𝐶.
• Let 𝐶 ′ be the same context as 𝐶, but with return set to resulttype ? .
• Under context 𝐶 ′ , the instruction sequence instr * must be valid with some type [] → [𝑡* ].
• Then the thread is valid with the result type [𝑡* ].
𝑆⊢𝐹 :𝐶 𝑆; 𝐶, return resulttype ? ⊢ instr * : [] → [𝑡* ]
𝑆; resulttype ? ⊢ 𝐹 ; instr * : [𝑡* ]

Frames {locals val * , module moduleinst}


• The module instance moduleinst must be valid with some module context 𝐶.
• Each value val 𝑖 in val * must be valid with some value type 𝑡𝑖 .
• Let 𝑡* be the concatenation of all 𝑡𝑖 in order.
• Let 𝐶 ′ be the same context as 𝐶, but with the value types 𝑡* prepended to the locals list.
• Then the frame is valid with frame context 𝐶 ′ .
𝑆 ⊢ moduleinst : 𝐶 (𝑆 ⊢ val : 𝑡)*
𝑆 ⊢ {locals val , module moduleinst} : (𝐶, locals 𝑡* )
*

7.4.7 Administrative Instructions


Typing rules for administrative instructions are specified as follows. In addition to the context 𝐶, typing of these
instructions is defined under a given store 𝑆.
To that end, all previous typing judgements 𝐶 ⊢ prop are generalized to include the store, as in 𝑆; 𝐶 ⊢ prop, by
implicitly adding 𝑆 to all rules – 𝑆 is never modified by the pre-existing rules, but it is accessed in the extra rules
for administrative instructions given below.

trap
• The instruction is valid with any valid instruction type of the form [𝑡*1 ] → [𝑡*2 ].
𝐶 ⊢ [𝑡*1 ] → [𝑡*2 ] : ok
𝑆; 𝐶 ⊢ trap : [𝑡*1 ] → [𝑡*2 ]

7.4. Type Soundness 261


WebAssembly Specification, Release 3.0 (2025-11-14)

val
• The value val must be valid with value type 𝑡.
• Then it is valid as an instruction with type [] → [𝑡].
𝑆 ⊢ val : 𝑡
𝑆; 𝐶 ⊢ val : [] → [𝑡]

label𝑛 {instr *0 } instr *


• The instruction sequence instr *0 must be valid with some type [𝑡𝑛1 ] →𝑥* [𝑡*2 ].
• Let 𝐶 ′ be the same context as 𝐶, but with the result type [𝑡𝑛1 ] prepended to the labels list.
• Under context 𝐶 ′ , the instruction sequence instr * must be valid with type [] →𝑥′ * [𝑡*2 ].
• Then the compound instruction is valid with type [] → [𝑡*2 ].
𝑆; 𝐶 ⊢ instr *0 : [𝑡𝑛1 ] →𝑥* [𝑡*2 ] 𝑆; 𝐶, labels [𝑡𝑛1 ] ⊢ instr * : [] →𝑥′* [𝑡*2 ]
𝑆; 𝐶 ⊢ label𝑛 {instr *0 } instr * : [] → [𝑡*2 ]

frame𝑛 {𝐹 } instr *
• Under the valid return type [𝑡𝑛 ], the thread 𝐹 ; instr * must be valid with result type [𝑡𝑛 ].
• Then the compound instruction is valid with type [] → [𝑡𝑛 ].
𝐶 ⊢ [𝑡𝑛 ] : ok 𝑆; [𝑡𝑛 ] ⊢ 𝐹 ; instr * : [𝑡𝑛 ]
𝑆; 𝐶 ⊢ frame𝑛 {𝐹 } instr * : [] → [𝑡𝑛 ]

handler𝑛 {catch * } instr *


• For every catch clause catch 𝑖 in catch * , catch 𝑖 must be valid.
• The instruction sequence instr * must be valid with some type [𝑡*1 ] → [𝑡*2 ].
• Then the compound instruction is valid with type [𝑡*1 ] → [𝑡*2 ].
(𝐶 ⊢ catch : ok)* 𝑆; 𝐶 ⊢ instr * : [𝑡*1 ] → [𝑡*2 ]
𝑆; 𝐶 ⊢ handler𝑛 {catch * } instr * : [𝑡*1 ] → [𝑡*2 ]

7.4.8 Store Extension


Programs can mutate the store and its contained instances. Any such modification must respect certain invariants,
such as not removing allocated instances or changing immutable definitions. While these invariants are inherent
to the execution semantics of WebAssembly instructions and modules, host functions do not automatically adhere
to them. Consequently, the required invariants must be stated as explicit constraints on the invocation of host
functions. Soundness only holds when the embedder ensures these constraints.
The necessary constraints are codified by the notion of store extension: a store state 𝑆 ′ extends state 𝑆, written
𝑆 ⪯ 𝑆 ′ , when the following rules hold.

Note

Extension does not imply that the new store is valid, which is defined separately above.

262 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Store 𝑆
• The length of 𝑆.tags must not shrink.
• The length of 𝑆.globals must not shrink.
• The length of 𝑆.mems must not shrink.
• The length of 𝑆.tables must not shrink.
• The length of 𝑆.funcs must not shrink.
• The length of 𝑆.datas must not shrink.
• The length of 𝑆.elems must not shrink.
• The length of 𝑆.structs must not shrink.
• The length of 𝑆.arrays must not shrink.
• The length of 𝑆.exns must not shrink.
• For each tag instance taginst 𝑖 in the original 𝑆.tags, the new tag instance must be an extension of the old.
• For each global instance globalinst 𝑖 in the original 𝑆.globals, the new global instance must be an extension
of the old.
• For each memory instance meminst 𝑖 in the original 𝑆.mems, the new memory instance must be an extension
of the old.
• For each table instance tableinst 𝑖 in the original 𝑆.tables, the new table instance must be an extension of the
old.
• For each function instance funcinst 𝑖 in the original 𝑆.funcs, the new function instance must be an extension
of the old.
• For each data instance datainst 𝑖 in the original 𝑆.datas, the new data instance must be an extension of the
old.
• For each element instance eleminst 𝑖 in the original 𝑆.elems, the new element instance must be an extension
of the old.
• For each structure instance structinst 𝑖 in the original 𝑆.structs, the new structure instance must be an ex-
tension of the old.
• For each array instance arrayinst 𝑖 in the original 𝑆.arrays, the new array instance must be an extension of
the old.
• For each exception instance exninst 𝑖 in the original 𝑆.exns, the new exception instance must be an extension
of the old.
*
𝑆1 .tags = taginst *1 𝑆2 .tags = taginst ′1 taginst *2 (⊢ taginst 1 ⪯ taginst ′1 )*
*
𝑆1 .globals = globalinst *1 𝑆2 .globals = globalinst ′1 globalinst *2 (⊢ globalinst 1 ⪯ globalinst ′1 )*
*
𝑆1 .mems = meminst *1 𝑆2 .mems = meminst ′1 meminst *2 (⊢ meminst 1 ⪯ meminst ′1 )*
*
𝑆1 .tables = tableinst *1 𝑆2 .tables = tableinst ′1 tableinst *2 (⊢ tableinst 1 ⪯ tableinst ′1 )*
*
𝑆1 .funcs = funcinst *1 𝑆2 .funcs = funcinst ′1 funcinst *2 (⊢ funcinst 1 ⪯ funcinst ′1 )*
*
𝑆1 .datas = datainst *1 𝑆2 .datas = datainst ′1 datainst *2 (⊢ datainst 1 ⪯ datainst ′1 )*
*
𝑆1 .elems = eleminst *1 𝑆2 .elems = eleminst ′1 eleminst *2 (⊢ eleminst 1 ⪯ eleminst ′1 )*
*
𝑆1 .structs = structinst *1 𝑆2 .structs = structinst ′1 structinst *2 (⊢ structinst 1 ⪯ structinst ′1 )*
*
𝑆1 .arrays = arrayinst *1 𝑆2 .arrays = arrayinst ′1 arrayinst *2 (⊢ arrayinst 1 ⪯ arrayinst ′1 )*
*
𝑆1 .exns = exninst *1 𝑆2 .exns = exninst ′1 exninst *2 (⊢ exninst 1 ⪯ exninst ′1 )*
⊢ 𝑆1 ⪯ 𝑆2

7.4. Type Soundness 263


WebAssembly Specification, Release 3.0 (2025-11-14)

Tag Instance taginst


• A tag instance must remain unchanged.

⊢ taginst ⪯ taginst

Global Instance globalinst


• The global type [Link] must remain unchanged.
• Let mut 𝑡 be the structure of [Link].
• If mut is empty, then the value [Link] must remain unchanged.
mut = mut ∨ val 1 = val 2
⊢ {type (mut 𝑡), value val 1 } ⪯ {type (mut 𝑡), value val 2 }

Memory Instance meminst


• The memory type [Link] must remain unchanged.
• The length of [Link] must not shrink.
𝑛1 ≤ 𝑛2
⊢ {type mt, bytes 𝑏𝑛1 1 } ⪯ {type mt, bytes 𝑏𝑛2 2 }

Table Instance tableinst


• The table type [Link] must remain unchanged.
• The length of [Link] must not shrink.
𝑛1 ≤ 𝑛2
⊢ {type tt, elem (fa ?1 )𝑛1 } ⪯ {type tt, elem (fa ?2 )𝑛2 }

Function Instance funcinst


• A function instance must remain unchanged.

⊢ funcinst ⪯ funcinst

Data Instance datainst


• The list [Link] must:
– either remain unchanged,
– or shrink to length 0.

⊢ {bytes 𝑏* } ⪯ {bytes 𝑏* }

⊢ {bytes 𝑏* } ⪯ {bytes 𝜖}

264 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Element Instance eleminst


• The reference type [Link] must remain unchanged.
• The list [Link] must:
– either remain unchanged,
– or shrink to length 0.

⊢ {type 𝑡, elem 𝑎* } ⪯ {type 𝑡, elem 𝑎* }

⊢ {type 𝑡, elem 𝑎* } ⪯ {type 𝑡, elem 𝜖}

Structure Instance structinst


• The defined type [Link] must remain unchanged.
• Assert: due to store well-formedness, the expansion of [Link] is a structure type.
• Let struct fieldtype * be the expansion of [Link].
• The length of the list [Link] must remain unchanged.
• Assert: due to store well-formedness, the length of [Link] is the same as the length of fieldtype * .
• For each field value fieldval 𝑖 in [Link] and corresponding field type fieldtype 𝑖 in fieldtype * :
– Let mut 𝑖 st 𝑖 be the structure of fieldtype 𝑖 .
– If mut 𝑖 is empty, then the field value fieldval 𝑖 must remain unchanged.
(mut = mut ∨ fieldval 1 = fieldval 2 )*
⊢ {type (mut st)* , fields fieldval *1 } ⪯ {type (mut st)* , fields fieldval *2 }

Array Instance arrayinst


• The defined type [Link] must remain unchanged.
• Assert: due to store well-formedness, the expansion of [Link] is an array type.
• Let array fieldtype be the expansion of [Link].
• The length of the list [Link] must remain unchanged.
• Let mut st be the structure of fieldtype.
• If mut is empty, then the sequence of field values [Link] must remain unchanged.
mut = mut ∨ fieldval *1 = fieldval *2
⊢ {type (mut st), fields fieldval *1 } ⪯ {type (mut st), fields fieldval *2 }

Exception Instance exninst


• An exception instance must remain unchanged.

⊢ exninst ⪯ exninst

7.4. Type Soundness 265


WebAssembly Specification, Release 3.0 (2025-11-14)

7.4.9 Theorems
Given the definition of valid configurations, the standard soundness theorems hold.5254
Theorem (Preservation). If a configuration 𝑆; 𝑇 is valid with result type [𝑡* ] (i.e., ⊢ 𝑆; 𝑇 : [𝑡* ]), and steps to
𝑆 ′ ; 𝑇 ′ (i.e., 𝑆; 𝑇 ˓→ 𝑆 ′ ; 𝑇 ′ ), then 𝑆 ′ ; 𝑇 ′ is a valid configuration with the same result type (i.e., ⊢ 𝑆 ′ ; 𝑇 ′ : [𝑡* ]).
Furthermore, 𝑆 ′ is an extension of 𝑆 (i.e., ⊢ 𝑆 ⪯ 𝑆 ′ ).
A terminal thread is one whose sequence of instructions is a result. A terminal configuration is a configuration
whose thread is terminal.
Theorem (Progress). If a configuration 𝑆; 𝑇 is valid (i.e., ⊢ 𝑆; 𝑇 : [𝑡* ] for some result type [𝑡* ]), then either it is
terminal, or it can step to some configuration 𝑆 ′ ; 𝑇 ′ (i.e., 𝑆; 𝑇 ˓→ 𝑆 ′ ; 𝑇 ′ ).
From Preservation and Progress the soundness of the WebAssembly type system follows directly.
Corollary (Soundness). If a configuration 𝑆; 𝑇 is valid (i.e., ⊢ 𝑆; 𝑇 : [𝑡* ] for some result type [𝑡* ]), then it either
diverges or takes a finite number of steps to reach a terminal configuration 𝑆 ′ ; 𝑇 ′ (i.e., 𝑆; 𝑇 ˓→ * 𝑆 ′ ; 𝑇 ′ ) that is
valid with the same result type (i.e., ⊢ 𝑆 ′ ; 𝑇 ′ : [𝑡* ]) and where 𝑆 ′ is an extension of 𝑆 (i.e., ⊢ 𝑆 ⪯ 𝑆 ′ ).
In other words, every thread in a valid configuration either runs forever, traps, throws an exception, or terminates
with a result that has the expected type. Consequently, given a valid store, no computation defined by instantiation or
invocation of a valid module can “crash” or otherwise (mis)behave in ways not covered by the execution semantics
given in this specification.

7.5 Type System Properties


7.5.1 Principal Types
The type system of WebAssembly features both subtyping and simple forms of polymorphism for instruction types.
That has the effect that every instruction or instruction sequence can be classified with multiple different instruction
types.
However, the typing rules still allow deriving principal types for instruction sequences. That is, every valid instruc-
tion sequence has one particular type scheme, possibly containing some unconstrained place holder type variables,
that is a subtype of all its valid instruction types, after substituting its type variables with suitable specific types.
Moreover, when deriving an instruction type in a “forward” manner, i.e., the input of the instruction sequence is
already fixed to specific types, then it has a principal output type expressible without type variables, up to a possibly
polymorphic stack bottom representable with one single variable. In other words, “forward” principal types are
effectively closed.

Note

For example, in isolation, the instruction ref.as_non_null has the type [(ref null ht)] → [(ref ht)] for any choice
of valid heap type ht. Moreover, if the input type [(ref null ht)] is already determined, i.e., a specific ht is given,
then the output type [(ref ht)] is fully determined as well.
The implication of the latter property is that a validator for complete instruction sequences (as they occur in
valid modules) can be implemented with a simple left-to-right algorithm that does not require the introduction
of type variables.
A typing algorithm capable of handling partial instruction sequences (as might be considered for program
analysis or program manipulation) needs to introduce type variables and perform substitutions, but it does not
need to perform backtracking or record any non-syntactic constraints on these type variables.

52 A machine-verified version of the formalization and soundness proof of the PLDI 2017 paper is described in the following article: Conrad

Watt. Mechanising and Verifying the WebAssembly Specification53 . Proceedings of the 7th ACM SIGPLAN Conference on Certified Programs
and Proofs (CPP 2018). ACM 2018.
53 [Link]
54 Machine-verified formalizations and soundness proofs of the semantics from the official specification are described in the following article:

Conrad Watt, Xiaojia Rao, Jean Pichon-Pharabod, Martin Bodin, Philippa Gardner. Two Mechanisations of WebAssembly 1.055 . Proceedings
of the 24th International Symposium on Formal Methods (FM 2021). Springer 2021.
55 [Link]

266 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Technically, the syntax of heap, value, and result types can be enriched with type variables as follows:

null ::= null? | 𝛼null


heaptype ::= . . . | 𝛼heaptype
reftype ::= ref null heaptype
valtype ::= . . . | 𝛼valtype | 𝛼numvectype
? *
resulttype ::= [𝛼valtype * valtype ]

where each 𝛼xyz ranges over a set of type variables for syntactic class xyz , respectively. The special class
numvectype is defined as numtype | vectype | bot, and is only needed to handle unannotated select instructions.
A type is closed when it does not contain any type variables, and open otherwise. A type substitution 𝜎 is a finite
mapping from type variables to closed types of the respective syntactic class. When applied to an open type, it
replaces the type variables 𝛼 from its domain with the respective 𝜎(𝛼).
Theorem (Principal Types). If an instruction sequence instr * is valid with some closed instruction type instrtype
(i.e., 𝐶 ⊢ instr * : instrtype), then it is also valid with a possibly open instruction type instrtype min (i.e., 𝐶 ⊢
instr * : instrtype min ), such that for every closed type instrtype ′ with which instr * is valid (i.e., for all 𝐶 ⊢
instr * : instrtype ′ ), there exists a substitution 𝜎, such that 𝜎(instrtype min ) is a subtype of instrtype ′ (i.e.,
𝐶 ⊢ 𝜎(instrtype min ) ≤ instrtype ′ ). Furthermore, instrtype min is unique up to the choice of type variables.
Theorem (Closed Principal Forward Types). If closed input type [𝑡*1 ] is given and the instruction sequence instr *
is valid with instruction type [𝑡*1 ] →𝑥* [𝑡*2 ] (i.e., 𝐶 ⊢ instr * : [𝑡*1 ] →𝑥* [𝑡*2 ]), then it is also valid with instruction
type [𝑡*1 ] →𝑥* [𝛼valtype * 𝑡* ] (i.e., 𝐶 ⊢ instr * : [𝑡*1 ] →𝑥* [𝛼valtype * 𝑡* ]), where all 𝑡* are closed, such that for
* *
every closed result type [𝑡′2 ] with which instr * is valid (i.e., for all 𝐶 ⊢ instr * : [𝑡*1 ] →𝑥* [𝑡′2 ]), there exists a
′*
substitution 𝜎, such that [𝑡2 ] = [𝜎(𝛼valtype * ) 𝑡 ].*

7.5.2 Type Lattice


The Principal Types property depends on the existence of a greatest lower bound for any pair of types.
Theorem (Greatest Lower Bounds for Value Types). For any two value types 𝑡1 and 𝑡2 that are valid (i.e.,
𝐶 ⊢ 𝑡1 : ok and 𝐶 ⊢ 𝑡2 : ok), there exists a valid value type 𝑡 that is a subtype of both 𝑡1 and 𝑡2 (i.e., 𝐶 ⊢ 𝑡 : ok
and 𝐶 ⊢ 𝑡 ≤ 𝑡1 and 𝐶 ⊢ 𝑡 ≤ 𝑡2 ), such that every valid value type 𝑡′ that also is a subtype of both 𝑡1 and 𝑡2 (i.e.,
for all 𝐶 ⊢ 𝑡′ : ok and 𝐶 ⊢ 𝑡′ ≤ 𝑡1 and 𝐶 ⊢ 𝑡′ ≤ 𝑡2 ), is a subtype of 𝑡 (i.e., 𝐶 ⊢ 𝑡′ ≤ 𝑡).

Note

The greatest lower bound of two types may be bot.

Theorem (Conditional Least Upper Bounds for Value Types). Any two value types 𝑡1 and 𝑡2 that are valid (i.e.,
𝐶 ⊢ 𝑡1 : ok and 𝐶 ⊢ 𝑡2 : ok) either have no common supertype, or there exists a valid value type 𝑡 that is a
supertype of both 𝑡1 and 𝑡2 (i.e., 𝐶 ⊢ 𝑡 : ok and 𝐶 ⊢ 𝑡1 ≤ 𝑡 and 𝐶 ⊢ 𝑡2 ≤ 𝑡), such that every valid value type 𝑡′
that also is a supertype of both 𝑡1 and 𝑡2 (i.e., for all 𝐶 ⊢ 𝑡′ : ok and 𝐶 ⊢ 𝑡1 ≤ 𝑡′ and 𝐶 ⊢ 𝑡2 ≤ 𝑡′ ), is a supertype
of 𝑡 (i.e., 𝐶 ⊢ 𝑡 ≤ 𝑡′ ).

Note

If a top type was added to the type system, a least upper bound would exist for any two types.

Corollary (Type Lattice). Assuming the addition of a provisional top type, value types form a lattice with respect
to their subtype relation.
Finally, value types can be partitioned into multiple disjoint hierarchies that are not related by subtyping, except
through bot.
Theorem (Disjoint Subtype Hierarchies). The greatest lower bound of two value types is bot or ref bot if and
only if they do not have a least upper bound.
In other words, types that do not have common supertypes, do not have common subtypes either (other than bot
or ref bot), and vice versa.

7.5. Type System Properties 267


WebAssembly Specification, Release 3.0 (2025-11-14)

Note

Types from disjoint hierarchies can safely be represented in mutually incompatible ways in an implementation,
because their values can never flow to the same place.

7.5.3 Compositionality
Valid instruction sequences can be freely composed, as long as their types match up.
Theorem (Composition). If two instruction sequences instr *1 and instr *2 are valid with types [𝑡*1 ] →𝑥*1 [𝑡* ] and
[𝑡* ] →𝑥*2 [𝑡*2 ], respectively (i.e., 𝐶 ⊢ instr *1 : [𝑡*1 ] →𝑥*1 [𝑡* ] and 𝐶 ⊢ instr *1 : [𝑡* ] →𝑥*2 [𝑡*2 ]), then the concatenated
instruction sequence (instr *1 instr *2 ) is valid with type [𝑡*1 ] →𝑥*1 𝑥*2 [𝑡*2 ] (i.e., 𝐶 ⊢ instr *1 instr *2 : [𝑡*1 ] →𝑥*1 𝑥*2 [𝑡*2 ]).

Note

More generally, instead of a shared type [𝑡* ], it suffices if the output type of instr *1 is a subtype of the input
type of instr *1 , since the subtype can always be weakened to its supertype by subsumption.

Inversely, valid instruction sequences can also freely be decomposed, that is, splitting them anywhere produces two
instruction sequences that are both valid.
Theorem (Decomposition). If an instruction sequence instr * that is valid with type [𝑡*1 ] →𝑥* [𝑡*2 ] (i.e., 𝐶 ⊢
instr * : [𝑡*1 ] →𝑥* [𝑡*2 ]) is split into two instruction sequences instr *1 and instr *2 at any point (i.e., instr * =
instr *1 instr *2 ), then these are separately valid with some types [𝑡*1 ] →𝑥*1 [𝑡* ] and [𝑡* ] →𝑥*2 [𝑡*2 ], respectively (i.e.,
𝐶 ⊢ instr *1 : [𝑡*1 ] →𝑥*1 [𝑡* ] and 𝐶 ⊢ instr *1 : [𝑡* ] →𝑥*2 [𝑡*2 ]), where 𝑥* = 𝑥*1 𝑥*2 .

Note

This property holds because validation is required even for unreachable code. Without that, instr *2 might not
be valid in isolation.

7.6 Validation Algorithm


The specification of WebAssembly validation is purely declarative. It describes the constraints that must be met
by a module or instruction sequence to be valid.
This section sketches the skeleton of a sound and complete algorithm for effectively validating code, i.e., sequences
of instructions. (Other aspects of validation are straightforward to implement.)
In fact, the algorithm is expressed over the flat sequence of opcodes as occurring in the binary format, and performs
only a single pass over it. Consequently, it can be integrated directly into a decoder.
The algorithm is expressed in typed pseudo code whose semantics is intended to be self-explanatory.

7.6.1 Data Structures


Types
Value types are representable as sets of enumerations:

type num_type = I32 | I64 | F32 | F64


type vec_type = V128
type heap_type =
Any | Eq | I31 | Struct | Array | None |
Func | Nofunc | Exn | Noexn | Extern | Noextern | Bot |
Def(def : def_type)
(continues on next page)

268 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

(continued from previous page)


type ref_type = Ref(heap : heap_type, null : bool)
type val_type = num_type | vec_type | ref_type | Bot

func is_num(t : val_type) : bool =


return t = I32 || t = I64 || t = F32 || t = F64 || t = Bot

func is_vec(t : val_type) : bool =


return t = V128 || t = Bot

func is_ref(t : val_type) : bool =


return not (is_num t || is_vec t) || t = Bot

Similarly, defined types def_type can be represented:

type pack_type = I8 | I16


type field_type = Field(val : val_type | pack_type, mut : bool)

type struct_type = Struct(fields : list(field_type))


type array_type = Array(fields : field_type)
type func_type = Func(params : list(val_type), results : list(val_type))
type comp_type = struct_type | array_type | func_type

type sub_type = Sub(super : list(def_type), body : comp_type, final : bool)


type rec_type = Rec(types : list(sub_type))

type def_type = Def(rec : rec_type, proj : int32)

func unpack_field(t : field_type) : val_type =


if (it = I8 || t = I16) return I32
return t

func expand_def(t : def_type) : comp_type =


return [Link][[Link]].body

These representations assume that all types have been closed by substituting all type indices (in concrete heap types
and in sub types) with their respective defined types. This includes recursive references to enclosing defined types,
such that type representations form graphs and may be cyclic for recursive types.
We assume that all types have been canonicalized, such that equality on two type representations holds if and only
if their closures are syntactically equivalent, making it a constant-time check.

Note

For the purpose of type canonicalization, recursive references from a heap type to an enclosing recursive type
(i.e., forward edges in the graph that form a cycle) need to be distinguished from references to previously
defined types. However, this distinction does not otherwise affect validation, so is ignored here. In the graph
representation, all recursive types are effectively infinitely unrolled.

We further assume that validation and subtyping checks are defined on value types, as well as a few auxiliary
functions on composite types:

func validate_val_type(t : val_type)


func validate_ref_type(t : ref_type)

func matches_val(t1 : val_type, t2 : val_type) : bool


func matches_ref(t1 : val_type, t2 : val_type) : bool
(continues on next page)

7.6. Validation Algorithm 269


WebAssembly Specification, Release 3.0 (2025-11-14)

(continued from previous page)

func is_func(t : comp_type) : bool


func is_struct(t : comp_type) : bool
func is_array(t : comp_type) : bool

Finally, the following function computes the least precise supertype of a given heap type (its corresponding top
type):

func top_heap_type(t : heap_type) : heap_type =


switch (t)
case (Any | Eq | I31 | Struct | Array | None)
return Any
case (Func | Nofunc)
return Func
case (Extern | Noextern)
return Extern
case (Def(dt))
switch ([Link][[Link]].body)
case (Struct(_) | Array(_))
return Any
case (Func(_))
return Func
case (Bot)
raise CannotOccurInSource

Context
Validation requires a context for checking uses of indices. For the purpose of presenting the algorithm, it is main-
tained in a set of global variables:

var return_type : list(val_type)


var types : array(def_type)
var locals : array(val_type)
var locals_init : array(bool)
var globals : array(global_type)
var funcs : array(func_type)
var tables : array(table_type)
var mems : array(mem_type)

This assumes suitable representations for the various types besides val_type, which are omitted here.
For locals, there is an additional array recording the initialization status of each local.

Stacks
The algorithm uses three separate stacks: the value stack, the control stack, and the initialization stack. The value
stack tracks the types of operand values on the stack. The control stack tracks surrounding structured control
instructions and their associated blocks. The initialization stack records all locals that have been initialized since
the beginning of the function.

type val_stack = stack(val_type)


type init_stack = stack(u32)

type ctrl_stack = stack(ctrl_frame)


type ctrl_frame = {
opcode : opcode
start_types : list(val_type)
(continues on next page)

270 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

(continued from previous page)


end_types : list(val_type)
val_height : nat
init_height : nat
unreachable : bool
}

For each entered block, the control stack records a control frame with the originating opcode, the types on the top
of the operand stack at the start and end of the block (used to check its result as well as branches), the height of the
operand stack at the start of the block (used to check that operands do not underflow the current block), the height
of the initialization stack at the start of the block (used to reset initialization status at the end of the block), and a
flag recording whether the remainder of the block is unreachable (used to handle stack-polymorphic typing after
branches).
For the purpose of presenting the algorithm, these stacks are simply maintained as global variables:

var vals : val_stack


var inits : init_stack
var ctrls : ctrl_stack

However, these variables are not manipulated directly by the main checking function, but through a set of auxiliary
functions:

func push_val(type : val_type) =


[Link](type)

func pop_val() : val_type =


if ([Link]() = ctrls[0].val_height && ctrls[0].unreachable) return Bot
error_if([Link]() = ctrls[0].val_height)
return [Link]()

func pop_val(expect : val_type) : val_type =


let actual = pop_val()
error_if(not matches_val(actual, expect))
return actual

func pop_num() : num_type | Bot =


let actual = pop_val()
error_if(not is_num(actual))
return actual

func pop_ref() : ref_type =


let actual = pop_val()
error_if(not is_ref(actual))
if (actual = Bot) return Ref(Bot, false)
return actual

func push_vals(types : list(val_type)) = foreach (t in types) push_val(t)


func pop_vals(types : list(val_type)) : list(val_type) =
var popped := []
foreach (t in reverse(types)) [Link](pop_val(t))
return popped

Pushing an operand value simply pushes the respective type to the value stack.
Popping an operand value checks that the value stack does not underflow the current block and then removes
one type. But first, a special case is handled where the block contains no known values, but has been marked as
unreachable. That can occur after an unconditional branch, when the stack is typed polymorphically. In that case,
the Bot type is returned, because that is a principal choice trivially satisfying all use constraints.

7.6. Validation Algorithm 271


WebAssembly Specification, Release 3.0 (2025-11-14)

A second function for popping an operand value takes an expected type, which the actual operand type is checked
against. The types may differ by subtyping, including the case where the actual type is Bot, and thereby matches
unconditionally. The function returns the actual type popped from the stack.
Finally, there are accumulative functions for pushing or popping multiple operand types.

Note

The notation stack[i] is meant to index the stack from the top, so that, e.g., ctrls[0] accesses the element
pushed last.

The initialization stack and the initialization status of locals is manipulated through the following functions:

func get_local(idx : u32) =


error_if(not locals_init[idx])

func set_local(idx : u32) =


if (not locals_init[idx])
[Link](idx)
locals_init[idx] := true

func reset_locals(height : nat) =


while ([Link]() > height)
locals_init[[Link]()] := false

Getting a local verifies that it is known to be initialized. When a local is set that was not set already, then its
initialization status is updated and the change is recorded in the initialization stack. Thus, the initialization status
of all locals can be reset to a previous state by denoting a specific height in the initialization stack.
The size of the initialization stack is bounded by the number of (non-defaultable) locals in a function, so can be
preallocated by an algorithm.
The control stack is likewise manipulated through auxiliary functions:

func push_ctrl(opcode : opcode, in : list(val_type), out : list(val_type)) =


let frame = ctrl_frame(opcode, in, out, [Link](), [Link](), false)
[Link](frame)
push_vals(in)

func pop_ctrl() : ctrl_frame =


error_if(ctrls.is_empty())
let frame = ctrls[0]
pop_vals(frame.end_types)
error_if([Link]() =/= frame.val_height)
reset_locals(frame.init_height)
[Link]()
return frame

func label_types(frame : ctrl_frame) : list(val_types) =


return (if ([Link] = loop) frame.start_types else frame.end_types)

func unreachable() =
[Link](ctrls[0].val_height)
ctrls[0].unreachable := true

Pushing a control frame takes the types of the label and result values. It allocates a new frame record recording
them along with the current height of the operand stack and marks the block as reachable.
Popping a frame first checks that the control stack is not empty. It then verifies that the operand stack contains the
right types of values expected at the end of the exited block and pops them off the operand stack. Afterwards, it

272 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

checks that the stack has shrunk back to its initial height. Finally, it undoes all changes to the initialization status
of locals that happened inside the block.
The type of the label associated with a control frame is either that of the stack at the start or the end of the frame,
determined by the opcode that it originates from.
Finally, the current frame can be marked as unreachable. In that case, all existing operand types are purged from the
value stack, in order to allow for the stack-polymorphism logic in pop_val to take effect. Because every function
has an implicit outermost label that corresponds to an implicit block frame, it is an invariant of the validation
algorithm that there always is at least one frame on the control stack when validating an instruction, and hence,
ctrls[0] is always defined.

Note

Even with the unreachable flag set, consecutive operands are still pushed to and popped from the operand stack.
That is necessary to detect invalid examples like (unreachable ([Link]) [Link]). However, a polymorphic
stack cannot underflow, but instead generates Bot types as needed.

7.6.2 Validation of Opcode Sequences


The following function shows the validation of a number of representative instructions that manipulate the stack.
Other instructions are checked in a similar manner.

func validate(opcode) =
switch (opcode)
case ([Link])
pop_val(I32)
pop_val(I32)
push_val(I32)

case (drop)
pop_val()

case (select)
pop_val(I32)
let t1 = pop_val()
let t2 = pop_val()
error_if(not (is_num(t1) && is_num(t2) || is_vec(t1) && is_vec(t2)))
error_if(t1 =/= t2 && t1 =/= Bot && t2 =/= Bot)
push_val(if (t1 = Bot) t2 else t1)

case (select t)
pop_val(I32)
pop_val(t)
pop_val(t)
push_val(t)

case (ref.is_null)
pop_ref()
push_val(I32)

case (ref.as_non_null)
let rt = pop_ref()
push_val(Ref([Link], false))

case ([Link] rt)


validate_ref_type(rt)
(continues on next page)

7.6. Validation Algorithm 273


WebAssembly Specification, Release 3.0 (2025-11-14)

(continued from previous page)


pop_val(Ref(top_heap_type(rt), true))
push_val(I32)

case ([Link] x)
get_local(x)
push_val(locals[x])

case ([Link] x)
pop_val(locals[x])
set_local(x)

case (unreachable)
unreachable()

case (block t1*->t2*)


pop_vals([t1*])
push_ctrl(block, [t1*], [t2*])

case (loop t1*->t2*)


pop_vals([t1*])
push_ctrl(loop, [t1*], [t2*])

case (if t1*->t2*)


pop_val(I32)
pop_vals([t1*])
push_ctrl(if, [t1*], [t2*])

case (end)
let frame = pop_ctrl()
push_vals(frame.end_types)

case (else)
let frame = pop_ctrl()
error_if([Link] =/= if)
push_ctrl(else, frame.start_types, frame.end_types)

case (br n)
error_if([Link]() < n)
pop_vals(label_types(ctrls[n]))
unreachable()

case (br_if n)
error_if([Link]() < n)
pop_val(I32)
pop_vals(label_types(ctrls[n]))
push_vals(label_types(ctrls[n]))

case (br_table n* m)
pop_val(I32)
error_if([Link]() < m)
let arity = label_types(ctrls[m]).size()
foreach (n in n*)
error_if([Link]() < n)
error_if(label_types(ctrls[n]).size() =/= arity)
push_vals(pop_vals(label_types(ctrls[n])))
pop_vals(label_types(ctrls[m]))
(continues on next page)

274 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

(continued from previous page)


unreachable()

case (br_on_null n)
error_if([Link]() < n)
let rt = pop_ref()
pop_vals(label_types(ctrls[n]))
push_vals(label_types(ctrls[n]))
push_val(Ref([Link], false))

case (br_on_cast n rt1 rt2)


validate_ref_type(rt1)
validate_ref_type(rt2)
pop_val(rt1)
push_val(rt2)
pop_vals(label_types(ctrls[n]))
push_vals(label_types(ctrls[n]))
pop_val(rt2)
push_val(diff_ref_type(rt2, rt1))

case (return)
pop_vals(return_types)
unreachable()

case (call_ref x)
let t = expand_def(types[x])
error_if(not is_func(t))
pop_vals([Link])
pop_val(Ref(Def(types[x])))
push_vals([Link])

case (return_call_ref x)
let t = expand_def(types[x])
error_if(not is_func(t))
pop_vals([Link])
pop_val(Ref(Def(types[x])))
error_if([Link]() =/= return_types.len())
push_vals([Link])
pop_vals(return_types)
unreachable()

case ([Link] x)
let t = expand_def(types[x])
error_if(not is_struct(t))
for (ti in reverse([Link]))
pop_val(unpack_field(ti))
push_val(Ref(Def(types[x])))

case ([Link] x n)
let t = expand_def(types[x])
error_if(not is_struct(t) || n >= [Link]())
pop_val(Ref(Def(types[x])))
pop_val(unpack_field([Link][n]))

case (throw x)
pop_vals(tags[x].[Link])
unreachable()
(continues on next page)

7.6. Validation Algorithm 275


WebAssembly Specification, Release 3.0 (2025-11-14)

(continued from previous page)

case (try_table t1*->t2* handler*)


pop_vals([t1*])
foreach (handler in handler*)
error_if([Link]() < [Link])
push_ctrl(catch, [], label_types(ctrls[[Link]]))
switch ([Link])
case (catch x)
push_vals(tags[x].[Link])
case (catch_ref x)
push_vals(tags[x].[Link])
push_val(Exnref)
case (catch_all)
skip
case (catch_all_ref)
push_val(Exnref)
pop_ctrl()
push_ctrl(try_table, [t1*], [t2*])

Note

It is an invariant under the current WebAssembly instruction set that an operand of Bot type is never duplicated
on the stack. This would change if the language were extended with stack instructions like dup. Under such an
extension, the above algorithm would need to be refined by replacing the Bot type with proper type variables
to ensure that all uses are consistent.

7.7 Custom Sections and Annotations


This appendix defines dedicated custom sections for WebAssembly’s binary format and annotations for the text
format. Such sections or annotations do not contribute to, or otherwise affect, the WebAssembly semantics, and
may be ignored by an implementation. However, they provide useful meta data that implementations can make use
of to improve user experience or take compilation hints.

7.7.1 Name Section


The name section is a custom section whose name string is itself ‘name’. The name section should appear only
once in a module, and only after the data section.
The purpose of this section is to attach printable names to definitions in a module, which e.g. can be used by a
debugger or when parts of the module are to be rendered in text form.

Note

All names are represented in Unicode56 encoded in UTF-8. Names need not be unique.

Subsections
The data of a name section consists of a sequence of subsections. Each subsection consists of a
• a one-byte subsection id,
• the u32 size of the contents, in bytes,
• the actual contents, whose structure is dependent on the subsection id.
56 [Link]

276 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

namesec ::= section0 (namedata)


namedata ::= 𝑛:name (if 𝑛 = ‘name’)
modulenamesubsec?
funcnamesubsec?
localnamesubsec?
typenamesubsec?
fieldnamesubsec?
tagnamesubsec?
namesubsection𝑁 (B) ::= 𝑁 :byte size:u32 B (if size = ||B||)
The following subsection ids are used:

Id Subsection
0 module name
1 function names
2 local names
4 type names
10 field names
11 tag names

Each subsection may occur at most once, and in order of increasing id.

Name Maps
A name map assigns names to indices in a given index space. It consists of a list of index/name pairs in order of
increasing index value. Each index must be unique, but the assigned names need not be.
namemap ::= list(nameassoc)
nameassoc ::= idx name
An indirect name map assigns names to a two-dimensional index space, where secondary indices are grouped by
primary indices. It consists of a list of primary index/name map pairs in order of increasing index value, where
each name map in turn maps secondary indices to names. Each primary index must be unique, and likewise each
secondary index per individual name map.
indirectnamemap ::= list(indirectnameassoc)
indirectnameassoc ::= idx namemap

Module Names
The module name subsection has the id 0. It simply consists of a single name that is assigned to the module itself.
modulenamesubsec ::= namesubsection0 (name)

Function Names
The function name subsection has the id 1. It consists of a name map assigning function names to function indices.
funcnamesubsec ::= namesubsection1 (namemap)

Local Names
The local name subsection has the id 2. It consists of an indirect name map assigning local names to local indices
grouped by function indices.
localnamesubsec ::= namesubsection2 (indirectnamemap)

7.7. Custom Sections and Annotations 277


WebAssembly Specification, Release 3.0 (2025-11-14)

Type Names
The type name subsection has the id 4. It consists of a name map assigning type names to type indices.

typenamesubsec ::= namesubsection4 (namemap)

Field Names
The field name subsection has the id 10. It consists of an indirect name map assigning field names to field indices
grouped by the type indices of their respective structure types.

fieldnamesubsec ::= namesubsection10 (indirectnamemap)

Tag Names
The tag name subsection has the id 11. It consists of a name map assigning tag names to tag indices.

tagnamesubsec ::= namesubsection11 (namemap)

7.7.2 Name Annotations


Name annotations are the textual analogue to the name section and provide a textual representation for it. Conse-
quently, their id is @name.
Analogous to the name section, name annotations are allowed on modules, functions, and locals (including pa-
rameters). They can be placed where the text format allows binding occurrences of respective identifiers. If both
an identifier and a name annotation are given, the annotation is expected after the identifier. In that case, the an-
notation takes precedence over the identifier as a textual representation of the binding’s name. At most one name
annotation may be given per binding.
All name annotations have the following format:

nameannot ::= ‘(@name’ string ‘)’

Note

All name annotations can be arbitrary UTF-8 strings. Names need not be unique.

Module Names
A module name annotation must be placed on a module definition, directly after the ‘module’ keyword, or if
present, after the following module identifier.

modulenameannot ::= nameannot

Function Names
A function name annotation must be placed on a function definition or function import, directly after the ‘func’
keyword, or if present, after the following function identifier or.

funcnameannot ::= nameannot

278 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Parameter Names
A parameter name annotation must be placed on a parameter declaration, directly after the ‘param’ keyword, or
if present, after the following parameter identifier. It may only be placed on a declaration that declares exactly one
parameter.

paramnameannot ::= nameannot

Local Names
A local name annotation must be placed on a local declaration, directly after the ‘local’ keyword, or if present,
after the following local identifier. It may only be placed on a declaration that declares exactly one local.

localnameannot ::= nameannot

Type Names
A type name annotation must be placed on a type declaration, directly after the ‘type’ keyword, or if present, after
the following type identifier.

typenameannot ::= nameannot

Field Names
A field name annotation must be placed on the field of a structure type, directly after the ‘field’ keyword, or if
present, after the following field identifier. It may only be placed on a declaration that declares exactly one field.

fieldnameannot ::= nameannot

Tag Names
A tag name annotation must be placed on a tag declaration or tag import, directly after the ‘tag’ keyword, or if
present, after the following tag identifier.

tagnameannot ::= nameannot

7.7.3 Custom Annotations


Custom annotations are a generic textual representation for any custom section. Their id is @custom. By gener-
ating custom annotations, tools converting between binary format and text format can maintain and round-trip the
content of custom sections even when they do not recognize them.
Custom annotations must be placed inside a module definition. They must occur anywhere after the ‘module’

7.7. Custom Sections and Annotations 279


WebAssembly Specification, Release 3.0 (2025-11-14)

keyword, or if present, after the following module identifier. They must not be nested into other constructs.

customannot ::= ‘(@custom’ string customplace? datastring ‘)’


customplace ::= ‘(’ ‘before’ ‘first’ ‘)’
| ‘(’ ‘before’ sec ‘)’
| ‘(’ ‘after’ sec ‘)’
| ‘(’ ‘after’ ‘last’ ‘)’
sec ::= ‘type’
| ‘import’
| ‘func’
| ‘table’
| ‘memory’
| ‘global’
| ‘export’
| ‘start’
| ‘elem’
| ‘code’
| ‘data’
| ‘datacount’

The first string in a custom annotation denotes the name of the custom section it represents. The remaining strings
collectively represent the section’s payload data, written as a data string, which can be split up into a possibly empty
sequence of individual string literals (similar to data segments).
An arbitrary number of custom annotations (even of the same name) may occur in a module, each defining a separate
custom section when converting to binary format. Placement of the sections in the binary can be customized via
explicit placement directives, that position them either directly before or directly after a known section. That section
must exist and be non-empty in the binary encoding of the annotated module. The placements (before first)
and (after last) denote virtual sections before the first and after the last known section, respectively. When the
placement directive is omitted, it defaults to (after last).
If multiple placement directives appear for the same position, then the sections are all placed there, in order of
their appearance in the text. For this purpose, the position after a section is considered different from the position
before the consecutive section, and the former occurs before the latter.

Note

Future versions of WebAssembly may introduce additional sections between others or at the beginning or end
of a module. Using first and last guarantees that placement will still go before or after any future section,
respectively.

If a custom section with a specific section id is given as well as annotations representing the same custom section
(e.g., @name annotations as well as a @custom annotation for a name section), then two sections are assumed to
be created. Their relative placement will depend on the placement directive given for the @custom annotation as
well as the implicit placement requirements of the custom section, which are applied to the other annotation.

Note

For example, the following module,


(module
(@custom "A" "aaa")
(type $t (func))
(@custom "B" (after func) "bbb")
(@custom "C" (before func) "ccc")
(@custom "D" (after last) "ddd")
(table 10 funcref)
(func (type $t))
(@custom "E" (after import) "eee")

280 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

(@custom "F" (before type) "fff")


(@custom "G" (after data) "ggg")
(@custom "H" (after code) "hhh")
(@custom "I" (after func) "iii")
(@custom "J" (before func) "jjj")
(@custom "K" (before first) "kkk")
)
will result in the following section ordering:
custom section "K"
custom section "F"
type section
custom section "E"
custom section "C"
custom section "J"
function section
custom section "B"
custom section "I"
table section
code section
custom section "H"
custom section "G"
custom section "A"
custom section "D"

7.8 Change History


Since the original release 1.0 of the WebAssembly specification, a number of proposals for extensions have been
integrated. The following sections provide an overview of what has changed.
All present and future versions of WebAssembly are intended to be backwards-compatible with all previous ver-
sions. Concretely:
1. All syntactically well-formed (in binary or text format) and valid modules remain well-formed and valid with
an equivalent module type (or a subtype).

Note

This allows previously malformed or invalid modules to become legal, e.g., by adding new features
or by relaxing typing rules.
It also allows reclassifying previously malformed modules as well-formed but invalid, or vice versa.
And it allows refining the typing of imports and exports, such that previously unlinkable modules
become linkable.
Historically, minor breaking changes to the text format have been allowed that turned previously
possible valid modules invalid, as long as they were unlikely to occur in practice.

2. All non-trapping executions of a valid program retain their behaviour with an equivalent set of possible
results (or a non-empty subset).

Note

This allows previously malformed or invalid programs to become executable.


It also allows program executions that previously trapped to execute successfully, although the

7.8. Change History 281


WebAssembly Specification, Release 3.0 (2025-11-14)

intention is to only exercise this where the possibility of such an extension has been previously
noted.
And it allows reducing the set of observable behaviours of a program execution, e.g., by reducing
non-determinism.
In a program linking prior modules with modules using new features, a prior module may encounter
new behaviours, e.g., new forms of control flow or side effects when calling into a latter module.

In addition, future versions of WebAssembly will not allocate the opcode 0xFF to represent an instruction or
instruction prefix.

7.8.1 Release 2.0


Sign Extension Instructions
Added new numeric instructions for performing sign extension within integer representations.57
• New numeric instructions:
– [Link] _s

Non-trapping Float-to-Int Conversions


Added new conversion instructions that avoid trapping when converting a floating-point number to an integer.58
• New numeric instructions:
– inn.trunc_sat_fmm_sx

Multiple Values
Generalized the result type of blocks and functions to allow for multiple values; in addition, introduced the ability
to have block parameters.59
• Function types allow more than one result
• Block types can be arbitrary function types

Reference Types
Added funcref and externref as new value types and respective instructions.60
• New reference value types:
– funcref
– externref
• New reference instructions:
– [Link]
– [Link]
– ref.is_null
• Extended parametric instruction:
– select with optional type immediate
• New declarative form of element segment
57 [Link]
58 [Link]
59 [Link]
60 [Link]

282 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Table Instructions
Added instructions to directly access and modify [Link] 282, 60
• Table types allow any reference type as element type
• New table instructions:
– [Link]
– [Link]
– [Link]
– [Link]

Multiple Tables
Added the ability to use multiple tables per [Link] 282, 60
• Modules may
– define multiple tables
– import multiple tables
– export multiple tables
• Table instructions take a table index immediate:
– [Link]
– [Link]
– [Link]
– [Link]
– call_indirect
• Element segments take a table index

Bulk Memory and Table Instructions


Added instructions that modify ranges of memory or table [Link] 282, 6061
• New memory instructions:
– [Link]
– [Link]
– [Link]
– [Link]
• New table instructions:
– [Link]
– [Link]
– [Link]
– [Link]
• New passive form of data segment
• New passive form of element segment
• New data count section in binary format
• Active data and element segments boundaries are no longer checked at compile time but may trap instead
61 [Link]

7.8. Change History 283


WebAssembly Specification, Release 3.0 (2025-11-14)

Vector Instructions
Added vector type and instructions that manipulate multiple numeric values in parallel (also known as SIMD, single
instruction multiple data)62
• New value type:
– v128
• New memory instructions:
– [Link]
– [Link]𝑁x𝑀_sx
– [Link]𝑁 _zero
– [Link]𝑁 _splat
– [Link]𝑁 _lane
– [Link]
– [Link]𝑁 _lane
• New constant vector instruction:
– [Link]
• New unary vector instructions:
– [Link]
– i𝑁x𝑀.abs
– i𝑁x𝑀.neg
– [Link]
– f𝑁x𝑀.abs
– f𝑁x𝑀.neg
– f𝑁x𝑀.sqrt
– f𝑁x𝑀.ceil
– f𝑁x𝑀.floor
– f𝑁x𝑀.trunc
– f𝑁x𝑀.nearest
• New binary vector instructions:
– [Link]
– [Link]
– [Link]
– [Link]
– i𝑁x𝑀.add
– i𝑁x𝑀.sub
– i𝑁x𝑀.mul
– i𝑁x𝑀.add_sat_sx
– i𝑁x𝑀.sub_sat_sx
– i𝑁x𝑀.min_sx
62 [Link]

284 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

– i𝑁x𝑀.max_sx
– i𝑁x𝑀.shl
– i𝑁x𝑀.shr_sx
– f𝑁x𝑀.add
– f𝑁x𝑀.sub
– f𝑁x𝑀.mul
– f𝑁x𝑀.div
– i16x8.extadd_pairwise_i8x16_sx
– i32x4.extadd_pairwise_i16x8_sx
– i𝑁x𝑀.extmul_half _i𝑁 ′x𝑀 ′_sx
– i16x8.q15mulr_sat_s
– i32x4.dot_i16x8_s
– i8x16.avgr_u
– i16x8.avgr_u
– f𝑁x𝑀.min
– f𝑁x𝑀.max
– f𝑁x𝑀.pmin
– f𝑁x𝑀.pmax
• New ternary vector instruction:
– [Link]
• New test vector instructions:
– v128.any_true
– i𝑁x𝑀.all_true
• New relational vector instructions:
– i𝑁x𝑀.eq
– i𝑁x𝑀.ne
– i𝑁x𝑀.lt_sx
– i𝑁x𝑀.gt_sx
– i𝑁x𝑀.le_sx
– i𝑁x𝑀.ge_sx
– f𝑁x𝑀.eq
– f𝑁x𝑀.ne
– f𝑁x𝑀.lt
– f𝑁x𝑀.gt
– f𝑁x𝑀.le
– f𝑁x𝑀.ge
• New conversion vector instructions:
– i32x4.trunc_sat_f32x4_sx
– i32x4.trunc_sat_f64x2_sx _zero

7.8. Change History 285


WebAssembly Specification, Release 3.0 (2025-11-14)

– f32x4.convert_i32x4_sx
– f32x4.demote_f64x2_zero
– f64x2.convert_low_i32x4_sx
– f64x2.promote_low_f32x4
• New lane access vector instructions:
– i𝑁x𝑀.extract_lane_sx ?
– i𝑁x𝑀.replace_lane
– f𝑁x𝑀.extract_lane
– f𝑁x𝑀.replace_lane
• New lane splitting/combining vector instructions:
– i𝑁x𝑀.extend_half _i𝑁 ′x𝑀 ′_sx
– i8x16.narrow_i16x8_sx
– i16x8.narrow_i32x4_sx
• New byte reordering vector instructions:
– [Link]
– [Link]
• New injection/projection vector instructions:
– i𝑁x𝑀.splat
– f𝑁x𝑀.splat
– i𝑁x𝑀.bitmask

7.8.2 Release 3.0


Extended Constant Expressions
Allowed basic numeric computations in constant expressions.63
• Extended set of constant instructions with:
– [Link]
– [Link]
– [Link]
– [Link] for any previously declared immutable global

Note

The garbage collection extension added further constant instructions.

Tail Calls
Added instructions to perform tail calls.64
• New control instructions:
– return_call
– return_call_indirect
63 [Link]
64 [Link]

286 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Exception Handling
Added tag definitions, imports, and exports, and instructions to throw and catch exceptions.65
• Modules may
– define tags
– import tags
– export tags
• New heap types:
– exn
– noexn
• New reference type short-hands:
– exnref
– nullexnref
• New control instructions:
– throw
– throw_ref
– try_table
• New tag section in binary format.

Multiple Memories
Added the ability to use multiple memories per module.66
• Modules may
– define multiple memories
– import multiple memories
– export multiple memories
• Memory instructions take a memory index immediate:
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]
– 𝑡.load
– 𝑡.store
– 𝑡.load𝑁_sx
– 𝑡.store𝑁
– [Link]𝑁x𝑀_sx
– [Link]𝑁_zero
– [Link]𝑁_splat
– [Link]𝑁_lane
65 [Link]
66 [Link]

7.8. Change History 287


WebAssembly Specification, Release 3.0 (2025-11-14)

– [Link]𝑁_lane
• Data segments take a memory index

64-bit Address Space


Added the ability to declare an i64 address type for tables and memories.67
• Address types denote a subset of the integral number types
• Table types include an address type
• Memory types include an address type
• Operand types of table and memory instructions now depend on the subject’s declared address type:
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]
– [Link]
– 𝑡.load
– 𝑡.store
– 𝑡.load𝑁_sx
– 𝑡.store𝑁
– [Link]𝑁x𝑀_sx
– [Link]𝑁_zero
– [Link]𝑁_splat
– [Link]𝑁_lane
– [Link]𝑁_lane

Typeful References
Added more precise types for references.68
• New generalised form of reference types:
– (ref null? heaptype)
• New class of heap types:
– func
– extern
67 [Link]
68 [Link]

288 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

– typeidx
• Basic subtyping on reference and value types
• New reference instructions:
– ref.as_non_null
– br_on_null
– br_on_non_null
• New control instruction:
– call_ref
• Refined typing of reference instruction:
– [Link] with more precise result type
• Refined typing of local instructions and instruction sequences to track the initialization status of locals with
non-defaultable type
• Refined decoding of active element segments with implicit element type and plain function indices (opcode
0) to produce non-null reference type
• Extended table definitions with optional initializer expression

Garbage Collection
Added managed reference types.69
• New forms of heap types:
– any
– eq
– i31
– struct
– array
– none
– nofunc
– noextern
• New reference type short-hands:
– anyref
– eqref
– i31ref
– structref
– arrayref
– nullref
– nullfuncref
– nullexternref
• New forms of type definitions:
– structure
– array types
69 [Link]

7.8. Change History 289


WebAssembly Specification, Release 3.0 (2025-11-14)

– sub types
– recursive types
• Enriched subtyping based on explicitly declared sub types and the new heap types
• New generic reference instructions:
– [Link]
– [Link]
– [Link]
– br_on_cast
– br_on_cast_fail
• New reference instructions for unboxed scalars:
– ref.i31
– i31.get_sx
• New reference instructions for structure types:
– [Link]
– struct.new_default
– struct.get_sx ?
– [Link]
• New reference instructions for array types:
– [Link]
– array.new_default
– array.new_fixed
– array.new_data
– array.new_elem
– array.get_sx ?
– [Link]
– [Link]
– [Link]
– [Link]
– array.init_data
– array.init_elem
• New reference instructions for converting external types:
– any.convert_extern
– extern.convert_any
• Extended set of constant instructions with:
– ref.i31
– [Link]
– struct.new_default
– [Link]
– array.new_default

290 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

– array.new_fixed
– any.convert_extern
– extern.convert_any

Relaxed Vector Instructions


Added new relaxed vector instructions, whose behaviour is non-deterministic and implementation-dependent.70
• New binary vector instruction:
– f𝑁x𝑀.relaxed_min
– f𝑁x𝑀.relaxed_max
– i16x8.relaxed_q15mulr_s
– i16x8.relaxed_dot_i8x16_i7x16_s
• New ternary vector instruction:
– f𝑁x𝑀.relaxed_madd
– f𝑁x𝑀.relaxed_nmadd
– i𝑁x𝑀.relaxed_laneselect
– i32x4.relaxed_dot_i8x16_i7x16_add_s
• New conversion vector instructions:
– i32x4.relaxed_trunc_f32x4_sx
– i32x4.relaxed_trunc_f64x2_sx _zero
• New byte reordering vector instruction:
– i8x16.relaxed_swizzle

Profiles
Introduced the concept of profile for specifying language subsets.
• A new profile defining a deterministic mode of execution.

Custom Annotations
Added generic syntax for custom annotations in the text format, mirroring the role of custom sections in the binary
format.71
• Annotations of the form ‘(@id . . . )’ are allowed anywhere in the text format
• Identifiers can be escaped as ‘@” . . . ”’ with arbitrary names
• Defined name annotations ‘(@name ” . . . ”)’ for:
– module names
– type names
– function names
– local names
– field names
• Defined custom annotation ‘(@custom ” . . . ”)’ to represent arbitrary custom sections in the text format
70 [Link]
71 [Link]

7.8. Change History 291


WebAssembly Specification, Release 3.0 (2025-11-14)

7.9 Index of Types

Category Constructor Binary Opcode


Type index 𝑥 (positive number as s32 or u32)
Number type i32 0x7F (-1 as s7)
Number type i64 0x7E (-2 as s7)
Number type f 32 0x7D (-3 as s7)
Number type f 64 0x7C (-4 as s7)
Vector type v128 0x7B (-5 as s7)
(reserved) 0x7A .. 0x79
Packed type i8 0x78 (-8 as s7)
Packed type i16 0x77 (-9 as s7)
(reserved) 0x78 .. 0x75
Heap type noexn 0x74 (-12 as s7)
Heap type nofunc 0x73 (-13 as s7)
Heap type noextern 0x72 (-14 as s7)
Heap type none 0x71 (-15 as s7)
Heap type func 0x70 (-16 as s7)
Heap type extern 0x6F (-17 as s7)
Heap type any 0x6E (-18 as s7)
Heap type eq 0x6D (-19 as s7)
Heap type i31 0x6C (-20 as s7)
Heap type struct 0x6B (-21 as s7)
Heap type array 0x6A (-22 as s7)
Heap type exn 0x69 (-23 as s7)
(reserved) 0x68 .. 0x65
Reference type ref 0x64 (-28 as s7)
Reference type ref null 0x63 (-29 as s7)
(reserved) 0x62 .. 0x61
Composite type func [valtype * ] → [valtype * ] 0x60 (-32 as s7)
Composite type struct fieldtype * 0x5F (-33 as s7)
Composite type array fieldtype 0x5E (-34 as s7)
(reserved) 0x5D .. 0x51
Sub type sub typeidx * comptype 0x50 (-48 as s7)
Sub type sub final typeidx * comptype 0x4F (-49 as s7)
Recursive type rec subtype * 0x4E (-50 as s7)
(reserved) 0x4D .. 0x41
Result type [𝜖] 0x40 (-64 as s7)
Tag type typeuse (none)
Global type mut valtype (none)
Memory type addrtype limits (none)
Table type addrtype limits reftype (none)

7.10 Index of Instructions

Instruction Binary Opcode Type Validation Execution


unreachable 0x00 [𝑡*1 ] → [𝑡*2 ] validation execution
nop 0x01 [] → [] validation execution
block bt 0x02 [𝑡*1 ] → [𝑡*2 ] validation execution
loop bt 0x03 [𝑡*1 ] → [𝑡*2 ] validation execution
if bt 0x04 [𝑡*1 i32] → [𝑡*2 ] validation execution
else 0x05
continues on n

292 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Table 2 – continued from previous page


Instruction Binary Opcode Type Validation Execution
(reserved) 0x06
(reserved) 0x07
throw 𝑥 0x08 [𝑡*1 𝑡*𝑥 ] → [𝑡*2 ] validation execution
(reserved) 0x09
throw_ref 0x0A [𝑡*1 exnref] → [𝑡*2 ] validation execution
end 0x0B
br 𝑙 0x0C [𝑡*1 𝑡* ] → [𝑡*2 ] validation execution
br_if 𝑙 0x0D [𝑡* i32] → [𝑡* ] validation execution
br_table 𝑙* 𝑙 0x0E [𝑡*1 𝑡* i32] → [𝑡*2 ] validation execution
return 0x0F [𝑡*1 𝑡* ] → [𝑡*2 ] validation execution
call 𝑥 0x10 [𝑡*1 ] → [𝑡*2 ] validation execution
call_indirect 𝑥 𝑦 0x11 [𝑡*1 i32] → [𝑡*2 ] validation execution
return_call 𝑥 0x12 [𝑡*1 ] → [𝑡*2 ] validation execution
return_call_indirect 𝑥 𝑦 0x13 [𝑡*1 i32] → [𝑡*2 ] validation execution
call_ref 𝑥 0x14 [𝑡*1 (ref null 𝑥)] → [𝑡*2 ] validation execution
return_call_ref 𝑥 0x15 [𝑡*1 (ref null 𝑥)] → [𝑡*2 ] validation execution
(reserved) 0x16
(reserved) 0x17
(reserved) 0x18
(reserved) 0x19
drop 0x1A [𝑡] → [] validation execution
select 0x1B [𝑡 𝑡 i32] → [𝑡] validation execution
select 𝑡 0x1C [𝑡 𝑡 i32] → [𝑡] validation execution
(reserved) 0x1D
(reserved) 0x1E
try_table bt 0x1F [𝑡*1 ] → [𝑡*2 ] validation execution
[Link] 𝑥 0x20 [] → [𝑡] validation execution
[Link] 𝑥 0x21 [𝑡] → [] validation execution
[Link] 𝑥 0x22 [𝑡] → [𝑡] validation execution
[Link] 𝑥 0x23 [] → [𝑡] validation execution
[Link] 𝑥 0x24 [𝑡] → [] validation execution
[Link] 𝑥 0x25 [at] → [𝑡] validation execution
[Link] 𝑥 0x26 [at 𝑡] → [] validation execution
(reserved) 0x27
[Link] 𝑥 memarg 0x28 [at] → [i32] validation execution
[Link] 𝑥 memarg 0x29 [at] → [i64] validation execution
f [Link] 𝑥 memarg 0x2A [at] → [f 32] validation execution
f [Link] 𝑥 memarg 0x2B [at] → [f 64] validation execution
i32.load8_s 𝑥 memarg 0x2C [at] → [i32] validation execution
i32.load8_u 𝑥 memarg 0x2D [at] → [i32] validation execution
i32.load16_s 𝑥 memarg 0x2E [at] → [i32] validation execution
i32.load16_u 𝑥 memarg 0x2F [at] → [i32] validation execution
i64.load8_s 𝑥 memarg 0x30 [at] → [i64] validation execution
i64.load8_u 𝑥 memarg 0x31 [at] → [i64] validation execution
i64.load16_s 𝑥 memarg 0x32 [at] → [i64] validation execution
i64.load16_u 𝑥 memarg 0x33 [at] → [i64] validation execution
i64.load32_s 𝑥 memarg 0x34 [at] → [i64] validation execution
i64.load32_u 𝑥 memarg 0x35 [at] → [i64] validation execution
[Link] 𝑥 memarg 0x36 [at i32] → [] validation execution
[Link] 𝑥 memarg 0x37 [at i64] → [] validation execution
f [Link] 𝑥 memarg 0x38 [at f 32] → [] validation execution
f [Link] 𝑥 memarg 0x39 [at f 64] → [] validation execution
i32.store8 𝑥 memarg 0x3A [at i32] → [] validation execution
i32.store16 𝑥 memarg 0x3B [at i32] → [] validation execution
i64.store8 𝑥 memarg 0x3C [at i64] → [] validation execution
continues on n

7.10. Index of Instructions 293


WebAssembly Specification, Release 3.0 (2025-11-14)

Table 2 – continued from previous page


Instruction Binary Opcode Type Validation Execution
i64.store16 𝑥 memarg 0x3D [at i64] → [] validation execution
i64.store32 𝑥 memarg 0x3E [at i64] → [] validation execution
[Link] 𝑥 0x3F [] → [at] validation execution
[Link] 𝑥 0x40 [at] → [at] validation execution
[Link] i32 0x41 [] → [i32] validation execution
[Link] i64 0x42 [] → [i64] validation execution
f [Link] f 32 0x43 [] → [f 32] validation execution
f [Link] f 64 0x44 [] → [f 64] validation execution
[Link] 0x45 [i32] → [i32] validation execution
[Link] 0x46 [i32 i32] → [i32] validation execution
[Link] 0x47 [i32 i32] → [i32] validation execution
i32.lt_s 0x48 [i32 i32] → [i32] validation execution
i32.lt_u 0x49 [i32 i32] → [i32] validation execution
i32.gt_s 0x4A [i32 i32] → [i32] validation execution
i32.gt_u 0x4B [i32 i32] → [i32] validation execution
i32.le_s 0x4C [i32 i32] → [i32] validation execution
i32.le_u 0x4D [i32 i32] → [i32] validation execution
i32.ge_s 0x4E [i32 i32] → [i32] validation execution
i32.ge_u 0x4F [i32 i32] → [i32] validation execution
[Link] 0x50 [i64] → [i32] validation execution
[Link] 0x51 [i64 i64] → [i32] validation execution
[Link] 0x52 [i64 i64] → [i32] validation execution
i64.lt_s 0x53 [i64 i64] → [i32] validation execution
i64.lt_u 0x54 [i64 i64] → [i32] validation execution
i64.gt_s 0x55 [i64 i64] → [i32] validation execution
i64.gt_u 0x56 [i64 i64] → [i32] validation execution
i64.le_s 0x57 [i64 i64] → [i32] validation execution
i64.le_u 0x58 [i64 i64] → [i32] validation execution
i64.ge_s 0x59 [i64 i64] → [i32] validation execution
i64.ge_u 0x5A [i64 i64] → [i32] validation execution
f [Link] 0x5B [f 32 f 32] → [i32] validation execution
f [Link] 0x5C [f 32 f 32] → [i32] validation execution
f [Link] 0x5D [f 32 f 32] → [i32] validation execution
f [Link] 0x5E [f 32 f 32] → [i32] validation execution
f [Link] 0x5F [f 32 f 32] → [i32] validation execution
f [Link] 0x60 [f 32 f 32] → [i32] validation execution
f [Link] 0x61 [f 64 f 64] → [i32] validation execution
f [Link] 0x62 [f 64 f 64] → [i32] validation execution
f [Link] 0x63 [f 64 f 64] → [i32] validation execution
f [Link] 0x64 [f 64 f 64] → [i32] validation execution
f [Link] 0x65 [f 64 f 64] → [i32] validation execution
f [Link] 0x66 [f 64 f 64] → [i32] validation execution
[Link] 0x67 [i32] → [i32] validation execution
[Link] 0x68 [i32] → [i32] validation execution
[Link] 0x69 [i32] → [i32] validation execution
[Link] 0x6A [i32 i32] → [i32] validation execution
[Link] 0x6B [i32 i32] → [i32] validation execution
[Link] 0x6C [i32 i32] → [i32] validation execution
i32.div_s 0x6D [i32 i32] → [i32] validation execution
i32.div_u 0x6E [i32 i32] → [i32] validation execution
i32.rem_s 0x6F [i32 i32] → [i32] validation execution
i32.rem_u 0x70 [i32 i32] → [i32] validation execution
[Link] 0x71 [i32 i32] → [i32] validation execution
[Link] 0x72 [i32 i32] → [i32] validation execution
[Link] 0x73 [i32 i32] → [i32] validation execution
continues on n

294 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Table 2 – continued from previous page


Instruction Binary Opcode Type Validation Execution
[Link] 0x74 [i32 i32] → [i32] validation execution
i32.shr_s 0x75 [i32 i32] → [i32] validation execution
i32.shr_u 0x76 [i32 i32] → [i32] validation execution
[Link] 0x77 [i32 i32] → [i32] validation execution
[Link] 0x78 [i32 i32] → [i32] validation execution
[Link] 0x79 [i64] → [i64] validation execution
[Link] 0x7A [i64] → [i64] validation execution
[Link] 0x7B [i64] → [i64] validation execution
[Link] 0x7C [i64 i64] → [i64] validation execution
[Link] 0x7D [i64 i64] → [i64] validation execution
[Link] 0x7E [i64 i64] → [i64] validation execution
i64.div_s 0x7F [i64 i64] → [i64] validation execution
i64.div_u 0x80 [i64 i64] → [i64] validation execution
i64.rem_s 0x81 [i64 i64] → [i64] validation execution
i64.rem_u 0x82 [i64 i64] → [i64] validation execution
[Link] 0x83 [i64 i64] → [i64] validation execution
[Link] 0x84 [i64 i64] → [i64] validation execution
[Link] 0x85 [i64 i64] → [i64] validation execution
[Link] 0x86 [i64 i64] → [i64] validation execution
i64.shr_s 0x87 [i64 i64] → [i64] validation execution
i64.shr_u 0x88 [i64 i64] → [i64] validation execution
[Link] 0x89 [i64 i64] → [i64] validation execution
[Link] 0x8A [i64 i64] → [i64] validation execution
f [Link] 0x8B [f 32] → [f 32] validation execution
f [Link] 0x8C [f 32] → [f 32] validation execution
f [Link] 0x8D [f 32] → [f 32] validation execution
f [Link] 0x8E [f 32] → [f 32] validation execution
f [Link] 0x8F [f 32] → [f 32] validation execution
f [Link] 0x90 [f 32] → [f 32] validation execution
f [Link] 0x91 [f 32] → [f 32] validation execution
f [Link] 0x92 [f 32 f 32] → [f 32] validation execution
f [Link] 0x93 [f 32 f 32] → [f 32] validation execution
f [Link] 0x94 [f 32 f 32] → [f 32] validation execution
f [Link] 0x95 [f 32 f 32] → [f 32] validation execution
f [Link] 0x96 [f 32 f 32] → [f 32] validation execution
f [Link] 0x97 [f 32 f 32] → [f 32] validation execution
f [Link] 0x98 [f 32 f 32] → [f 32] validation execution
f [Link] 0x99 [f 64] → [f 64] validation execution
f [Link] 0x9A [f 64] → [f 64] validation execution
f [Link] 0x9B [f 64] → [f 64] validation execution
f [Link] 0x9C [f 64] → [f 64] validation execution
f [Link] 0x9D [f 64] → [f 64] validation execution
f [Link] 0x9E [f 64] → [f 64] validation execution
f [Link] 0x9F [f 64] → [f 64] validation execution
f [Link] 0xA0 [f 64 f 64] → [f 64] validation execution
f [Link] 0xA1 [f 64 f 64] → [f 64] validation execution
f [Link] 0xA2 [f 64 f 64] → [f 64] validation execution
f [Link] 0xA3 [f 64 f 64] → [f 64] validation execution
f [Link] 0xA4 [f 64 f 64] → [f 64] validation execution
f [Link] 0xA5 [f 64 f 64] → [f 64] validation execution
f [Link] 0xA6 [f 64 f 64] → [f 64] validation execution
i32.wrap_i64 0xA7 [i64] → [i32] validation execution
i32.trunc_f 32_s 0xA8 [f 32] → [i32] validation execution
i32.trunc_f 32_u 0xA9 [f 32] → [i32] validation execution
i32.trunc_f 64_s 0xAA [f 64] → [i32] validation execution
continues on n

7.10. Index of Instructions 295


WebAssembly Specification, Release 3.0 (2025-11-14)

Table 2 – continued from previous page


Instruction Binary Opcode Type Validation Execution
i32.trunc_f 64_u 0xAB [f 64] → [i32] validation execution
i64.extend_i32_s 0xAC [i32] → [i64] validation execution
i64.extend_i32_u 0xAD [i32] → [i64] validation execution
i64.trunc_f 32_s 0xAE [f 32] → [i64] validation execution
i64.trunc_f 32_u 0xAF [f 32] → [i64] validation execution
i64.trunc_f 64_s 0xB0 [f 64] → [i64] validation execution
i64.trunc_f 64_u 0xB1 [f 64] → [i64] validation execution
f 32.convert_i32_s 0xB2 [i32] → [f 32] validation execution
f 32.convert_i32_u 0xB3 [i32] → [f 32] validation execution
f 32.convert_i64_s 0xB4 [i64] → [f 32] validation execution
f 32.convert_i64_u 0xB5 [i64] → [f 32] validation execution
f 32.demote_f 64 0xB6 [f 64] → [f 32] validation execution
f 64.convert_i32_s 0xB7 [i32] → [f 64] validation execution
f 64.convert_i32_u 0xB8 [i32] → [f 64] validation execution
f 64.convert_i64_s 0xB9 [i64] → [f 64] validation execution
f 64.convert_i64_u 0xBA [i64] → [f 64] validation execution
f 64.promote_f 32 0xBB [f 32] → [f 64] validation execution
i32.reinterpret_f 32 0xBC [f 32] → [i32] validation execution
i64.reinterpret_f 64 0xBD [f 64] → [i64] validation execution
f 32.reinterpret_i32 0xBE [i32] → [f 32] validation execution
f 64.reinterpret_i64 0xBF [i64] → [f 64] validation execution
i32.extend8_s 0xC0 [i32] → [i32] validation execution
i32.extend16_s 0xC1 [i32] → [i32] validation execution
i64.extend8_s 0xC2 [i64] → [i64] validation execution
i64.extend16_s 0xC3 [i64] → [i64] validation execution
i64.extend32_s 0xC4 [i64] → [i64] validation execution
(reserved) 0xC5
(reserved) 0xC6
(reserved) 0xC7
(reserved) 0xC8
(reserved) 0xC9
(reserved) 0xCA
(reserved) 0xCB
(reserved) 0xCC
(reserved) 0xCD
(reserved) 0xCE
(reserved) 0xCF
[Link] ht 0xD0 [] → [(ref null ht)] validation execution
ref.is_null 0xD1 [(ref null ht)] → [i32] validation execution
[Link] 𝑥 0xD2 [] → [ref ht] validation execution
[Link] 0xD3 [eqref eqref] → [i32] validation execution
ref.as_non_null 0xD4 [(ref null ht)] → [(ref ht)] validation execution
br_on_null 𝑙 0xD5 [𝑡* (ref null ht)] → [𝑡* (ref ht)] validation execution
br_on_non_null 𝑙 0xD6 [𝑡* (ref null ht)] → [𝑡* ] validation execution
(reserved) 0xD7
(reserved) 0xD8
(reserved) 0xD9
(reserved) 0xDA
(reserved) 0xDB
(reserved) 0xDC
(reserved) 0xDD
(reserved) 0xDE
(reserved) 0xDF
(reserved) 0xE0
(reserved) 0xE1
continues on n

296 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Table 2 – continued from previous page


Instruction Binary Opcode Type Validation Execution
(reserved) 0xE2
(reserved) 0xE3
(reserved) 0xE4
(reserved) 0xE5
(reserved) 0xE6
(reserved) 0xE7
(reserved) 0xE8
(reserved) 0xE9
(reserved) 0xEA
(reserved) 0xEB
(reserved) 0xEC
(reserved) 0xED
(reserved) 0xEE
(reserved) 0xEF
(reserved) 0xF0
(reserved) 0xF1
(reserved) 0xF2
(reserved) 0xF3
(reserved) 0xF4
(reserved) 0xF5
(reserved) 0xF6
(reserved) 0xF7
(reserved) 0xF8
(reserved) 0xF9
(reserved) 0xFA
[Link] 𝑥 0xFB 0x00 [𝑡* ] → [(ref 𝑥)] validation execution
struct.new_default 𝑥 0xFB 0x01 [] → [(ref 𝑥)] validation execution
[Link] 𝑥 𝑦 0xFB 0x02 [(ref null 𝑥)] → [𝑡] validation execution
struct.get_s 𝑥 𝑦 0xFB 0x03 [(ref null 𝑥)] → [i32] validation execution
struct.get_u 𝑥 𝑦 0xFB 0x04 [(ref null 𝑥)] → [i32] validation execution
[Link] 𝑥 𝑦 0xFB 0x05 [(ref null 𝑥) 𝑡] → [] validation execution
[Link] 𝑥 0xFB 0x06 [𝑡 i32] → [(ref 𝑥)] validation execution
array.new_default 𝑥 0xFB 0x07 [i32] → [(ref 𝑥)] validation execution
array.new_fixed 𝑥 𝑛 0xFB 0x08 [𝑡𝑛 ] → [(ref 𝑥)] validation execution
array.new_data 𝑥 𝑦 0xFB 0x09 [i32 i32] → [(ref 𝑥)] validation execution
array.new_elem 𝑥 𝑦 0xFB 0x0A [i32 i32] → [(ref 𝑥)] validation execution
[Link] 𝑥 0xFB 0x0B [(ref null 𝑥) i32] → [𝑡] validation execution
array.get_s 𝑥 0xFB 0x0C [(ref null 𝑥) i32] → [i32] validation execution
array.get_u 𝑥 0xFB 0x0D [(ref null 𝑥) i32] → [i32] validation execution
[Link] 𝑥 0xFB 0x0E [(ref null 𝑥) i32 𝑡] → [] validation execution
[Link] 0xFB 0x0F [(ref null array)] → [i32] validation execution
[Link] 𝑥 0xFB 0x10 [(ref null 𝑥) i32 𝑡 i32] → [] validation execution
[Link] 𝑥 𝑦 0xFB 0x11 [(ref null 𝑥) i32 (ref null 𝑦) i32 i32] → [] validation execution
array.init_data 𝑥 𝑦 0xFB 0x12 [(ref null 𝑥) i32 i32 i32] → [] validation execution
array.init_elem 𝑥 𝑦 0xFB 0x13 [(ref null 𝑥) i32 i32 i32] → [] validation execution
[Link] (ref 𝑡) 0xFB 0x14 [(ref 𝑡′ )] → [i32] validation execution
[Link] (ref null 𝑡) 0xFB 0x15 [(ref null 𝑡′ )] → [i32] validation execution
[Link] (ref 𝑡) 0xFB 0x16 [(ref 𝑡′ )] → [(ref 𝑡)] validation execution
[Link] (ref null 𝑡) 0xFB 0x17 [(ref null 𝑡′ )] → [(ref null 𝑡)] validation execution
br_on_cast 𝑡1 𝑡2 0xFB 0x18 [𝑡1 ] → [𝑡1 ∖ 𝑡2 ] validation execution
br_on_cast_fail 𝑡1 𝑡2 0xFB 0x19 [𝑡1 ] → [𝑡2 ] validation execution
any.convert_extern 0xFB 0x1A [(ref null extern)] → [(ref null any)] validation execution
extern.convert_any 0xFB 0x1B [(ref null any)] → [(ref null extern)] validation execution
ref.i31 0xFB 0x1C [i32] → [(ref i31)] validation execution
i31.get_s 0xFB 0x1D [i31ref] → [i32] validation execution
continues on n

7.10. Index of Instructions 297


WebAssembly Specification, Release 3.0 (2025-11-14)

Table 2 – continued from previous page


Instruction Binary Opcode Type Validation Execution
i31.get_u 0xFB 0x1E [i31ref] → [i32] validation execution
(reserved) 0xFB 0x1E . . .
i32.trunc_sat_f 32_s 0xFC 0x00 [f 32] → [i32] validation execution
i32.trunc_sat_f 32_u 0xFC 0x01 [f 32] → [i32] validation execution
i32.trunc_sat_f 64_s 0xFC 0x02 [f 64] → [i32] validation execution
i32.trunc_sat_f 64_u 0xFC 0x03 [f 64] → [i32] validation execution
i64.trunc_sat_f 32_s 0xFC 0x04 [f 32] → [i64] validation execution
i64.trunc_sat_f 32_u 0xFC 0x05 [f 32] → [i64] validation execution
i64.trunc_sat_f 64_s 0xFC 0x06 [f 64] → [i64] validation execution
i64.trunc_sat_f 64_u 0xFC 0x07 [f 64] → [i64] validation execution
[Link] 𝑥 𝑦 0xFC 0x08 [at i32 i32] → [] validation execution
[Link] 𝑥 0xFC 0x09 [] → [] validation execution
[Link] 𝑥 𝑦 0xFC 0x0A [at 1 at 2 at] → [] validation execution
[Link] 𝑦 0xFC 0x0B [at i32 at] → [] validation execution
[Link] 𝑥 𝑦 0xFC 0x0C [at i32 i32] → [] validation execution
[Link] 𝑥 0xFC 0x0D [] → [] validation execution
[Link] 𝑥 𝑦 0xFC 0x0E [at 1 at 2 at] → [] validation execution
[Link] 𝑥 0xFC 0x0F [𝑡 at] → [at] validation execution
[Link] 𝑥 0xFC 0x10 [] → [at] validation execution
[Link] 𝑥 0xFC 0x11 [at 𝑡 at] → [] validation execution
(reserved) 0xFC 0x1E . . .
[Link] 𝑥 memarg 0xFD 0x00 [at] → [v128] validation execution
v128.load8x8_s 𝑥 memarg 0xFD 0x01 [at] → [v128] validation execution
v128.load8x8_u 𝑥 memarg 0xFD 0x02 [at] → [v128] validation execution
v128.load16x4_s 𝑥 memarg 0xFD 0x03 [at] → [v128] validation execution
v128.load16x4_u 𝑥 memarg 0xFD 0x04 [at] → [v128] validation execution
v128.load32x2_s 𝑥 memarg 0xFD 0x05 [at] → [v128] validation execution
v128.load32x2_u 𝑥 memarg 0xFD 0x06 [at] → [v128] validation execution
v128.load8_splat 𝑥 memarg 0xFD 0x07 [at] → [v128] validation execution
v128.load16_splat 𝑥 memarg 0xFD 0x08 [at] → [v128] validation execution
v128.load32_splat 𝑥 memarg 0xFD 0x09 [at] → [v128] validation execution
v128.load64_splat 𝑥 memarg 0xFD 0x0A [at] → [v128] validation execution
[Link] 𝑥 memarg 0xFD 0x0B [at v128] → [] validation execution
[Link] i128 0xFD 0x0C [] → [v128] validation execution
[Link] laneidx 16 0xFD 0x0D [v128 v128] → [v128] validation execution
[Link] 0xFD 0x0E [v128 v128] → [v128] validation execution
[Link] 0xFD 0x0F [i32] → [v128] validation execution
[Link] 0xFD 0x10 [i32] → [v128] validation execution
[Link] 0xFD 0x11 [i32] → [v128] validation execution
[Link] 0xFD 0x12 [i64] → [v128] validation execution
f [Link] 0xFD 0x13 [f 32] → [v128] validation execution
f [Link] 0xFD 0x14 [f 64] → [v128] validation execution
i8x16.extract_lane_s laneidx 0xFD 0x15 [v128] → [i32] validation execution
i8x16.extract_lane_u laneidx 0xFD 0x16 [v128] → [i32] validation execution
i8x16.replace_lane laneidx 0xFD 0x17 [v128 i32] → [v128] validation execution
i16x8.extract_lane_s laneidx 0xFD 0x18 [v128] → [i32] validation execution
i16x8.extract_lane_u laneidx 0xFD 0x19 [v128] → [i32] validation execution
i16x8.replace_lane laneidx 0xFD 0x1A [v128 i32] → [v128] validation execution
i32x4.extract_lane laneidx 0xFD 0x1B [v128] → [i32] validation execution
i32x4.replace_lane laneidx 0xFD 0x1C [v128 i32] → [v128] validation execution
i64x2.extract_lane laneidx 0xFD 0x1D [v128] → [i64] validation execution
i64x2.replace_lane laneidx 0xFD 0x1E [v128 i64] → [v128] validation execution
f 32x4.extract_lane laneidx 0xFD 0x1F [v128] → [f 32] validation execution
f 32x4.replace_lane laneidx 0xFD 0x20 [v128 f 32] → [v128] validation execution
f 64x2.extract_lane laneidx 0xFD 0x21 [v128] → [f 64] validation execution
continues on n

298 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Table 2 – continued from previous page


Instruction Binary Opcode Type Validation Execution
f 64x2.replace_lane laneidx 0xFD 0x22 [v128 f 64] → [v128] validation execution
[Link] 0xFD 0x23 [v128 v128] → [v128] validation execution
[Link] 0xFD 0x24 [v128 v128] → [v128] validation execution
i8x16.lt_s 0xFD 0x25 [v128 v128] → [v128] validation execution
i8x16.lt_u 0xFD 0x26 [v128 v128] → [v128] validation execution
i8x16.gt_s 0xFD 0x27 [v128 v128] → [v128] validation execution
i8x16.gt_u 0xFD 0x28 [v128 v128] → [v128] validation execution
i8x16.le_s 0xFD 0x29 [v128 v128] → [v128] validation execution
i8x16.le_u 0xFD 0x2A [v128 v128] → [v128] validation execution
i8x16.ge_s 0xFD 0x2B [v128 v128] → [v128] validation execution
i8x16.ge_u 0xFD 0x2C [v128 v128] → [v128] validation execution
[Link] 0xFD 0x2D [v128 v128] → [v128] validation execution
[Link] 0xFD 0x2E [v128 v128] → [v128] validation execution
i16x8.lt_s 0xFD 0x2F [v128 v128] → [v128] validation execution
i16x8.lt_u 0xFD 0x30 [v128 v128] → [v128] validation execution
i16x8.gt_s 0xFD 0x31 [v128 v128] → [v128] validation execution
i16x8.gt_u 0xFD 0x32 [v128 v128] → [v128] validation execution
i16x8.le_s 0xFD 0x33 [v128 v128] → [v128] validation execution
i16x8.le_u 0xFD 0x34 [v128 v128] → [v128] validation execution
i16x8.ge_s 0xFD 0x35 [v128 v128] → [v128] validation execution
i16x8.ge_u 0xFD 0x36 [v128 v128] → [v128] validation execution
[Link] 0xFD 0x37 [v128 v128] → [v128] validation execution
[Link] 0xFD 0x38 [v128 v128] → [v128] validation execution
i32x4.lt_s 0xFD 0x39 [v128 v128] → [v128] validation execution
i32x4.lt_u 0xFD 0x3A [v128 v128] → [v128] validation execution
i32x4.gt_s 0xFD 0x3B [v128 v128] → [v128] validation execution
i32x4.gt_u 0xFD 0x3C [v128 v128] → [v128] validation execution
i32x4.le_s 0xFD 0x3D [v128 v128] → [v128] validation execution
i32x4.le_u 0xFD 0x3E [v128 v128] → [v128] validation execution
i32x4.ge_s 0xFD 0x3F [v128 v128] → [v128] validation execution
i32x4.ge_u 0xFD 0x40 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x41 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x42 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x43 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x44 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x45 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x46 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x47 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x48 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x49 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x4A [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x4B [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x4C [v128 v128] → [v128] validation execution
[Link] 0xFD 0x4D [v128] → [v128] validation execution
[Link] 0xFD 0x4E [v128 v128] → [v128] validation execution
[Link] 0xFD 0x4F [v128 v128] → [v128] validation execution
[Link] 0xFD 0x50 [v128 v128] → [v128] validation execution
[Link] 0xFD 0x51 [v128 v128] → [v128] validation execution
[Link] 0xFD 0x52 [v128 v128 v128] → [v128] validation execution
v128.any_true 0xFD 0x53 [v128] → [i32] validation execution
v128.load8_lane memarg laneidx 0xFD 0x54 [at v128] → [v128] validation execution
v128.load16_lane memarg laneidx 0xFD 0x55 [at v128] → [v128] validation execution
v128.load32_lane memarg laneidx 0xFD 0x56 [at v128] → [v128] validation execution
v128.load64_lane memarg laneidx 0xFD 0x57 [at v128] → [v128] validation execution
v128.store8_lane memarg laneidx 0xFD 0x58 [at v128] → [] validation execution
continues on n

7.10. Index of Instructions 299


WebAssembly Specification, Release 3.0 (2025-11-14)

Table 2 – continued from previous page


Instruction Binary Opcode Type Validation Execution
v128.store16_lane memarg laneidx 0xFD 0x59 [at v128] → [] validation execution
v128.store32_lane memarg laneidx 0xFD 0x5A [at v128] → [] validation execution
v128.store64_lane memarg laneidx 0xFD 0x5B [at v128] → [] validation execution
v128.load32_zero memarg 0xFD 0x5C [at] → [v128] validation execution
v128.load64_zero memarg 0xFD 0x5D [at] → [v128] validation execution
f 32x4.demote_f64x2_zero 0xFD 0x5E [v128] → [v128] validation execution
f 64x2.promote_low_f32x4 0xFD 0x5F [v128] → [v128] validation execution
[Link] 0xFD 0x60 [v128] → [v128] validation execution
[Link] 0xFD 0x61 [v128] → [v128] validation execution
[Link] 0xFD 0x62 [v128] → [v128] validation execution
i8x16.all_true 0xFD 0x63 [v128] → [i32] validation execution
[Link] 0xFD 0x64 [v128] → [i32] validation execution
i8x16.narrow_i16x8_s 0xFD 0x65 [v128 v128] → [v128] validation execution
i8x16.narrow_i16x8_u 0xFD 0x66 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x67 [v128] → [v128] validation execution
f [Link] 0xFD 0x68 [v128] → [v128] validation execution
f [Link] 0xFD 0x69 [v128] → [v128] validation execution
f [Link] 0xFD 0x6A [v128] → [v128] validation execution
[Link] 0xFD 0x6B [v128 i32] → [v128] validation execution
i8x16.shr_s 0xFD 0x6C [v128 i32] → [v128] validation execution
i8x16.shr_u 0xFD 0x6D [v128 i32] → [v128] validation execution
[Link] 0xFD 0x6E [v128 v128] → [v128] validation execution
i8x16.add_sat_s 0xFD 0x6F [v128 v128] → [v128] validation execution
i8x16.add_sat_u 0xFD 0x70 [v128 v128] → [v128] validation execution
[Link] 0xFD 0x71 [v128 v128] → [v128] validation execution
i8x16.sub_sat_s 0xFD 0x72 [v128 v128] → [v128] validation execution
i8x16.sub_sat_u 0xFD 0x73 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x74 [v128] → [v128] validation execution
f [Link] 0xFD 0x75 [v128] → [v128] validation execution
i8x16.min_s 0xFD 0x76 [v128 v128] → [v128] validation execution
i8x16.min_u 0xFD 0x77 [v128 v128] → [v128] validation execution
i8x16.max_s 0xFD 0x78 [v128 v128] → [v128] validation execution
i8x16.max_u 0xFD 0x79 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x7A [v128] → [v128] validation execution
i8x16.avgr_u 0xFD 0x7B [v128 v128] → [v128] validation execution
i16x8.extadd_pairwise_i8x16_s 0xFD 0x7C [v128] → [v128] validation execution
i16x8.extadd_pairwise_i8x16_u 0xFD 0x7D [v128] → [v128] validation execution
i32x4.extadd_pairwise_i16x8_s 0xFD 0x7E [v128] → [v128] validation execution
i32x4.extadd_pairwise_i16x8_u 0xFD 0x7F [v128] → [v128] validation execution
[Link] 0xFD 0x80 0x01 [v128] → [v128] validation execution
[Link] 0xFD 0x81 0x01 [v128] → [v128] validation execution
i16x8.q15mulr_sat_s 0xFD 0x82 0x01 [v128 v128] → [v128] validation execution
i16x8.all_true 0xFD 0x83 0x01 [v128] → [i32] validation execution
[Link] 0xFD 0x84 0x01 [v128] → [i32] validation execution
i16x8.narrow_i32x4_s 0xFD 0x85 0x01 [v128 v128] → [v128] validation execution
i16x8.narrow_i32x4_u 0xFD 0x86 0x01 [v128 v128] → [v128] validation execution
i16x8.extend_low_i8x16_s 0xFD 0x87 0x01 [v128] → [v128] validation execution
i16x8.extend_high_i8x16_s 0xFD 0x88 0x01 [v128] → [v128] validation execution
i16x8.extend_low_i8x16_u 0xFD 0x89 0x01 [v128] → [v128] validation execution
i16x8.extend_high_i8x16_u 0xFD 0x8A 0x01 [v128] → [v128] validation execution
[Link] 0xFD 0x8B 0x01 [v128 i32] → [v128] validation execution
i16x8.shr_s 0xFD 0x8C 0x01 [v128 i32] → [v128] validation execution
i16x8.shr_u 0xFD 0x8D 0x01 [v128 i32] → [v128] validation execution
[Link] 0xFD 0x8E 0x01 [v128 v128] → [v128] validation execution
i16x8.add_sat_s 0xFD 0x8F 0x01 [v128 v128] → [v128] validation execution
continues on n

300 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Table 2 – continued from previous page


Instruction Binary Opcode Type Validation Execution
i16x8.add_sat_u 0xFD 0x90 0x01 [v128 v128] → [v128] validation execution
[Link] 0xFD 0x91 0x01 [v128 v128] → [v128] validation execution
i16x8.sub_sat_s 0xFD 0x92 0x01 [v128 v128] → [v128] validation execution
i16x8.sub_sat_u 0xFD 0x93 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0x94 0x01 [v128] → [v128] validation execution
[Link] 0xFD 0x95 0x01 [v128 v128] → [v128] validation execution
i16x8.min_s 0xFD 0x96 0x01 [v128 v128] → [v128] validation execution
i16x8.min_u 0xFD 0x97 0x01 [v128 v128] → [v128] validation execution
i16x8.max_s 0xFD 0x98 0x01 [v128 v128] → [v128] validation execution
i16x8.max_u 0xFD 0x99 0x01 [v128 v128] → [v128] validation execution
(reserved) 0xFD 0x9A 0x01
i16x8.avgr_u 0xFD 0x9B 0x01 [v128 v128] → [v128] validation execution
i16x8.extmul_low_i8x16_s 0xFD 0x9C 0x01 [v128 v128] → [v128] validation execution
i16x8.extmul_high_i8x16_s 0xFD 0x9D 0x01 [v128 v128] → [v128] validation execution
i16x8.extmul_low_i8x16_u 0xFD 0x9E 0x01 [v128 v128] → [v128] validation execution
i16x8.extmul_high_i8x16_u 0xFD 0x9F 0x01 [v128 v128] → [v128] validation execution
[Link] 0xFD 0xA0 0x01 [v128] → [v128] validation execution
[Link] 0xFD 0xA1 0x01 [v128] → [v128] validation execution
(reserved) 0xFD 0xA2 0x01
i32x4.all_true 0xFD 0xA3 0x01 [v128] → [i32] validation execution
[Link] 0xFD 0xA4 0x01 [v128] → [i32] validation execution
(reserved) 0xFD 0xA5 0x01
(reserved) 0xFD 0xA6 0x01
i32x4.extend_low_i16x8_s 0xFD 0xA7 0x01 [v128] → [v128] validation execution
i32x4.extend_high_i16x8_s 0xFD 0xA8 0x01 [v128] → [v128] validation execution
i32x4.extend_low_i16x8_u 0xFD 0xA9 0x01 [v128] → [v128] validation execution
i32x4.extend_high_i16x8_u 0xFD 0xAA 0x01 [v128] → [v128] validation execution
[Link] 0xFD 0xAB 0x01 [v128 i32] → [v128] validation execution
i32x4.shr_s 0xFD 0xAC 0x01 [v128 i32] → [v128] validation execution
i32x4.shr_u 0xFD 0xAD 0x01 [v128 i32] → [v128] validation execution
[Link] 0xFD 0xAE 0x01 [v128 v128] → [v128] validation execution
(reserved) 0xFD 0xAF 0x01
(reserved) 0xFD 0xB0 0x01
[Link] 0xFD 0xB1 0x01 [v128 v128] → [v128] validation execution
(reserved) 0xFD 0xB2 0x01
(reserved) 0xFD 0xB3 0x01
(reserved) 0xFD 0xB4 0x01
[Link] 0xFD 0xB5 0x01 [v128 v128] → [v128] validation execution
i32x4.min_s 0xFD 0xB6 0x01 [v128 v128] → [v128] validation execution
i32x4.min_u 0xFD 0xB7 0x01 [v128 v128] → [v128] validation execution
i32x4.max_s 0xFD 0xB8 0x01 [v128 v128] → [v128] validation execution
i32x4.max_u 0xFD 0xB9 0x01 [v128 v128] → [v128] validation execution
i32x4.dot_i16x8_s 0xFD 0xBA 0x01 [v128 v128] → [v128] validation execution
i32x4.extmul_low_i16x8_s 0xFD 0xBC 0x01 [v128 v128] → [v128] validation execution
i32x4.extmul_high_i16x8_s 0xFD 0xBD 0x01 [v128 v128] → [v128] validation execution
i32x4.extmul_low_i16x8_u 0xFD 0xBE 0x01 [v128 v128] → [v128] validation execution
i32x4.extmul_high_i16x8_u 0xFD 0xBF 0x01 [v128 v128] → [v128] validation execution
[Link] 0xFD 0xC0 0x01 [v128] → [v128] validation execution
[Link] 0xFD 0xC1 0x01 [v128] → [v128] validation execution
(reserved) 0xFD 0xC2 0x01
i64x2.all_true 0xFD 0xC3 0x01 [v128] → [i32] validation execution
[Link] 0xFD 0xC4 0x01 [v128] → [i32] validation execution
(reserved) 0xFD 0xC5 0x01
(reserved) 0xFD 0xC6 0x01
i64x2.extend_low_i32x4_s 0xFD 0xC7 0x01 [v128] → [v128] validation execution
continues on n

7.10. Index of Instructions 301


WebAssembly Specification, Release 3.0 (2025-11-14)

Table 2 – continued from previous page


Instruction Binary Opcode Type Validation Execution
i64x2.extend_high_i32x4_s 0xFD 0xC8 0x01 [v128] → [v128] validation execution
i64x2.extend_low_i32x4_u 0xFD 0xC9 0x01 [v128] → [v128] validation execution
i64x2.extend_high_i32x4_u 0xFD 0xCA 0x01 [v128] → [v128] validation execution
[Link] 0xFD 0xCB 0x01 [v128 i32] → [v128] validation execution
i64x2.shr_s 0xFD 0xCC 0x01 [v128 i32] → [v128] validation execution
i64x2.shr_u 0xFD 0xCD 0x01 [v128 i32] → [v128] validation execution
[Link] 0xFD 0xCE 0x01 [v128 v128] → [v128] validation execution
(reserved) 0xFD 0xCF 0x01
(reserved) 0xFD 0xD0 0x01
[Link] 0xFD 0xD1 0x01 [v128 v128] → [v128] validation execution
(reserved) 0xFD 0xD2 0x01
(reserved) 0xFD 0xD3 0x01
(reserved) 0xFD 0xD4 0x01
[Link] 0xFD 0xD5 0x01 [v128 v128] → [v128] validation execution
[Link] 0xFD 0xD6 0x01 [v128 v128] → [v128] validation execution
[Link] 0xFD 0xD7 0x01 [v128 v128] → [v128] validation execution
i64x2.lt_s 0xFD 0xD8 0x01 [v128 v128] → [v128] validation execution
i64x2.gt_s 0xFD 0xD9 0x01 [v128 v128] → [v128] validation execution
i64x2.le_s 0xFD 0xDA 0x01 [v128 v128] → [v128] validation execution
i64x2.ge_s 0xFD 0xDB 0x01 [v128 v128] → [v128] validation execution
i64x2.extmul_low_i32x4_s 0xFD 0xDC 0x01 [v128 v128] → [v128] validation execution
i64x2.extmul_high_i32x4_s 0xFD 0xDD 0x01 [v128 v128] → [v128] validation execution
i64x2.extmul_low_i32x4_u 0xFD 0xDE 0x01 [v128 v128] → [v128] validation execution
i64x2.extmul_high_i32x4_u 0xFD 0xDF 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xE0 0x01 [v128] → [v128] validation execution
f [Link] 0xFD 0xE1 0x01 [v128] → [v128] validation execution
(reserved) 0xFD 0xE2 0x01
f [Link] 0xFD 0xE3 0x01 [v128] → [v128] validation execution
f [Link] 0xFD 0xE4 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xE5 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xE6 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xE7 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xE8 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xE9 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xEA 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xEB 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xEC 0x01 [v128] → [v128] validation execution
f [Link] 0xFD 0xED 0x01 [v128] → [v128] validation execution
(reserved) 0xFD 0xEE 0x01
f [Link] 0xFD 0xEF 0x01 [v128] → [v128] validation execution
f [Link] 0xFD 0xF0 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xF1 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xF2 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xF3 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xF4 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xF5 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xF6 0x01 [v128 v128] → [v128] validation execution
f [Link] 0xFD 0xF7 0x01 [v128 v128] → [v128] validation execution
i32x4.trunc_sat_f32x4_s 0xFD 0xF8 0x01 [v128] → [v128] validation execution
i32x4.trunc_sat_f32x4_u 0xFD 0xF9 0x01 [v128] → [v128] validation execution
f 32x4.convert_i32x4_s 0xFD 0xFA 0x01 [v128] → [v128] validation execution
f 32x4.convert_i32x4_u 0xFD 0xFB 0x01 [v128] → [v128] validation execution
i32x4.trunc_sat_f64x2_s_zero 0xFD 0xFC 0x01 [v128] → [v128] validation execution
i32x4.trunc_sat_f64x2_u_zero 0xFD 0xFD 0x01 [v128] → [v128] validation execution
f 64x2.convert_low_i32x4_s 0xFD 0xFE 0x01 [v128] → [v128] validation execution
continues on n

302 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

Table 2 – continued from previous page


Instruction Binary Opcode Type Validation Execution
f 64x2.convert_low_i32x4_u 0xFD 0xFF 0x01 [v128] → [v128] validation execution
i8x16.relaxed_swizzle 0xFD 0x80 0x02 [v128 v128] → [v128] validation execution
i32x4.relaxed_trunc_f32x4_s 0xFD 0x81 0x02 [v128] → [v128] validation execution
i32x4.relaxed_trunc_f32x4_u 0xFD 0x82 0x02 [v128] → [v128] validation execution
i32x4.relaxed_trunc_f64x2_s 0xFD 0x83 0x02 [v128] → [v128] validation execution
i32x4.relaxed_trunc_f64x2_u 0xFD 0x84 0x02 [v128] → [v128] validation execution
f 32x4.relaxed_madd 0xFD 0x85 0x02 [v128 v128 v128] → [v128] validation execution
f 32x4.relaxed_nmadd 0xFD 0x86 0x02 [v128 v128 v128] → [v128] validation execution
f 64x2.relaxed_madd 0xFD 0x87 0x02 [v128 v128 v128] → [v128] validation execution
f 64x2.relaxed_nmadd 0xFD 0x88 0x02 [v128 v128 v128] → [v128] validation execution
i8x16.relaxed_laneselect 0xFD 0x89 0x02 [v128 v128 v128] → [v128] validation execution
i16x8.relaxed_laneselect 0xFD 0x8A 0x02 [v128 v128 v128] → [v128] validation execution
i32x4.relaxed_laneselect 0xFD 0x8B 0x02 [v128 v128 v128] → [v128] validation execution
i64x2.relaxed_laneselect 0xFD 0x8C 0x02 [v128 v128 v128] → [v128] validation execution
f 32x4.relaxed_min 0xFD 0x8D 0x02 [v128 v128] → [v128] validation execution
f 32x4.relaxed_max 0xFD 0x8E 0x02 [v128 v128] → [v128] validation execution
f 64x2.relaxed_min 0xFD 0x8F 0x02 [v128 v128] → [v128] validation execution
f 64x2.relaxed_max 0xFD 0x90 0x02 [v128 v128] → [v128] validation execution
i16x8.relaxed_q15mulr_s 0xFD 0x91 0x02 [v128 v128] → [v128] validation execution
i16x8.relaxed_dot_i8x16_i7x16_s 0xFD 0x92 0x02 [v128 v128] → [v128] validation execution
i32x4.relaxed_dot_i8x16_i7x16_add_s 0xFD 0x93 0x02 [v128 v128 v128] → [v128] validation execution
(reserved) 0xFD 0x94 0x02 . . .
(reserved) 0xFE
(reserved) 0xFF

Note

Multi-byte opcodes are given with the shortest possible encoding in the table. However, what is following the
first byte is actually a u32 with variable-length encoding and consequently has multiple possible representations.

7.10. Index of Instructions 303


WebAssembly Specification, Release 3.0 (2025-11-14)

7.11 Index of Semantic Rules


7.11.1 Well-formedness of Types

Construct Judgement
Numeric type 𝐶 ⊢ numtype : ok
Vector type 𝐶 ⊢ vectype : ok
Heap type 𝐶 ⊢ heaptype : ok
Reference type 𝐶 ⊢ reftype : ok
Value type 𝐶 ⊢ valtype : ok
Packed type 𝐶 ⊢ packtype : ok
Storage type 𝐶 ⊢ storagetype : ok
Field type 𝐶 ⊢ fieldtype : ok
Result type 𝐶 ⊢ resulttype : ok
Instruction type 𝐶 ⊢ instrtype : ok
Composite type 𝐶 ⊢ comptype : ok
Sub type 𝐶 ⊢ subtype : ok
Recursive type 𝐶 ⊢ rectype : ok
Defined type 𝐶 ⊢ deftype : ok
Block type 𝐶 ⊢ blocktype : instrtype
Tag type 𝐶 ⊢ tagtype : ok
Global type 𝐶 ⊢ globaltype : ok
Memory type 𝐶 ⊢ memtype : ok
Table type 𝐶 ⊢ tabletype : ok
External type 𝐶 ⊢ externtype : ok
Type definitions 𝐶 ⊢ type * : ok

7.11.2 Typing of Static Constructs

Construct Judgement
Instruction 𝑆; 𝐶 ⊢ instr : instrtype
Instruction sequence 𝑆; 𝐶 ⊢ instr * : instrtype
Catch clause 𝐶 ⊢ catch : ok
Expression 𝐶 ⊢ expr : resulttype
Limits 𝐶 ⊢ limits : 𝑘
Tag 𝐶 ⊢ tag : tagtype
Global 𝐶 ⊢ global : globaltype
Memory 𝐶 ⊢ mem : memtype
Table 𝐶 ⊢ table : tabletype
Function 𝐶 ⊢ func : deftype
Local 𝐶 ⊢ local : localtype
Element segment 𝐶 ⊢ elem : reftype
Element mode 𝐶 ⊢ elemmode : reftype
Data segment 𝐶 ⊢ data : ok
Data mode 𝐶 ⊢ datamode : ok
Start function 𝐶 ⊢ start : ok
Import 𝐶 ⊢ import : externtype
Export 𝐶 ⊢ export : externtype
Module ⊢ module : externtype * → externtype *

304 Chapter 7. Appendix


WebAssembly Specification, Release 3.0 (2025-11-14)

7.11.3 Typing of Runtime Constructs

Construct Judgement
Value 𝑆 ⊢ val : valtype
Result 𝑆 ⊢ result : resulttype
Packed value 𝑆 ⊢ packval : packtype
Field value 𝑆 ⊢ fieldval : storagetype
External address 𝑆 ⊢ externaddr : externtype
Tag instance 𝑆 ⊢ taginst : tagtype
Global instance 𝑆 ⊢ globalinst : globaltype
Memory instance 𝑆 ⊢ meminst : memtype
Table instance 𝑆 ⊢ tableinst : tabletype
Function instance 𝑆 ⊢ funcinst : deftype
Data instance 𝑆 ⊢ datainst : ok
Element instance 𝑆 ⊢ eleminst : 𝑡
Structure instance 𝑆 ⊢ structinst : ok
Array instance 𝑆 ⊢ arrayinst : ok
Export instance 𝑆 ⊢ exportinst : ok
Module instance 𝑆 ⊢ moduleinst : 𝐶
Store ⊢ store : ok
Configuration ⊢ config : [𝑡* ]
Thread 𝑆; resulttype ? ⊢ thread : resulttype
Frame 𝑆 ⊢ frame : 𝐶

7.11.4 Constantness

Construct Judgement
Constant expression 𝐶 ⊢ expr const
Constant instruction 𝐶 ⊢ instr const

7.11.5 Matching

Construct Judgement
Number type 𝐶 ⊢ numtype 1 ≤ numtype 2
Vector type 𝐶 ⊢ vectype 1 ≤ vectype 2
Heap type 𝐶 ⊢ heaptype 1 ≤ heaptype 2
Reference type 𝐶 ⊢ reftype 1 ≤ reftype 2
Value type 𝐶 ⊢ valtype 1 ≤ valtype 2
Packed type 𝐶 ⊢ packtype 1 ≤ packtype 2
Storage type 𝐶 ⊢ storagetype 1 ≤ storagetype 2
Field type 𝐶 ⊢ fieldtype 1 ≤ fieldtype 2
Result type 𝐶 ⊢ resulttype 1 ≤ resulttype 2
Instruction type 𝐶 ⊢ instrtype 1 ≤ instrtype 2
Composite type 𝐶 ⊢ comptype 1 ≤ comptype 2
Defined type 𝐶 ⊢ deftype 1 ≤ deftype 2
Limits 𝐶 ⊢ limits 1 ≤ limits 2
Tag type 𝐶 ⊢ tagtype 1 ≤ tagtype 2
Global type 𝐶 ⊢ globaltype 1 ≤ globaltype 2
Memory type 𝐶 ⊢ memtype 1 ≤ memtype 2
Table type 𝐶 ⊢ tabletype 1 ≤ tabletype 2
External type 𝐶 ⊢ externtype 1 ≤ externtype 2

7.11. Index of Semantic Rules 305


WebAssembly Specification, Release 3.0 (2025-11-14)

7.11.6 Store Extension

Construct Judgement
Tag instance ⊢ taginst 1 ⪯ taginst 2
Global instance ⊢ globalinst 1 ⪯ globalinst 2
Memory instance ⊢ meminst 1 ⪯ meminst 2
Table instance ⊢ tableinst 1 ⪯ tableinst 2
Function instance ⊢ funcinst 1 ⪯ funcinst 2
Data instance ⊢ datainst 1 ⪯ datainst 2
Element instance ⊢ eleminst 1 ⪯ eleminst 2
Structure instance ⊢ structinst 1 ⪯ structinst 2
Array instance ⊢ arrayinst 1 ⪯ arrayinst 2
Store ⊢ store 1 ⪯ store 2

7.11.7 Execution

Construct Judgement
*
Instruction 𝑆; 𝐹 ; instr * ˓→ 𝑆 ′ ; 𝐹 ′ ; instr ′
Expression 𝑆; 𝐹 ; expr ˓→ 𝑆 ′ ; 𝐹 ′ ; expr ′

306 Chapter 7. Appendix


Index

Symbols global, 24, 73


: abstract syntax global address, 82
administrative instruction, 87 global index, 23
global instance, 84
A global type, 13, 38
grammar, 5
abbreviations, 206
handler, 86
abstract syntax, 5, 177, 205, 247, 249
heap type, 9, 29, 35
array address, 82
host address, 82
array instance, 85
import, 26, 76
array type, 12, 36
instruction, 14–20, 48, 54, 55, 57, 60, 66, 120,
block type, 11, 15, 36
133, 134, 137, 144, 157, 159
byte, 7
instruction type, 31, 36
composite type, 12, 36
integer, 7
data, 25, 74
label, 86
data address, 82
label index, 23
data index, 23
limits, 12, 38
data instance, 85
list, 6
data type, 13
local, 25, 74
defined type, 30, 44
local index, 23
element, 25, 75
local type, 32
element address, 82
memory, 24, 73
element index, 23
memory address, 82
element instance, 85
memory index, 23
element mode, 25
memory instance, 84
element type, 13
memory type, 13, 38
exception address, 82
module, 23, 77
exception instance, 86
module instance, 83
export, 26, 76
mutability, 13
export instance, 85
name, 8
expression, 23, 70, 164
notation, 5
external address, 83
number type, 9, 34
external index, 26
packed type, 12, 36
external type, 13, 39
packed value, 85
field index, 23
recursive type, 12, 37
field type, 12, 36
recursive type index, 29
field value, 85
reference type, 10, 35
floating-point number, 7
result, 82
frame, 86
result type, 11, 36
function, 25, 74
signed integer, 7
function address, 82
start function, 26, 75
function index, 23
storage type, 12, 36
function instance, 84
store, 82
function type, 12, 36
structure address, 82

307
WebAssembly Specification, Release 3.0 (2025-11-14)

structure instance, 85 array address


structure type, 12, 36 abstract syntax, 82
sub type, 12, 29, 37 array instance, 82, 85, 117, 255, 258, 265
table, 25, 73 abstract syntax, 85
table address, 82 array type, 12, 36, 40, 43, 85, 117, 181, 213, 255,
table index, 23 268, 289
table instance, 84 abstract syntax, 12
table type, 13, 38 binary format, 181
tag, 24, 72 text format, 213
tag address, 82 validation, 36
tag index, 23 ASCII, 207, 208, 210
tag instance, 85
tag type, 13, 38 B
type, 9, 72 binary format, 8, 177, 240, 247, 250, 268, 276
type definition, 24 aggregate type, 181
type index, 23 array type, 181
type use, 9, 35 block type, 183
uninterpreted integer, 7 byte, 179
unsigned integer, 7 composite type, 181
value, 7, 81 custom section, 199
value type, 11, 29, 35, 36 data, 202
vector, 8 data count, 202
vector type, 35 data index, 198
abstract type, 9, 29 element, 201
activation, 86 element index, 198
active, 25, 25 export, 200
address, 82, 120, 133, 134, 137, 165 expression, 198
array, 82 external type, 183
data, 82 field index, 198
element, 82 field type, 181
exception, 82 floating-point number, 179
external, 83 function, 200, 201
function, 82 function index, 198
global, 82 function type, 181
host, 82 global, 200
memory, 82 global index, 198
structure, 82 global type, 182
table, 82 grammar, 177
tag, 82 heap type, 180
address type, 213, 288 import, 200
text format, 213 instruction, 183–187, 191
administrative instruction, 260, 261 integer, 179
: abstract syntax, 87 label index, 198
administrative instructions, 87 limits, 182
aggregate instruction, 186, 221 list, 178
aggregate reference, 62 local, 201
aggregate type, 12, 24, 36, 43, 181, 213 local index, 198
binary format, 181 memory, 200
text format, 213 memory index, 198
validation, 36 memory type, 182
algorithm, 268 module, 203
allocation, 82, 165, 240, 251 mutability, 182
annotation, 209, 276, 291 name, 179
arithmetic NaN, 7 notation, 177
array, 12, 81, 117 number type, 180
address, 82 packed type, 181
instance, 85 recursive type, 182
type, 12 reference type, 181

308 Index
WebAssembly Specification, Release 3.0 (2025-11-14)

result type, 181 text format, 213


section, 198 validation, 36
signed integer, 179 composite types, 43
start function, 201 compositionality, 268
storage type, 181 concepts, 3
structure type, 181 concrete type, 9, 29
sub type, 182 configuration, 80, 88, 260, 265
table, 200 constant, 23–25, 70, 73–75, 81, 286
table index, 198 context, 32, 47, 48, 54, 55, 57, 77, 203, 252, 259, 261
table type, 183 control frame, 86
tag, 202 control instruction, 15
tag index, 198 control instructions, 48, 120, 183, 216
tag type, 182 custom annotation, 279
type, 180 custom section, 199, 276, 279, 291
type index, 198 binary format, 199
type section, 200
uninterpreted integer, 179 D
unsigned integer, 179 data, 23, 24, 25, 74, 87, 166, 202, 203, 233, 235, 249
value, 178 abstract syntax, 25
value type, 181 address, 82
vector type, 180 binary format, 202
bit, 90 index, 23
bit width, 7, 9, 12, 88, 137 instance, 85
block, 11, 15, 48, 120, 130, 183, 216, 282 section, 202
type, 11, 15 segment, 25, 74, 202, 233, 235
block type, 11, 15, 36, 48, 183 text format, 233, 235
abstract syntax, 11, 15 type, 13
binary format, 183 validation, 74
validation, 36 data address, 83, 166, 167
Boolean, 3, 90, 91 abstract syntax, 82
bottom type, 29, 252 data count, 202
branch, 15, 48, 120, 183, 216 binary format, 202
byte, 7, 8, 25, 74, 84, 85, 91, 165, 177, 179, 202, 210,section, 202
211, 233, 235, 244, 256, 258 data count section, 202
abstract syntax, 7 data index, 23, 25, 198, 231
binary format, 179 abstract syntax, 23
text format, 210 binary format, 198
text format, 231
C data instance, 82, 83, 85, 166, 167, 255, 258, 264
call, 86, 87, 131, 286 abstract syntax, 85
call frame, 86 data section, 202
canonical NaN, 7 data segment, 77, 84, 85, 167, 202, 236, 283, 287
cast, 18 data type, 13
caught, 87 abstract syntax, 13
caught exception, 87 declaration, 236
changes, 281 declarative, 25
character, 2, 8, 207, 207, 208, 210, 211, 249, 251 decoding, 4
text format, 207 default value, 81
closed type, 29 defaultable, 73
closure, 84 defined type, 13, 30, 31, 40, 44, 72, 85, 116, 254,
code, 14, 250 255, 257, 258, 268
section, 201 abstract syntax, 30, 44
code section, 201 design goals, 1
comment, 207, 208 determinism, 88, 99, 134, 141, 157, 249, 291
composite type, 12, 12, 36, 37, 181, 182, 213, 268, deterministic profile, 249
289 dynamic type, 116
abstract syntax, 12
binary format, 181

Index 309
WebAssembly Specification, Release 3.0 (2025-11-14)

E validation, 76
element, 13, 23, 25, 25, 75, 87, 166, 201, 203, 233, export instance, 83, 85, 167, 242, 259
235, 243, 249 abstract syntax, 85
abstract syntax, 25 export section, 200
address, 82 expression, 23, 24, 25, 70, 73–75, 164, 198, 200–202,
binary format, 201 231–233, 235, 286
index, 23 abstract syntax, 23
instance, 85 binary format, 198
mode, 25 constant, 23, 70, 198, 231
section, 201 execution, 164
segment, 25, 75, 201, 233, 235 text format, 231
text format, 233, 235 validation, 70
type, 13 external
validation, 75 address, 83
element address, 83, 134, 166, 167 type, 13
abstract syntax, 82 external address, 13, 83, 85, 118, 167, 259
element expression, 85 abstract syntax, 83
element index, 23, 25, 198, 231 external index, 26, 236
abstract syntax, 23 abstract syntax, 26
binary format, 198 external reference, 65, 81
text format, 231 external type, 13, 39, 46, 118, 167, 183, 214, 247,
element instance, 82, 83, 85, 134, 166, 167, 255, 259
258, 264 abstract syntax, 13
abstract syntax, 85 binary format, 183
element mode, 25 text format, 214
abstract syntax, 25 validation, 39
element section, 201
element segment, 77, 84, 85, 167, 236, 282, 283 F
element type, 13, 46 field, 23, 278, 279
abstract syntax, 13 index, 23
embedder, 2, 3, 82, 84, 85, 239 field index, 23, 198, 278
embedding, 239 abstract syntax, 23
evaluation context, 80 binary format, 198
exception, 15, 82, 86, 87, 130, 171, 174, 245, 254, field type, 12, 36, 43, 44, 181, 213, 258, 265, 268,
286 289
address, 82 abstract syntax, 12
instance, 86 binary format, 181
exception address, 82, 245 text format, 213
abstract syntax, 82 validation, 36
exception handling, 183 field value, 85, 258, 265
exception instance, 82, 86, 245, 259, 265 abstract syntax, 85
abstract syntax, 86 file extension, 177, 205
exception tag, 13, 38, 72, 85, 119, 130, 182, 202, final, 12, 37
232 floating point, 2
exception type, 245 floating-point, 3, 7, 8, 9, 19, 81, 88, 90, 97, 282
execution, 4, 9, 11, 79, 247, 251 floating-point number, 179, 210
expression, 164 abstract syntax, 7
instruction, 120, 133, 134, 137, 144, 157, 159 binary format, 179
expand, 254 text format, 210
expansion, 31 folded instruction, 230
exponent, 7, 90 frame, 86, 87, 88, 120, 131, 133, 134, 137, 251, 260–
export, 23, 26, 76, 77, 85, 167, 174, 200, 203, 232– 262, 268
234, 236, 241, 242, 249, 283, 287 abstract syntax, 86
abstract syntax, 26 full profile, 249
binary format, 200 funciton type, 43
instance, 85 function, 2, 3, 10–12, 15, 23, 25, 26, 32, 74, 77, 83,
section, 200 84, 86, 87, 117, 131, 166, 167, 174, 200, 201,
text format, 232–234, 236

310 Index
WebAssembly Specification, Release 3.0 (2025-11-14)

203, 234, 236, 242, 249–251, 277–279, 282, abstract syntax, 84


286, 288, 291 global section, 200
abstract syntax, 25, 74 global type, 13, 13, 24, 26, 29, 32, 38, 39, 45, 46, 73,
address, 82 76, 119, 165, 182, 200, 214, 232, 236, 245,
binary format, 200, 201 255, 256
export, 26 abstract syntax, 13
import, 26 binary format, 182
index, 23 text format, 214
instance, 84 validation, 38
section, 200 grammar notation, 5, 177, 205
text format, 234 greatest lower bound, 267
type, 12 grow, 167
function address, 83, 84, 87, 119, 166, 167, 174,
242, 243, 256 H
abstract syntax, 82 handler, 86, 87, 130, 262, 286
function index, 15, 23, 25, 26, 48, 74–76, 120, 167, abstract syntax, 86
183, 198, 200, 201, 216, 231, 233–236, 277 heap type, 9, 10, 18, 29, 35, 40, 180, 212, 233, 252,
abstract syntax, 23 254, 288, 289
binary format, 198 abstract syntax, 9, 29
text format, 231 binary format, 180
function instance, 82, 83, 84, 87, 117, 131, 166, text format, 212
167, 174, 242, 251, 255, 257, 262, 264 validation, 35
abstract syntax, 84 host, 2, 82, 239
function section, 200 address, 82
function type, 10, 11, 12, 13, 15, 24, 26, 29, 32, 36, host address, 81
38–40, 46, 72, 74, 76, 83, 117, 119, 120, 166, abstract syntax, 82
174, 181, 182, 200, 201, 203, 213, 214, 232, host function, 84, 132, 242, 257
234, 236, 242, 245, 255, 257, 268, 288
abstract syntax, 12 I
binary format, 181 identifier, 205, 206, 231–234, 236, 251, 291
text format, 213 identifier context, 206, 236
validation, 36 identifiers, 211
function type index, 202 text format, 211
IEEE 754, 2, 3, 7, 9, 90, 97
G implementation, 239, 249
global, 13, 16, 23, 24, 26, 32, 73, 77, 83, 84, 165, 167, implementation limitations, 249
200, 203, 232, 236, 245, 249 import, 2, 13, 23–25, 26, 74, 76, 77, 118, 167, 200,
abstract syntax, 24 203, 232–234, 236, 241, 249, 283, 287
address, 82 abstract syntax, 26
binary format, 200 binary format, 200
export, 26 section, 200
import, 26 text format, 232–234, 236
index, 23 validation, 76
instance, 84 import section, 200
mutability, 13 index, 23, 26, 76, 83, 198, 200, 206, 215, 231–234,
section, 200 236, 277
text format, 232 data, 23
type, 13 element, 23
validation, 73 field, 23
global address, 83, 119, 133, 165, 167, 245 function, 23
abstract syntax, 82 global, 23
global index, 16, 23, 24, 26, 54, 76, 133, 167, 184, label, 23
198, 200, 217, 231, 232, 236 local, 23
abstract syntax, 23 memory, 23
binary format, 198 table, 23
text format, 231 tag, 23
global instance, 82, 83, 84, 133, 165, 167, 245, 251, type, 23
255, 256, 262, 264 index space, 23, 26, 29, 32, 206, 277

Index 311
WebAssembly Specification, Release 3.0 (2025-11-14)

instance, 83, 171 memory, 13


array, 85 table, 13
data, 85 text format, 214
element, 85 validation, 38
exception, 86 linear memory, 3
export, 85 list, 6, 11, 12, 15, 25, 48, 120, 178, 183, 207, 216
function, 84 abstract syntax, 6
global, 84 binary format, 178
memory, 84 text format, 207
module, 83 little endian, 17, 91, 179
structure, 85 local, 16, 23, 25, 31, 32, 74, 86, 201, 234, 249, 261,
table, 84 277, 279, 288, 291
tag, 85 abstract syntax, 25
instantiation, 4, 9, 26, 171, 241, 265 binary format, 201
instantiation. module, 29 index, 23
instruction, 3, 11, 14, 23, 31, 47, 69, 84, 86–88, 120, text format, 234
130, 183, 215, 249, 261, 262, 266, 268, 282, type, 32
283, 286–288, 291, 292 validation, 74
abstract syntax, 14–20 local index, 16, 23, 25, 31, 32, 54, 74, 133, 184, 198,
binary format, 183–187, 191 217, 231, 277
execution, 120, 133, 134, 137, 144, 157, 159 abstract syntax, 23
text format, 216–218, 220, 221, 224 binary format, 198
type, 31 text format, 231
validation, 48, 54, 55, 57, 60, 66 local type, 32, 32, 69, 74, 288
instruction sequence, 69, 130 abstract syntax, 32
instruction type, 31, 36, 43, 47, 83, 266–268, 288
abstract syntax, 31 M
validation, 36 magnitude, 7
instructions, 283 mantissa, 210
integer, 3, 7, 8, 9, 19, 81, 88, 90, 91, 134, 137, 179, matching, 39, 167, 288
209, 282 memmory argument, 57
abstract syntax, 7 memory, 3, 9, 13, 17, 23, 24, 25, 26, 32, 73, 74, 77, 83,
binary format, 179 84, 87, 91, 165, 167, 200, 202, 203, 233, 235,
signed, 7 236, 244, 249, 283, 287, 288
text format, 209 abstract syntax, 24
uninterpreted, 7 address, 82
unsigned, 7 binary format, 200
invocation, 4, 84, 174, 242, 265 data, 25, 74, 202, 233, 235
export, 26
K import, 26
keyword, 207 index, 23
instance, 84
L limits, 12, 13
label, 15, 48, 86, 87, 120, 131, 183, 216, 251, 262, 268 section, 200
abstract syntax, 86 text format, 233
index, 23 type, 13
label index, 15, 23, 48, 120, 183, 198, 215, 216, 231 validation, 73
abstract syntax, 23 memory address, 83, 119, 137, 165, 167, 244
binary format, 198 abstract syntax, 82
text format, 215, 231 memory index, 17, 23, 24–26, 57, 74, 76, 137, 167,
lane, 8, 90 185, 198, 200, 202, 218, 231, 233, 235, 236,
least upper bound, 267 287
LEB128, 179, 183 abstract syntax, 23
lexical format, 207 binary format, 198
limits, 12, 13, 24, 25, 38, 45, 46, 134, 137, 165–167, text format, 231
182, 183, 214, 256 memory instance, 82, 83, 84, 87, 137, 165, 167, 244,
abstract syntax, 12 251, 255, 256, 262, 264
binary format, 182 abstract syntax, 84

312 Index
WebAssembly Specification, Release 3.0 (2025-11-14)

memory instruction, 17, 57, 137, 185, 218 O


memory section, 200 offset, 23
memory type, 12, 13, 13, 24, 26, 29, 32, 38, 39, 46, opcode, 183, 268, 273
73, 76, 84, 119, 165, 182, 200, 214, 233, 236, operand, 14
244, 255, 256 operand stack, 14, 47
abstract syntax, 13
binary format, 182 P
text format, 214
packed type, 12, 36, 44, 90, 181, 213, 258, 268
validation, 38
abstract syntax, 12
module, 2, 3, 23, 32, 77, 82, 84, 167, 171, 174, 177,
binary format, 181
203, 236, 240, 242, 249, 250, 265, 268, 277,
text format, 213
278, 291
validation, 36
abstract syntax, 23
packed value, 85, 258
binary format, 203
abstract syntax, 85
instance, 83
page size, 13, 17, 24, 84, 182, 214, 233
text format, 236
parameter, 12, 23, 249, 278
validation, 77
parametric instruction, 14, 120, 183, 216
module instance, 84, 86, 116, 166, 167, 174, 241,
parametric instructions, 48
242, 251, 259, 261
passive, 25, 25
abstract syntax, 83
payload, 7
module instruction, 88
phases, 4
mutability, 13, 13, 24, 36, 38, 44, 45, 84, 119, 165,
polymorphism, 47, 48, 183, 216, 266
181, 182, 213, 214, 256, 264
portability, 1
abstract syntax, 13
preservation, 265
binary format, 182
principal types, 266
global, 13
profile, 247
text format, 214
deterministic, 249
full, 249
N profiles, 291
name, 2, 8, 26, 76, 83, 85, 179, 200, 211, 232–234, 236, progress, 265
249, 259, 276, 278
abstract syntax, 8 R
binary format, 179
reachability, 256
text format, 211
recursive type, 12, 30, 31, 37, 44, 72, 77, 182, 200,
name annotation, 278
213, 231, 236, 252, 254, 268, 289
name map, 277
abstract syntax, 12, 37
name section, 236, 276
binary format, 182
NaN, 7, 88, 99, 157
text format, 213
arithmetic, 7
recursive type index, 12, 29, 252, 254
canonical, 7
abstract syntax, 29
payload, 7
reduction rules, 80
non-determinism, 88, 99, 134, 141, 157, 249, 291
reference, 10, 18, 81, 134, 144, 216, 246, 258, 282,
notation, 5, 177, 205
288, 289
abstract syntax, 5
type, 10
binary format, 177
reference instruction, 18, 18, 186, 220
text format, 205
reference instructions, 60, 144
null, 10, 18
reference type, 10, 11, 13, 18, 35, 38, 42, 60, 73, 81,
null reference, 117
134, 181, 183, 212, 214, 233, 246, 252, 268,
number, 20, 81
282, 286, 288, 289
type, 9
abstract syntax, 10
number type, 9, 11, 34, 35, 39, 42, 81, 180, 181, 212,
binary format, 181
268, 288
text format, 212
abstract syntax, 9
validation, 35
binary format, 180
reftype, 87
text format, 212
result, 12, 82, 242, 249, 254
validation, 34
abstract syntax, 82
numeric instruction, 19, 66, 157, 187, 221
type, 11
numeric vector, 8, 20, 90

Index 313
WebAssembly Specification, Release 3.0 (2025-11-14)

result type, 11, 12, 29, 31, 32, 36, 43, 48, 70, 120, validation, 36
181, 183, 213, 216, 254, 261, 262, 282 store, 9, 79, 82, 82, 83, 86, 88, 117, 118, 120, 132–
abstract syntax, 11 134, 137, 165, 171, 174, 240, 242–245, 255,
binary format, 181 258, 260–262
validation, 36 abstract syntax, 82
rewrite rule, 206 store extension, 262
roll, 12 string, 210
rolling, 29, 31 text format, 210
rounding, 98 structure, 12, 81, 117
runtime, 81, 304 address, 82
instance, 85
S type, 12
S-expression, 205, 230 structure address
scalar reference, 65, 117 abstract syntax, 82
section, 198, 203, 250, 276 structure field, 291
binary format, 198 structure instance, 82, 85, 117, 255, 258, 265
code, 201 abstract syntax, 85
custom, 199 structure type, 12, 36, 40, 43, 85, 117, 181, 213,
data, 202 255, 268, 279, 289
data count, 202 abstract syntax, 12
element, 201 binary format, 181
export, 200 text format, 213
function, 200 validation, 36
global, 200 structured control, 15, 48, 120, 183, 216
import, 200 structured control instruction, 249
memory, 200 sub type, 12, 29, 31, 37, 182, 213, 252, 268, 289
name, 236 abstract syntax, 12, 29, 37
start, 201 binary format, 182
table, 200 text format, 213
tag, 202 substitution, 30
type, 200 subtyping, 12, 29, 37, 39, 247, 266–268, 288
security, 2 syntax, 266
segment, 87
shape, 90 T
sign, 91 table, 3, 10, 13, 15, 16, 23, 25, 25, 26, 32, 73, 75, 77,
signed integer, 7, 91, 179, 209 83, 84, 87, 166, 167, 200, 203, 233, 236, 243,
abstract syntax, 7 249, 282, 283, 288
binary format, 179 abstract syntax, 25
text format, 209 address, 82
significand, 7, 90 binary format, 200
SIMD, 8, 9, 20, 283, 291 element, 25, 75, 201, 233, 235
soundness, 252, 265 export, 26
source text, 207, 207, 251 import, 26
stack, 79, 86, 174, 268 index, 23
stack machine, 14 instance, 84
stack type, 15 limits, 12, 13
start function, 23, 26, 75, 77, 201, 203, 236 section, 200
abstract syntax, 26 text format, 233
binary format, 201 type, 13
section, 201 validation, 73
text format, 236 table address, 83, 119, 120, 134, 166, 167, 243
validation, 75 abstract syntax, 82
start section, 201 table index, 16, 23, 25, 26, 55, 75, 76, 134, 167, 185,
state, 88 198, 200, 201, 218, 231, 233, 235, 236, 283
storage type, 12, 36, 44, 181, 213, 258, 289 abstract syntax, 23
abstract syntax, 12 binary format, 198
binary format, 181 text format, 231
text format, 213

314 Index
WebAssembly Specification, Release 3.0 (2025-11-14)

table instance, 82, 83, 84, 87, 120, 134, 166, 167, export, 232–234, 236
243, 251, 255, 256, 262, 264 expression, 231
abstract syntax, 84 external type, 214
table instruction, 16, 55, 134, 185, 218 field type, 213
table section, 200 floating-point number, 210
table type, 12, 13, 13, 25, 26, 29, 32, 38, 39, 46, function, 234
73, 76, 84, 119, 166, 183, 200, 214, 233, 236, function index, 231
243, 255, 256, 282 function type, 213
abstract syntax, 13 global, 232
binary format, 183 global index, 231
text format, 214 global type, 214
validation, 38 grammar, 205
tag, 13, 15, 23, 24, 26, 32, 72, 77, 83, 85–87, 130, 165, heap type, 212
167, 202, 203, 232, 236, 245, 249, 259, 278, identifiers, 211
279, 286 import, 232–234, 236
abstract syntax, 24 instruction, 216–218, 220, 221, 224
address, 82 integer, 209
binary format, 202 label index, 215, 231
export, 26 limits, 214
import, 26 list, 207
index, 23 local, 234
instance, 85 local index, 231
section, 202 memory, 233
text format, 232 memory index, 231
type, 13 memory type, 214
validation, 72 module, 236
tag address, 83, 86, 87, 119, 165, 167, 245, 259 mutability, 214
abstract syntax, 82 name, 211
tag index, 23, 26, 48, 76, 167, 183, 198, 200, 216, notation, 205
231, 232, 236, 278 number type, 212
abstract syntax, 23 packed type, 213
binary format, 198 recursive type, 213
text format, 231 reference type, 212
tag instance, 82, 83, 85, 87, 165, 167, 245, 255, 256, signed integer, 209
263 start function, 236
abstract syntax, 85 storage type, 213
tag section, 202 string, 210
tag type, 13, 13, 15, 24, 26, 29, 32, 38, 45, 46, 72, 76, structure type, 213
85, 119, 165, 182, 200, 202, 214, 232, 236, sub type, 213
245, 255, 256, 286 table, 233
abstract syntax, 13 table index, 231
binary format, 182 table type, 214
text format, 214 tag, 232
validation, 38 tag index, 231
terminal configuration, 265 tag type, 214
text format, 2, 205, 240, 247, 251, 276, 291 token, 207
address type, 213 type, 211, 231
aggregate type, 213 type index, 231
annotation, 209 type use, 214
array type, 213 uninterpreted integer, 209
byte, 210 unsigned integer, 209
character, 207 value, 209
comment, 208 value type, 212
composite type, 213 vector type, 212
data, 233, 235 white space, 208
data index, 231 thread, 88, 261, 265
element, 233, 235 throw, 254
element index, 231 throw context, 130, 262

Index 315
WebAssembly Specification, Release 3.0 (2025-11-14)

token, 207, 251 abstract syntax, 7


trap, 3, 15–17, 82, 87, 130, 157, 171, 174, 254, 261, binary format, 179
282 text format, 209
try block, 15 unroll, 12, 44, 254
two's complement, 3, 7, 19, 91, 179 unrolling, 29, 31
type, 9, 72, 116, 167, 180, 211, 231, 249, 277–279, unsigned integer, 7, 91, 179, 209
291, 304 abstract syntax, 7
abstract syntax, 9, 72 binary format, 179
array, 12 text format, 209
binary format, 180 unwinding, 15
block, 11, 15 UTF-8, 2, 8, 179, 205, 210
data, 13
element, 13 V
external, 13 validation, 4, 9, 29, 117, 118, 120, 240, 247, 251,
function, 12 258, 268, 304
global, 13 aggregate type, 36
index, 23 array type, 36
instruction, 31 block type, 36
local, 32 composite type, 36
memory, 13 data, 74
number, 9 element, 75
reference, 10 export, 76
result, 11 expression, 70
section, 200 external type, 39
structure, 12 field type, 36
table, 13 function type, 36
tag, 13 global, 73
text format, 211, 231 global type, 38
value, 11 heap type, 35
type closure, 33 import, 76
type definition, 23, 24, 77, 200, 203, 236 instruction, 48, 54, 55, 57, 60, 66
abstract syntax, 24 instruction type, 36
type equivalence, 31, 44 limits, 38
type index, 9, 11, 15, 23, 24–26, 29, 35, 48, 72, 74, local, 74
116, 120, 183, 198, 200, 201, 216, 231, 234, memory, 73
277, 278 memory type, 38
abstract syntax, 23 module, 77
binary format, 198 number type, 34
text format, 231 packed type, 36
type instance, 82, 83 reference type, 35
type instantiation, 116 result type, 36
type lattice, 267 start function, 75
type section, 200 storage type, 36
binary format, 200 structure type, 36
type system, 29, 252, 266 table, 73
type use, 9, 9, 13, 35, 214 table type, 38
abstract syntax, 9 tag, 72
text format, 214 tag type, 38
validation, 35 type use, 35
typing rules, 33 value type, 35
vector type, 35
U validity, 265
unboxed scalar, 9, 81 value, 3, 7, 19, 20, 24, 47, 81, 82, 84, 86, 88, 117, 120,
unboxed scalar type, 40 133, 134, 137, 157, 165, 174, 178, 209, 242,
Unicode, 2, 8, 179, 205, 207, 210, 249 245, 246, 251, 254, 256, 261, 264
unicode, 251 abstract syntax, 7, 81
Unicode UTF-8, 276, 278 binary format, 178
uninterpreted integer, 7, 91, 179, 209 text format, 209

316 Index
WebAssembly Specification, Release 3.0 (2025-11-14)

type, 11
value type, 11, 11, 13–15, 19, 20, 25, 29, 31, 32, 35,
36, 38, 42–45, 48, 74, 81, 90, 117, 119, 137,
157, 165, 181–183, 212–214, 216, 246, 247,
252, 254, 261, 268, 282, 283, 288
abstract syntax, 11, 29
binary format, 181
text format, 212
validation, 35
variable instruction, 16
variable instructions, 54, 133, 184, 217
vector
abstract syntax, 8
vector instruction, 20, 66, 159, 191, 224, 291
vector number, 81
vector type, 9, 11, 35, 39, 81, 180, 212, 268, 283
binary format, 180
text format, 212
validation, 35
version, 203

W
white space, 207, 208

Index 317

You might also like