4.7 KiB
title, description
| title | description |
|---|---|
| Stone Memory | Immutable arena allocation |
Overview
Stone memory is a separate allocation arena for immutable values. Objects in stone memory are permanent — they are never moved, never freed, and never touched by the garbage collector.
The stone() function in ƿit petrifies a value, deeply freezing it and all its descendants. Stoned objects have the S bit set in their object header.
The Stone Arena
Stone memory uses bump allocation from a contiguous arena:
stone_base ──────── stone_free ──────── stone_end
[allocated objects] [free space ]
Allocation advances stone_free forward. When the arena is exhausted, overflow pages are allocated via the system allocator and linked together:
struct StonePage {
struct StonePage *next;
size_t size;
uint8_t data[];
};
The S Bit
Bit 3 of the object header is the stone flag. When set:
- The object is immutable — writes disrupt
- The object is excluded from GC — the collector skips it entirely
- For text objects, the length field caches the hash instead of the character count (since the text cannot change, the hash is computed once and reused)
What Gets Stoned
When stone(value) is called:
- If the value is already stone, return immediately
- Recursively walk all nested values (array elements, record fields, etc.)
- Copy each mutable object into the stone arena
- Set the S bit on each copied object
- Return the stoned value
The operation is deep — an entire object graph becomes permanently immutable.
Text Interning
The stone arena maintains a hash table for text interning. When a text value is stoned, it is looked up in the intern table. If an identical string already exists in stone memory, the existing one is reused. This deduplicates strings and makes equality comparison O(1) for stoned text.
The hash is computed with fash64 over the packed UTF-32 words.
Usage Patterns
Module Return Values
Every module's return value is automatically stoned:
// config.cm
return {
debug: true,
timeout: 30
}
// The returned object is stone — shared safely between actors
Message Passing
Messages between actors are stoned before delivery, ensuring actors never share mutable state.
Constants
Literal objects and arrays that can be determined at compile time may be allocated directly in stone memory.
Mutable Text Concatenation
String concatenation in a loop (s = s + "x") is optimized to O(n) amortized by leaving concat results unstoned with over-allocated capacity. On the next concatenation, if the destination text is mutable (S bit clear) and has enough room, the VM appends in-place with zero allocation.
How It Works
When the VM executes concat dest, dest, src (same destination and left operand — a self-assign pattern):
-
Inline fast path: If
destholds a heap text, is not stoned, andlength + src_length <= capacity— append characters in place, update length, done. No allocation, no GC possible. -
Growth path (
JS_ConcatStringGrow): Allocate a new text withcapacity = max(new_length * 2, 16), copy both operands, and return the result without stoning it. The 2x growth factor means a loop of N concatenations does O(log N) allocations totaling O(N) character copies. -
Exact-fit path (
JS_ConcatString): Whendest != left(not self-assign), the existing exact-fit stoned path is used. This is the normal case for expressions likevar c = a + b.
Safety Invariant
An unstoned heap text is uniquely referenced by exactly one slot. This is enforced by the stone_text mcode instruction, which the streamline optimizer inserts before any instruction that would create a second reference to the value (move, store, push, setarg, put). Two VM-level guards cover cases where the compiler cannot prove the type: get (closure reads) and return (inter-frame returns).
Why Over-Allocation Is GC-Safe
- The copying collector copies based on
cap56(the object header's capacity field), notlength. Over-allocated capacity survives GC. js_alloc_stringzero-fills the packed data region, so padding beyondlengthis always clean.- String comparisons, hashing, and interning all use
length, notcap56. Extra capacity is invisible to string operations.
Relationship to GC
The Cheney copying collector only operates on the mutable heap. During collection, when the collector encounters a pointer to stone memory (S bit set), it skips it — stone objects are roots that never move. This means stone memory acts as a permanent root set with zero GC overhead.