WebAssembly Instruction Set Architecture Guide
This article provides a comprehensive overview of the primary instructions that make up the WebAssembly (Wasm) instruction set architecture. WebAssembly is designed as a low-level, stack-based virtual machine, and understanding its core instruction categories—including numeric, parametric, variable, memory, and control flow instructions—is essential for understanding how Wasm executes code with near-native speed and security.
The Stack-Based Design
Before diving into the instruction categories, it is important to note that WebAssembly operates on a conceptual operand stack. Most instructions pop their arguments off this stack, perform an operation, and push the result back onto the stack.
1. Numeric Instructions
Numeric instructions perform basic arithmetic, bitwise operations,
comparisons, and type conversions. WebAssembly supports four primary
numeric types: 32-bit integers (i32), 64-bit integers
(i64), 32-bit floats (f32), and 64-bit floats
(f64).
- Arithmetic Operations: Standard math operations
such as addition (
add), subtraction (sub), multiplication (mul), and division (div_sfor signed,div_ufor unsigned, ordivfor floats). Wasm also supports remainder (rem_s/rem_u), square root (sqrt), and absolute value (abs). - Bitwise and Shift Operations: Operations used to
manipulate bits, including
and,or,xor, shift left (shl), shift right (shr_s/shr_u), and rotation (rotl/rotr). - Comparison Operations: Used to compare two values,
pushing a boolean
1(true) or0(false) to the stack. Examples include equal (eq), not equal (ne), less than (lt), and greater than (gt). - Conversion Operations: Instructions that convert a
value from one type to another, such as wrapping, truncating, promoting,
demoting, or converting between integers and floating-point numbers
(e.g.,
i32.wrap_i64orf32.convert_i32_s).
2. Variable Instructions
Variable instructions provide access to local variables within a function, as well as global variables accessible across the entire module.
local.get: Reads the value of a specific local variable and pushes it onto the stack.local.set: Pops a value from the stack and writes it to a specific local variable.local.tee: Writes the top value of the stack to a local variable but leaves the value on the stack for subsequent instructions.global.get: Reads the value of a global variable.global.set: Mutates the value of a global variable (if the global is defined as mutable).
3. Parametric Instructions
Parametric instructions are generic operations that manipulate values on the operand stack regardless of their specific Wasm data type.
drop: Pops the top value off the stack and discards it. This is useful for ignoring the return value of a function call.select: Operates like a ternary operator. It takes three values from the stack: two operands and a condition (i32). If the condition is non-zero, it keeps the first operand; otherwise, it keeps the second operand.
4. Memory Instructions
WebAssembly utilizes a flat, linear memory model represented as a contiguous array of raw bytes. Memory instructions allow the virtual machine to read from and write to this space.
- Load Instructions: Read a value from a specified
memory address and push it onto the stack (e.g.,
i32.load,f64.load). Variants likei32.load8_sread a single byte and sign-extend it to a 32-bit integer. - Store Instructions: Pop a value from the stack and
write it to a specified memory address (e.g.,
i32.store,f32.store). memory.size: Returns the current size of the linear memory in pages (where one page is 64 KiB).memory.grow: Dynamically increases the size of the linear memory by a specified number of pages.
5. Control Flow Instructions
Unlike traditional assembly languages that use arbitrary jumps (like
goto), WebAssembly enforces structured control flow. This
makes validation faster and ensures execution safety.
block: Defines a sequence of instructions. Jumping out of a block moves execution to the instruction immediately following the block.loop: Defines a block of instructions that can be branched back to, creating a loop execution path.if/else/end: Conditional blocks. Theifinstruction pops ani32from the stack; if it is non-zero, theifbranch executes, otherwise theelsebranch (if present) executes.br(Branch): Performs an unconditional branch to a target label (defined by surrounding control blocks).br_if: Performs a conditional branch if the top stack value is non-zero.br_table: A jump table instruction, useful for compilingswitchstatements.return: Immediately exits the current function, returning any values currently on the stack as the function’s results.call: Invokes another function by its index.call_indirect: Invokes a function dynamically through a table of function pointers, which is crucial for implementing features like virtual method tables and dynamic dispatch.