WebAssembly (abbreviated Wasm [1]) 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 Group.
This document describes version 1.0 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 GoalsThe design goals of WebAssembly are the following:
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. ScopeAt 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 encoding, 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.2. Security ConsiderationsWebAssembly provides no ambient access to the computing environment in which code is executed. Any interaction 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 capabilities 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.2.1. DependenciesWebAssembly depends on two existing standards:
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.
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.3. Overview 1.3.1. ConceptsWebAssembly encodes a low-level, assembly-like programming language. This language is structured around the following concepts.
Conceptually, the semantics of WebAssembly is divided into three phases. For each part of the language, the specification specifies each of them.
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.
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 NotationThe following conventions are adopted in defining grammar rules for abstract syntax.
When dealing with syntactic constructs the following notation is also used:
Moreover, the following conventions are employed:
Productions of the following form are interpreted as records that map a fixed set of fields fieldi to “values” Ai, respectively:
r ::= {field1 A1,field2 A2,…}
The following notation is adopted for manipulating such records:
r.field denotes the contents of the field component of r.
rwithfield=A denotes the same record as r, except that the contents of the field component is replaced with A.
r1⊕r2 denotes the composition of two records with the same fields of sequences by appending each sequence point-wise:
{field1A1∗,field2A2∗,…}⊕{field1B1∗,field2B2∗,…}={field1A1∗ B1∗,field2A2∗ B2∗,…}⨁r∗ 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)+:
where rwith .field=A is shortened to rwithfield=A.
2.1.3. VectorsVectors are bounded sequences of the form An (or A∗), where the A can either be values or complex constructions. A vector can have at most 232−1 elements.
2.2. ValuesWebAssembly 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. BytesThe simplest form of value are raw uninterpreted bytes. In the abstract syntax they are represented as hexadecimal literals.
2.2.1.1. ConventionsDifferent classes of integers with different value ranges are distinguished by their bit width N and by whether they are unsigned or signed.
uNsNiN::=::=::=0 ∣ 1 ∣ … ∣ 2N−1−2N−1 ∣ … ∣ −1 ∣ 0 ∣ 1 ∣ … ∣ 2N−1−1uNThe latter class 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 u32, u64, s32, s64, i8, i16, i32, i64. However, other sizes occur as auxiliary constructions, e.g., in the definition of floating-point numbers.
2.2.2.1. ConventionsFloating-point data represents 32 or 64 bit values that correspond to the respective binary formats of the [IEEE-754-2019] standard (Section 3.3).
Every value has a sign and a magnitude. Magnitudes can either be expressed as normal numbers of the form m0.m1m2…mM⋅2e, where e is the exponent and m is the significand whose most signifcant bit m0 is 1, or as a subnormal number where the exponent is fixed to the smallest possible value and m0 is 0; among the subnormals are positive and negative zero values. Since the significands are binary values, normals are represented in the form (1+m⋅2−M)⋅2e, where M is the bit width of m; 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.
where M=signif(N) and E=expon(N) with
A canonical NaN is a floating-point value ±nan(canonN) where canonN is a payload whose most significant bit is 1 while all others are 0:
An arithmetic NaN is a floating-point value ±nan(n) with n≥canonN, 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.
2.2.3.1. ConventionsNames are sequences of characters, which are scalar values as defined by [UNICODE] (Section 2.4).
Due to the limitations of the binary format, the length of a name is bounded by the length of its UTF-8 encoding.
2.2.4.1. ConventionVarious entities in WebAssembly are classified by types. Types are checked during validation, instantiation, and possibly execution.
2.3.1. Value TypesValue types classify the individual values that WebAssembly code can compute with and the values that a variable accepts.
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 f32 and f64 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-754-2019] standard (Section 3.3).
2.3.1.1. ConventionsResult types classify the result of executing instructions or blocks, which is a sequence of values written with brackets.
Note
In the current version of WebAssembly, at most one value is allowed as a result. However, this may be generalized to sequences of values in future versions.
2.3.3. Function TypesFunction types classify the signature of functions, mapping a vector of parameters to a vector of results, written as follows.
Note
In the current version of WebAssembly, the length of the result type vector of a valid function type may be at most 1. This restriction may be removed in future versions.
2.3.4. LimitsLimits classify the size range of resizeable storage associated with memory types and table types.
If no maximum is given, the respective storage can grow to any size.
2.3.5. Memory TypesMemory types classify linear memories and their size range.
The limits constrain the minimum and optionally the maximum size of a memory. The limits are given in units of page size.
2.3.6. Table TypesTable types classify tables over elements of element types within a size range.
Like memories, tables are constrained by limits for their minimum and optionally maximum size. The limits are given in numbers of entries.
The element type funcref is the infinite union of all function types. A table of that type thus contains references to functions of heterogeneous type.
Note
In future versions of WebAssembly, additional element types may be introduced.
2.3.7. Global TypesGlobal types classify global variables, which hold a value and can either be mutable or immutable.
2.4. InstructionsWebAssembly 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.
Note
In the current version of WebAssembly, at most one result value can be pushed by a single instruction. This restriction may be lifted in future versions.
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 bracket nested sequences of instructions.
The following sections group instructions into a number of different categories.
2.4.1. Numeric InstructionsNumeric instructions provide basic operations over numeric values of specific type. These operations closely match respective operations available in hardware.
Numeric instructions are divided by value type. For each type, several subcategories can be distinguished:
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.
2.4.1.1. ConventionsOccasionally, it is convenient to group operators together according to the following grammar shorthands:
2.4.2. Parametric InstructionsInstructions in this group can operate on operands of any value type.
The drop operator simply throws away a single operand.
The select operator selects one of its first two operands based on whether its third operand is zero or not.
2.4.3. Variable InstructionsVariable instructions are concerned with access to local or global variables.
These instructions get or set the values of variables, respectively. The local.tee instruction is like local.set but also returns its argument.
2.4.4. Memory InstructionsInstructions in this group are concerned with linear memory.
Memory is accessed with load and store instructions for the different value types. They all take a memory immediate memarg that contains an address offset and the expected alignment (expressed as the exponent of a power of 2). Integer loads and stores can optionally specify a storage size 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.
The static address offset is added to the dynamic address operand, yielding a 33 bit effective address that is the zero-based index at which the memory is accessed. All values are read and written in little endian byte order. A trap results if any of the accessed memory bytes lies outside the address range implied by the memory’s current size.
Note
Future version of WebAssembly might provide memory instructions with 64 bit address ranges.
The memory.size instruction returns the current size of a memory. The memory.grow instruction grows 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.
Note
In the current version of WebAssembly, all memory instructions implicitly operate on memory index 0. This restriction may be lifted in future versions.
2.4.5. Control InstructionsInstructions in this group affect the flow of control.
The nop instruction does nothing.
The unreachable instruction causes an unconditional trap.
The block, loop and if instructions are structured instructions. They bracket nested sequences of instructions, called blocks, terminated with, or separated by, end or else pseudo-instructions. As the grammar prescribes, they must be well-nested. A structured instruction can produce a value as described by the annotated result 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 matching end. In case of loop it is a backward jump to the beginning of the loop.
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 vector that is an immediate to the instruction, or to a default target if the operand is out of bounds. 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, forward branches that target a control instruction with a non-empty result type consume matching operands first and push them back on the operand stack after unwinding, as a result for the terminated structured instruction.
The call instruction invokes another function, consuming the necessary arguments from the stack and returning the result values of the call. The call_indirect instruction calls a function indirectly through an operand indexing into a table. Since tables may contain function elements of heterogeneous type funcref, the callee is dynamically checked against the function type indexed by the instruction’s immediate, and the call aborted with a trap if it does not match.
Note
In the current version of WebAssembly, call_indirect implicitly operates on table index 0. This restriction may be lifted in future versions.
2.4.6. ExpressionsFunction bodies, initialization values for globals, and offsets of element or data segments are given as expressions, which are sequences of instructions terminated by an end marker.
In some places, validation restricts expressions to be constant, which limits the set of allowable instructions.
2.5. ModulesWebAssembly programs are organized into modules, which are the unit of deployment, loading, and compilation. A module collects definitions for types, functions, tables, memories, and globals. In addition, it can declare imports and exports and provide initialization logic in the form of data and element segments or a start function.
Each of the vectors – and thus the entire module – may be empty.
2.5.1. IndicesDefinitions are referenced with zero-based indices. Each class of definition has its own index space, as distinguished by the following classes.
The index space for functions, tables, memories and globals includes respective imports declared in the same module. The indices of these imports precede the indices of other definitions in the same index space.
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.
2.5.1.1. ConventionsThe types component of a module defines a vector of function types.
All function types used in a module must be defined in this component. They are referenced by type indices.
Note
Future versions of WebAssembly may add additional forms of type definitions.
2.5.3. FunctionsThe funcs component of a module defines a vector of functions with the following structure:
The type of a function declares its signature by reference to a 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 vector 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.
The body is an instruction sequence that upon termination 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 import.
2.5.4. TablesThe tables component of a module defines a vector of tables described by their table type:
A table is a vector of opaque values of a particular table element type. The min size in the limits of the table type specifies the initial size of that table, while its max, if present, restricts the size to which it can grow later.
Tables can be initialized through element segments.
Tables are referenced through table indices, starting with the smallest index not referencing a table import. Most constructs implicitly reference table index 0.
Note
In the current version of WebAssembly, at most one table may be defined or imported in a single module, and all constructs implicitly reference this table 0. This restriction may be lifted in future versions.
2.5.5. MemoriesThe mems component of a module defines a vector of linear memories (or memories for short) as described by their memory type:
A memory is a vector of raw uninterpreted bytes. The min size in the limits of the memory type specifies the initial size of that memory, while its max, if present, restricts the size to which it can grow later. Both are in units of page size.
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.
Note
In the current version of WebAssembly, at most one memory may be defined or imported in a single module, and all constructs implicitly reference this memory 0. This restriction may be lifted in future versions.
2.5.6. GlobalsThe globals component of a module defines a vector of global variables (or globals for short):
Each global stores a single value of the given global type. Its type also specifies whether a global is immutable or mutable. Moreover, each global is initialized with an init 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.7. Element SegmentsThe initial contents of a table is uninitialized. The elem component of a module defines a vector of element segments that initialize a subrange of a table, at a given offset, from a static vector of elements.
The offset is given by a constant expression.
Note
In the current version of WebAssembly, at most one table is allowed in a module. Consequently, the only valid tableidx is 0.
2.5.8. Data SegmentsThe initial contents of a memory are zero-valued bytes. The data component of a module defines a vector of data segments that initialize a range of memory, at a given offset, with a static vector of bytes.
The offset is given by a constant expression.
Note
In the current version of WebAssembly, at most one memory is allowed in a module. Consequently, the only valid memidx is 0.
2.5.9. Start FunctionThe start component 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.
Note
The start function is intended for initializing the state of a module. The module and its exports are not accessible before this initialization has completed.
2.5.10. ExportsThe exports component of a module defines a set of exports that become accessible to the host environment once the module has been instantiated.
Each export is labeled by a unique name. Exportable definitions are functions, tables, memories, and globals, which are referenced through a respective descriptor.
2.5.11. ImportsThe imports component of a module defines a set of imports that are required for instantiation.
Each import is labeled by a two-level name space, consisting of a module name and a name for an entity within that module. Importable definitions are functions, tables, memories, and globals. Each import is specified by a descriptor with a respective 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/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.
3. Validation 3.1. ConventionsValidation 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:
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. ContextsValidity of an individual definition is specified relative to a context, which collects relevant information about the surrounding module and the definitions in scope:
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.
More concretely, contexts are defined as records C with abstract syntax:
In addition to field access written C.field the following notation is adopted for manipulating contexts:
Note
We use indexing notation like C.labels[i] to look up indices in their respective index space in the context. Context extension notation C,fieldA is primarily used to locally extend relative index spaces, such as label indices. Accordingly, the notation is defined to append at the front of the respective sequence, introducing a new relative index 0 and shifting the existing ones.
3.1.2. Prose NotationValidation 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 A is said to be “valid with type T” if and only if all constraints expressed by the respective rules are met. The form of T depends on what A is.
The rules implicitly assume a given context C.
In some places, this context is locally extended to a context C′ with additional entries. The formulation “Under context C′, … statement …” is adopted to express that the following statement must apply under the assumptions embodied in the extended context.
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. [2]
The proposition that a phrase A has a respective type T is written A:T. In general, however, typing is dependent on a context C. To express this explicitly, the complete form is a judgement C⊢A:T, which says that A:T holds under the assumptions encoded in C.
The formal typing rules use a standard approach for specifying type systems, rendering them into deduction rules. Every rule has the following general form:
conclusionpremise1premise2…premisen
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 C⊢A:T, and there is one respective rule for each relevant construct A of the abstract syntax.
Note
For example, the typing rule for the i32.add instruction can be given as an axiom:
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 local.get can be typed as follows:
Here, the premise enforces that the immediate local index x exists in the context. The instruction produces a value of its respective type t (and does not consume any values). If C.locals[x] 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:
A block instruction is only valid when the instruction sequence in its body is. Moreover, the result type must match the block’s annotation [t?]. If so, then the block instruction has the same type as the body. Inside the body an additional label of the same type is available, which is expressed by extending the context C with the additional label information for the premise.
3.2. TypesMost types are universally valid. However, restrictions apply to function types as well as the limits of table types and memory types, which must be checked during validation.
3.2.1. LimitsLimits must have meaningful bounds that are within a given range.
3.2.1.1. {min n,max m?}Function types may not specify more than one result.
3.2.2.1. [t1n]→[t2m]Note
The restriction to at most one result may be removed in future versions of WebAssembly.
3.2.4. Memory Types 3.2.4.1. limits 3.3. InstructionsInstructions are classified by function types [t1∗]→[t2∗] that describe how they manipulate the operand stack. The types describe the required input stack with argument values of types t1∗ that an instruction pops off and the provided output stack with result values of types t2∗ that it pushes back.
Note
For example, the instruction i32.add has type [i32 i32]→[i32], consuming two i32 values and producing one.
Typing extends to instruction sequences instr∗. Such a sequence has a function type [t1∗]→[t2∗] if the accumulative effect of executing the instructions is consuming values of types t1∗ off the operand stack and pushing new values of types t2∗.
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:
In both cases, the unconstrained types or type sequences can be chosen arbitrarily, as long as they meet the constraints imposed for the surrounding parts of the program.
Note
For example, the select instruction is valid with type [t t i32]→[t], for any possible value type t. Consequently, both instruction sequences
and
are valid, with t in the typing of select being instantiated to i32 or f64, respectively.
The unreachable instruction is valid with type [t1∗]→[t2∗] for any possible sequences of value types t1∗ and t2∗. Consequently,
is valid by assuming type []→[i32 i32] for the unreachable instruction. In contrast,
is invalid, because there is no possible type to pick for the unreachable instruction that would make the sequence well-typed.
3.3.1. Numeric Instructions 3.3.1.1. t.const cNote
The notation C,labels[t?] inserts the new label type at index 0, shifting all others.
The fact that the nested instruction sequence instr∗ must have type []→[t?] implies that it cannot access operands that have been pushed on the stack before the block was entered. This may be generalized in future versions of WebAssembly.
3.3.5.4. loop [t?] instr∗ endNote
The notation C,labels[] inserts the new label type at index 0, shifting all others.
The fact that the nested instruction sequence instr∗ must have type []→[t?] implies that it cannot access operands that have been pushed on the stack before the loop was entered. This may be generalized in future versions of WebAssembly.
3.3.5.5. if [t?] instr1∗ else instr2∗ endNote
The notation C,labels[t?] inserts the new label type at index 0, shifting all others.
The fact that the nested instruction sequence instr∗ must have type []→[t?] implies that it cannot access operands that have been pushed on the stack before the conditional was entered. This may be generalized in future versions of WebAssembly.
3.3.5.6. br lNote
The label index space in the context C contains the most recent label first, so that C.labels[l] performs a relative lookup as expected.
3.3.5.8. br_table l∗ lNNote
The return instruction is stack-polymorphic.
C.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.
3.3.5.10. call xTyping of instruction sequences is defined recursively.
3.3.6.1. Empty Instruction Sequence: ϵExpressions expr are classified by result types of the form [t?].
3.3.7.2. Constant ExpressionsNote
Currently, constant expressions occurring as initializers of globals are further constrained in that contained global.get instructions are only allowed to refer to imported globals. This is enforced in the validation rule for modules by constraining the context C accordingly.
The definition of constant expression may be extended in future versions of WebAssembly.
3.4. ModulesModules are valid when all the components they contain are valid. Furthermore, most definitions are themselves classified with a suitable type.
3.4.1. FunctionsFunctions func are classified by function types of the form [t1∗]→[t2?].
3.4.1.1. {type x,locals t∗,body expr}Note
The restriction on the length of the result types t2∗ may be lifted in future versions of WebAssembly.
3.4.5. Element SegmentsElement segments elem are not classified by a type.
3.4.6. Data SegmentsData segments data are not classified by any type.
3.4.7. Start FunctionStart function declarations start are not classified by any type.
3.4.7.1. {func x}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 C for validation of the module’s content is constructed from the definitions in the module.
Note
Most definitions in a module – particularly functions – are mutually recursive. Consequently, the definition of the context C 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 C. However, this recursion is just a specification device. All types needed to construct C can easily be determined from a simple pre-pass over the module that does not perform any actual validation.
Globals, however, are not recursive. The effect of defining the limited context C′ for validating the module’s globals is that their initialization expressions can only access imported globals and nothing else.
Note
The restriction on the number of tables and memories may be lifted in future versions of WebAssembly.
4. Execution 4.1. ConventionsWebAssembly 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:
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 NotationExecution is specified by stylised, step-wise rules for each instruction of the abstract syntax. The following conventions are adopted in stating these rules.
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. [2]
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↪configurationA 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 (S;F;instr∗) consisting of the current store S, the call frame F 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 S and the frame F are 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 instructions, and a sequence of const instructions can be interpreted as an operand “stack” that grows to the right.
Note
For example, the reduction rule for the i32.add instruction can be given as follows:
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 value off the stack and pushing the result.
When no result is produced, an instruction reduces to the empty sequence:
Labels and frames are similarly defined to be part of an instruction sequence.
The order of reduction is determined by the definition of an appropriate evaluation context.
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 const instructions, which can be interpreted as the values of the resulting operand stack, or if a trap occurred.
Note
For example, the following instruction sequence,
terminates after three steps:
where x4=−x2 and x5=−x2+x3 and x6=x1⋅(−x2+x3).
4.2. Runtime StructureStore, 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. ValuesWebAssembly computations manipulate values of the four basic value types: integers and floating-point data of 32 or 64 bit width each, respectively.
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 producing them:
4.2.2. ResultsA result is the outcome of a computation. It is either a sequence of values or a trap.
Note
In the current version of WebAssembly, a result can consist of at most one value.
4.2.3. StoreThe 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, and globals that have been allocated during the life time of the abstract machine. [1]
Syntactically, the store is defined as a record listing the existing instances of each category:
4.2.3.1. ConventionFunction instances, table instances, memory instances, and global instances in the store are referenced with abstract addresses. These are simply indices into the respective store component.
An embedder may assign identity to exported store objects corresponding to their addresses, even where this identity 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.
4.2.5. Module InstancesA 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.
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, and global instances are referenced with an indirection through 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.
4.2.6. Function InstancesA 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.
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, the embedder might provide implicit or explicit means for distinguishing their addresses.
4.2.7. Table InstancesA table instance is the runtime representation of a table. It holds a vector of function elements and an optional maximum size, if one was specified in the table type at the table’s definition site.
Each function element is either empty, representing an uninitialized table entry, or a function address. Function elements can be mutated through the execution of an element segment or by external means provided by the embedder.
It is an invariant of the semantics that the length of the element vector never exceeds the maximum size, if present.
Note
Other table elements may be added in future versions of WebAssembly.
4.2.8. Memory InstancesA memory instance is the runtime representation of a linear memory. It holds a vector of bytes and an optional maximum size, if one was specified at the definition site of the memory.
The length of the vector always is a multiple of the WebAssembly page size, which is defined to be the constant 65536 – abbreviated 64Ki. Like in a memory type, the maximum size in a memory instance is given in units of this page size.
The bytes can be mutated through memory instructions, the execution of a data segment, or by external means provided by the embedder.
It is an invariant of the semantics that the length of the byte vector, divided by page size, never exceeds the maximum size, if present.
4.2.9. Global InstancesA global instance is the runtime representation of a global variable. It holds an individual value and a flag indicating whether it is mutable.
The value of mutable globals can be mutated through variable instructions or by external means provided by the embedder.
4.2.10. Export InstancesAn export instance is the runtime representation of an export. It defines the export’s name and the associated external value.
4.2.12. StackBesides the store, most instructions interact with an implicit stack. The stack contains three kinds of entries:
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.
4.2.12.1. ValuesValues are represented by themselves.
4.2.12.2. LabelsLabels carry an argument arity n and their associated branch target, which is expressed syntactically as an instruction sequence:
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
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
When branching, the empty continuation ends the targeted block, such that execution can proceed with consecutive instructions.
4.2.12.3. Activations and FramesActivation frames carry the return arity n 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:
The values of the locals are mutated by respective variable instructions.
4.2.12.4. ConventionsNote
In the current version of WebAssembly, the arities of labels and frames cannot be larger than 1. This may be generalized in future versions.
4.2.13. Administrative InstructionsIn order to express the reduction of traps, calls, and control instructions, the syntax of instructions is extended to include the following administrative instructions:
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.
The invoke instruction represents the imminent invocation of a function instance, identified by its address. It unifies the handling of different forms of calls.
The init_elem and init_data instructions perform initialization of element and data segments during module instantiation.
Note
The reason for splitting instantiation into individual reduction steps is to provide a semantics that is compatible with future extensions like threads.
The label and frame instructions model labels and frames “on the stack”. Moreover, the administrative syntax maintains the nesting structure of the original structured control instruction or function body and their instruction sequences with an end marker. That way, the end of the inner instruction sequence is known when part of an outer sequence.
Note
For example, the reduction rule for block is:
This replaces the block with a label instruction, which can be interpreted as “pushing” the label on the stack. When end is reached, i.e., the inner instruction sequence has been reduced to the empty sequence – or rather, a sequence of n const instructions representing the resulting values – then the label instruction is eliminated courtesy of its own reduction rule:
This can be interpreted as removing the label from the stack and only leaving the locally accumulated operand values.
4.2.13.1. Block ContextsIn order to specify the reduction of branches, the following syntax of block contexts is defined, indexed by the count k of labels surrounding a hole [_] that marks the place where the next step of computation is taking place:
This definition allows to index active labels surrounding a branch or return instruction.
Note
For example, the reduction of a simple branch can be defined as follows:
Here, the hole [_] of the context is instantiated with a branch instruction. When a branch occurs, this rule replaces the targeted label and associated instruction sequence with the label’s continuation. The selected label is identified through the label index l, which corresponds to the number of surrounding label instructions that must be hopped over – which is exactly the count encoded in the index of a block context.
4.2.13.2. ConfigurationsA configuration consists of the current store and an executing thread.
A thread is a computation over instructions that operates relative to a current frame referring to the module instance in which the computation runs, i.e., where the current function originates from.
Note
The current version of WebAssembly is single-threaded, but configurations with multiple threads may be supported in the future.
4.2.13.3. Evaluation ContextsFinally, the following definition of evaluation context and associated structural rules enable reduction inside instruction sequences and administrative forms as well as the propagation of traps:
Reduction terminates when a thread’s instruction sequence has been reduced to a result, that is, either a sequence of values or to a trap.
Note
The restriction on evaluation contexts rules out contexts like [_] and ϵ [_] ϵ for which E[trap]=trap.
For an example of reduction under evaluation contexts, consider the following instruction sequence.
This can be decomposed into E[(f64.const x2) f64.neg] where
Moreover, this is the only possible choice of evaluation context where the contents of the hole matches the left-hand side of a reduction rule.
4.3. NumericsNumeric primitives are defined in a generic manner, by operators indexed over a bit width N.
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.
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:
This definition is to be read as a shorthand for the following expansion of each clause into two separate ones:
Conventions:
The meta variable d is used to range over single bits.
The meta variable p is used to range over (signless) magnitudes of floating-point values, including nan and ∞.
The meta variable q is used to range over (signless) rational magnitudes, excluding nan or ∞.
The notation f−1 denotes the inverse of a bijective function f.
Truncation of rational values is written trunc(±q), with the usual mathematical definition:
trunc(±q)=±i(ifi∈N∧+q−1<i≤+q)Numbers have an underlying binary representation as a sequence of bits:
Each of these functions is a bijection, hence they are invertible.
4.3.1.1. IntegersIntegers are represented as base two unsigned numbers:
ibitsN(i)=dN−1 … d0(i=2N−1⋅dN−1+⋯+20⋅d0)Boolean operators like ∧, ∨, or ⊻ are lifted to bit sequences of equal length by applying them pointwise.
4.3.1.3. StorageWhen a number is stored into memory, it is converted into a sequence of bytes in little endian byte order:
Again these functions are invertable bijections.
4.3.2. Integer Operations 4.3.2.1. Sign InterpretationInteger operators are defined on iN 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):
This function is bijective, and hence invertible.
4.3.2.2. Boolean InterpretationThe 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.
4.3.2.3. iaddN(i1,i2)Note
This operator is partial. Besides division by 0, the result of (−2N−1)/(−1)=+2N−1 is not representable as an N-bit signed integer.
4.3.2.8. irem_uN(i1,i2)Note
This operator is partial.
As long as both operators are defined, it holds that i1=i2⋅idiv_u(i1,i2)+irem_u(i1,i2).
4.3.2.9. irem_sN(i1,i2)Note
This operator is partial.
As long as both operators are defined, it holds that i1=i2⋅idiv_s(i1,i2)+irem_s(i1,i2).
4.3.2.10. iandN(i1,i2)Floating-point arithmetic follows the [IEEE-754-2019] standard, with the following qualifications:
Note
Some of these limitations may be lifted in future versions of WebAssembly.
4.3.3.1. RoundingRounding always is round-to-nearest ties-to-even, in correspondence with [IEEE-754-2019] (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 N.
A limit number for a given floating-point bit width N 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 N (that magnitude is 2128 for N=32 and 21024 for N=64).
A candidate number is either an exact floating-point number or a positive or negative limit number for the given bit width N.
A candidate pair is a pair z1,z2 of candidate numbers, such that no candidate number exists that lies between the two.
A real number r is converted to a floating-point value of bit width N as follows:
where:
exactNlimitNcandidateNcandidatepairNevenN((d+m⋅2−M)⋅2e)evenN(±limitN)====⇔⇔fN∩Q22expon(N)−1exactN∪{+limitN,−limitN}{(z1,z2)∈candidateN2 ∣ z1<z2∧∀z∈candidateN,z≤z1∨z≥z2}mmod2=0true 4.3.3.2. NaN PropagationWhen 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:
This non-deterministic result is expressed by the following auxiliary function producing a set of allowed outputs from a set of inputs:
4.3.3.3. faddN(z1,z2)Note
Up to the non-determinism regarding NaNs, it always holds that fsubN(z1,z2)=faddN(z1,fnegN(z2)).
4.3.3.5. fmulN(z1,z2)Note
In the abstract syntax, unsigned extension just reinterprets the same value.
4.3.4.3. wrapM,N(i)Note
This operator is partial. It is not defined for NaNs, infinities, or values for which the result is out of range.
4.3.4.5. truncsM,N(z)Note
This operator is partial. It is not defined for NaNs, infinities, or values for which the result is out of range.
4.3.4.7. demoteM,N(z)WebAssembly computation is performed by executing individual instructions.
4.4.1. Numeric InstructionsNumeric 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:
opiN(n1,…,nk)opfN(z1,…,zk)==iopN(n1,…,nk)fopN(z1,…,zk)
And for conversion operators:
cvtopt1,t2sx?(c)=cvtop∣t1∣,∣t2∣sx?(c)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 i32.add applied to operands i1,i2 invokes addi32(i1,i2), which maps to the generic iadd32(i1,i2) via the above definition. Similarly, i64.trunc_f32_s applied to z invokes truncf32,i64s(z), which maps to the generic truncs32,64(z).
4.4.1.1. t.const cNote
No formal reduction rule is required for this instruction, since const instructions coincide with values.
4.4.1.2. t.unopNote
The alignment memarg.align in load and store instructions does not affect the semantics. It is an indication that the offset ea at which the memory is accessed is intended to satisfy the property eamod2memarg.align=0. A WebAssembly implementation can use this hint to optimize for the intended use. Unaligned access violating that property is still allowed and must succeed regardless of the annotation. However, it may be substantially slower on some hardware.
4.4.4.4. memory.growNote
The memory.grow 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.
4.4.5. Control Instructions 4.4.5.3. block [t?] instr∗ endThe following auxiliary rules define the semantics of executing an instruction sequence that forms a block.
4.4.6.1. Entering instr∗ with label LNote
No formal reduction rule is needed for entering an instruction sequence, because the label L is embedded in the administrative instruction that structured control instructions reduce to directly.
4.4.6.2. Exiting instr∗ with label LWhen the end of a block is reached without a jump or trap aborting it, then the following steps are performed.
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.
4.4.7. Function CallsThe following auxiliary rules define the semantics of invoking a function instance through one of the call instructions and returning from it.
4.4.7.2. Returning from a functionWhen the end of a function is reached without a jump (i.e., return) or trap aborting it, then the following steps are performed.
Invoking a host function has non-deterministic behavior. It may either terminate with a trap 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.
Here, hf(S;valn) denotes the implementation-defined execution of host function hf in current store S with arguments valn. It yields a set of possible outcomes, where each element is either a pair of a modified store S′ 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 S, and given arguments valn matching the ascribed parameter types t1n, executing the host function must yield a non-empty set of possible outcomes each of which is either divergence or consists of a valid store S′ that is an extension of S and a result matching the ascribed return types t2m. 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.4.8. ExpressionsAn expression is evaluated relative to a current frame pointing to its containing module instance.
The value val is the result of the evaluation.
Note
Evaluation iterates this reduction rule until reaching a value. Expressions constituting function bodies are executed during function invocation.
4.5. ModulesFor modules, the execution semantics primarily defines instantiation, which allocates instances for a module and its contained definitions, inititializes tables and memories from contained element and data segments, and invokes the start function if present. It also includes invocation of exported functions.
Instantiation depends on a number of auxiliary notions for type-checking imports and allocating instances.
4.5.1. External TypingFor the purpose of checking external values against imports, such values are classified by external types. The following auxiliary typing rules specify this typing relation relative to a store S in which the referenced instances live.
4.5.2. Import MatchingWhen instantiating a module, external values must be provided whose types are matched against the respective external types classifying each import. In some cases, this allows for a simple form of subtyping, as defined below.
4.5.2.1. LimitsLimits {min n1,max m1?} match limits {min n2,max m2?} if and only if:
New instances of functions, tables, memories, and globals are allocated in a store S, as defined by the following auxiliary functions.
4.5.3.6. Growing tablesThe allocation function for modules requires a suitable list of external values that are assumed to match the import vector of the module, and a list of initialization values for the module’s globals.
1. Let module be the module to allocate and externvalim∗ the vector of external values providing the module’s imports, and val∗ the initialization values of the module’s globals.
where:
moduleinstS1,funcaddr∗S2,tableaddr∗S3,memaddr∗S′,globaladdr∗exportinst∗funcs(externvalex∗)tables(externvalex∗)mems(externvalex∗)globals(externvalex∗)=========={ types module.types,funcaddrs funcs(externvalim∗) funcaddr∗,tableaddrs tables(externvalim∗) tableaddr∗,memaddrs mems(externvalim∗) memaddr∗,globaladdrs globals(externvalim∗) globaladdr∗,exports exportinst∗ }allocfunc∗(S,module.funcs,moduleinst)alloctable∗(S1,(table.type)∗) (wheretable∗=module.tables)allocmem∗(S2,(mem.type)∗) (wheremem∗=module.mems)allocglobal∗(S3,(global.type)∗,val∗) (whereglobal∗=module.globals){name (export.name),value externvalex}∗(whereexport∗=module.exports)(moduleinst.funcaddrs[x])∗ (wherex∗=funcs(module.exports))(moduleinst.tableaddrs[x])∗(wherex∗=tables(module.exports))(moduleinst.memaddrs[x])∗(wherex∗=mems(module.exports))(moduleinst.globaladdrs[x])∗(wherex∗=globals(module.exports))Here, the notation allocx∗ is shorthand for multiple allocations of object kind X, defined as follows:
allocx∗(S0,Xn,…)where for all i < n:Si+1,an[i]==Sn,anallocx(Si,Xn[i],…)
Moreover, if the dots … are a sequence An (as for globals), then the elements of this sequence are passed to the allocation function pointwise.
Note
The definition of module allocation is mutually recursive with the allocation of its associated functions, because the resulting module instance moduleinst is passed to the function allocator 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.5.4. InstantiationGiven a store S, a module module is instantiated with a list of external values externvaln 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 a trap from executing the start function. It is up to the embedder to define how such conditions are reported.
Let val∗ be the vector of global initialization values determined by module and externvaln. These may be calculated as follows.
Let moduleinst be a new module instance allocated from module in store S with imports externvaln and global initializer values val∗, and let S′ be the extended store produced by module allocation.
Let F be the frame {module moduleinst,locals ϵ}.
Push the frame F to the stack.
For each element segment elemi in module.elem, do:
For each data segment datai in module.data, do:
Assert: due to validation, the frame F is now on the top of the stack.
Pop the frame from the stack.
For each element segment elemi in module.elem, do:
For each data segment datai in module.data, do:
If the start function module.start is not empty, then:
Note
Module allocation and the evaluation of global initializers are mutually recursive because the global initialization values val∗ are passed to the module allocator but depend on the store S′ and module instance moduleinst returned by allocation. However, this recursion is just a specification device. Due to validation, the initialization values can easily be determined from a simple pre-pass that evaluates global initializers in the initial store.
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.
4.5.5. InvocationOnce a module has been instantiated, any exported function can be invoked externally via its function address funcaddr in the store S 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 a 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 invocation, then no failure other than traps can occur.
The following steps are performed:
Once the function has returned, the following steps are executed:
The values valresm are returned as the results of the invocation.
5. Binary Format 5.1. ConventionsThe binary format for WebAssembly modules is a dense linear encoding of their abstract syntax. [1]
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 recommended Media Type is “application/wasm”.
5.1.1. GrammarThe following conventions are adopted in defining grammar rules for the binary format. They mirror the conventions 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.
Note
For example, the binary grammar for value types is given as follows:
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 value type.
The binary grammar for limits is defined as follows:
That is, a limits pair is encoded as either the byte 0x00 followed by the encoding of a u32 value, or the byte 0x01 followed by two such encodings. The variables n and m name the attributes of the respective u32 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 NotationWhen dealing with binary encodings the following notation is also used:
Vectors are encoded with their u32 length followed by the encoding of their element sequence.
5.2. Values 5.2.1. BytesBytes encode themselves.
byte::=∣∣0x000xFF⇒…⇒0x000xFF 5.2.2. IntegersAll integers are encoded using the LEB128 variable-length integer encoding, in either unsigned or signed variant.
Unsigned integers are encoded in unsigned LEB128 format. As an additional constraint, the total number of bytes encoding a value of type uN must not exceed ceil(N/7) bytes.
uN::=∣n:byten:byte m:u(N−7)⇒⇒n27⋅m+(n−27)(ifn<27∧n<2N)(ifn≥27∧N>7)Signed integers are encoded in signed LEB128 format, which uses a two’s complement representation. As an additional constraint, the total number of bytes encoding a value of type sN must not exceed ceil(N/7) bytes.
sN::=∣∣n:byten:byten:byte m:s(N−7)⇒⇒⇒nn−2727⋅m+(n−27)(ifn<26∧n<2N−1)(if26≤n<27∧n≥27−2N−1)(ifn≥27∧N>7)Uninterpreted integers are encoded as signed integers.
Note
The side conditions N>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 a s16.
The side conditions on the value n 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.4. NamesNames are encoded as a vector of bytes containing the [UNICODE] (Section 3.9) UTF-8 encoding of the name’s character sequence.
The auxiliary utf8 function expressing this encoding is defined as follows:
utf8(c∗)utf8(c)utf8(c)utf8(c)utf8(c)=====(utf8(c))∗bb1 b2b1 b2 b3b1 b2 b3 b4(if∧c<U+80c=b)(if∧U+80≤c<U+800c=26(b1−0xC0)+(b2−0x80))(if∧U+800≤c<U+D800∨U+E000≤c<U+10000c=212(b1−0xE0)+26(b2−0x80)+(b3−0x80))(if∧U+10000≤c<U+110000c=218(b1−0xF0)+212(b2−0x80)+26(b3−0x80)+(b4−0x80))whereb2,b3,b4<0xC0Note
Unlike in some other formats, name strings are not 0-terminated.
5.3. Types 5.3.1. Value TypesValue types are encoded by a single byte.
Note
In future versions of WebAssembly, value types may include types denoted by type indices. Thus, the binary format for types corresponds to the signed LEB128 encoding of small negative sN values, so that they can coexist with (positive) type indices in the future.
5.3.2. Result TypesThe only result types occurring in the binary format are the types of blocks. These are encoded in special compressed form, by either the byte 0x40 indicating the empty type or as a single value type.
Note
In future versions of WebAssembly, this scheme may be extended to support multiple results or more general block types.
5.3.3. Function TypesFunction types are encoded by the byte 0x60 followed by the respective vectors of parameter and result types.
5.3.4. LimitsLimits are encoded with a preceding flag indicating whether a maximum is present.
5.4. InstructionsInstructions are encoded by opcodes. Each opcode is represented by a single byte, and is followed by the instruction’s immediate arguments, where present. The only exception are structured control instructions, which consist of several opcodes bracketing their nested instruction sequences.
Note
Gaps in the byte code ranges for encoding instructions are reserved for future extensions.
5.4.1. Control InstructionsControl instructions have varying encodings. For structured instructions, the instruction sequences forming nested blocks are terminated with explicit opcodes for end and else.
Note
The else opcode 0x05 in the encoding of an if instruction can be omitted if the following instruction sequence is empty.
Note
In future versions of WebAssembly, the zero byte occurring in the encoding of the call_indirect instruction may be used to index additional tables.
5.4.3. Variable InstructionsVariable instructions are represented by byte codes followed by the encoding of the respective index.
5.4.4. Memory InstructionsEach variant of memory instruction is encoded with a different byte code. Loads and stores are followed by the encoding of their memarg immediate.
Note
In future versions of WebAssembly, the additional zero bytes occurring in the encoding of the memory.size and memory.grow instructions may be used to index additional memories.
5.4.5. Numeric InstructionsAll variants of numeric instructions are represented by separate byte codes.
The const instructions are followed by the respective literal.
All other numeric instructions are plain opcodes without any immediates.
5.4.6. ExpressionsExpressions are encoded by their instruction sequence terminated with an explicit 0x0B opcode for end.
5.5. ModulesThe 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. IndicesAll indices are encoded with their respective value.
5.5.2. SectionsEach section consists of
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 N and contents described by the grammar B.
For most sections, the contents B encodes a vector. In these cases, the empty result ϵ is interpreted as the empty vector.
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 B.
The following section ids are used:
5.5.3. Custom SectionCustom 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.
Note
If an implementation interprets the contents of a custom section, then errors in that contents, or the placement of the section, must not invalidate the module.
5.5.4. Type SectionThe type section has the id 1. It decodes into a vector of function types that represent the types component of a module.
5.5.5. Import SectionThe import section has the id 2. It decodes into a vector of imports that represent the imports component of a module.
5.5.7. Table SectionThe table section has the id 4. It decodes into a vector of tables that represent the tables component of a module.
5.5.8. Memory SectionThe memory section has the id 5. It decodes into a vector of memories that represent the mems component of a module.
5.5.9. Global SectionThe global section has the id 6. It decodes into a vector of globals that represent the globals component of a module.
5.5.10. Export SectionThe export section has the id 7. It decodes into a vector of exports that represent the exports component of a module.
5.5.11. Start SectionThe start section has the id 8. It decodes into an optional start function that represents the start component of a module.
5.5.12. Element SectionThe element section has the id 9. It decodes into a vector of element segments that represent the elem component of a module.
5.5.13. Code SectionThe code section has the id 10. It decodes into a vector of code entries that are pairs of value type vectors and expressions. They represent the locals and body field of the functions in the funcs component of a module. The type fields of the respective functions are encoded separately in the function section.
The encoding of each code entry consists of
Local declarations are compressed into a vector whose entries consist of
denoting count locals of the same value type.
Here, code ranges over pairs (valtype∗,expr). The meta function concat((t∗)∗) concatenates all sequences ti∗ in (t∗)∗. Any code for which the length of the resulting sequence is out of bounds of the maximum size of a vector 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 SectionThe data section has the id 11. It decodes into a vector of data segments that represent the data component of a module.
5.5.15. ModulesThe 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 vectors produced by the (possibly empty) function and code section must match up.
where for each ti∗,ei in coden,
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 forward-compatible, such that future extensions can be made without incrementing its version.
6. Text Format 6.1. ConventionsThe textual format for WebAssembly modules is a rendering of their abstract syntax into S-expressions.
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 identifers.
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 [UNICODE] (Section 2.5).
6.1.1. GrammarThe 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.
Note
For example, the textual grammar for value types is given as follows:
The textual grammar for limits is defined as follows:
The variables n and m name the attributes of the respective u32 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. AbbreviationsIn 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:
abbreviation 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. ContextsThe text format allows the use of symbolic identifiers in place of indices. To resolve these identifiers into concrete indices, some grammar production are indexed by an identifier context I 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.
It is convenient to define identifier contexts as records I with abstract syntax as follows:
For each index space, such a context contains the list of identifiers assigned to the defined indices. Unnamed indices are associated with empty (ϵ) entries in these lists.
An identifier context is well-formed if no index space contains duplicate identifiers.
6.1.3.1. ConventionsTo 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. VectorsVectors are written as plain sequences, but with a restriction on the length of these sequence.
vec(A)::=(x:A)n⇒xn(ifn<232) 6.2. Lexical Format 6.2.1. CharactersThe text format assigns meaning to source text, which consists of a sequence of characters. Characters are assumed to be represented as valid [UNICODE] (Section 2.4) scalar values.
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 ASCII subset of Unicode.
6.2.2. TokensThe character stream in the source text is divided, from left to right, into a sequence of tokens, as defined by the following grammar.
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.
The set of keyword tokens is defined implicitly, by all occurrences of 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 or white space. For example, ‘0$x’ is a single reserved token. Consequently, it is not recognized as two separate tokens ‘0’ and ‘$x’, 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 SpaceWhite space is any sequence of literal space characters, formatting characters, or comments. The allowed formatting characters correspond to a subset of the ASCII format effectors, namely, horizontal tabulation (U+09), line feed (U+0A), and carriage return (U+0D).
The only relevance of white space is to separate tokens. It is otherwise ignored.
6.3. ValuesThe grammar productions in this section define lexical syntax, hence no white space is allowed.
6.3.1. IntegersAll integers can be written in either decimal or hexadecimal notation. In both cases, digits can optionally be separated by underscores.
The allowed syntax for integer literals depends on size and signedness. Moreover, their value must lie within the range of the respective type.
Uninterpreted integers can be written as either signed or unsigned, and are normalized to unsigned in the abstract syntax.
6.3.2. Floating-PointFloating-point values can be represented in either decimal or hexadecimal notation.
The value of a literal must not lie outside the representable range of the corresponding [IEEE-754-2019] type (that is, a numeric value must not overflow to ±infinity), 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.
6.3.3. StringsStrings 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 ASCII control characters, quotation marks (‘"’), or backslash (‘\’), except when expressed with an escape sequence.
Each character in a string literal represents the byte sequence corresponding to its UTF-8 [UNICODE] (Section 2.5) encoding, except for hexadecimal escape sequences ‘\hh’, which represent raw bytes of the respective value.
stringchar::=∣∣∣∣∣∣∣c:char‘\t’‘\n’‘\r’‘\"’‘\′’‘\\’‘\u{ n:hexnum ‘}’’⇒⇒⇒⇒⇒⇒⇒⇒cU+09U+0AU+0DU+22U+27U+5CU+(n)(ifc≥U+20∧c=U+7F∧c=‘"’∧c=‘\’)(ifn<0xD800∨0xE000≤n<0x110000) 6.3.4. NamesNames are strings denoting a literal character sequence. A name string must form a valid UTF-8 encoding as defined by [UNICODE] (Section 2.5) and is interpreted as a string of Unicode scalar values.
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. IdentifiersIndices can be given in both numeric and symbolic form. Symbolic identifiers that stand in lieu of indices start with ‘$’, followed by any sequence of printable ASCII characters that does not contain a space, quotation mark, comma, semicolon, or bracket.
ididchar::=::=∣∣∣∣‘$’ idchar+‘0’ ∣ … ∣ ‘9’‘A’ ∣ … ∣ ‘Z’‘a’ ∣ … ∣ ‘z’‘!’ ∣ ‘#’ ∣ ‘$’ ∣ ‘%’ ∣ ‘&’ ∣ ‘′’ ∣ ‘∗’ ∣ ‘+’ ∣ ‘−’ ∣ ‘.’ ∣ ‘/’‘:’ ∣ ‘<’ ∣ ‘=’ ∣ ‘>’ ∣ ‘?’ ∣ ‘@’ ∣ ‘\’ ∣ ‘ ^’ ∣ ‘_’ ∣ ‘ ˋ’ ∣ ‘∣’ ∣ ‘ ~’ 6.3.5.1. ConventionsThe 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.
6.4. Types 6.4.2. Result TypesNote
In future versions of WebAssembly, this scheme may be extended to support multiple results or more general result types.
6.4.3. Function Types 6.4.3.1. AbbreviationsMultiple anonymous parameters or results may be combined into a single declaration:
6.4.6. Table TypesNote
Additional element types may be introduced in future versions of WebAssembly.
6.5. InstructionsInstructions are syntactically distinguished into plain and structured instructions.
In addition, as a syntactic abbreviation, instructions can be written as S-expressions in folded form, to group them visually.
6.5.1. LabelsStructured 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.
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.
6.5.2. Control InstructionsStructured control instructions can bind an optional symbolic label identifier. The same label identifier may optionally be repeated after the corresponding end and else pseudo instructions, to indicate the matching delimiters.
All other control instruction are represented verbatim.
Note
The side condition stating that the identifier context I′ must be empty in the rule for call_indirect enforces that no identifier can be bound in any param declaration appearing in the type annotation.
6.5.2.1. AbbreviationsThe ‘else’ keyword of an ‘if’ instruction can be omitted if the following instruction sequence is empty.
6.5.3. Parametric Instructions 6.5.4. Variable Instructions 6.5.5. Memory InstructionsThe 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 phrase is considered a single keyword token, so no white space is allowed around the ‘=’.
6.5.6. Numeric Instructions 6.5.7. Folded InstructionsInstructions 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 foldedinstr. Such a folded instruction can appear anywhere a regular instruction can.
Note
For example, the instruction sequence
(local.get $x) (i32.const 2) i32.add (i32.const 3) i32.mul
can be folded into
(i32.mul (i32.add (local.get $x) (i32.const 2)) (i32.const 3))
Folded instructions are solely syntactic sugar, no additional syntactic or type-based checking is implied.
6.5.8. ExpressionsExpressions are written as instruction sequences. No explicit ‘end’ keyword is included, since they only occur in bracketed positions.
6.6. Modules 6.6.1. IndicesIndices 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 I.
6.6.3. Type UsesA type use is a reference to a type definition. 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.
The synthesized attribute of a typeuse is a pair consisting of both the used type index and the updated identifier context including possible parameter identifiers. The following auxiliary function extracts optional identifiers from parameters:
id(‘(’ ‘param’ id? … ‘)’)=id?Note
Both productions overlap for the case that the function type is []→[]. However, in that case, they also produce the same results, so that the choice is immaterial.
The well-formedness condition on I′ ensures that the parameters do not contain duplicate identifier.
6.6.3.1. AbbreviationsA typeuse may also be replaced entirely by inline parameter and result declarations. In that case, a type index is automatically inserted:
where x is the smallest existing type index whose definition in the current module is the function type [t1∗]→[t2∗]. If no such index exists, then a new type definition of the 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.6.4. ImportsThe descriptors in imports can bind a symbolic function, table, memory, or global identifier.
6.6.4.1. AbbreviationsAs an abbreviation, imports may also be specified inline with function, table, memory, or global definitions; see the respective sections.
6.6.5. FunctionsFunction definitions can bind a symbolic function identifier, and local identifiers for its parameters and locals.
The definition of the local identifier context I′′ uses the following auxiliary function to extract optional identifiers from locals:
id(‘(’ ‘local’ id? … ‘)’)=id?Note
The well-formedness condition on I′′ ensures that parameters and locals do not contain duplicate identifiers.
6.6.5.1. AbbreviationsMultiple anonymous locals may be combined into a single declaration:
Functions can be defined as imports or exports inline:
The latter abbreviation can be applied repeatedly, with “…” containing another import or export.
6.6.6. TablesTable definitions can bind a symbolic table identifier.
6.6.6.1. AbbreviationsAn 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:
Tables can be defined as imports or exports inline:
The latter abbreviation can be applied repeatedly, with “…” containing another import or export or an inline elements segment.
6.6.7. MemoriesMemory definitions can bind a symbolic memory identifier.
6.6.7.1. AbbreviationsA data segment can be given inline with a memory definition, in which case its offset is 0 the limits of the memory type are inferred from the length of the data, rounded up to page size:
Memories can be defined as imports or exports inline:
The latter abbreviation can be applied repeatedly, with “…” containing another import or export or an inline data segment.
6.6.8. GlobalsGlobal definitions can bind a symbolic global identifier.
6.6.8.1. AbbreviationsGlobals can be defined as imports or exports inline:
The latter abbreviation can be applied repeatedly, with “…” containing another import or export.
6.6.9. ExportsThe syntax for exports mirrors their abstract syntax directly.
6.6.9.1. AbbreviationsAs an abbreviation, exports may also be specified inline with function, table, memory, or global definitions; see the respective sections.
6.6.10. Start FunctionA start function is defined in terms of its index.
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. Element SegmentsElement segments allow for an optional table index to identify the table to initialize.
Note
In the current version of WebAssembly, the only valid table index is 0 or a symbolic table identifier resolving to the same value.
6.6.11.1. AbbreviationsAs an abbreviation, a single instruction may occur in place of the offset:
Also, the table index can be omitted, defaulting to 0.
‘(’ ‘elem’ ‘(’ ‘offset’ exprI ‘)’ … ‘)’≡‘(’ ‘elem’ 0 ‘(’ ‘offset’ exprI ‘)’ … ‘)’As another abbreviation, element segments may also be specified inline with table definitions; see the respective section.
6.6.12. Data SegmentsData 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.
Note
In the current version of WebAssembly, the only valid memory index is 0 or a symbolic memory identifier resolving to the same value.
6.6.12.1. AbbreviationsAs an abbreviation, a single instruction may occur in place of the offset:
Also, the memory index can be omitted, defaulting to 0.
‘(’ ‘data’ ‘(’ ‘offset’ exprI ‘)’ … ‘)’≡‘(’ ‘data’ 0 ‘(’ ‘offset’ exprI ‘)’ … ‘)’As another abbreviation, data segments may also be specified inline with memory definitions; see the respective section.
6.6.13. ModulesA module consists of a sequence of fields that can occur in any order. All definitions and their respective bound identifiers scope over the entire module, including the text preceding them.
A module may optionally bind an identifier that names the module. The name serves a documentary role only.
The following restrictions are imposed on the composition of modules: m1⊕m2 is defined if and only if
Note
The first condition ensures that there is at most one start function. The second condition enforces that all imports must occur before any regular definition of a function, table, memory, or global, thereby maintaining the ordering of the respective index spaces.
The well-formedness condition on I in the grammar for module ensures that no namespace contains duplicate identifiers.
The definition of the initial identifier context I uses the following auxiliary definition which maps each relevant definition to a singular context with one (possibly empty) identifier:
6.6.13.1. AbbreviationsIn a source file, the toplevel (module …) surrounding the module body may be omitted.
A Appendix A.1 EmbeddingA 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.
TypesIn 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 n:u32 is used to specify a symbolic name in addition to the respective value range.
ErrorsFailure of an interface operation is indicated by an auxiliary syntactic class:
In addition to the error conditions specified explicitly in this section, 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 classifications and diagnostic messages.
Pre- and Post-ConditionsSome operations state pre-conditions about their arguments or post-conditions about their results. It is the embedder’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, externval, addresses):
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.
Modules module_instantiate(store,module,externval∗):(store,moduleinst ∣ error)Note
The store may be modified even in case of an error.
Functions func_invoke(store,funcaddr,val∗):(store,val∗ ∣ error)Note
The store may be modified even in case of an error.
Tables table_write(store,tableaddr,i:u32,funcaddr?):store ∣ errorImplementations typically impose additional restrictions on a number of aspects of a WebAssembly module or execution. These may stem from:
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.
Syntactic Limits Binary FormatFor a module given in binary format, additional limitations may be imposed on the following dimensions:
For a module given in text format, additional limitations may be imposed on the following dimensions:
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.
ExecutionRestrictions on the following dimensions may be imposed during execution of a WebAssembly program:
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.
A.3 Validation AlgorithmThe 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.
Data StructuresThe algorithm uses two separate stacks: the operand stack and the control stack. The former tracks the types of operand values on the stack, the latter surrounding structured control instructions and their associated blocks.
type val_type = I32 | I64 | F32 | F64 type opd_stack = stack(val_type | Unknown) type ctrl_stack = stack(ctrl_frame) type ctrl_frame = { label_types : list(val_type) end_types : list(val_type) height : nat unreachable : bool }
For each value, the operand stack records its value type, or Unknown
when the type is not known.
For each entered block, the control stack records a control frame with the type of the associated label (used to type-check branches), the result type of the block (used to check its result), the height of the operand stack at the start of the block (used to check that operands do not underflow the current block), and a flag recording whether the remainder of the block is unreachable (used to handle stack-polymorphic typing after branches).
Note
In the presentation of this algorithm, multiple values are supported for the result types classifying blocks and labels. With the current version of WebAssembly, the list
could be simplified to an optional value.
For the purpose of presenting the algorithm, the operand and control stacks are simply maintained as global variables:
var opds : opd_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_opd(type : val_type | Unknown) = opds.push(type) func pop_opd() : val_type | Unknown = if (opds.size() = ctrls[0].height && ctrls[0].unreachable) return Unknown error_if(opds.size() = ctrls[0].height) return opds.pop() func pop_opd(expect : val_type | Unknown) : val_type | Unknown = let actual = pop_opd() if (actual = Unknown) return expect if (expect = Unknown) return actual error_if(actual =/= expect) return actual func push_opds(types : list(val_type)) = foreach (t in types) push_opd(t) func pop_opds(types : list(val_type)) = foreach (t in reverse(types)) pop_opd(t)
Pushing an operand simply pushes the respective type to the operand stack.
Popping an operand checks that the operand 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 operands, but has been marked as unreachable. That can occur after an unconditional branch, when the stack is typed polymorphically. In that case, an unknown type is returned.
A second function for popping an operand takes an expected type, which the actual operand type is checked against. The types may differ in case one of them is Unknown. The more specific type is returned.
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 ctrls[0]
accesses the element pushed last.
The control stack is likewise manipulated through auxiliary functions:
func push_ctrl(label : list(val_type), out : list(val_type)) = let frame = ctrl_frame(label, out, opds.size(), false) ctrls.push(frame) func pop_ctrl() : list(val_type) = error_if(ctrls.is_empty()) let frame = ctrls[0] pop_opds(frame.end_types) error_if(opds.size() =/= frame.height) ctrls.pop() return frame.end_types func unreachable() = opds.resize(ctrls[0].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 checks that the stack has shrunk back to its initial height.
Finally, the current frame can be marked as unreachable. In that case, all existing operand types are purged from the operand stack, in order to allow for the stack-polymorphism logic in pop_opd
to take effect.
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 (i32.const) i64.add). However, a polymorphic stack cannot underflow, but instead generates Unknown
types as needed.
The following function shows the validation of a number of representative instructions that manipulate the stack. Other instructions are checked in a similar manner.
Note
Various instructions not shown here will additionally require the presence of a validation context for checking uses of indices. That is an easy addition and therefore omitted from this presentation.
func validate(opcode) = switch (opcode) case (i32.add) pop_opd(I32) pop_opd(I32) push_opd(I32) case (drop) pop_opd() case (select) pop_opd(I32) let t1 = pop_opd() let t2 = pop_opd(t1) push_opd(t2) case (unreachable) unreachable() case (block t*) push_ctrl([t*], [t*]) case (loop t*) push_ctrl([], [t*]) case (if t*) pop_opd(I32) push_ctrl([t*], [t*]) case (end) let results = pop_ctrl() push_opds(results) case (else) let results = pop_ctrl() push_ctrl(results, results) case (br n) error_if(ctrls.size() < n) pop_opds(ctrls[n].label_types) unreachable() case (br_if n) error_if(ctrls.size() < n) pop_opd(I32) pop_opds(ctrls[n].label_types) push_opds(ctrls[n].label_types) case (br_table n* m) error_if(ctrls.size() < m) foreach (n in n*) error_if(ctrls.size() < n || ctrls[n].label_types =/= ctrls[m].label_types) pop_opd(I32) pop_opds(ctrls[m].label_types) unreachable()
Note
It is an invariant under the current WebAssembly instruction set that an operand of Unknown
type is never duplicated on the stack. This would change if the language were extended with stack operators like dup
. Under such an extension, the above algorithm would need to be refined by replacing the Unknown
type with proper type variables to ensure that all uses are consistent.
This appendix defines dedicated custom sections for WebAssembly’s binary format. Such sections do not contribute to, or otherwise affect, the WebAssembly semantics, and like any custom section they 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.
Currently, only one dedicated custom section is defined, the name section.
Name SectionThe 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 [UNICODE] encoded in UTF-8. Names need not be unique.
SubsectionsThe data of a name section consists of a sequence of subsections. Each subsection consists of a
The following subsection ids are used:
Each subsection may occur at most once, and in order of increasing id.
Name MapsA name map assigns names to indices in a given index space. It consists of a vector of index/name pairs in order of increasing index value. Each index must be unique, but the assigned names need not be.
An indirect name map assigns names to a two-dimensional index space, where secondary indices are grouped by primary indices. It consists of a vector 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.
Module NamesThe module name subsection has the id 0. It simply consists of a single name that is assigned to the module itself.
Function NamesThe function name subsection has the id 1. It consists of a name map assigning function names to function indices.
A.5 SoundnessThe type system of WebAssembly is sound, implying both type safety and memory safety with respect to the WebAssembly semantics. For example:
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. [1]
Store ValidityThe following typing rules specify when a runtime store S is valid. A valid store must consist of function, table, memory, global, and module instances that are themselves valid, relative to S.
To that end, each kind of instance is classified by a respective function, table, memory, or global type. Module instances are classified by module contexts, which are regular contexts repurposed as module types describing the index spaces defined by a module.
Host Function Instances {type functype,hostcode hf}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.
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.
Administrative InstructionsTyping rules for administrative instructions are specified as follows. In addition to the context C, typing of these instructions is defined under a given store S. To that end, all previous typing judgements C⊢prop are generalized to include the store, as in S;C⊢prop, by implicitly adding S to all rules – S is never modified by the pre-existing rules, but it is accessed in the extra rules for administrative instructions given below.
trapPrograms 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 S′ extends state S, written S⪯S′, when the following rules hold.
Note
Extension does not imply that the new store is valid, which is defined separately above.
TheoremsGiven the definition of valid configurations, the standard soundness theorems hold. [2]
Theorem (Preservation). If a configuration S;T is valid with result type [t∗] (i.e., ⊢S;T:[t∗]), and steps to S′;T′ (i.e., S;T↪S′;T′), then S′;T′ is a valid configuration with the same result type (i.e., ⊢S′;T′:[t∗]). Furthermore, S′ is an extension of S (i.e., ⊢S⪯S′).
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 S;T is valid (i.e., ⊢S;T:[t∗] for some result type [t∗]), then either it is terminal, or it can step to some configuration S′;T′ (i.e., S;T↪S′;T′).
From Preservation and Progress the soundness of the WebAssembly type system follows directly.
Corollary (Soundness). If a configuration S;T is valid (i.e., ⊢S;T:[t∗] for some result type [t∗]), then it either diverges or takes a finite number of steps to reach a terminal configuration S′;T′ (i.e., S;T↪∗S′;T′) that is valid with the same result type (i.e., ⊢S′;T′:[t∗]) and where S′ is an extension of S (i.e., ⊢S⪯S′).
In other words, every thread in a valid configuration either runs forever, traps, 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.
A.7 Index of Instructions Instruction Binary Opcode Type Validation Execution unreachable 0x00 [t1∗]→[t2∗] validation execution nop 0x01 []→[] validation execution block [t?] 0x02 []→[t∗] validation execution loop [t?] 0x03 []→[t∗] validation execution if [t?] 0x04 [i32]→[t∗] validation execution else 0x05 (reserved) 0x06 (reserved) 0x07 (reserved) 0x08 (reserved) 0x09 (reserved) 0x0A end 0x0B br l 0x0C [t1∗ t?]→[t2∗] validation execution br_if l 0x0D [t? i32]→[t?] validation execution br_table l∗ l 0x0E [t1∗ t? i32]→[t2∗] validation execution return 0x0F [t1∗ t?]→[t2∗] validation execution call x 0x10 [t1∗]→[t2∗] validation execution call_indirect x 0x11 [t1∗ i32]→[t2∗] validation execution (reserved) 0x12 (reserved) 0x13 (reserved) 0x14 (reserved) 0x15 (reserved) 0x16 (reserved) 0x17 (reserved) 0x18 (reserved) 0x19 drop 0x1A [t]→[] validation execution select 0x1B [t t i32]→[t] validation execution (reserved) 0x1C (reserved) 0x1D (reserved) 0x1E (reserved) 0x1F local.get x 0x20 []→[t] validation execution local.set x 0x21 [t]→[] validation execution local.tee x 0x22 [t]→[t] validation execution global.get x 0x23 []→[t] validation execution global.set x 0x24 [t]→[] validation execution (reserved) 0x25 (reserved) 0x26 (reserved) 0x27 i32.load memarg 0x28 [i32]→[i32] validation execution i64.load memarg 0x29 [i32]→[i64] validation execution f32.load memarg 0x2A [i32]→[f32] validation execution f64.load memarg 0x2B [i32]→[f64] validation execution i32.load8_s memarg 0x2C [i32]→[i32] validation execution i32.load8_u memarg 0x2D [i32]→[i32] validation execution i32.load16_s memarg 0x2E [i32]→[i32] validation execution i32.load16_u memarg 0x2F [i32]→[i32] validation execution i64.load8_s memarg 0x30 [i32]→[i64] validation execution i64.load8_u memarg 0x31 [i32]→[i64] validation execution i64.load16_s memarg 0x32 [i32]→[i64] validation execution i64.load16_u memarg 0x33 [i32]→[i64] validation execution i64.load32_s memarg 0x34 [i32]→[i64] validation execution i64.load32_u memarg 0x35 [i32]→[i64] validation execution i32.store memarg 0x36 [i32 i32]→[] validation execution i64.store memarg 0x37 [i32 i64]→[] validation execution f32.store memarg 0x38 [i32 f32]→[] validation execution f64.store memarg 0x39 [i32 f64]→[] validation execution i32.store8 memarg 0x3A [i32 i32]→[] validation execution i32.store16 memarg 0x3B [i32 i32]→[] validation execution i64.store8 memarg 0x3C [i32 i64]→[] validation execution i64.store16 memarg 0x3D [i32 i64]→[] validation execution i64.store32 memarg 0x3E [i32 i64]→[] validation execution memory.size 0x3F []→[i32] validation execution memory.grow 0x40 [i32]→[i32] validation execution i32.const i32 0x41 []→[i32] validation execution i64.const i64 0x42 []→[i64] validation execution f32.const f32 0x43 []→[f32] validation execution f64.const f64 0x44 []→[f64] validation execution i32.eqz 0x45 [i32]→[i32] validation execution, operator i32.eq 0x46 [i32 i32]→[i32] validation execution, operator i32.ne 0x47 [i32 i32]→[i32] validation execution, operator i32.lt_s 0x48 [i32 i32]→[i32] validation execution, operator i32.lt_u 0x49 [i32 i32]→[i32] validation execution, operator i32.gt_s 0x4A [i32 i32]→[i32] validation execution, operator i32.gt_u 0x4B [i32 i32]→[i32] validation execution, operator i32.le_s 0x4C [i32 i32]→[i32] validation execution, operator i32.le_u 0x4D [i32 i32]→[i32] validation execution, operator i32.ge_s 0x4E [i32 i32]→[i32] validation execution, operator i32.ge_u 0x4F [i32 i32]→[i32] validation execution, operator i64.eqz 0x50 [i64]→[i32] validation execution, operator i64.eq 0x51 [i64 i64]→[i32] validation execution, operator i64.ne 0x52 [i64 i64]→[i32] validation execution, operator i64.lt_s 0x53 [i64 i64]→[i32] validation execution, operator i64.lt_u 0x54 [i64 i64]→[i32] validation execution, operator i64.gt_s 0x55 [i64 i64]→[i32] validation execution, operator i64.gt_u 0x56 [i64 i64]→[i32] validation execution, operator i64.le_s 0x57 [i64 i64]→[i32] validation execution, operator i64.le_u 0x58 [i64 i64]→[i32] validation execution, operator i64.ge_s 0x59 [i64 i64]→[i32] validation execution, operator i64.ge_u 0x5A [i64 i64]→[i32] validation execution, operator f32.eq 0x5B [f32 f32]→[i32] validation execution, operator f32.ne 0x5C [f32 f32]→[i32] validation execution, operator f32.lt 0x5D [f32 f32]→[i32] validation execution, operator f32.gt 0x5E [f32 f32]→[i32] validation execution, operator f32.le 0x5F [f32 f32]→[i32] validation execution, operator f32.ge 0x60 [f32 f32]→[i32] validation execution, operator f64.eq 0x61 [f64 f64]→[i32] validation execution, operator f64.ne 0x62 [f64 f64]→[i32] validation execution, operator f64.lt 0x63 [f64 f64]→[i32] validation execution, operator f64.gt 0x64 [f64 f64]→[i32] validation execution, operator f64.le 0x65 [f64 f64]→[i32] validation execution, operator f64.ge 0x66 [f64 f64]→[i32] validation execution, operator i32.clz 0x67 [i32]→[i32] validation execution, operator i32.ctz 0x68 [i32]→[i32] validation execution, operator i32.popcnt 0x69 [i32]→[i32] validation execution, operator i32.add 0x6A [i32 i32]→[i32] validation execution, operator i32.sub 0x6B [i32 i32]→[i32] validation execution, operator i32.mul 0x6C [i32 i32]→[i32] validation execution, operator i32.div_s 0x6D [i32 i32]→[i32] validation execution, operator i32.div_u 0x6E [i32 i32]→[i32] validation execution, operator i32.rem_s 0x6F [i32 i32]→[i32] validation execution, operator i32.rem_u 0x70 [i32 i32]→[i32] validation execution, operator i32.and 0x71 [i32 i32]→[i32] validation execution, operator i32.or 0x72 [i32 i32]→[i32] validation execution, operator i32.xor 0x73 [i32 i32]→[i32] validation execution, operator i32.shl 0x74 [i32 i32]→[i32] validation execution, operator i32.shr_s 0x75 [i32 i32]→[i32] validation execution, operator i32.shr_u 0x76 [i32 i32]→[i32] validation execution, operator i32.rotl 0x77 [i32 i32]→[i32] validation execution, operator i32.rotr 0x78 [i32 i32]→[i32] validation execution, operator i64.clz 0x79 [i64]→[i64] validation execution, operator i64.ctz 0x7A [i64]→[i64] validation execution, operator i64.popcnt 0x7B [i64]→[i64] validation execution, operator i64.add 0x7C [i64 i64]→[i64] validation execution, operator i64.sub 0x7D [i64 i64]→[i64] validation execution, operator i64.mul 0x7E [i64 i64]→[i64] validation execution, operator i64.div_s 0x7F [i64 i64]→[i64] validation execution, operator i64.div_u 0x80 [i64 i64]→[i64] validation execution, operator i64.rem_s 0x81 [i64 i64]→[i64] validation execution, operator i64.rem_u 0x82 [i64 i64]→[i64] validation execution, operator i64.and 0x83 [i64 i64]→[i64] validation execution, operator i64.or 0x84 [i64 i64]→[i64] validation execution, operator i64.xor 0x85 [i64 i64]→[i64] validation execution, operator i64.shl 0x86 [i64 i64]→[i64] validation execution, operator i64.shr_s 0x87 [i64 i64]→[i64] validation execution, operator i64.shr_u 0x88 [i64 i64]→[i64] validation execution, operator i64.rotl 0x89 [i64 i64]→[i64] validation execution, operator i64.rotr 0x8A [i64 i64]→[i64] validation execution, operator f32.abs 0x8B [f32]→[f32] validation execution, operator f32.neg 0x8C [f32]→[f32] validation execution, operator f32.ceil 0x8D [f32]→[f32] validation execution, operator f32.floor 0x8E [f32]→[f32] validation execution, operator f32.trunc 0x8F [f32]→[f32] validation execution, operator f32.nearest 0x90 [f32]→[f32] validation execution, operator f32.sqrt 0x91 [f32]→[f32] validation execution, operator f32.add 0x92 [f32 f32]→[f32] validation execution, operator f32.sub 0x93 [f32 f32]→[f32] validation execution, operator f32.mul 0x94 [f32 f32]→[f32] validation execution, operator f32.div 0x95 [f32 f32]→[f32] validation execution, operator f32.min 0x96 [f32 f32]→[f32] validation execution, operator f32.max 0x97 [f32 f32]→[f32] validation execution, operator f32.copysign 0x98 [f32 f32]→[f32] validation execution, operator f64.abs 0x99 [f64]→[f64] validation execution, operator f64.neg 0x9A [f64]→[f64] validation execution, operator f64.ceil 0x9B [f64]→[f64] validation execution, operator f64.floor 0x9C [f64]→[f64] validation execution, operator f64.trunc 0x9D [f64]→[f64] validation execution, operator f64.nearest 0x9E [f64]→[f64] validation execution, operator f64.sqrt 0x9F [f64]→[f64] validation execution, operator f64.add 0xA0 [f64 f64]→[f64] validation execution, operator f64.sub 0xA1 [f64 f64]→[f64] validation execution, operator f64.mul 0xA2 [f64 f64]→[f64] validation execution, operator f64.div 0xA3 [f64 f64]→[f64] validation execution, operator f64.min 0xA4 [f64 f64]→[f64] validation execution, operator f64.max 0xA5 [f64 f64]→[f64] validation execution, operator f64.copysign 0xA6 [f64 f64]→[f64] validation execution, operator i32.wrap_i64 0xA7 [i64]→[i32] validation execution, operator i32.trunc_f32_s 0xA8 [f32]→[i32] validation execution, operator i32.trunc_f32_u 0xA9 [f32]→[i32] validation execution, operator i32.trunc_f64_s 0xAA [f64]→[i32] validation execution, operator i32.trunc_f64_u 0xAB [f64]→[i32] validation execution, operator i64.extend_i32_s 0xAC [i32]→[i64] validation execution, operator i64.extend_i32_u 0xAD [i32]→[i64] validation execution, operator i64.trunc_f32_s 0xAE [f32]→[i64] validation execution, operator i64.trunc_f32_u 0xAF [f32]→[i64] validation execution, operator i64.trunc_f64_s 0xB0 [f64]→[i64] validation execution, operator i64.trunc_f64_u 0xB1 [f64]→[i64] validation execution, operator f32.convert_i32_s 0xB2 [i32]→[f32] validation execution, operator f32.convert_i32_u 0xB3 [i32]→[f32] validation execution, operator f32.convert_i64_s 0xB4 [i64]→[f32] validation execution, operator f32.convert_i64_u 0xB5 [i64]→[f32] validation execution, operator f32.demote_f64 0xB6 [f64]→[f32] validation execution, operator f64.convert_i32_s 0xB7 [i32]→[f64] validation execution, operator f64.convert_i32_u 0xB8 [i32]→[f64] validation execution, operator f64.convert_i64_s 0xB9 [i64]→[f64] validation execution, operator f64.convert_i64_u 0xBA [i64]→[f64] validation execution, operator f64.promote_f32 0xBB [f32]→[f64] validation execution, operator i32.reinterpret_f32 0xBC [f32]→[i32] validation execution, operator i64.reinterpret_f64 0xBD [f64]→[i64] validation execution, operator f32.reinterpret_i32 0xBE [i32]→[f32] validation execution, operator f64.reinterpret_i64 0xBF [i64]→[f64] validation execution, operator A.8 Index of Semantic Rules Typing of Static Constructs Typing of Runtime ConstructsRetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.3