diff options
Diffstat (limited to 'compiler/ccgtrav.nim')
-rw-r--r-- | compiler/ccgtrav.nim | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim new file mode 100644 index 000000000..ed4c79d9a --- /dev/null +++ b/compiler/ccgtrav.nim @@ -0,0 +1,195 @@ +# +# +# 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) |