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 worksWasm exposes one or more growable byte arrays called memories. \`memory.grow\` adds 64 KiB pages; loads and stores use \`i32\` addresses into index 0 by default in MVP modules.
Properties:
Hosts map the same linear memory for JS \`WebAssembly.Memory\` views or WASI \`mmap\` equivalents.
For example, \`memory.grow(1)\` on a 1-page memory yields 2 pages (128 KiB). An \`i32.store\` at offset 70000 traps on a single-page memory.
\`data\` segments copy initializer bytes into linear memory at compile time or instantiation.
Hosts may share one linear memory with multiple views (i8, i32). Alignment rules still apply; unaligned atomics have their own rules in threaded proposals you may see in newer specs.
This exercise asks you to document linear memory layout and \`memory.grow\` semantics. You will explain page growth and why every access must be bounds-checked for sandbox safety.
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.
Model WebAssembly linear memory: a byte array whose size is a whole number of 64 KiB pages. It has a declared minimum and an optional maximum. memory.grow returns the old size in pages, or -1. Loads and stores are little-endian, come in several widths, zero- or sign-extend, and take an offset immediate. The effective address base + offset is computed without 32-bit wraparound. Any access past the end traps, including a bulk memory.fill/memory.copy, which checks its whole range before touching a byte.
;; starts a comment. Numbers are decimal or 0x hex. Negative numbers are reinterpreted as u32 (-1 is 0xFFFFFFFF).
cLoading…
cLoading…
0x%08x, after zero- or sign-extending (_u/_s) to 32 bits.memory: N page(s) (B bytes), plus , max M when a max was given.trap: out of bounds memory access (address A + W bytes, memory is S bytes), where A is base + offset as a 64-bit number and W is the access width (or the length for bulk operations). A trapping operation changes nothing. copy checks the source range first.%08x: and the bytes.Errors:
no memory defined (before the first memory)memory: MIN [max MAX], memory: min A is larger than max B, memory: this model allows at most 16 pagesgrow: PAGESstore: ADDR VALUE [offset=N] (by the command's name)load: ADDR [offset=N]fill: DST BYTE LEN, copy: DST SRC LEN, dump: ADDR LEN (1-32)bad offset, and OP: missing address when only an offset= is givenunknown command XInput:
cLoading…
Output:
cLoading…
base + offset + width in 64 bits before comparing with the memory size. A 32-bit sum could wrap and pass the check.Hidden tests cover a zero-page memory that grows, overlapping copy, fill at the edge (no partial write), addresses that would wrap in 32 bits, 16-bit sign extension, growth to the model's limit, and command errors.