mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-03 14:09:05 +00:00
nimAsgnYrc/nimSinkYrc were emitted for EVERY ref type, ignoring .acyclic. The barrier defers the dec into a stripe queue, drainStripe hands the cell to registerLocal, and it enters the collector as a capture ROOT -- so types annotated precisely to stay out of the cycle collector were traced by it anyway, through capture/deadness/commit. Gate that barrier on canFormAcycle (the same predicate ccgtypes.nim:1903 uses to set the descriptor's acyclic flag, so codegen and runtime cannot disagree) and let acyclic refs fall through to the prompt arc-style path. nimDecRefIsLastDyn stops forwarding to nimDecRefIsLastCyclicDyn and does a prompt atomic dec. No grace period is needed for those cells and that is not an accident: the collector cannot reach one by traversal (liftdestructors only emits nimTraceRef when isCyclic) and cannot hold one as a root (roots come only from registerLocal on a drained dec). The queued dec was the only way in. This also removes the reason for the earlier nimDecRefIsLastCyclicStatic workaround for final acyclic types, so that is reverted. compiler/astdef.nim now emits 97 nimDecRefIsLastDyn + 9 nimDecRefIsLast + 38 nimIncRef and zero nimAsgnYrc/nimDecRefIsLastCyclic*, matching ORC. Compiler self-compile (--compileOnly compiler/nim.nim): 37.65s -> 6.99s, against orc 6.96s and arc 6.77s. RSS 743MB vs orc 746MB. yrcbench is unchanged (0.78s/5.13s CPU) and still passes its leak assertion, so cyclic collection is unaffected. koch boot -d:release --mm:yrc reaches 'executables are equal: SUCCESS!'. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>