Accessing memory


The accessing instructions contain load and load series. All load instructions pop off an i32 value as an unsigned integer byte offset. You can see how many bytes the instruction would read or extend. The loaded value is pushed onto the stack.

  • i32.load8_s: load 1 byte and sign-extend i8 to i32
  • i32.load8_u: load 1 byte and zero-extend i8 to i32
  • i32.load16_s: load 2 bytes and sign-extend i16 to i32
  • i32.load16_u: load 2 bytes and zero-extend i16 to i32
  • i32.load: load 4 bytes as i32
  • i64.load8_s: load 1 byte and sign-extend i8 to i64
  • i64.load8_u: load 1 byte and zero-extend i8 to i64
  • i64.load16_s: load 2 bytes and sign-extend i16 to i64
  • i64.load16_u: load 2 bytes and zero-extend i16 to i64
  • i64.load32_s: load 4 bytes and sign-extend i32 to i64
  • i64.load32_u: load 4 bytes and zero-extend i32 to i64
  • i64.load: load 8 bytes as i64
  • f32.load: load 4 bytes as f32
  • f64.load: load 8 bytes as f64

The following module uses i32.load8_s read 8 bytes five times.

(module
    (import "env" "log" (func $log (param i32)))
    (memory (data "Hello"))
    (func $main
        (local $i i32)
        loop
            (i32.load8_s (get_local $i))
            call $log
            (set_local $i 
                (i32.add
                    (get_local $i)
                    (i32.const 1)
                )
            )
            (br_if 0 
                (i32.ne
                    (get_local $i)
                    (i32.const 5)
                ) 
            )  
        end
    )
    (start $main)
)

The imported $log function uses String.fromCharCode to create a string every time so the console will print "Hello".

const importObj = {
    env: {
        log(n) {
            console.log(String.fromCharCode(n));
        }
    }
};

WebAssembly.instantiateStreaming(fetch('program.wasm'), importObj);

If any of the accessed bytes are beyond the current memory size, the access is considered out-of-bounds.

All store instructions pop off the value you want to save and then an unsigned integer byte offset. For example, if you want to save 72:

(module
    (import "env" "log" (func $log (param i32)))
    (memory 1)
    (func $main
        i32.const 0   ;; offset
        i32.const 72  ;; the value you want to save
        i32.store8
        i32.const 0
        i32.load8_s
        call $log
    )
    (start $main)
)

The code is not intuitive; however, you can use the style shown below.

(module
    (import "env" "log" (func $log (param i32)))
    (memory 1)
    (func $main
        (i32.store8 (i32.const 0) (i32.const 72))
        (i32.load8_s (i32.const 0))
        call $log
    )
    (start $main)
)

Store instructions do not produce a value.

  • i32.store8: wrap i32 to i8 and store 1 byte
  • i32.store16: wrap i32 to i16 and store 2 bytes
  • i32.store: (no conversion) store 4 bytes
  • i64.store8: wrap i64 to i8 and store 1 byte
  • i64.store16: wrap i64 to i16 and store 2 bytes
  • i64.store32: wrap i64 to i32 and store 4 bytes
  • i64.store: (no conversion) store 8 bytes
  • f32.store: (no conversion) store 4 bytes
  • f64.store: (no conversion) store 8 bytes