Linear Memory
8.1 Memory Basics
Linear memory is a byte array measured in pages of 64 KiB. It has an initial and an optional maximum size, and can grow (memory.grow) but never shrink.
Wasm32 addresses are i32 (max 4 GiB). Memory64 allows i64 addresses (Module 27).
All accesses are bounds-checked. Out-of-bounds accesses trap.
(module
(memory (export "memory") 1 10) ;; 1 page initially, max 10 pages
(data (i32.const 0) "Hello, Wasm!") ;; active data segment at offset 0
(func (export "sum_bytes") (param $ptr i32) (param $len i32) (result i32)
(local $i i32) (local $acc i32)
(block $done
(loop $next
(br_if $done (i32.ge_u (local.get $i) (local.get $len)))
(local.set $acc
(i32.add (local.get $acc)
(i32.load8_u (i32.add (local.get $ptr) (local.get $i)))))
(local.set $i (i32.add (local.get $i) (i32.const 1)))
(br $next)))
(local.get $acc))
(func (export "grow") (param $pages i32) (result i32)
(memory.grow (local.get $pages))) ;; returns the previous size in pages, or -1 on failure
(func (export "size") (result i32) (memory.size)))8.2 Load and Store Instructions
i32.load, i64.load, f32.load, f64.load Load full-width values
i32.load8_s/u, i32.load16_s/u, i64.load8/16/32_s/u Load narrower values with sign/zero extension
i32.store, i64.store, f32.store, f64.store i32.store8, i32.store16, i64.store8/16/32 Store narrower values memory.size, memory.grow
memory.fill, memory.copy, memory.init, data.drop Bulk memory (Module 21)
offset is a static immediate added to the address. align is a hint (a power of two). Wasm is little-endian.
(i32.store offset=4 align=4 (local.get $ptr) (i32.const 99)) ;; store at ptr+4
(i32.load offset=8 (local.get $ptr))8.3 Memory Management Strategies
Wasm itself has no malloc. Languages bring an allocator in linear memory:
C/C++: dlmalloc/emmalloc/mimalloc (Emscripten), wasi-libc malloc
Rust: its default allocator (dlmalloc for wasm32), or talc/lol_alloc for size
AssemblyScript: incremental/minimal/stub runtimes A simple bump allocator in WAT:
Memory layout in typical compiled programs: [static data | stack (grows down, in linear memory for address-taken locals) | heap (grows up)].
(global $heap (mut i32) (i32.const 1024))
(func $alloc (export "alloc") (param $size i32) (result i32)
(local $ptr i32)
(local.set $ptr (global.get $heap))
(global.set $heap (i32.add (global.get $heap) (local.get $size)))
(local.get $ptr))