ccgtrav.nim 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. Traversal procs are only an
  10. ## optimization; the GC works without them too.
  11. # included from cgen.nim
  12. type
  13. TTraversalClosure = object
  14. p: BProc
  15. visitorFrmt: string
  16. proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType)
  17. proc genCaseRange(p: BProc, branch: PNode)
  18. proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)
  19. proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, n: PNode;
  20. typ: PType) =
  21. if n == nil: return
  22. case n.kind
  23. of nkRecList:
  24. for i in countup(0, sonsLen(n) - 1):
  25. genTraverseProc(c, accessor, n.sons[i], typ)
  26. of nkRecCase:
  27. if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc")
  28. var p = c.p
  29. let disc = n.sons[0].sym
  30. if disc.loc.r == nil: fillObjectFields(c.p.module, typ)
  31. if disc.loc.t == nil:
  32. internalError(n.info, "genTraverseProc()")
  33. lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
  34. for i in countup(1, sonsLen(n) - 1):
  35. let branch = n.sons[i]
  36. assert branch.kind in {nkOfBranch, nkElse}
  37. if branch.kind == nkOfBranch:
  38. genCaseRange(c.p, branch)
  39. else:
  40. lineF(p, cpsStmts, "default:$n", [])
  41. genTraverseProc(c, accessor, lastSon(branch), typ)
  42. lineF(p, cpsStmts, "break;$n", [])
  43. lineF(p, cpsStmts, "} $n", [])
  44. of nkSym:
  45. let field = n.sym
  46. if field.typ.kind == tyVoid: return
  47. if field.loc.r == nil: fillObjectFields(c.p.module, typ)
  48. if field.loc.t == nil:
  49. internalError(n.info, "genTraverseProc()")
  50. genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t)
  51. else: internalError(n.info, "genTraverseProc()")
  52. proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
  53. if not m.compileToCpp:
  54. result = "$1.Sup" % [accessor]
  55. else:
  56. result = accessor
  57. proc genTraverseProc(c: var 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. genTraverseProc(c, accessor, lastSon(typ))
  63. of tyArray:
  64. let arraySize = lengthOrd(typ.sons[0])
  65. var i: TLoc
  66. getTemp(p, getSysType(tyInt), i)
  67. let oldCode = p.s(cpsStmts)
  68. linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
  69. i.r, arraySize.rope)
  70. let oldLen = p.s(cpsStmts).len
  71. genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1])
  72. if p.s(cpsStmts).len == oldLen:
  73. # do not emit dummy long loops for faster debug builds:
  74. p.s(cpsStmts) = oldCode
  75. else:
  76. lineF(p, cpsStmts, "}$n", [])
  77. of tyObject:
  78. for i in countup(0, sonsLen(typ) - 1):
  79. var x = typ.sons[i]
  80. if x != nil: x = x.skipTypes(skipPtrs)
  81. genTraverseProc(c, accessor.parentObj(c.p.module), x)
  82. if typ.n != nil: genTraverseProc(c, accessor, typ.n, typ)
  83. of tyTuple:
  84. let typ = getUniqueType(typ)
  85. for i in countup(0, sonsLen(typ) - 1):
  86. genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.rope), typ.sons[i])
  87. of tyRef, tyString, tySequence:
  88. lineCg(p, cpsStmts, c.visitorFrmt, accessor)
  89. of tyProc:
  90. if typ.callConv == ccClosure:
  91. lineCg(p, cpsStmts, c.visitorFrmt, rfmt(nil, "$1.ClE_0", accessor))
  92. else:
  93. discard
  94. proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) =
  95. var p = c.p
  96. assert typ.kind == tySequence
  97. var i: TLoc
  98. getTemp(p, getSysType(tyInt), i)
  99. let oldCode = p.s(cpsStmts)
  100. lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
  101. [i.r, accessor, rope(if c.p.module.compileToCpp: "len" else: "Sup.len")])
  102. let oldLen = p.s(cpsStmts).len
  103. genTraverseProc(c, "$1->data[$2]" % [accessor, i.r], typ.sons[0])
  104. if p.s(cpsStmts).len == oldLen:
  105. # do not emit dummy long loops for faster debug builds:
  106. p.s(cpsStmts) = oldCode
  107. else:
  108. lineF(p, cpsStmts, "}$n", [])
  109. proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash;
  110. reason: TTypeInfoReason): Rope =
  111. var c: TTraversalClosure
  112. var p = newProc(nil, m)
  113. result = "Marker_" & getTypeName(m, origTyp, sig)
  114. var typ = origTyp.skipTypes(abstractInst)
  115. if typ.kind == tyOpt: typ = optLowering(typ)
  116. case reason
  117. of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
  118. else: assert false
  119. let header = "static N_NIMCALL(void, $1)(void* p, NI op)" % [result]
  120. let t = getTypeDesc(m, typ)
  121. lineF(p, cpsLocals, "$1 a;$n", [t])
  122. lineF(p, cpsInit, "a = ($1)p;$n", [t])
  123. c.p = p
  124. assert typ.kind != tyTypeDesc
  125. if typ.kind == tySequence:
  126. genTraverseProcSeq(c, "a".rope, typ)
  127. else:
  128. if skipTypes(typ.sons[0], typedescInst).kind == tyArray:
  129. # C's arrays are broken beyond repair:
  130. genTraverseProc(c, "a".rope, typ.sons[0])
  131. else:
  132. genTraverseProc(c, "(*a)".rope, typ.sons[0])
  133. let generatedProc = "$1 {$n$2$3$4}$n" %
  134. [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
  135. m.s[cfsProcHeaders].addf("$1;$n", [header])
  136. m.s[cfsProcs].add(generatedProc)
  137. proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
  138. discard genTypeInfo(m, s.loc.t)
  139. var c: TTraversalClosure
  140. var p = newProc(nil, m)
  141. var sLoc = s.loc.r
  142. result = getTempName(m)
  143. if sfThread in s.flags and emulatedThreadVars():
  144. accessThreadLocalVar(p, s)
  145. sLoc = "NimTV_->" & sLoc
  146. c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
  147. c.p = p
  148. let header = "static N_NIMCALL(void, $1)(void)" % [result]
  149. genTraverseProc(c, sLoc, s.loc.t)
  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)