summary refs log tree commit diff stats
path: root/compiler/ccgtrav.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/ccgtrav.nim')
-rw-r--r--compiler/ccgtrav.nim156
1 files changed, 88 insertions, 68 deletions
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim
index 7a2e221ee..ed4c79d9a 100644
--- a/compiler/ccgtrav.nim
+++ b/compiler/ccgtrav.nim
@@ -7,8 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-## Generates traversal procs for the C backend. Traversal procs are only an
-## optimization; the GC works without them too.
+## Generates traversal procs for the C backend.
 
 # included from cgen.nim
 
@@ -17,27 +16,30 @@ type
     p: BProc
     visitorFrmt: string
 
-proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType)
+const
+  visitorFrmt = "#nimGCvisit((void*)$1, $2);$n"
+
+proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType)
 proc genCaseRange(p: BProc, branch: PNode)
-proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)
+proc getTemp(p: BProc, t: PType, needsInit=false): TLoc
 
-proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, n: PNode;
+proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
                      typ: PType) =
   if n == nil: return
   case n.kind
   of nkRecList:
-    for i in countup(0, sonsLen(n) - 1):
-      genTraverseProc(c, accessor, n.sons[i], typ)
+    for i in 0..<n.len:
+      genTraverseProc(c, accessor, n[i], typ)
   of nkRecCase:
-    if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc")
+    if (n[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
     var p = c.p
-    let disc = n.sons[0].sym
-    if disc.loc.r == nil: fillObjectFields(c.p.module, typ)
+    let disc = n[0].sym
+    if disc.loc.snippet == "": fillObjectFields(c.p.module, typ)
     if disc.loc.t == nil:
-      internalError(n.info, "genTraverseProc()")
-    lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
-    for i in countup(1, sonsLen(n) - 1):
-      let branch = n.sons[i]
+      internalError(c.p.config, n.info, "genTraverseProc()")
+    lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.snippet])
+    for i in 1..<n.len:
+      let branch = n[i]
       assert branch.kind in {nkOfBranch, nkElse}
       if branch.kind == nkOfBranch:
         genCaseRange(c.p, branch)
@@ -49,11 +51,11 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, n: PNode;
   of nkSym:
     let field = n.sym
     if field.typ.kind == tyVoid: return
-    if field.loc.r == nil: fillObjectFields(c.p.module, typ)
+    if field.loc.snippet == "": fillObjectFields(c.p.module, typ)
     if field.loc.t == nil:
-      internalError(n.info, "genTraverseProc()")
-    genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t)
-  else: internalError(n.info, "genTraverseProc()")
+      internalError(c.p.config, n.info, "genTraverseProc()")
+    genTraverseProc(c, "$1.$2" % [accessor, field.loc.snippet], field.loc.t)
+  else: internalError(c.p.config, n.info, "genTraverseProc()")
 
 proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
   if not m.compileToCpp:
@@ -61,110 +63,128 @@ proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
   else:
     result = accessor
 
-proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType) =
+proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType)
+proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
   if typ == nil: return
 
   var p = c.p
   case typ.kind
-  of tyGenericInst, tyGenericBody, tyTypeDesc, tyAlias, tyDistinct, tyInferred:
-    genTraverseProc(c, accessor, lastSon(typ))
+  of tyGenericInst, tyGenericBody, tyTypeDesc, tyAlias, tyDistinct, tyInferred,
+     tySink, tyOwned:
+    genTraverseProc(c, accessor, skipModifier(typ))
   of tyArray:
-    let arraySize = lengthOrd(typ.sons[0])
-    var i: TLoc
-    getTemp(p, getSysType(tyInt), i)
-    let oldCode = p.s(cpsStmts)
+    let arraySize = lengthOrd(c.p.config, typ.indexType)
+    var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
+    var oldCode = p.s(cpsStmts)
+    freeze oldCode
     linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
-            i.r, arraySize.rope)
+            [i.snippet, arraySize])
     let oldLen = p.s(cpsStmts).len
-    genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1])
+    genTraverseProc(c, ropecg(c.p.module, "$1[$2]", [accessor, i.snippet]), typ.elementType)
     if p.s(cpsStmts).len == oldLen:
       # do not emit dummy long loops for faster debug builds:
       p.s(cpsStmts) = oldCode
     else:
       lineF(p, cpsStmts, "}$n", [])
   of tyObject:
-    for i in countup(0, sonsLen(typ) - 1):
-      var x = typ.sons[i]
-      if x != nil: x = x.skipTypes(skipPtrs)
-      genTraverseProc(c, accessor.parentObj(c.p.module), x)
+    var x = typ.baseClass
+    if x != nil: x = x.skipTypes(skipPtrs)
+    genTraverseProc(c, accessor.parentObj(c.p.module), x)
     if typ.n != nil: genTraverseProc(c, accessor, typ.n, typ)
   of tyTuple:
     let typ = getUniqueType(typ)
