Allocator selection is instruction selection.

Mica’s intermediate language never names malloc. It emits allocator intrinsics, and which implementation those bind to is decided when you link.

Code generation is byte-identical across both deployment classes. The same object code, the same instruction schedule, the same register assignment — only the archive it links against differs. This is measured, not asserted: the generated assembly and object file match by SHA-256 across hosted, fixed-arena, and a fixed-arena built with a different byte budget.

The two classes

Hosted — libc calloc/free underneath. The point of keeping this is tooling: Valgrind and AddressSanitizer keep working, because to them a Mica program allocates the way a C program does.

Fixed-arena — a statically budgeted bump allocator with no OS heap at all, selected as --memory-class fixed-arena and optionally sized (fixed-arena=<bytes>). This is the freestanding class: the program’s entire memory footprint is decided before it runs. Changing the budget does not change one instruction of the program; it changes only a generated data-only object holding the arena reservation.

Regions are scheduled, not selected

The region allocator is not a deployment class, and there is no flag for it. Within whichever class you link, the compiler picks the allocator per allocation site from the lifetime it proved: an owner-bound site (new T until F) gets a region, with bulk reclaim when the owner exits; manual and transferred sites get per-cell allocation. Both appear in the same binary, and regions work inside the fixed-arena class too.

The lineage is the region calculus of Tofte and Talpin, with one deliberate difference: the region is chosen by the compiler from a proven lifetime and named by the programmer (until F), rather than inferred invisibly. You can see which allocations landed in which region, because the compiler tells you — one line per site, naming the lifetime class and the allocator it selected.

Why this shape

A systems language usually forces the deployment decision into the source. Code written against a pool allocator is not the code you would write against malloc, and porting between them is a rewrite.

Here it is a link flag. One source tree serves a Linux server, an allocation-bound batch job that benefits from bulk reclaim, and a statically budgeted embedded target — with no #ifdef, no allocator abstraction layer in your own code, and no divergent test corpus, because the generated code is the same in every case.

The seam is a genuine plug-in rather than an internal switch: a third-party archive that honours the symbol contract links and runs with no compiler change.

See also