Wasm Introduction (Part 3): Memory
Written by the CoinEx Chain lab, this article is the third one of the Wasm Introduction series and introduces Memory. 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.
The previous article introduced the WebAssembly(Wasm for short) instruction set and the concepts such as the opcode, immediate arguments, operands, and operand stack, with details on parametric instructionsand numeric instructions. This article will focus on Wasm memory and related instructions.
Memory
Each Wasm modulecan defineor importone memory. The unit of memory is page, and the page size is 64K. When defining memory, you need to specify a lower limit on the number of pages of memory. The maximum number of pages is optional and can be specified or not. The initial data of the memory can be specified in data sections. Here is a WATexample showing the definition of memory and data segments:

There are 25 instructions related to memory, which are introduced below one by one.
memory.size
The memory.size
instruction (opcode 0x3F
) pushes the current page number of memory onto the top of the stack as i32
. The memory.size
instruction takes a 1-byte immediate argument that specifies which memory is being manipulated. As the Wasml.0 specification stipulates that there can be at most one memory, the immediate argument can only be 0 at present. The following is a diagram of the memory.size
instruction:

memory.grow
The memory.grow
instruction (opcode 0x40
) increases memory by n
pages, where n
is an integer of type i32
and is popped from the top of the stack. If the operation is successful, push the number of pages before growth to the top of the stack as i32
type; otherwise push -1
to the top of the stack. Like the memory.size
instruction, the memory. grow
instruction also carries a 1-byte immediate argument, which must be 0. Here is the schematic diagram of the memory. grow
instruction:

load
Load instructions read data from memory and push it to the top of the stack. How many bytes of data are read and what types of data are interpreted vary from instruction to instruction. Wasm uses the “immediate arguments + operands” memory addressing method. All load instructions carry two immediate arguments in u32
type (LEB28-encoded32-bit unsigned integers), one for alignment and the other for memory offset. Load instructions also need to pop an i32
-type operand from the top of the stack. The immediate argument and the operand are added to obtain the actual starting address of the memory to be read. The alignment only serves as a hint and does not affect the actual operation. This article does not provide more information about alignment. For details, please refer to the Wasm specification. Take the i64.load
instruction (opcode 0x29
) as an example. The following is a schematic diagram of it:

There are 14 load instructions. In order to explain these instructions in a unified manner, we assume that the memory address calculated when the instructions are executed is a
, and the data stored here is 0xABCDEF1234567890
. Since Wasm stores data in little-endianway, the memory data looks like this:

The following table shows the opcodes of the 14 load instructions, the bytes actually read, and how to interpret the bytes:

store
Store instructions pop the operand from the top of the stack and write it to memory. How to interpret the operand and how many bytes are written vary from instruction to instruction. All store instructions also carry two immediate arguments, which have the same meaning as load instructions. Different from load instructions, store instructions pop two operands from the top of the stack. One is to calculate the memory address, and the other is the data to be written. Take i64.store
instruction (opcode 0x37
) as an example. The following is its schematic diagram:

There are a total of 9 store instructions. To explain these instructions uniformly, we also assume that the memory address calculated when the instructions are executed is a
. The following table shows the opcodes, top-of-stack operand, and actual execution results of these 9 instructions. Effects are given in Golang pseudo-code, with mem
represents memory, and LE
represents byte array after little-endian encoding.
