GizStack
View .mdOpen in ChatGPTOpen in Claude

Runtime

runtime/ is the C platform layer. Generated programs link against it. bin/giz builds it as libgizlang_runtime.a and libgizlang_runtime.so. A program an installed toolchain builds on Linux or macOS loads the release's lib/gizlang/TARGET/libgizlang_runtime.so (.dylib on macOS: the runtime, libuv and OpenSSL) from its versions folder, so a runtime fix reaches it without a relink and the programs on a host share one copy; a fast (-O0) source build loads the build folder's. GIZLANG_RUNTIME_STATIC=1 links the archive, for a program copied to a machine without the toolchain. The toolchain's own programs link the archive (tools/cli/build.giz runtimeShared). Windows: see Windows.

The runtime owns no language semantics. The compiler checks types, effects and borrows. The runtime gives storage, handles and I/O through a narrow gizlang_* C ABI.

Files

FileOwns
resources.cOne handle table of files, sockets and processes: handles checked by generation, leases, borrows, deferred disposal, owner thread.
heap.cThe precise, non-moving managed heap of each World, for Ref<T>: its own handles, typed roots, holds for values owned outside frames (task boxes, channel items, live state), collection. MEMORY owns the model.
value_layout.cWalks the layout descriptors that the compiler emits (scalars, Refs, slices, products, variants): traces Refs, counts buffers as generated dup and drop do, and encodes a value independently of its position, for replay.
replay.cRecords the inputs of a run (declared I/O results, Task.now, batches of woken tasks) and replays them with no I/O (giz run --record/--replay LOG). A different call is a divergence (status 76).
services.cBinds one heap, one handle table and one I/O loop to a call context.
refs.cRef create, load, store and collect. Holds and roots over the heap of the calling context (gizlang_services_heap).
io.cThe only event loop, on pinned libuv 1.53.1 (commit eb497c58). Timers, files, TCP connect, listen and accept, DNS, cancellation tokens.
fs.cFiles scoped by capability: attenuating grants, directory-relative opens that do not follow links, file size and time, directory creation, remove and list.
text.cConsole output (with the console grant of the call).
base64.cBase64. It is freestanding: the native and the Wasm runtime both link it. Refer to Base64 in C.
isolate.cA process spawned isolated confines itself at start: namespaces, its folder as root, no capabilities, seccomp, no new machine code.
uring.cThe C part of System.ring: one io_uring of 128-byte entries that carries URING_CMD (the ublk driver of fs/ublk.giz), and the read-only map of a descriptor area (System.mapShared). It is the only io_uring of the runtime. Refer to SYSTEM.
levels.cgizlang_cpu_level: the x86-64 level (baseline, v3 or v4) that the vector functions of a program run at (tools/cli/levels.giz gives each one a copy for each level). It reads the CPU once, or the level that GIZLANG_CPU names, and stops a program with a wrong GIZLANG_CPU before main.
machine.cgizlang:machine, the one owner of the host's CPU facts: the instruction-set features, capped at the levels.c level (no AVX-512 under GIZLANG_CPU=v3), the CPUs of the process's affinity, each cache instance and the CPUs that share it, and the memory nodes. It reads them once a process (sysfs on Linux, sysctl on macOS).
glibc235.cLinked into every program, so that it runs on glibc 2.35 and later. It gives the __isoc23_* functions that glibc 2.38 headers call under _GNU_SOURCE. It is compiled without _GNU_SOURCE, so it calls the older functions. tests/tools/levels checks that no symbol is newer than 2.35. On Windows it holds the thread's marked bytes instead (a DLL cannot share a thread-local variable).
win32.cWindows only (empty elsewhere): the POSIX file, directory, descriptor and process calls that win32.h declares, on Win32 handles, so the other files keep one code path. Refer to Windows.
format.cValue text, and UTF-8 validation of the C strings that native calls return. It uses memory only, so Wasm shares it. string(bytes) validation and byte search are Gizlang SIMD (utf8Valid in sdk/core/runtime.giz, bytes.indexOf and indexOfAny in sdk/core/text.giz). gizlang_text_utf8, _find and _find_any stay only for a CLI that the seed builds, until the next new seed.
task.cStructured tasks: stackful coroutines (x86-64 and AArch64 switch, guarded MAP_NORESERVE stacks, ASan fiber hooks), one ready queue, the io.c loop when nothing is ready, cancellation and deadlock faults, and bounded channels whose values are checked by layout key.
system.cThe services behind gizlang:system: one handle table of directories, files, TCP and pipe streams, listeners, datagram sockets, Ready sets and child processes. The task that opened each one owns it. It operates over fs.c and io.c.
state.cNamed live state (gizlang:live): objects held by World and name, migrated by exact schema keys. Process and thread teardown release only the bindings of that World.
process.cRuns an entry. The process main, the test runners and the live host share the World, grants, memory limit and leak check.
live.cThe giz live host. A builder builds generations when sources change. A forked host loads a complete immutable function table and publishes it through the execution owner.
compiler_driver.c, compiler_transport.cThe file transport of the compiler executable, linked with memory.c and format.c (string conversion and search).
wasm.c, wasm/, wasm.mjsThe Wasm platform layer (wasm64, no C library). wasm/ declares the C functions that it defines. format.c, refs.c, state.c, heap.c, resources.c and value_layout.c are built for it. Refer to Wasm.

