summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorringabout <43030857+ringabout@users.noreply.github.com>2022-12-28 23:23:37 +0800
committerGitHub <noreply@github.com>2022-12-28 16:23:37 +0100
commit4b63ac4b87c54a1b31d60b7555e2c60d232817c8 (patch)
tree5cfcf092d967d47dbe9a5b8433755211589c19af
parent7a74c2dc3a82488671237555faa95fb38ef31bd5 (diff)
downloadNim-4b63ac4b87c54a1b31d60b7555e2c60d232817c8.tar.gz
fixes #21171; dynamic acyclic refs need to use dyn decRef (#21184)
* fixes #21171; dyn destructors for acyclic inherited  refs

* add a test

* Update compiler/liftdestructors.nim
-rw-r--r--compiler/liftdestructors.nim7
-rw-r--r--lib/system/orc.nim13
-rw-r--r--tests/arc/t21184.nim77
3 files changed, 97 insertions, 0 deletions
diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim
index 5174a908f..2b27a58fc 100644
--- a/compiler/liftdestructors.nim
+++ b/compiler/liftdestructors.nim
@@ -609,6 +609,11 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
   createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen)
   let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType)
 
+  let isInheritableAcyclicRef = c.g.config.selectedGC == gcOrc and
+                      (not isPureObject(elemType)) and
+                      tfAcyclic in skipTypes(elemType, abstractInst+{tyOwned}-{tyTypeDesc}).flags
+  # dynamic Acyclic refs need to use dyn decRef
+
   let tmp =
     if isCyclic and c.kind in {attachedAsgn, attachedSink}:
       declareTempOf(c, body, x)
@@ -632,6 +637,8 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
       cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo)
     else:
       cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, tmp)
+  elif isInheritableAcyclicRef:
+    cond = callCodegenProc(c.g, "nimDecRefIsLastDyn", c.info, x)
   else:
     cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x)
   cond.typ = getSysType(c.g, x.info, tyBool)
diff --git a/lib/system/orc.nim b/lib/system/orc.nim
index 83b983ee1..a56a0c057 100644
--- a/lib/system/orc.nim
+++ b/lib/system/orc.nim
@@ -485,6 +485,19 @@ proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} =
     #if cell.color == colPurple:
     rememberCycle(result, cell, cast[ptr PNimTypeV2](p)[])
 
+proc nimDecRefIsLastDyn(p: pointer): bool {.compilerRtl, inl.} =
+  if p != nil:
+    var cell = head(p)
+    if (cell.rc and not rcMask) == 0:
+      result = true
+      #cprintf("[DESTROY] %p\n", p)
+    else:
+      dec cell.rc, rcIncrement
+    #if cell.color == colPurple:
+    if result:
+      if cell.rootIdx > 0:
+        unregisterCycle(cell)
+
 proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimTypeV2): bool {.compilerRtl, inl.} =
   if p != nil:
     var cell = head(p)
diff --git a/tests/arc/t21184.nim b/tests/arc/t21184.nim
new file mode 100644
index 000000000..91d0c42c7
--- /dev/null
+++ b/tests/arc/t21184.nim
@@ -0,0 +1,77 @@
+discard """
+  matrix: "--mm:orc"
+"""
+
+import std/[with]
+
+type
+  Node* {.acyclic.} = ref object of RootObj
+    name: string
+    data: pointer
+    children: seq[Node]
+  TextNode = ref object of Node
+    text: string
+
+proc fakeEcho(s: string) =
+  if s.len < 0:
+    echo s
+
+proc newNode[T: Node](parent: Node): T =
+  new result
+  result.data = alloc0(250)
+  parent.children.add(result)
+
+proc newRootNode(): Node =
+  new result
+  result.data = alloc0(250)
+
+method printNode(node: Node) {.base.} =
+  fakeEcho node.name
+
+method printNode(node: TextNode) =
+  procCall printNode(Node(node))
+  fakeEcho node.text
+
+proc printChildren(node: Node) =
+  for child in node.children:
+    child.printNode()
+    printChildren(child)
+
+proc free(node: Node) =
+  for child in node.children:
+    free(child)
+  dealloc(node.data)
+
+template node(parent: Node, body: untyped): untyped =
+  var node = newNode[Node](parent)
+  with node:
+    body
+
+proc textNode(parent: Node, text: string) =
+  var node = newNode[TextNode](parent)
+  node.text = text
+
+template withRootNode(body: untyped): untyped =
+  var root = newRootNode()
+  root.name = "root"
+  with root:
+    body
+  root.printNode()
+  printChildren(root)
+  root.free()
+
+proc doTest() =
+  withRootNode:
+    node:
+      name = "child1"
+      node:
+        name = "child2"
+        node:
+          name = "child3"
+          textNode "Hello, world!"
+
+
+# bug #21171
+if isMainModule:
+  for i in 0..100000:
+    doTest()