A language-building environment, on ARM

Down to the metal.
Inside your browser.

Kevin Greer’s TURTLES, booting from a real ARM machine-code image. QEMU runs in this tab. The language runs in the emulated machine.

AArch64No guest operating systemCompiler written in T0

One session · choose its language


Checking the latest build…

Preparing the demo
Latest verified image

A whole machine, one small language.

Boot one T0 environment. Switch to JS-like or SOM whenever you like; your bindings and objects stay in the same session.

Desktop Chrome recommended. No account or installation required.

Click the terminal to type. Enter runs a line; use :paste and :end for multiline input.

Try an example

Switch readers with the language buttons or :t0, :js and :som. Your session stays alive until reboot.

What is running?

All the way into the guest.

The browser downloads QEMU as WebAssembly and boots the ARM image. One boot loads T0 and both language layers. The language command simply selects which parser/compiler reads your next input. Both are T0 programs. New code is parsed and compiled inside that machine. The JavaScript host option runs the same language sources in the original T0 interpreter.

Bare metal here means no operating system beneath T0 in the virtual machine. This demo does not claim a boot on physical ARM hardware.

Run it locally

Same bytes. Another machine.

Download the single ELF image below. Install QEMU (brew install qemu on macOS; sudo apt install qemu-system-arm on Ubuntu), then run:

qemu-system-aarch64 -machine virt-8.2 -cpu cortex-a53 -accel tcg -m 512M -smp 1 -nographic -device loader,file=turtles.elf,cpu-num=0

The image boots into T0. Enter :js or :som to select that reader; :t0 returns to T0 without clearing any state. Exit QEMU with Ctrl-a, then x. For multiline input, enter :paste, your program, and :end on its own line.

Memory, browser support and self-hosting

The guest has 512 MiB RAM and no garbage collector. Its arena and heap grow monotonically. Exhaustion halts the guest; reboot starts a fresh machine and clears its state.

The browser emulator reserves a larger shared memory address space than the guest RAM. Desktop Chrome is the primary target. A download of approximately 58 MB is required on first boot; a supported browser and enough memory are needed. GitHub Pages uses a same-origin service worker to enable WebAssembly threads.

The JS-like and SOM parser/compiler layers execute in T0. A language switch changes how the next input is read, while keeping the stack, bindings and heap. Their calling conventions and object models can differ; shared storage does not make the dialects identical. The ARM primitive core is assembly, and the image builder remains JavaScript running under Node. A guest that rebuilds its own native image is a future milestone.

Target: 64-bit ARMv8-A (AArch64), Cortex-A53, QEMU’s virt-8.2 board, 512 MiB RAM and PL011 serial console. This is a different platform from upstream’s planned RP2040 / Cortex-M0+ target.

ARM strings use UTF-8 storage: len and byteLen count bytes, while strlen counts code points. charAt reads at a byte offset, nextCharPos advances to the next character, and $indexOf returns a byte offset. On arrays, len counts elements and @ reads an element. charCode constructs a Unicode scalar. The JavaScript prototype keeps ordinary length and character indexing, with nextCharPos adding one. Memory is bounded, with repairs for malformed input and captured locals. JavaScript host objects and prototypes are not exposed by the ARM guest. The JS-like dialect has function-scoped let, functions, arrows, mutable closures and recursion; it does not implement full JavaScript, objects, classes, string literals or const.

ARM values are untagged 64-bit words. Arithmetic uses signed integers, with wrapping addition and multiplication and truncating division. Floating-point literals are unsupported. Use +$ for string concatenation and print$ for text; print and automatic REPL results display signed words. Operations assume the right operand representation. The JavaScript host retains its Number arithmetic.

The SOM layer uses Kevin’s closure-based objects and direct T0 source generation for expressions, messages, blocks and classes. String messages include ,, length, at: and printString. On ARM, string lengths are bytes and at: takes a one-based byte offset; arrays use size, arrayAt: and at:put:. Inheritance delegates to parent closures. Fractional literals, native primitive declarations, nonlocal returns from blocks and the full SOM standard library are unsupported. Ordinary method ^ returns are supported.

Browser QEMU 8.2 comes from pinned, checksum-verified author-hosted Wasm artifacts. These binaries are downloaded on demand; the author did not identify their exact source commit.