Base64 in C

Base64 stays in C. Three Gizlang versions were measured against the C version (the limit is 1.3 times):

DateGizlang versionResult
2026-10-10Scalar33 ms (encode) and 38 ms (decode) for 30 MB, against 9 ms and 7 ms for C with AVX2.
2026-10-11SIMD types2.0 times (encode) and 1.8 times (decode) the time of C. string() validates its output, and a new buffer starts with zeros.
2026-10-11The C algorithm with shuffle, mul_high and lookup161.15 times at 30 MB, but 2.2 times (encode) and 1.4 times (decode) at 64 KB. There, the copy and check of string() on output that is ASCII by construction took 13 of the 31 ms of the encoder.

Wasm

Besides a process main, the Wasm layer runs host calls. Each entry-module function export function NAME(input: bytes): bytes (the table that compiler/entry.giz emits) runs in one World that is kept between calls. Thus gizlang:live state persists. wasm.mjs is the host for Node and browsers. It grants only console output.

Contracts

One owner for each concern

There is one handle table, one heap for each World and one event loop. Language adapters never get their own file, socket or scheduler stack.

Handles, not pointers

Every resource is a handle that is checked by generation and bound to a World and an owner thread. A stale or foreign handle fails. Pointers never leave the runtime.

Owned values

  • A string, bytes or Vec value is {address, length}. A nonzero address points immediately after a 16-byte header {count, capacity} (Gizlang_BufferHeader).
  • Generated code owns the counting. It allocates, shares, appends in place when the count is 1, and frees.
  • A negative count marks an immortal buffer. Literals are immortal, and so is any owned value that a host passes in. The compiler driver does this for its input.
  • Every allocation is charged to memory_remaining of the context. Every free returns it.

Managed memory

MEMORY owns the model: the owners, the budget, roots and collection.

  • Layouts come from the compiler as LLVM constant expressions. Thus there is no second layout calculator in C.
  • Collection validates every edge before it sweeps.
  • A root slot of an expression temporary ends where the temporary ends (dropTemporaries in compiler/emit.giz). An if, while or for condition drops its temporaries before the body runs.
  • A dead or foreign handle in a root, hold or traced edge fails collection with -40207 (GIZLANG_HEAP_ROOT). This is a defect of the compiler or runtime, not of the Ref that the caller gave.
  • Trace callbacks cannot allocate or run user code.
  • A Ref load gives the caller one more owner of the value's buffers (copy on write). Later stores or collections cannot change it. A stale Ref fails with -40208.
  • GIZLANG_GC_STRESS=1 collects at every Ref allocation and store while 64 objects or fewer live, and at one in live/64 past that. A Ref that generated code holds without a root then fails at once. It is the default of giz test for programs and suites (GIZLANG_GC_STRESS=0 turns it off). The compiler itself always runs without it. A test pass under stress is stored apart from a normal pass.

