vbci-memory
Skill3.7k starsChanged 3 months agoMITView on GitHub
Verona interpreter (vbci) memory management model — regions, reference counting, write barriers, dragging, cowns, and finalization. Use when working on or debugging vbci runtime memory management code.
Trending
Quiet this year.about the whole repository
Who's talking about microsoft/verona
- A Hacker News story“Microsoft Project Verona: Research programming language for concurrent ownership”Hacker News · Jan 17, 2020 · 142 points
- A Hacker News story“Project Verona FAQ”Hacker News · Feb 10, 2020 · 29 points
- A Hacker News story“Project Verona: Research programming language for concurrent ownership”Hacker News · Jan 16, 2020 · 7 points
- A Hacker News story“Microsoft/Verona”Hacker News · Jan 18, 2020 · 3 points
- A Hacker News story“Concurrent Ownership in Verona”Hacker News · Dec 14, 2022 · 2 points
The biggest 5 of 18 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 18
Talked about on GitHub and Hacker News (18 times).
On GitHub · 12
- Dec 31, 2023Check ideas from Verona language for concurrency — lambdaclass/concrete0 reactions
- Jul 21, 2023Add Verona — ChessMax/awesome-programming-languages0 reactions
- Jul 13, 2023Move the Verona compiler to microsoft/verona — microsoft/Trieste0 reactions
- Oct 24, 2022Optimise for waking an empty queue — microsoft/verona-rt0 reactions
- Oct 24, 2022Token source — microsoft/verona-rt0 reactions
7 more on GitHub
- Oct 20, 2022Small optimisations and refactors around message send and receive — microsoft/verona-rt0 reactions
- Jul 29, 2022Don't run CI on doc-only changes — microsoft/CCF0 reactions · 4 comments
- Aug 26, 2021Enable passthrough to an underlying allocator — microsoft/snmalloc0 reactions · 1 comment
- Jan 25, 2021Meta: Some interesting pointers to borrow ideas — flix/flix0 reactions · 1 comment
- Jan 4, 2021Meta: Some interesting pointers to borrow ideas — HigherOrderCO/Kind0 reactions
- Jun 18, 2020Refactor Pal and LargeAlloc interaction. — microsoft/snmalloc0 reactions
- Jan 27, 2020Automating keeping snmalloc up to date. — SchrodingerZhu/snmalloc-rs0 reactions · 2 comments
On Hacker News · 6
- Jan 17, 2020Microsoft Project Verona: Research programming language for concurrent ownership142 points · 16 comments
- Feb 10, 2020Project Verona FAQ29 points · 8 comments
- Jan 16, 2020Project Verona: Research programming language for concurrent ownership7 points
- Jan 18, 2020Microsoft/Verona3 points
- Dec 14, 2022Concurrent Ownership in Verona2 points
1 more on Hacker News
- Sep 17, 2023Microsoft Project Verona, a research programming language1 point
In this repository19 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- add-testSkill
- debugSkill
- docs-updateSkill
- reviewSkill
- testsuiteSkill
- verona-codingSkill
- verona-conventionsSkill
- verona-type-inferenceSkill
- add-testSkill
- docs-updateSkill
- reviewSkill
- testsuiteSkill
- vbci-memorySkill
- verona-codingSkill
- verona-conventionsSkill
- verona-type-inferenceSkill
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 3 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 14
Every object/array has a Location (encoded as a tagged uintptr_t):
- Very specific: line 73
Phase 1: Run finalizers on stack objects (via run_sync with readonly reference)
- Very specific: line 79
When an object in a frame-local region needs to escape (return to parent frame, be stored in a region, be sent to a cown), it is dragged …
- Distinctive: line 83
Check that child regions can be parented (no existing owner, no cycles)
- Distinctive: line 132
Cannot have new field references: no object/array can create a new field pointing to a readonly value
- Distinctive: line 170
After freezing, the region's stack_rc must be adjusted to account for stack references that now point to immutable objects:
- Very specific: line 181
When the freeze DFS discovers an entry point to a sub-region, it pushes it to a worklist.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
vbci Memory Management
Overview
The Verona interpreter uses a region-based memory model with reference counting. Objects live in regions, regions form strict trees (single parent, single entry point), and cowns provide a forest of independent region trees for concurrency.
Object Locations
Every object/array has a Location (encoded as a tagged uintptr_t):
| Location | Meaning | RC type | Collected by |
| Stack | Stack-allocated in a frame | No RC | Frame teardown (destruct) |
| Frame-local | In a frame's embedded RegionRC | Object RC | RC=0 collection, or free_contents for cycles |
| Region | In a heap RegionRC | Object RC | RC=0 collection, or free_contents for cycles |
| Immutable | Frozen, shareable | ARC (atomic) | ARC=0 collection |
| Immortal | Primitive values, constants | No RC | Never collected |
Two Independent RC Systems
Object RC (Header::rc)
Counts all incoming references to an object, regardless of source (registers, fields, anywhere). When RC hits 0, the object is collected individually via collect(). The region's stack_rc is irrelevant to individual object collection.
inc<needs_stack_rc>(): increments object RC; ifneeds_stack_rc, also increments the region's stack_rcdec<needs_stack_rc>(): decrements object RC; if RC hits 0, queues for collection viacollect()
The needs_stack_rc template parameter indicates whether the reference is from a register/stack/frame-local context (true) or from a field within a region (false).
Region Stack RC (Region::stack_rc)
Counts references into the region from outside the region's own object graph — specifically from:
- Frame registers
- Fields of stack-allocated or frame-local objects/arrays
This keeps entire regions alive. A region can be collected (freed as a whole) when:
- It has no parent (not parented to another region, not cown-owned)
- Its stack_rc is 0 (no external references)
Stack_rc is NOT per-object — it's per-region.
Regions
Regions are containers of objects that form strict trees:
- Each region has at most one parent region
- There is exactly one entry point from a parent to a child region
- Cowns can own regions, creating a forest of region trees
Region Types
- RegionRC: Reference-counted region with a
headersset tracking all contained objects - Regions track:
stack_rc,parent(with tag bits for parent type),finalizingflag
Region Parenting
The parent field encodes the owner:
0: no owner (root region, collectible if stack_rc == 0)- Pointer with no tag bits: parent is another Region
parent_tag_cown: owned by a cownparent_tag_frame_local: frame-local region
Frame Teardown
Each frame has:
- Stack allocations: objects allocated with
Op::Stackon the frame's stack area - Frame-local region: an embedded
RegionRCfor objects created withOp::New
Teardown order:
frame->drop(): Clears all registers. RC decrements may trigger individual object collection viacollect().- Phase 1: Run finalizers on stack objects (via
run_syncwith readonly reference) - Phase 2: Destruct stack objects (drop field references, no finalizer)
free_contents(): Finalize and deallocate everything remaining in the frame-local region. This handles cyclic garbage — objects whose RC never hit 0 because they only have internal references within the region.
Dragging
When an object in a frame-local region needs to escape (return to parent frame, be stored in a region, be sent to a cown), it is dragged via drag_allocation():
- DFS traversal from the root object to find all reachable frame-local objects
- Track internal RC (edges within the dragged set) vs external RC
- Check that child regions can be parented (no existing owner, no cycles)
- Move all objects to the destination region, adjusting RCs and setting parents
The ignore_parent parameter allows drags during exchange: when the outgoing value's region will be unparented by apply_out, the drag can treat that region as unowned without actually unparenting it first.
Write Barrier (writebarrier.h)
The write barrier handles stores (field writes, array element writes) with a prepare/apply pattern:
write_ops<is_move>()
.prepare_store(store_loc) // where the store target lives
.prepare_out(prev_loc) // where the outgoing (old) value lives
.prepare_in(next_loc) // where the incoming (new) value livesThen:
apply_in(): executes drag, writes value, adjusts incoming RC/stack_rc/parentapply_out(): adjusts outgoing RC/stack_rc, unparents outgoing region
Key operations planned during prepare:
- Incoming: drag (frame-local → region), RC inc/clear, stack_rc adjust, region parent
- Outgoing: RC dec, stack_rc adjust, region unparent
drop(): simplified version for field drops during finalization (no incoming value)
Ordering constraint
apply_out runs AFTER apply_in. When the incoming drag needs the outgoing region to be unparented first, ignore_parent on drag_allocation resolves this without reordering.
Collection (collect.cc)
The collect() function handles deferred deallocation to avoid re-entrancy issues:
- First call: sets
in_collection = true, processes worklist - Nested calls (from
deallocate()→finalize()→ field drops → more RC=0): add to worklist, return immediately - Worklist processes until empty, then
in_collection = false
Each worklist item calls deallocate() which calls finalize() then frees the memory.
Cowns
Cowns (verona::rt::VCown) own a value and optionally a region:
add_reference(): stores a value in the cown, potentially dragging frame-local to a fresh region and setting cown ownershipexchange(): swaps the cown's content, handling region re-parenting with rollback on failure- Cown-owned regions have
parent = parent_tag_cown
Readonly Values
Readonly values always come from a readonly cown (via Read op or behavior cown args with read-only slots). Key properties:
- Cannot be mutated: stores through readonly refs raise
BadStoreTarget - Cannot have new field references: no object/array can create a new field pointing to a readonly value
- No object/array RC:
reg_inc/reg_decskip object RC and stack_rc for readonly objects/arrays - Cowns still need RC: readonly cown values (
ValueType::Cown) still needcown->inc()/cown->dec()— the cown itself is ref-counted independently of its content's readonly status - CownRef needs no RC:
CownRefvalues exist only as behavior arguments and are alive for the behavior's lifetime — no RC needed
Finalization
Objects with a final method have their finalizer run during collection/teardown:
- Called with a read-only reference to the object (prevents resurrection)
- Finalizers must not mutate — stores through readonly refs raise
BadStoreTarget Object::finalize(): runs finalizer viarun_sync(), then drops all field references viawritebarrier::drop()Object::destruct(): drops field references without running the finalizer (for stack objects after Phase 1)
Finalization ordering
The collector uses a two-phase approach: Phase 1 finalizes all objects (running finalizers, dropping field references), Phase 2 frees memory. This prevents use-after-free when finalizers reference sibling objects — all finalizers run before any memory is freed.
Sendability
An object is sendable if its region:
- Has no owner (no parent region, no cown owner)
- Has stack_rc == 1 (only the current register references it)
Frame-local objects are dragged to a fresh region first, then the region is checked for sendability. This ensures data-race freedom — only objects with exclusive ownership can be sent to behaviors.
Freezing (freeze.cc)
Freezing converts a reachable subgraph from mutable region objects to immutable objects with ARC tracking. The region survives with any unfrozen objects.
Two entry points
freeze(Header* root): Freezes reachable subgraph in a heap region. Handles frame-local roots by delegating tofreeze_local. Returns true on success.freeze_local(Header* root): Freezes frame-local objects in place, then delegates discovered heap sub-regions tofreeze()in phase 2.
SCC detection with rc-transfer
Uses Tarjan-style DFS with union-find. During SCC detection, scc_union(child, rep) transfers child.rc - 1 to rep (subtracting the tree edge). Back edges decrement rep.rc. At SCC completion, set_arc(rep->get_rc()) gives the exact external ref count without needing separate inc_arc calls.
Union-by-address (using uintptr_t of header as rank) with path compression gives O(α(n)) amortized.
Stack_rc adjustment
After freezing, the region's stack_rc must be adjusted to account for stack references that now point to immutable objects:
stack_adjustment = arc_sum - frozen_cross - unfrozen_to_frozenarc_sum: sum of all SCC arcs (total external refs to frozen objects)frozen_cross: cross-edges between newly-frozen SCCs (tracked viafrozen_set)unfrozen_to_frozen: field refs from surviving region objects to newly-frozen objects
Sub-region handling
When the freeze DFS discovers an entry point to a sub-region, it pushes it to a worklist. After freezing the parent region, sub-regions are processed. Ownership is cleared only when root == region->get_entry_point().
Entry point tracking
Region stores a Header* entry_point set during set_parent() and set_cown_owner(). This is needed to:
- Assert the single-entry-point invariant during freeze
- Guard ownership clearing (only clear when freezing the entry point)
Location states during freeze
| State | Location | rc/arc field | Meaning |
| UNMARKED | Region ptr | rc = field refs | Normal mutable, not yet visited |
| PENDING | Pending tag | rc = accumulated external refs | On DFS path, SCC candidate |
| SCC_PTR | SCC ptr to rep | unused | Union-find member, points toward root |
| IMMUTABLE | Immutable tag | arc = external ref count | Frozen SCC root |
Immutable object lifecycle
field_inc()on immutable →arc++field_dec()on immutable →arc--; if 0,collect_scc()walks all SCC members via SCC_PTR chains, finalizes, and freesreg_inc()/reg_dec()on immutable → onlyfield_inc()/field_dec()(no stack_rc)
Key Files
| File | Purpose |
header.h | Base Header class: RC, location, region access, inc/dec |
region.h | Region struct: stack_rc, parent, ownership |
region_rc.h/cc | RegionRC: headers set, insert/remove/rfree/free_contents |
location.h/cc | Location encoding, drag_allocation |
writebarrier.h | Write barrier: prepare/apply pattern for stores |
collect.h/cc | Deferred collection worklist |
object.h | Object: init, finalize, destruct, deallocate |
array.h | Array: element access, finalize, deallocate |
cown.h | Cown: add_reference, exchange |
value.h/cc | Value union type: RC forwarding, location queries |
register.h | Register wrapper: ownership semantics |
thread.h/cc | Frame management, teardown, run_sync |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

