ccgtrav.nim 6.6 KB

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