Tasks

  • The scheduler is in context word 3. It runs on the owner thread.
  • Each task keeps its own root chain. While the task is suspended, the chain is parked in the heap, so collection traces every task.
  • Each task keeps its own stack floor: the end of its stack plus the reserve (gizlang_stack_floor for the own stack of a thread).
  • The box of a task holds its closure, then its result. The layout key of the result is checked when the result is taken.
  • When a task ends, it cancels and waits for its unfinished children. The process root does this before the leak check.

Pure parallel frames

A pool worker owns a shared computation budget and no World.

  • Before dispatch, the initialized capture is checked one time through the same typed transfer owner as threads and crossing channels. This includes erased callable environments.
  • Nonzero Refs are refused. The check does not borrow the heap of the caller.
  • Frame registration alone cannot certify slots that are filled later.
  • Vectors without references, including recursive types, are skipped by their immutable element layout. The cost of tracing does not increase with their population.
  • Retirement requires the original frame and context. Ordinary unbound calls still refuse registration.
  • The worker never borrows a World.

Verification:

  • Twelve callable-transfer fixtures pass without cached verdicts, with one core and with two cores, in an isolated compiler build at a fixed point. They include owned BLOB rows built in pure parallel bodies, and owned BLOB temporaries in scalar fill bodies, also with a short final chunk.
  • Three repeated parallel and fill failures keep fault 4, and a later dispatch in the same process succeeds.
  • Ordinary recursive copy-on-write page directories keep captured BLOB versions across a parallel transfer. A callable that hides a Ref-bearing page payload still refuses with fault 14.
  • The checks include rejection of an erased Ref. Compiler SHA-256: 3dee5edae234d94386c2ea5019e214c11bb72ff9a49e37e5500e74bdff5daf73. Runtime archive: 711ddf6d94701e2235e864f7276f1801861bb1aef1d6be54e333317d008559a8.
  • tests/runtime/tasks/owned-blob-kernels uses the same fixtures as a scenario that always runs, at -O2. It passed with two-core admission, independently of the -O0 checks of the normal test-file runner. The two-core admission of the runtime was checked independently.
  • These fixtures do not prove multicore SQL throughput.

I/O lifetime

  • A buffer lives longer than its operation.
  • Cancellation is a request. Only the completion callback releases the storage of the operation.
  • Cancellation from a different thread goes through retained tokens and one wakeup queue on the owner loop.

Live code swap

  • One publication shows the complete function table.
  • Named dispatch and indirect callable invocation pin one table for their execution boundary.
  • The scheduler saves the table across suspension, and gives it to spawned tasks and threads.
  • Pure parallel workers inherit it without a World and without a change to their allocation budget.
  • Dispatch restores the previous token before a fault propagates.
  • This contract does not include transactional migration of state or schema, or safe early reclamation. Libraries that loaded successfully stay loaded, for their data layouts, callbacks and literals.