-    for i in countup(0, sonsLen(typ) - 1):
-      genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.rope), typ.sons[i])
-  of tyRef, tyString, tySequence:
-    lineCg(p, cpsStmts, c.visitorFrmt, accessor)
+    for i, a in typ.ikids:
+      genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", [accessor, i]), a)
+  of tyRef:
+    lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
+  of tySequence:
+    if optSeqDestructors notin c.p.module.config.globalOptions:
+      lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
+    elif containsGarbageCollectedRef(typ.elementType):
+      # destructor based seqs are themselves not traced but their data is, if
+      # they contain a GC'ed type:
+      lineCg(p, cpsStmts, "#nimGCvisitSeq((void*)$1, $2);$n", [accessor, c.visitorFrmt])
+      #genTraverseProcSeq(c, accessor, typ)
+  of tyString:
+    if tfHasAsgn notin typ.flags:
+      lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
   of tyProc:
     if typ.callConv == ccClosure:
-      lineCg(p, cpsStmts, c.visitorFrmt, rfmt(nil, "$1.ClE_0", accessor))
+      lineCg(p, cpsStmts, visitorFrmt, [ropecg(c.p.module, "$1.ClE_0", [accessor]), c.visitorFrmt])
   else:
     discard
 
-proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) =
+proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
   var p = c.p
   assert typ.kind == tySequence
-  var i: TLoc
-  getTemp(p, getSysType(tyInt), i)
-  let oldCode = p.s(cpsStmts)
-  lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
-      [i.r, accessor, rope(if c.p.module.compileToCpp: "len" else: "Sup.len")])
+  var i = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
+  var oldCode = p.s(cpsStmts)
+  freeze oldCode
+  var a = TLoc(snippet: accessor)
+
+  lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
+      [i.snippet, lenExpr(c.p, a)])
   let oldLen = p.s(cpsStmts).len
-  genTraverseProc(c, "$1->data[$2]" % [accessor, i.r], typ.sons[0])
+  genTraverseProc(c, "$1$3[$2]" % [accessor, i.snippet, dataField(c.p)], typ.elementType)
   if p.s(cpsStmts).len == oldLen:
     # do not emit dummy long loops for faster debug builds:
     p.s(cpsStmts) = oldCode
   else:
     lineF(p, cpsStmts, "}$n", [])
 
-proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash;
-                     reason: TTypeInfoReason): Rope =
-  var c: TTraversalClosure
+proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
   var p = newProc(nil, m)
   result = "Marker_" & getTypeName(m, origTyp, sig)
-  var typ = origTyp.skipTypes(abstractInst)
-  if typ.kind == tyOpt: typ = optLowering(typ)
-
-  case reason
-  of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
-  else: assert false
+  let
+    hcrOn = m.hcrOn
+    typ = origTyp.skipTypes(abstractInstOwned)
+    markerName = if hcrOn: result & "_actual" else: result
+    header = "static N_NIMCALL(void, $1)(void* p, NI op)" % [markerName]
+    t = getTypeDesc(m, typ)
 
-  let header = "static N_NIMCALL(void, $1)(void* p, NI op)" % [result]
-
-  let t = getTypeDesc(m, typ)
   lineF(p, cpsLocals, "$1 a;$n", [t])
   lineF(p, cpsInit, "a = ($1)p;$n", [t])
 
-  c.p = p
+  var c = TTraversalClosure(p: p,
+    visitorFrmt: "op" # "#nimGCvisit((void*)$1, op);$n"
+    )
+
   assert typ.kind != tyTypeDesc
   if typ.kind == tySequence:
     genTraverseProcSeq(c, "a".rope, typ)
   else:
-    if skipTypes(typ.sons[0], typedescInst).kind == tyArray:
+    if skipTypes(typ.elementType, typedescInst+{tyOwned}).kind == tyArray:
       # C's arrays are broken beyond repair:
-      genTraverseProc(c, "a".rope, typ.sons[0])
+      genTraverseProc(c, "a".rope, typ.elementType)
     else:
-      genTraverseProc(c, "(*a)".rope, typ.sons[0])
+      genTraverseProc(c, "(*a)".rope, typ.elementType)
 
-  let generatedProc = "$1 {$n$2$3$4}$n" %
+  let generatedProc = "$1 {$n$2$3$4}\n" %
         [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
 
-  m.s[cfsProcHeaders].addf("$1;$n", [header])
+  m.s[cfsProcHeaders].addf("$1;\n", [header])
   m.s[cfsProcs].add(generatedProc)
 
-proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
-  discard genTypeInfo(m, s.loc.t)
+  if hcrOn:
+    m.s[cfsProcHeaders].addf("N_NIMCALL_PTR(void, $1)(void*, NI);\n", [result])
+    m.s[cfsDynLibInit].addf("\t$1 = (N_NIMCALL_PTR(void, )(void*, NI)) hcrRegisterProc($3, \"$1\", (void*)$2);\n",
+         [result, markerName, getModuleDllPath(m)])
+
+proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
+  discard genTypeInfoV1(m, s.loc.t, info)
 
-  var c: TTraversalClosure
   var p = newProc(nil, m)
-  var sLoc = s.loc.r
+  var sLoc = rdLoc(s.loc)
   result = getTempName(m)
 
-  if sfThread in s.flags and emulatedThreadVars():
+  if sfThread in s.flags and emulatedThreadVars(m.config):
     accessThreadLocalVar(p, s)
     sLoc = "NimTV_->" & sLoc
 
-  c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
-  c.p = p
+  var c = TTraversalClosure(p: p,
+    visitorFrmt: "0" # "#nimGCvisit((void*)$1, 0);$n"
+  )
+
   let header = "static N_NIMCALL(void, $1)(void)" % [result]
   genTraverseProc(c, sLoc, s.loc.t)