Memory Model

Bee uses a deterministic, three-tier hybrid memory model engineered for zero-overhead in critical paths, safe parallel execution, and low latency. The three tiers are Atomic Reference Counting (ARC) for mutable heap data, Region-Based Arenas for transient rule-local values managed with zap, and a compacting generational GC devoted solely to immutable strings and ropes.

Overview of the three tiers

#TierOwnsReclaim strategyDeterminism
1 Atomic Reference Counting (ARC) Mutable heap: objects, dynamic collections, OS handles Immediate free on last reference release Immediate, synchronous
2 Region-Based Arena Transient rule/block locals Single-instruction unwind on scope exit or zap Immediate, scope-bounded
3 Compacting Generational GC Immutable strings, slices, rope buffers Background two-space copying compaction Amortized, lock-free

Tier 1 — Atomic Reference Counting (ARC)

ARC is the default management for mutable dynamic structures, object instances, and system resources (files, channels, sockets). It guarantees immediate, deterministic resource cleanup when the last reference is released.

Allocation scope

  • Objects (object)
  • Dynamic collections (array, map, list, set)
  • System OS handles (files, channels, sockets)

Header layout (16 bytes)

Every ARC-allocated object carries a standardized 16-byte header preceding a variable-width payload:

+-------------------+-------------------+-----------------------+
|  RefCount (64bit) |   TypeID (32bit)  | Flags / Metadata(32) |
+-------------------+-------------------+-----------------------+
|                   Payload Data (Variable Width)               |
+---------------------------------------------------------------+

Operational semantics

  • On assignment / copy: AtomicInc(RefHeader.RefCount)
  • On scope exit / re-assignment: if AtomicDec(RefHeader.RefCount) == 0 then DestructAndFree(Object)
  • Destructor execution is immediate and synchronous, releasing backing native resources (e.g. file descriptors) on the calling thread.

Tier 2 — Region-Based Arena & zap

Every rule (and nested block frame) allocates a light, stack-bound Region Arena (2 KB initial chunk). Short-lived locals allocate directly from the active arena offset with no per-object heap allocation (ptr = arena.top; arena.top += size).

Region cleanup

On block termination or an iteration jump (return, done, next), the arena offset is unwound in a single instruction (arena.top = arena.base), instantly reclaiming all region-allocated memory.

Manual deallocation (zap)

zap identifier;

In Hot Zones (performance-critical loops), zap explicitly invalidates the pointer and resets the target memory slot immediately.

  • Static analysis invariant: the compiler performs lifetime tracking. Reading or writing an identifier after zap in the same control-flow graph is a compile-time error E0801: AccessAfterZap.
  • Runtime safety guard: in non-optimized debug builds (-d), zap zero-fills the target pointer slot, so a later dereference raises Panic: UseAfterZap.

Tier 3 — Compacting Generational GC (immutable strings & ropes)

A special-purpose garbage collector is dedicated to immutable string literals, dynamic string concatenations, and rope nodes. It guarantees efficient interning, zero fragmentation, and lock-free thread-safe sharing.

GC roots

  • Thread execution stacks
  • Region Arenas
  • ARC object payload pointers that point into the String Heap

Compaction

The generational GC runs independently on background threads. Because string payloads are strictly immutable, compaction uses two-space copying without requiring write barriers on reader threads.

Assignment & mutability semantics

Two assignment operators govern how values are written; their behavior depends on the storage class of the target (native vs boxed vs reference).

OperatorMeaningEffect
:= Assign With new: allocate a new storage location. With let: update the existing value in place.
:: Clone Boxed/objects: deep copy (structural clone) into an independent heap payload. Primitive natives: equivalent to :=.

Value modification rules (let with :=)

  • Native variable → value mutated in place.
  • Boxed variable → the boxed value is changed in place.
  • Reference on the right-hand side → value is transferred by deep copy.

Mutability modifiers

new    identifier ((∈) | in) type_specifier ;   (* declare *)
let    identifier (:= | ::) expression ;        (* mutable update *)
alter  identifier ...                           (* modify an existing element *)
  • new — declare and allocate a fresh storage location.
  • let — update the value of an existing variable.
  • alter — modify an existing variable in place (explicit mutation).

Formal EBNF

(* Memory Management Statements *)
zap_statement     ::= "zap" identifier ";" ;
new_statement     ::= "new" identifier [ ":" type_specifier ]
                      [ ( ":=" | "::" ) expression ] ";" ;
let_statement     ::= "let" identifier ( ":=" | "::" ) expression ";" ;

(* Variable Mutability Modifiers *)
variable_decl     ::= "new" identifier ( "∈" | "in" ) type_specifier ";" ;
mutability_prefix ::= "let" | "alter" ;

Concurrency & cross-thread boundaries

  • Thread isolation: spawned tasks (begin) run in isolated Region Arenas.
  • Immutable sharing: GC-managed immutable strings and ropes cross thread boundaries without locks or reference copies.
  • Mutable ARC transfer: passing a mutable ARC object to a spawned thread increments its atomic reference count (LOCK XADD).
  • Parallel error isolation: an uncaught exception or panic in a worker thread freezes that thread's local Region Arena and captures diagnostic context into the thread-local $trial handle, preventing corruption of parent state.

Diagnostics & safety protocols

CodeViolationMitigation / diagnostic action
E0801AccessAfterZap: use of identifier after zapCompile-time fatal error with source line location; runtime Panic: UseAfterZap under -d.
E0802RegionEscape: pointer escapes Region Arena to outer scopeCompiler automatically promotes the allocation from Region to ARC Heap.
E0803ArcCycleLeak: unhandled cycle in an ARC structureStatic lifetime analysis, or runtime leak warning under -d.
E0804CrossThreadUnsharedMutation: invalid cross-thread mutation of an unshared referenceCompile-time data-race restriction.
Resolved (2026-09-14): the memory block moved out of the overloaded E04xx range (owned by spec/04-structure.md). The memory model now uses the dedicated E08xx block (E0801–E0804), and every code is registered centrally in registry/diagnostics.json.