summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2019-01-30 18:17:40 +0100
committerAraq <rumpf_a@web.de>2019-01-30 18:17:49 +0100
commit0a628f36f077f4ae1162e17549203ba30a8bf1f2 (patch)
treec31e38f6710f1ae0c4633a9ce49466a3730fb8c9
parent0c2c2dca2a8a3bcdb9729021d1f4734b8db9efbd (diff)
downloadNim-0a628f36f077f4ae1162e17549203ba30a8bf1f2.tar.gz
destructors: do not produce strong backrefs in closure environments so that refcounting works
-rw-r--r--compiler/lambdalifting.nim21
1 files changed, 17 insertions, 4 deletions
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index ddde1be31..1c12688a3 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -320,17 +320,30 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
     rawAddSon(result, obj)
     c.ownerToType[owner.id] = result
 
+proc getEnvTypeForOwnerUp(c: var DetectionPass; owner: PSym;
+                          info: TLineInfo): PType =
+  var r = c.getEnvTypeForOwner(owner, info)
+  result = newType(tyPtr, owner)
+  rawAddSon(result, r.base)
+
 proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
   let refObj = c.getEnvTypeForOwner(dest, info) # getHiddenParam(dest).typ
   let obj = refObj.lastSon
-  let fieldType = c.getEnvTypeForOwner(dep, info) #getHiddenParam(dep).typ
+  # The assumption here is that gcDestructors means we cannot deal
+  # with cycles properly, so it's better to produce a weak ref (=ptr) here.
+  # This seems to be generally correct but since it's a bit risky it's only
+  # enabled for gcDestructors.
+  let fieldType = if c.graph.config.selectedGc == gcDestructors:
+                    c.getEnvTypeForOwnerUp(dep, info) #getHiddenParam(dep).typ
+                  else:
+                    c.getEnvTypeForOwner(dest, info)
   if refObj == fieldType:
     localError(c.graph.config, dep.info, "internal error: invalid up reference computed")
 
   let upIdent = getIdent(c.graph.cache, upName)
   let upField = lookupInRecord(obj.n, upIdent)
   if upField != nil:
-    if upField.typ != fieldType:
+    if upField.typ.base != fieldType.base:
       localError(c.graph.config, dep.info, "internal error: up references do not agree")
   else:
     let result = newSym(skField, upIdent, obj.owner, obj.owner.info)
@@ -555,7 +568,7 @@ proc rawClosureCreation(owner: PSym;
   let upField = lookupInRecord(env.typ.lastSon.n, getIdent(d.graph.cache, upName))
   if upField != nil:
     let up = getUpViaParam(d.graph, owner)
-    if up != nil and upField.typ == up.typ:
+    if up != nil and upField.typ.base == up.typ.base:
       result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info),
                  up, env.info))
     #elif oldenv != nil and oldenv.typ == upField.typ:
@@ -586,7 +599,7 @@ proc closureCreationForIter(iter: PNode;
   let upField = lookupInRecord(v.typ.lastSon.n, getIdent(d.graph.cache, upName))
   if upField != nil:
     let u = setupEnvVar(owner, d, c)
-    if u.typ == upField.typ:
+    if u.typ.base == upField.typ.base:
       result.add(newAsgnStmt(rawIndirectAccess(vnode, upField, iter.info),
                  u, iter.info))
     else: