123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- #
- #
- # The Nim Compiler
- # (c) Copyright 2013 Andreas Rumpf
- #
- # See the file "copying.txt", included in this
- # distribution, for details about the copyright.
- #
- ## Generates traversal procs for the C backend.
- # included from cgen.nim
- type
- TTraversalClosure = object
- p: BProc
- visitorFrmt: string
- 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, needsInit=false): TLoc
- proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
- typ: PType) =
- if n == nil: return
- case n.kind
- of nkRecList:
- for i in 0..<n.len:
- genTraverseProc(c, accessor, n[i], typ)
- of nkRecCase:
- if (n[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
- var p = c.p
- let disc = n[0].sym
- if disc.loc.snippet == "": fillObjectFields(c.p.module, typ)
- if disc.loc.t == nil:
- 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)
- else:
- lineF(p, cpsStmts, "default:$n", [])
- genTraverseProc(c, accessor, lastSon(branch), typ)
- lineF(p, cpsStmts, "break;$n", [])
- lineF(p, cpsStmts, "} $n", [])
- of nkSym:
- let field = n.sym
- if field.typ.kind == tyVoid: return
- if field.loc.snippet == "": fillObjectFields(c.p.module, typ)
- if field.loc.t == nil:
- 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:
- result = "$1.Sup" % [accessor]
- else:
- result = accessor
- 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,
- tySink, tyOwned:
- genTraverseProc(c, accessor, skipModifier(typ))
- of tyArray:
- 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.snippet, arraySize])
- let oldLen = p.s(cpsStmts).len
- 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:
- 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, 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, visitorFrmt, [ropecg(c.p.module, "$1.ClE_0", [accessor]), c.visitorFrmt])
- else:
- discard
- proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
- var p = c.p
- assert typ.kind == tySequence
- 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$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): Rope =
- var p = newProc(nil, m)
- result = "Marker_" & getTypeName(m, origTyp, sig)
- 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)
- lineF(p, cpsLocals, "$1 a;$n", [t])
- lineF(p, cpsInit, "a = ($1)p;$n", [t])
- 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.elementType, typedescInst+{tyOwned}).kind == tyArray:
- # C's arrays are broken beyond repair:
- genTraverseProc(c, "a".rope, typ.elementType)
- else:
- genTraverseProc(c, "(*a)".rope, typ.elementType)
- 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[cfsProcs].add(generatedProc)
- 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 p = newProc(nil, m)
- var sLoc = rdLoc(s.loc)
- result = getTempName(m)
- if sfThread in s.flags and emulatedThreadVars(m.config):
- accessThreadLocalVar(p, s)
- sLoc = "NimTV_->" & sLoc
- 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)
- 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[cfsProcs].add(generatedProc)
|