ccgtrav.nim 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2013 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Generates traversal procs for the C backend.
  10. # included from cgen.nim
  11. type
  12. TTraversalClosure = object
  13. p: BProc
  14. visitorFrmt: string
  15. proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType)
  16. proc genCaseRange(p: BProc, branch: PNode)
  17. proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)
  18. proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
  19. typ: PType) =
  20. if n == nil: return
  21. case n.kind
  22. of nkRecList:
  23. for i in countup(0, sonsLen(n) - 1):
  24. genTraverseProc(c, accessor, n.sons[i], typ)
  25. of nkRecCase:
  26. if (n.sons[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
  27. var p = c.p
  28. let disc = n.sons[0].sym
  29. if disc.loc.r == nil: fillObjectFields(c.p.module, typ)
  30. if disc.loc.t == nil:
  31. internalError(c.p.config, n.info, "genTraverseProc()")
  32. lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
  33. for i in countup(1, sonsLen(n) - 1):
  34. let branch = n.sons[i]
  35. assert branch.kind in {nkOfBranch, nkElse}
  36. if branch.kind == nkOfBranch:
  37. genCaseRange(c.p, branch)
  38. else:
  39. lineF(p, cpsStmts, "default:$n", [])
  40. genTraverseProc(c, accessor, lastSon(branch), typ)
  41. lineF(p, cpsStmts, "break;$n", [])
  42. lineF(p, cpsStmts, "} $n", [])
  43. of nkSym:
  44. let field = n.sym
  45. if field.typ.kind == tyVoid: return
  46. if field.loc.r == nil: fillObjectFields(c.p.module, typ)
  47. if field.loc.t == nil:
  48. internalError(c.p.config, n.info, "genTraverseProc()")
  49. genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t)
  50. else: internalError(c.p.config, n.info, "genTraverseProc()")
  51. proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
  52. if not m.compileToCpp:
  53. result = "$1.Sup" % [accessor]
  54. else:
  55. result = accessor
  56. proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType)
  57. proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
  58. if typ == nil: return
  59. var p = c.p
  60. case typ.kind
  61. of tyGenericInst, tyGenericBody, tyTypeDesc, tyAlias, tyDistinct, tyInferred,
  62. tySink:
  63. genTraverseProc(c, accessor, lastSon(typ))
  64. of tyArray:
  65. let arraySize = lengthOrd(c.p.config, typ.sons[0])
  66. var i: TLoc
  67. getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i)
  68. let oldCode = p.s(cpsStmts)
  69. linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
  70. i.r, arraySize.rope)
  71. let oldLen = p.s(cpsStmts).len
  72. genTraverseProc(c, ropecg(c.p.module, "$1[$2]", accessor, i.r), typ.sons[1])
  73. if p.s(cpsStmts).len == oldLen:
  74. # do not emit dummy long loops for faster debug builds:
  75. p.s(cpsStmts) = oldCode
  76. else:
  77. lineF(p, cpsStmts, "}$n", [])
  78. of tyObject:
  79. for i in countup(0, sonsLen(typ) - 1):
  80. var x = typ.sons[i]
  81. if x != nil: x = x.skipTypes(skipPtrs)
  82. genTraverseProc(c, accessor.parentObj(c.p.module), x)
  83. if typ.n != nil: genTraverseProc(c, accessor, typ.n, typ)
  84. of tyTuple:
  85. let typ = getUniqueType(typ)
  86. for i in countup(0, sonsLen(typ) - 1):
  87. genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", accessor, i.rope), typ.sons[i])
  88. of tyRef:
  89. lineCg(p, cpsStmts, c.visitorFrmt, accessor)
  90. of tySequence:
  91. if tfHasAsgn notin typ.flags:
  92. lineCg(p, cpsStmts, c.visitorFrmt, accessor)
  93. elif containsGarbageCollectedRef(typ.lastSon):
  94. # destructor based seqs are themselves not traced but their data is, if
  95. # they contain a GC'ed type:
  96. genTraverseProcSeq(c, accessor, typ)
  97. of tyString:
  98. if tfHasAsgn notin typ.flags:
  99. lineCg(p, cpsStmts, c.visitorFrmt, accessor)
  100. of tyProc:
  101. if typ.callConv == ccClosure:
  102. lineCg(p, cpsStmts, c.visitorFrmt, ropecg(c.p.module, "$1.ClE_0", accessor))
  103. else:
  104. discard
  105. proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
  106. var p = c.p
  107. assert typ.kind == tySequence
  108. var i: TLoc
  109. getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i)
  110. let oldCode = p.s(cpsStmts)
  111. var a: TLoc
  112. a.r = accessor
  113. lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
  114. [i.r, lenExpr(c.p, a)])
  115. let oldLen = p.s(cpsStmts).len
  116. genTraverseProc(c, "$1$3[$2]" % [accessor, i.r, dataField(c.p)], typ.sons[0])
  117. if p.s(cpsStmts).len == oldLen:
  118. # do not emit dummy long loops for faster debug builds:
  119. p.s(cpsStmts) = oldCode
  120. else:
  121. lineF(p, cpsStmts, "}$n", [])
  122. proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
  123. var c: TTraversalClosure
  124. var p = newProc(nil, m)
  125. result = "Marker_" & getTypeName(m, origTyp, sig)
  126. var typ = origTyp.skipTypes(abstractInst)
  127. let header = "static N_NIMCALL(void, $1)(void* p, NI op)" % [result]
  128. let t = getTypeDesc(m, typ)
  129. lineF(p, cpsLocals, "$1 a;$n", [t])
  130. lineF(p, cpsInit, "a = ($1)p;$n", [t])
  131. c.p = p
  132. c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
  133. assert typ.kind != tyTypeDesc
  134. if typ.kind == tySequence:
  135. genTraverseProcSeq(c, "a".rope, typ)
  136. else:
  137. if skipTypes(typ.sons[0], typedescInst).kind == tyArray:
  138. # C's arrays are broken beyond repair:
  139. genTraverseProc(c, "a".rope, typ.sons[0])
  140. else:
  141. genTraverseProc(c, "(*a)".rope, typ.sons[0])
  142. let generatedProc = "$1 {$n$2$3$4}$n" %
  143. [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
  144. m.s[cfsProcHeaders].addf("$1;$n", [header])
  145. m.s[cfsProcs].add(generatedProc)
  146. proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
  147. discard genTypeInfo(m, s.loc.t, info)
  148. var c: TTraversalClosure
  149. var p = newProc(nil, m)
  150. var sLoc = s.loc.r
  151. result = getTempName(m)
  152. if sfThread in s.flags and emulatedThreadVars(m.config):
  153. accessThreadLocalVar(p, s)
  154. sLoc = "NimTV_->" & sLoc
  155. c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
  156. c.p = p
  157. let header = "static N_NIMCALL(void, $1)(void)" % [result]
  158. genTraverseProc(c, sLoc, s.loc.t)
  159. let generatedProc = "$1 {$n$2$3$4}$n" %
  160. [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
  161. m.s[cfsProcHeaders].addf("$1;$n", [header])
  162. m.s[cfsProcs].add(generatedProc)