Wasm Introduction (Part 5): Control Instructions
Written by the CoinEx Chain lab, this article is the fifth one of the Wasm Introduction series and introduces Control Instructions. CoinEx Chain is the world’s first public chain exclusively designed for DEX, and will also include a Smart Chain supporting smart contracts and a Privacy Chain protecting users’ privacy.
There are a total of 11 WebAssembly(referred to as Wasm) control instructions, of which unreachable
instruction (opcode 0x00
) and nop
instruction (opcode 0x01
) are relatively simple and thus will be omitted from this series. We have introduced call
instruction (opcode 0x10
) in the previous article, and will provide more information about the call_indirect
instruction (opcode 0x11
) next time. This article focuses on 7 instructions, i.e. block
(opcode 0x02
), loop
(opcode 0x03
), if
(opcode 0x04
), br
(opcode 0x0C
), br_if
(opcode 0x0D
), br_table
(opcode 0x0E
), and return
(opcode 0x0F
).
block
The effect of block
instruction is equivalent to a parameterless inline function call. The return value type of the function, which is the result type of the block
instruction (referred to as rt
in the diagram below), is encoded in the first immediate argument of the instruction. The function's instructions (possibly many) are encoded and stored in the second immediate argument. The block instruction must end with end
instruction (opcode 0x0B
). Since end
instruction and else
instruction (opcode 0x05
) to be described later only serve as a marker and have no execution effect, these two instructions are not counted in the control instructions.
The Wasml.0 specification stipulates that block
instruction cannot have more than one result, so rt
can be represented by one byte: 0x40
indicates no result, 0x7F
indicates i32
type, 0x7E
indicates i64
type, 0x7D
indicates f32
type, and 0x7C
indicates f64
type. According to the discussion, when the block
instruction is executed, it does not use any operand that already exists on the stack. After the execution is completed, an operand may be left on the top of the stack. The following diagram shows how block
instruction works:
Here is a very simple WATexample that shows the use of the block instruction:
loop
loop
instructions are very similar to block
instructions. The only difference is how to jump out of the control block, which will be discussed further in the introduction of br
instructions later. The following diagram shows the the difference of jumps:
if
Like block
instructions, if
instructions are similar to an inline function. There are two main differences. First, the if
'inline function' takes an i32
type parameter. Second, the if
'inline function' has two pieces of code (two branches), separated by an else
instruction. When the if
instruction is executed, the i32
type parameter is popped from the top of the stack first. If the parameter value is not equal to 0, the code of first branch is executed; otherwise the code of second branch is executed. The following diagram shows how if
instruction works:
You can also omit the else
branch of the if
instruction, but in this case the if
instruction cannot have any results. The following is a schematic diagram of the if instruction when the else branch is omitted:
br
br
instructions (which can be understood as break, or branch) can perform an unconditional jump. Unlike the JUMP
instruction in traditional assembly language, the br
instruction cannot jump to arbitrary position, but can only jump out (break for block
and if
instructions, and continue for loop
instruction, which will not be emphasized later.) of control blocks generated by other control instructions. br
instructions take an immediate argument of type u32
(a 32-bit unsigned integer) that specifies the number of layers to jump out: 0 means to jump out of the current block, 1 means to jump out of the Layer-2 block, and so on. Here is a WAT example showing the use of nested blocks and br
instructions:
br_if
The br_if
instruction pops an operand of type i32
from the top of the stack. If the value of the operand is 0, no jump is performed; otherwise the br
logic is executed. The following diagram shows how br_if
instruction works:
Please note that the loop
instruction does not automatically loop, and must be used in conjunction with jump instructions such as br
.
br_table
Whether it is a br
or br_if
instruction, there is only one immediate argument, which can specify a jump depth. The br_table
instruction breaks this limitation. It can take N + 1 immediate arguments and specify N + 1 jump depths. When the br_table
instruction is executed, an operand n
of i32
type is popped from the top of the stack. If n
is less than or equal to N, it jumps by the nth depth; otherwise it jumps by the last depth. The following diagram shows how br_table
instruction works:
return
The return
instruction can be considered a special form of the br
instruction: it directly jumps out of the outermost loop (that is, the entire function). The return
instruction has no immediate argument. The following WAT example shows how to implement switch-case statements in high-level languages such as Go with block
, br_table
, and return
instructions:
If the select3()
function defined in the above example is translated into Go language code, it should be as follows: