Skip to content

Instantly share code, notes, and snippets.

@dy
Last active June 22, 2023 17:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dy/a946ff52c3de95a09edd080f0bf3705c to your computer and use it in GitHub Desktop.
Save dy/a946ff52c3de95a09edd080f0bf3705c to your computer and use it in GitHub Desktop.
WASM gotchas

Params order

First taken from stack as block, then augmented with inline param.

(func $x (param i32 i32 i32))
...
(i32.const 0)(i32.const 1) (call $x (i32.const 3))

;; converts to
(call $x (i32.const 0)(i32.const 1)(i32.const 3))

Multiple function calls

Function call pops value from stack. Stack doesn't have to match fn signature - it should only have enough elements for the call.

...
(i32.const 0)(i32.const 1)(i32.const 2)
(call $log)(call $log)(call $log)

;; 2, 1, 0

Loop, if, block params

They pick args from the stack, not enforce it. But they pick it only once, at the moment of entry. Single loop cannot be used to flush stack.

(func $x
    (i32.const 0)(i32.const 1)
    (loop (param i32)
      (call $log) ;; prints 1
    )
)

Local variables

Numerated from 0 after params

(func $x (param i32 i32) (result i32) (local i32)
(local.get 0) ;; first param
(local.get 1) ;; second param
(local.get 2) ;; local
)

Functions numeration

Starts from 0

(func
    (return)
)
(export "x" (func 0))

Blocks/loops/ifs branching index

Branching index counts structured controls blocks, like

(func
    (local i32)
    
    (block (;2;)
      (loop (;1;)
        (if (...) (;0;)
          (then
            (br_if 0 (i32.const 1))
            ;; (br 1) here would be the same as
          )
        )
        ;; (br 0) here
      )
    )
  )

Early return

Return be called within blocks/loops/conditions & that breaks function with last value from stack, it ignores any con

(func $x (result f64)
  (f64.convert_i32_s
    (if (xxx) (then
      (block
        (return (f64.const 3.14))
      )
    ))
    (i32.const 1)
  )
)

Sync compilation vs async:

Main thread buffer is limited to 4kb:

  // sync instance - limits buffer size to 4kb
  const mod = new WebAssembly.Module(buffer)
  const instance = new WebAssembly.Instance(mod, config)

  // async instance - buffer size can be any but compiles slower
  const instance WebAssembly.instantiate(buffer, config)

Max array multiple values return

That's 1000. If return is more that 1000 it throws error : return count of 1001 exceeds internal limit of 1000 @+14

(func $x (result i32 i32 ...i32x1001)
  (return)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment