diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 0f78d5c1c7..e5d3a39d09 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -748,12 +748,19 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # YRC uses dedicated runtime procs for the entire write barrier: if c.g.config.selectedGC == gcYrc: + let desc = + if isFinal(elemType): + let ti = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType)) + ti.typ = getSysType(c.g, c.info, tyPointer) + ti + else: + newNodeIT(nkNilLit, c.info, getSysType(c.g, c.info, tyPointer)) case c.kind of attachedAsgn, attachedDup: - body.add callCodegenProc(c.g, "nimAsgnYrc", c.info, genAddr(c, x), y) + body.add callCodegenProc(c.g, "nimAsgnYrc", c.info, genAddr(c, x), y, desc) return of attachedSink: - body.add callCodegenProc(c.g, "nimSinkYrc", c.info, genAddr(c, x), y) + body.add callCodegenProc(c.g, "nimSinkYrc", c.info, genAddr(c, x), y, desc) return else: discard # fall through for destructor, trace, wasMoved @@ -842,13 +849,15 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = xenv.typ = getSysType(c.g, c.info, tyPointer) # YRC uses dedicated runtime procs for the write barrier on the env pointer: + # Closure envs are always polymorphic, so pass nil for desc (uses Dyn variant): if c.g.config.selectedGC == gcYrc: + let nilDesc = newNodeIT(nkNilLit, c.info, getSysType(c.g, c.info, tyPointer)) case c.kind of attachedAsgn, attachedDup: - body.add callCodegenProc(c.g, "nimAsgnYrc", c.info, genAddr(c, xenv), y) + body.add callCodegenProc(c.g, "nimAsgnYrc", c.info, genAddr(c, xenv), y, nilDesc) return of attachedSink: - body.add callCodegenProc(c.g, "nimSinkYrc", c.info, genAddr(c, xenv), y) + body.add callCodegenProc(c.g, "nimSinkYrc", c.info, genAddr(c, xenv), y, nilDesc) return else: discard # fall through for destructor, trace, wasMoved diff --git a/lib/system/yrc.nim b/lib/system/yrc.nim index bd981f51be..b2225a565c 100644 --- a/lib/system/yrc.nim +++ b/lib/system/yrc.nim @@ -390,7 +390,7 @@ proc GC_partialCollect*(limit: int) = roots.len = limit proc GC_fullCollect* = - collectCycles() + GC_runOrc() proc GC_enableMarkAndSweep*() = GC_enableOrc() proc GC_disableMarkAndSweep*() = GC_disableOrc() @@ -448,7 +448,13 @@ proc unsureAsgnRef(dest: ptr pointer, src: pointer) {.inline.} = dest[] = src if src != nil: nimIncRefCyclic(src, true) -proc nimAsgnYrc(dest: ptr pointer; src: pointer) {.compilerRtl.} = +proc yrcDec(tmp: pointer; desc: PNimTypeV2) {.inline.} = + if desc != nil: + discard nimDecRefIsLastCyclicStatic(tmp, desc) + else: + discard nimDecRefIsLastCyclicDyn(tmp) + +proc nimAsgnYrc(dest: ptr pointer; src: pointer; desc: PNimTypeV2) {.compilerRtl.} = ## YRC write barrier for ref copy assignment. ## Atomically stores src into dest, then buffers RC adjustments. ## Freeing is always done by the cycle collector, never inline. @@ -457,15 +463,15 @@ proc nimAsgnYrc(dest: ptr pointer; src: pointer) {.compilerRtl.} = if src != nil: nimIncRefCyclic(src, true) if tmp != nil: - discard nimDecRefIsLastCyclicDyn(tmp) + yrcDec(tmp, desc) -proc nimSinkYrc(dest: ptr pointer; src: pointer) {.compilerRtl.} = +proc nimSinkYrc(dest: ptr pointer; src: pointer; desc: PNimTypeV2) {.compilerRtl.} = ## YRC write barrier for ref sink (move). No incRef on source. ## Freeing is always done by the cycle collector, never inline. let tmp = dest[] atomicStoreN(dest, src, ATOMIC_RELEASE) if tmp != nil: - discard nimDecRefIsLastCyclicDyn(tmp) + yrcDec(tmp, desc) proc nimMarkCyclic(p: pointer) {.compilerRtl, inl.} = when optimizedOrc: