mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-29 01:14:41 +00:00
(cherry picked from commit 7eb34d170a)
This commit is contained in:
@@ -390,6 +390,16 @@ proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
|
||||
v.addVar(result, lowerings.newIntLit(c.g, body.info, first))
|
||||
body.add v
|
||||
|
||||
proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode =
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextId(c.idgen), c.fn, c.info)
|
||||
temp.typ = value.typ
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
|
||||
var v = newNodeI(nkVarSection, c.info)
|
||||
result = newSymNode(temp)
|
||||
v.addVar(result, value)
|
||||
body.add v
|
||||
|
||||
proc addIncStmt(c: var TLiftCtx; body, i: PNode) =
|
||||
let incCall = genBuiltin(c.g, mInc, "inc", i)
|
||||
incCall.add lowerings.newIntLit(c.g, c.info, 1)
|
||||
@@ -506,43 +516,75 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
discard "strings are atomic and have no inner elements that are to trace"
|
||||
|
||||
proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
#[ bug #15753 is really subtle. Usually the classical write barrier for reference
|
||||
counting looks like this::
|
||||
|
||||
incRef source # increment first; this takes care of self-assignments1
|
||||
decRef dest
|
||||
dest[] = source
|
||||
|
||||
However, 'decRef dest' might trigger a cycle collection and then the collector
|
||||
traverses the graph. It is crucial that when it follows the pointers the assignment
|
||||
'dest[] = source' already happened so that we don't do trial deletion on a wrong
|
||||
graph -- this causes premature freeing of objects! The correct barrier looks like
|
||||
this::
|
||||
|
||||
let tmp = dest
|
||||
incRef source
|
||||
dest[] = source
|
||||
decRef tmp
|
||||
|
||||
]#
|
||||
var actions = newNodeI(nkStmtList, c.info)
|
||||
let elemType = t.lastSon
|
||||
|
||||
createTypeBoundOps(c.g, c.c, elemType, c.info)
|
||||
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType)
|
||||
|
||||
let tmp =
|
||||
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
|
||||
declareTempOf(c, body, x)
|
||||
else:
|
||||
x
|
||||
|
||||
if isFinal(elemType):
|
||||
addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr))
|
||||
addDestructorCall(c, elemType, actions, genDeref(tmp, nkDerefExpr))
|
||||
var alignOf = genBuiltin(c.g, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType))
|
||||
alignOf.typ = getSysType(c.g, c.info, tyInt)
|
||||
actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x, alignOf)
|
||||
actions.add callCodegenProc(c.g, "nimRawDispose", c.info, tmp, alignOf)
|
||||
else:
|
||||
addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr))
|
||||
actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, x)
|
||||
|
||||
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType)
|
||||
addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(tmp, nkDerefExpr))
|
||||
actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, tmp)
|
||||
|
||||
var cond: PNode
|
||||
if isCyclic:
|
||||
if isFinal(elemType):
|
||||
let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
|
||||
typInfo.typ = getSysType(c.g, c.info, tyPointer)
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, x, typInfo)
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo)
|
||||
else:
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, x)
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, tmp)
|
||||
else:
|
||||
cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x)
|
||||
cond.typ = getSysType(c.g, x.info, tyBool)
|
||||
|
||||
case c.kind
|
||||
of attachedSink:
|
||||
body.add genIf(c, cond, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
if isCyclic:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, cond, actions)
|
||||
else:
|
||||
body.add genIf(c, cond, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedAsgn:
|
||||
body.add genIf(c, y, callCodegenProc(c.g,
|
||||
if isCyclic: "nimIncRefCyclic" else: "nimIncRef", c.info, y))
|
||||
body.add genIf(c, cond, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
if isCyclic:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, cond, actions)
|
||||
else:
|
||||
body.add genIf(c, cond, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDestructor:
|
||||
body.add genIf(c, cond, actions)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
@@ -569,19 +611,30 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
let xenv = genBuiltin(c.g, mAccessEnv, "accessEnv", x)
|
||||
xenv.typ = getSysType(c.g, c.info, tyPointer)
|
||||
|
||||
let isCyclic = c.g.config.selectedGC == gcOrc
|
||||
let tmp =
|
||||
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
|
||||
declareTempOf(c, body, xenv)
|
||||
else:
|
||||
xenv
|
||||
|
||||
var actions = newNodeI(nkStmtList, c.info)
|
||||
actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, xenv)
|
||||
actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, tmp)
|
||||
|
||||
let decRefProc =
|
||||
if c.g.config.selectedGC == gcOrc: "nimDecRefIsLastCyclicDyn"
|
||||
if isCyclic: "nimDecRefIsLastCyclicDyn"
|
||||
else: "nimDecRefIsLast"
|
||||
let cond = callCodegenProc(c.g, decRefProc, c.info, xenv)
|
||||
let cond = callCodegenProc(c.g, decRefProc, c.info, tmp)
|
||||
cond.typ = getSysType(c.g, x.info, tyBool)
|
||||
|
||||
case c.kind
|
||||
of attachedSink:
|
||||
body.add genIf(c, cond, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
if isCyclic:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, cond, actions)
|
||||
else:
|
||||
body.add genIf(c, cond, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedAsgn:
|
||||
let yenv = genBuiltin(c.g, mAccessEnv, "accessEnv", y)
|
||||
yenv.typ = getSysType(c.g, c.info, tyPointer)
|
||||
@@ -589,8 +642,12 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
if c.g.config.selectedGC == gcOrc: "nimIncRefCyclic"
|
||||
else: "nimIncRef"
|
||||
body.add genIf(c, yenv, callCodegenProc(c.g, incRefProc, c.info, yenv))
|
||||
body.add genIf(c, cond, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
if isCyclic:
|
||||
body.add newAsgnStmt(x, y)
|
||||
body.add genIf(c, cond, actions)
|
||||
else:
|
||||
body.add genIf(c, cond, actions)
|
||||
body.add newAsgnStmt(x, y)
|
||||
of attachedDestructor:
|
||||
body.add genIf(c, cond, actions)
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
|
||||
33
tests/arc/torc_selfcycles.nim
Normal file
33
tests/arc/torc_selfcycles.nim
Normal file
@@ -0,0 +1,33 @@
|
||||
discard """
|
||||
output: '''ok'''
|
||||
cmd: '''nim c --gc:orc -d:useMalloc -d:nimStressOrc $file'''
|
||||
valgrind: "leaks"
|
||||
"""
|
||||
|
||||
# bug #15753
|
||||
|
||||
type
|
||||
NodeKind = enum
|
||||
nkDancing,
|
||||
nkColumn
|
||||
|
||||
DancingNode = ref object
|
||||
right: DancingNode
|
||||
column: DancingNode
|
||||
kind: NodeKind
|
||||
|
||||
proc newColumnNode(): DancingNode =
|
||||
result = DancingNode(kind: nkColumn)
|
||||
result.right = result
|
||||
result.column = result
|
||||
|
||||
proc createDLXList(): DancingNode =
|
||||
result = newColumnNode()
|
||||
|
||||
for i in 0 .. 15:
|
||||
let n = newColumnNode()
|
||||
n.right = result.right
|
||||
result = n
|
||||
echo "ok"
|
||||
|
||||
var dlxlist = createDLXList()
|
||||
Reference in New Issue
Block a user