Sikau

WebAssembly · Day 5 · about 35 min

A stack machine

Wasm instructions push and pop an operand stack — interpret them yourself.

No registers, just a stack

Unlike RISC-V, wasm is a stack machine: i32.const 2 pushes 2, i32.add pops two values and pushes their sum. Locals hold named values. This makes the bytecode tiny and easy to validate — and easy to interpret.

An interpreter

function runStack(code, locals = []) {
  const stack = [];
  const L = [...locals];
  const pop = () => {
    if (!stack.length) throw new Error("Stack underflow");
    return stack.pop();
  };
  for (const line of code) {
    const [op, arg] = line.split(" ");
    switch (op) {
      case "i32.const": stack.push(Number(arg) | 0); break;
      case "local.get": stack.push(L[Number(arg)]); break;
      case "local.set": L[Number(arg)] = pop(); break;
      case "drop": pop(); break;
      case "i32.add": { const b = pop(), a = pop(); stack.push((a + b) | 0); break; }
      case "i32.sub": { const b = pop(), a = pop(); stack.push((a - b) | 0); break; }
      case "i32.mul": { const b = pop(), a = pop(); stack.push(Math.imul(a, b)); break; }
      default: throw new Error(`Unknown instruction: ${op}`);
    }
  }
  return { result: stack[stack.length - 1], stack };
}

The rest of this lesson

  • Tracing the stackexplain
  • Order matters for subexplain
  • Run it in your headpredict
  • Subtract on a stackpredict
  • Interpret itwrite code
  • Badge quizquiz
  • What you learnedrecap

Continue this lesson free — run real code in your browser

Continue with Google

See all 8 lessons of WebAssembly