ccgtrav.nim 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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, info: var SwitchCaseBuilder)
  17. proc getTemp(p: BProc, t: PType, needsInit=false): TLoc
  18. proc visit(p: BProc, data, visitor: Snippet) =
  19. p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimGCvisit"),
  20. cCast(CPointer, data),
  21. visitor)
  22. proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
  23. typ: PType) =
  24. if n == nil: return
  25. case n.kind
  26. of nkRecList:
  27. for i in 0..<n.len:
  28. genTraverseProc(c, accessor, n[i], typ)
  29. of nkRecCase:
  30. if (n[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
  31. var p = c.p
  32. let disc = n[0].sym
  33. if disc.loc.snippet == "": fillObjectFields(c.p.module, typ)
  34. if disc.loc.t == nil:
  35. internalError(c.p.config, n.info, "genTraverseProc()")
  36. let discField = dotField(accessor, disc.loc.snippet)
  37. p.s(cpsStmts).addSwitchStmt(discField):
  38. for i in 1..<n.len:
  39. let branch = n[i]
  40. assert branch.kind in {nkOfBranch, nkElse}
  41. var caseBuilder: SwitchCaseBuilder
  42. p.s(cpsStmts).addSwitchCase(caseBuilder):
  43. if branch.kind == nkOfBranch:
  44. genCaseRange(c.p, branch, caseBuilder)
  45. else:
  46. p.s(cpsStmts).addCaseElse(caseBuilder)
  47. do:
  48. genTraverseProc(c, accessor, lastSon(branch), typ)
  49. p.s(cpsStmts).addBreak()
  50. of nkSym:
  51. let field = n.sym
  52. if field.typ.kind == tyVoid: return
  53. if field.loc.snippet == "": fillObjectFields(c.p.module, typ)
  54. if field.loc.t == nil:
  55. internalError(c.p.config, n.info, "genTraverseProc()")
  56. genTraverseProc(c, dotField(accessor, field.loc.snippet), field.loc.t)
  57. else: internalError(c.p.config, n.info, "genTraverseProc()")
  58. proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
  59. if not m.compileToCpp:
  60. result = dotField(accessor, "Sup")
  61. else:
  62. result = accessor
  63. proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType)
  64. proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
  65. if typ == nil: return
  66. var p = c.p
  67. case typ.kind
  68. of tyGenericInst, tyGenericBody, tyTypeDesc, tyAlias, tyDistinct, tyInferred,
  69. tySink, tyOwned:
  70. genTraverseProc(c, accessor, skipModifier(typ))
  71. of tyArray:
  72. let arraySize = lengthOrd(c.p.config, typ.indexType)
  73. var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
  74. var oldCode = p.s(cpsStmts)
  75. var oldLen, newLen: int
  76. p.s(cpsStmts).addForRangeExclusive(i.snippet, cIntValue(0), cIntValue(arraySize)):
  77. oldLen = p.s(cpsStmts).buf.len
  78. genTraverseProc(c, subscript(accessor, i.snippet), typ.elementType)
  79. newLen = p.s(cpsStmts).buf.len
  80. if oldLen == newLen:
  81. # do not emit dummy long loops for faster debug builds:
  82. p.s(cpsStmts) = oldCode
  83. of tyObject:
  84. var x = typ.baseClass
  85. if x != nil: x = x.skipTypes(skipPtrs)
  86. genTraverseProc(c, accessor.parentObj(c.p.module), x)
  87. if typ.n != nil: genTraverseProc(c, accessor, typ.n, typ)
  88. of tyTuple:
  89. let typ = getUniqueType(typ)
  90. for i, a in typ.ikids:
  91. genTraverseProc(c, dotField(accessor, "Field" & $i), a)
  92. of tyRef:
  93. visit(p, accessor, c.visitorFrmt)
  94. of tySequence:
  95. if optSeqDestructors notin c.p.module.config.globalOptions:
  96. visit(p, accessor, c.visitorFrmt)
  97. elif containsGarbageCollectedRef(typ.elementType):
  98. # destructor based seqs are themselves not traced but their data is, if
  99. # they contain a GC'ed type:
  100. p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimGCvisitSeq"),
  101. cCast(CPointer, accessor),
  102. c.visitorFrmt)
  103. #genTraverseProcSeq(c, accessor, typ)
  104. of tyString:
  105. if tfHasAsgn notin typ.flags:
  106. visit(p, accessor, c.visitorFrmt)
  107. of tyProc:
  108. if typ.callConv == ccClosure:
  109. visit(p, dotField(accessor, "ClE_0"), c.visitorFrmt)
  110. else:
  111. discard
  112. proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
  113. var p = c.p
  114. assert typ.kind == tySequence
  115. var i = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
  116. var oldCode = p.s(cpsStmts)
  117. var oldLen, newLen: int
  118. var a = TLoc(snippet: accessor)
  119. let le = lenExpr(c.p, a)
  120. p.s(cpsStmts).addForRangeExclusive(i.snippet, cIntValue(0), le):
  121. oldLen = p.s(cpsStmts).buf.len
  122. genTraverseProc(c, subscript(dataField(c.p, accessor), i.snippet), typ.elementType)
  123. newLen = p.s(cpsStmts).buf.len
  124. if newLen == oldLen:
  125. # do not emit dummy long loops for faster debug builds:
  126. p.s(cpsStmts) = oldCode
  127. proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
  128. var p = newProc(nil, m)
  129. result = "Marker_" & getTypeName(m, origTyp, sig)
  130. let
  131. hcrOn = m.hcrOn
  132. typ = origTyp.skipTypes(abstractInstOwned)
  133. markerName = if hcrOn: result & "_actual" else: result
  134. t = getTypeDesc(m, typ)
  135. p.s(cpsLocals).addVar(kind = Local, name = "a", typ = t)
  136. p.s(cpsInit).addAssignment("a", cCast(t, "p"))
  137. var c = TTraversalClosure(p: p,
  138. visitorFrmt: "op" # "#nimGCvisit((void*)$1, op);$n"
  139. )
  140. assert typ.kind != tyTypeDesc
  141. if typ.kind == tySequence:
  142. genTraverseProcSeq(c, "a".rope, typ)
  143. else:
  144. if skipTypes(typ.elementType, typedescInst+{tyOwned}).kind == tyArray:
  145. # C's arrays are broken beyond repair:
  146. genTraverseProc(c, "a".rope, typ.elementType)
  147. else:
  148. genTraverseProc(c, cDeref("a"), typ.elementType)
  149. var headerBuilder = newBuilder("")
  150. headerBuilder.addProcHeaderWithParams(ccNimCall, markerName, CVoid):
  151. var paramBuilder: ProcParamBuilder
  152. headerBuilder.addProcParams(paramBuilder):
  153. headerBuilder.addParam(paramBuilder, name = "p", typ = CPointer)
  154. headerBuilder.addParam(paramBuilder, name = "op", typ = NimInt)
  155. let header = extract(headerBuilder)
  156. m.s[cfsProcHeaders].addDeclWithVisibility(StaticProc):
  157. m.s[cfsProcHeaders].add(header)
  158. m.s[cfsProcHeaders].finishProcHeaderAsProto()
  159. m.s[cfsProcs].addDeclWithVisibility(StaticProc):
  160. m.s[cfsProcs].add(header)
  161. m.s[cfsProcs].finishProcHeaderWithBody():
  162. m.s[cfsProcs].add(extract(p.s(cpsLocals)))
  163. m.s[cfsProcs].add(extract(p.s(cpsInit)))
  164. m.s[cfsProcs].add(extract(p.s(cpsStmts)))
  165. if hcrOn:
  166. var desc = newBuilder("")
  167. var unnamedParamBuilder: ProcParamBuilder
  168. desc.addProcParams(unnamedParamBuilder):
  169. desc.addUnnamedParam(unnamedParamBuilder, CPointer)
  170. desc.addUnnamedParam(unnamedParamBuilder, NimInt)
  171. let unnamedParams = extract(desc)
  172. m.s[cfsProcHeaders].addProcVar(ccNimCall, result, unnamedParams, CVoid)
  173. m.s[cfsDynLibInit].addAssignmentWithValue(result):
  174. m.s[cfsDynLibInit].addCast(procPtrTypeUnnamed(ccNimCall, CVoid, unnamedParams)):
  175. m.s[cfsDynLibInit].addCall("hcrRegisterProc",
  176. getModuleDllPath(m),
  177. '"' & result & '"',
  178. cCast(CPointer, markerName))
  179. proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
  180. discard genTypeInfoV1(m, s.loc.t, info)
  181. var p = newProc(nil, m)
  182. var sLoc = rdLoc(s.loc)
  183. result = getTempName(m)
  184. if sfThread in s.flags and emulatedThreadVars(m.config):
  185. accessThreadLocalVar(p, s)
  186. sLoc = derefField("NimTV_", sLoc)
  187. var c = TTraversalClosure(p: p,
  188. visitorFrmt: cIntValue(0) # "#nimGCvisit((void*)$1, 0);$n"
  189. )
  190. genTraverseProc(c, sLoc, s.loc.t)
  191. var headerBuilder = newBuilder("")
  192. headerBuilder.addProcHeaderWithParams(ccNimCall, result, CVoid):
  193. var paramBuilder: ProcParamBuilder
  194. headerBuilder.addProcParams(paramBuilder):
  195. # (void)
  196. discard
  197. let header = extract(headerBuilder)
  198. m.s[cfsProcHeaders].addDeclWithVisibility(StaticProc):
  199. m.s[cfsProcHeaders].add(header)
  200. m.s[cfsProcHeaders].finishProcHeaderAsProto()
  201. m.s[cfsProcs].addDeclWithVisibility(StaticProc):
  202. m.s[cfsProcs].add(header)
  203. m.s[cfsProcs].finishProcHeaderWithBody():
  204. m.s[cfsProcs].add(extract(p.s(cpsLocals)))
  205. m.s[cfsProcs].add(extract(p.s(cpsInit)))
  206. m.s[cfsProcs].add(extract(p.s(cpsStmts)))