# 30 — shared structure the heap already mark-sweeps. this stage adds objects many pointers can hold, collected by that sweep when none of them remain. there is no second heap and no reference count. a cycle is just a mark that sees the same cell twice. bit 8 of the header flags (`F_SHARE`, value 8) means shared. bits 0..2 stay what they were: live, releasing or marked, and the pin bit on a quarantined block something still points at. `share(p)` sets bit 8, clears the owner, and leaves the object live. `free` of a shared object returns without quarantining and without poisoning. `own` will not record an owner for one, and `release` will not follow one, so a unique container can point at a shared child without freeing it. the sweep masks the low three bits: an unmarked live cell is freed whether or not bit 8 is set, and a marked cell is restored to live with bit 8 kept. unique `free` still quarantines, and the sweep still returns a quarantined block only when nothing points at it. memdebug's allocation note is the one `new` already writes. `car`, `cdr` and `tget` call `checkptr` when bit 1 of the memdebug flags is on, so a shared cell is checked the same way as any other heap pointer. `cons(a, b)` and `triple(a, b, c)` allocate, publish any child that is a heap object, and publish the cell. publishing a child means a later `free` from its old owner does not clear a cell that still points at it. `snew`, `scat`, `sslice` and `ntos` return shared strings, so a byte string is a value you can copy. code literals `b"..."` are not heap objects; they live in the image. `is_shared` reads the bit. `tests/share.zc` builds two cells on one pair, a string held by two cells, a cycle, and a triple, then drops every root, scrubs the data stack and collects. the line is `1 2 1 4 1 1 1 1 42 1 1 1 6 0`. the last 0 is `live_objects` back to the baseline, on the resident compiler and on a run-only image. `tests/share_dbg.zc` turns memdebug on, frees a shared cell, and reads it back: `7 1`. the fixpoint image is 100757 words. the run-only reservation stays 14336 in the 36864-word machine; `tests/bytes.zc` is the largest of those images at 13871 words. the small compiler's stage-0 image is 96736 words against 97280, in the 180224-word machine. neither hole moved. the type-area cut from stage 29 stays: the 1m compiler still does not hand 0x9C000..0x9FFFF back to the allocator. `tests/bench_share.zc` is a run-only image. it builds one 40-cell spine, hangs two parents off it, and walks the spine 200 times. the checksum of one repetition is 156003. `bench_share.sh` times that without the resident compiler. on this host: interpreter 2.939 ms, microcore 2.679 ms, arm64 jit under qemu-user 1.733 ms, llvm 0.434 ms. `test.sh` after this stage: 368 passed, 0 failed. the eighteen new checks are the sharing line and the memdebug line on the interpreter, the microcore, the arm64 jit and the llvm backend; both of those on the small microcore and on `core.c` at that size; the run-only sharing line; both virt boards running `tests/share.zc` and compiling it; and one llvm run with `ZYHOT=1`. the fixpoint is the same 100757 words on the interpreter, the microcore, the jit and llvm. what is still open: a store through a shared pointer is not trapped, so immutability is the discipline of `car`, `cdr` and `tget` rather than a hardware check. the cycle test uses that store on purpose. the collector is still conservative, so a stale stack word can keep a cell alive until `scrub`. a shared object is not quarantined, so after the sweep reclaims it a leftover pointer is dangling; `checkptr` reports that on the next `car`. there is no write barrier and no compaction.