Explicit durability

  • A write is durable only after Stream.sync returns. Stream.sync runs fdatasync on the thread pool of the loop.
  • The file calls of a process (read, write, sync) share one pool of 64 threads (libuv's default is 4: four fsyncs that wait stopped every other file call). UV_THREADPOOL_SIZE sets another size. A process whose cgroup allows fewer than 1024 tasks keeps 4 (runtime/io.c).
  • A created, renamed or removed entry is durable only after Dir.sync of its directory.
  • Dir.syncFilesystem makes all data written to the file system of a directory durable, with the entries of its directories, in one syncfs on the thread pool (sync where there is no syncfs). It needs write authority. Use it for many files: 950 kept blobs took 3 s of fsyncs 4 at a time on backup.
  • readAt, writeAt and truncate address a file by offset. readMany reads many offsets in one io_uring batch (runtime/uring.c).

Teardown never guesses

  • A World with active calls, pending operations, roots or borrows refuses release, and reports the reason.
  • It never drains, cancels or rolls back implicitly.
  • Nothing undoes completed external effects (files written, bytes sent).

Limits

LimitValueFault
Owned values and heap objects of a WorldGIZLANG_MEMORY_LIMIT bytes. The default is 80% of the machine's memory, or of its cgroup's memory.max when that is lower (4 GiB where neither is known). Tests run with 256 MiB.R011
Call depth10,000R009
Wall-clock timeNo limit.

When main returns, every buffer must be free. If bytes are still taken, the process entry reports them on stderr and exits with status 70. Thus each test run is also a leak check.

Warning: Isolation is per process (SpawnOptions.isolated, SYSTEM), not in the process. Do not run code that you do not trust in the process and call it isolated. The compiler, LLVM and the C runtime are trusted. None of them has had an independent security review.

Windows

x86_64-pc-windows-gnu (Windows 10 1709+ x64, UCRT) builds with llvm-mingw: bin/giz tools/windows/runtime.giz build ARCHIVES WORK OUT writes libgizlang_runtime.a, libgizlang_runtime.dll with its import library libgizlang_runtime.dll.a, and target.o from pinned archives. The DLL holds the runtime, libuv, OpenSSL and winpthreads, and imports only Windows' own DLLs (the tool refuses anything else). The compiler's IR has no target triple and passes only scalars to the runtime, so the same IR is compiled for Windows. A program links target.o and the import library, and finds the DLL beside it or on PATH. There is no native construction yet (tools/distribution/builder.giz), so no Windows toolchain release links it.

  • One code path: win32.h gives the other files the POSIX names with their POSIX meaning (openat under a directory handle, unlinkat and renameat with POSIX semantics, flock, posix_spawnp handing the child only its three standard handles); win32.c implements them. Paths the runtime returns separate with /, and a capability path with \ or : is refused (fs.c valid_path). TLS trusts the system ROOT store (org.openssl.winstore://).
  • The task switch also saves rdi, rsi, xmm6–xmm15 and the thread block's stack bounds (task.c).
  • Not on Windows (UV_ENOSYS, or exit 2 for GIZLANG_WORKERS): exec, stream pairs, descriptor handoff over Unix sockets, the parent lifeline and worker processes. Tests run one after another in the process. Signals are INT and TERM only.
  • Error codes: the SDK names Linux numbers (sdk/core/system.giz). An error from the runtime goes through osError (runtime/system.c gizlang_error_portable), which maps libuv's codes (UV_E*, such as -4058) and the C runtime's -errno (ENOTEMPTY is 41, not 39) to those numbers, so NOT_FOUND and the other names match on every OS.
  • Host and process facts (memory, CPUs, caches, NUMA nodes, environment, usage), terminals, users, priorities and network interfaces come from libuv or the OS API in the runtime (memory.c, machine.c, system.c), not from /proc or Linux record layouts. User and group ids are -1, and setting them is UV_ENOSYS, on Windows.
  • Open: before a Windows release ships the DLL, licenses/third-party needs its rows: libuv, OpenSSL 3.6.5 (MSYS2 clang64, not the Linux 3.0.13), winpthreads and the mingw-w64 runtime.
  • Checked on the win11 guest: hello, files, directories, rename, removal, refused escapes, temporary folders, sleep, tasks, child processes and TLS to a public host.

Status

  • Source programs reach heap.c, value_layout.c and refs.c through gizlang:memory (tests/language/programs/program-memory*.giz).
  • They reach io.c and fs.c through gizlang:system: files, directories, TCP, UDP, Ready, timers, standard streams and child processes (tests/runtime/system/).