WebAssembly Easy · Lesson 1 · On the house

Tables and call_indirect

funcref table, elem init, call_indirect for dynamic dispatch. Lesson 1 is free — on the house.

Lessons · WebAssembly Easy · Lesson 1 of 10 · On the house

Tables and call_indirect

funcref table, elem init, call_indirect for dynamic dispatch.

Illustration for WebAssembly
Lesson 1 is on the house.

A table holds references — commonly funcref — so you can pick a function at runtime. Declare (table 2 funcref) for two slots, or import a table from the host.

(elem (i32.const 0) $add $mul) fills table slots starting at index 0 with function references. Active elem segments initialize at instantiate; passive ones need table.init.

call_indirect (type $binop) pops a table index (i32), looks up that funcref, and calls it. The type immediate must match the callee signature or the engine traps.

Compilers use tables for virtual calls, switch-to-call lowering, and dynamic linking. Direct call $name stays cheaper when the target is known; call_indirect is for dynamic dispatch.

Misses: omitting the type on call_indirect, indexing past table size, or putting numeric values in a funcref table instead of function refs.

tables-indirect

(module
  (type $binop (func (param i32 i32) (result i32)))
  (func $add (type $binop)
    local.get 0 local.get 1 i32.add)
  (func $mul (type $binop)
    local.get 0 local.get 1 i32.mul)
  (table 2 funcref)
  (elem (i32.const 0) $add $mul)
  (func (export "apply") (param $i i32) (param $a i32) (param $b i32) (result i32)
    local.get $a
    local.get $b
    local.get $i
    call_indirect (type $binop)))
Match this when you type.

Quiz

What does a funcref table store?

Quiz

What does call_indirect need besides stack args?

Quiz

What does (elem (i32.const 0) $add $mul) do?

Quiz

What happens if call_indirect’s type does not match the callee?

Check

Match the still for: Tables and call_indirect.

Open-book: the answers are on this page. Pass every quiz and check (5) to mark the lesson done. This visit: 0/5.