mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-20 22:00:57 +00:00
better write barrier, now works as the documenation says it needs to work
This commit is contained in:
@@ -730,11 +730,33 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
dest[] = source
|
||||
decRef tmp
|
||||
|
||||
For YRC the write barrier is more complicated still and must be:
|
||||
|
||||
let tmp = dest
|
||||
# assignment must come first so that the collector sees the most-recent graph:
|
||||
atomic: dest[] = source
|
||||
# Then teach the cycle collector about the changes edge (these use locks, see yrc.nim):
|
||||
incRef source
|
||||
decRef tmp
|
||||
|
||||
This is implemented as a single runtime call (nimAsgnYrc / nimSinkYrc).
|
||||
]#
|
||||
var actions = newNodeI(nkStmtList, c.info)
|
||||
let elemType = t.elementType
|
||||
|
||||
createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen)
|
||||
|
||||
# YRC uses dedicated runtime procs for the entire write barrier:
|
||||
if c.g.config.selectedGC == gcYrc:
|
||||
case c.kind
|
||||
of attachedAsgn, attachedDup:
|
||||
body.add callCodegenProc(c.g, "nimAsgnYrc", c.info, genAddr(c, x), y)
|
||||
return
|
||||
of attachedSink:
|
||||
body.add callCodegenProc(c.g, "nimSinkYrc", c.info, genAddr(c, x), y)
|
||||
return
|
||||
else: discard # fall through for destructor, trace, wasMoved
|
||||
|
||||
let isCyclic = c.g.config.selectedGC in {gcOrc, gcYrc} and types.canFormAcycle(c.g, elemType)
|
||||
|
||||
let isInheritableAcyclicRef = c.g.config.selectedGC in {gcOrc, gcYrc} and
|
||||
@@ -819,6 +841,17 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
let xenv = genBuiltin(c, mAccessEnv, "accessEnv", x)
|
||||
xenv.typ = getSysType(c.g, c.info, tyPointer)
|
||||
|
||||
# YRC uses dedicated runtime procs for the write barrier on the env pointer:
|
||||
if c.g.config.selectedGC == gcYrc:
|
||||
case c.kind
|
||||
of attachedAsgn, attachedDup:
|
||||
body.add callCodegenProc(c.g, "nimAsgnYrc", c.info, genAddr(c, xenv), y)
|
||||
return
|
||||
of attachedSink:
|
||||
body.add callCodegenProc(c.g, "nimSinkYrc", c.info, genAddr(c, xenv), y)
|
||||
return
|
||||
else: discard # fall through for destructor, trace, wasMoved
|
||||
|
||||
let isCyclic = c.g.config.selectedGC in {gcOrc, gcYrc}
|
||||
let tmp =
|
||||
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
|
||||
@@ -852,7 +885,6 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.add genIf(c, cond, actions)
|
||||
else:
|
||||
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRef", c.info, yenv))
|
||||
|
||||
body.add genIf(c, cond, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDup:
|
||||
|
||||
@@ -448,6 +448,25 @@ proc unsureAsgnRef(dest: ptr pointer, src: pointer) {.inline.} =
|
||||
dest[] = src
|
||||
if src != nil: nimIncRefCyclic(src, true)
|
||||
|
||||
proc nimAsgnYrc(dest: ptr pointer; src: pointer) {.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.
|
||||
let tmp = dest[]
|
||||
atomicStoreN(dest, src, ATOMIC_RELEASE)
|
||||
if src != nil:
|
||||
nimIncRefCyclic(src, true)
|
||||
if tmp != nil:
|
||||
discard nimDecRefIsLastCyclicDyn(tmp)
|
||||
|
||||
proc nimSinkYrc(dest: ptr pointer; src: pointer) {.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)
|
||||
|
||||
proc nimMarkCyclic(p: pointer) {.compilerRtl, inl.} =
|
||||
when optimizedOrc:
|
||||
if p != nil:
|
||||
|
||||
Reference in New Issue
Block a user