Master the fundamental concepts of webassembly internals through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksBrowsers refuse to instantiate invalid modules. Validation is a static type and stack check over every function body before execution, catching bad stacks and type mismatches early.
The validator tracks:
Rules mirror the spec: \`i32.add\` requires two \`i32\` values; \`call\` must target a function with compatible params; \`end\` must leave the stack matching the enclosing block signature.
For example, \`i32.add\` with only one \`i32\` on the stack is a validation error, not a runtime surprise.
\`\`\` error: type mismatch at i32.add stack: [i32] (expected [i32 i32]) \`\`\`
Validate before execute on every untrusted module. Browsers depend on this pass for safety; your interpreter should refuse modules that fail stack typing rather than corrupting memory at runtime.
This exercise asks you to implement a validator for a Wasm subset before your interpreter runs code. You will type-check function bodies and reject modules with impossible stack states.
You will use the same mental model here when reading production interpreter source later in the track. Sketch one concrete input on paper, predict the outcome, then confirm with code. That discipline catches logic errors early and makes debugging far faster when you extend the implementation in follow-on tasks.
Implement WebAssembly validation: type-check each function body before it may run, using the algorithm from the spec's appendix. Keep an operand stack of types and a stack of control frames. Each frame records its kind, its result type, the operand-stack height at entry, and whether the rest of the frame is unreachable. After unreachable, br or return, the stack becomes polymorphic: popping below the frame's height yields "any" instead of an error.
;; starts a comment.
cLoading…
The function's last end closes its body. Instructions:
i32.const i64.const (the argument is ignored).i32.add sub mul (i32 i32 → i32), i32.eq lt_s (→ i32), i32.eqz (i32 → i32).i64.add sub mul (i64 i64 → i64), i64.eq lt_s (i64 i64 → i32), i64.eqz (i64 → i32).i32.wrap_i64, i64.extend_i32_s.local.get/set/tee I.drop; select (i32 condition, then two operands of the same type).nop unreachable block [T] loop [T] if [T] else end br L br_if L return call NAME (calls may refer to later functions).expected T, found nothing. Otherwise it pops, and a mismatch fails with expected T, found U.br L pops the label's type, then makes the frame unreachable.br_if L pops an i32, pops the label's type, and pushes it back.return pops the function result and makes the frame unreachable.if first pops an i32. Then a frame opens at the current height.N extra value(s) on the stack at end). An if with a result but no else fails with if without else cannot produce a value. The result is then pushed onto the enclosing frame.unknown local I, unknown label L, unknown function X, unknown instruction X, bad block type Xelse without matching if, N extra value(s) on the stack at elseinstructions after the function's end, missing endOne line per function, in order, then a summary:
cLoading…
The position is the instruction index within the function, starting at 0, followed by the instruction and its argument. Only the first error in each function is reported. Loader messages: line N: bad func, line N: bad func header word X, line N: outside a func.
Input:
cLoading…
Output:
cLoading…
pop with the unreachable rule exactly. Code after unreachable or br must type-check against any operand.Hidden tests cover if/else with results (and the missing-else case), a mismatched else-branch, polymorphic stacks after unreachable and br, br_if carrying a value, branches with the wrong type, loop labels, unknown labels, forward calls, argument mismatches, select mismatches, and structural errors.