Luce / engineering
Learn Luce LuciaOS

The runtime beneath both execution paths

LLVM can emit scalar arithmetic directly. Lists, class lifetime, worker transfer, text storage, and source-aware traps use the native runtime shared by compiled programs and the test interpreter.

A useful dividing line

If an operation depends only on scalar registers, LLVM can often inline it. If it needs Luce’s heap, object table, host capabilities, or error state, generated assembly calls the Zig runtime.

Where the runtime sits

Two callers, one semantic libraryBoth execution paths call the same operations
Native codecalls the published luce_rt_* C exports
Interpretercalls the Zig runtime surface from its MIR dispatch loop
libluce_rtone heap, value, container, text, operator, resource, worker, and trap implementation

Both execution paths call the same runtime operations for lists, text, objects, workers, and traps. A differential test can then focus on whether native code and MIR dispatch invoke those operations in the same order with the same values.

The runtime modules

The 24-byte value passed around the runtime

Runtime operations exchange a C-layout 24-byte Value. A tag selects the view: scalar bits, inline or outside text, an object handle, absence, a function pair, or another defined representation. Zig callers use a tagged view(); generated code uses constants whose layout is asserted against the Zig struct.

Handles make moving storage safe

A program holds object-table handles containing an index and generation. This indirection lets a list reallocate its buffer while aliases keep the same handle, prevents an old weak handle from matching a reused row, and lets the runtime inspect all live objects at the end of a run.

Failure at the runtime boundary

A fallible C export returns a status and writes results through out-pointers. A trap is recorded in the runtime once, then propagated through generated frames. Allocation exhaustion has its own run status. Callers can therefore distinguish a recoverable language error, a program trap, and exhausted machine resources.

The library stands below the compiler

Dependency arrows point from the compiler and runners toward the runtime. Shared enum vocabulary—trap codes, error codes, operators, and service failures—lives under support/. This keeps front-end parser and analyzer code out of the library linked into every artifact.