diff options
Diffstat (limited to 'compiler/ccgtrav.nim')
-rw-r--r-- | compiler/ccgtrav.nim | 156 |
1 files changed, 88 insertions, 68 deletions
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 7a2e221ee..ed4c79d9a 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -7,8 +7,7 @@ # distribution, for details about the copyright. # -## Generates traversal procs for the C backend. Traversal procs are only an -## optimization; the GC works without them too. +## Generates traversal procs for the C backend. # included from cgen.nim @@ -17,27 +16,30 @@ type p: BProc visitorFrmt: string -proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType) +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, result: var TLoc; needsInit=false) +proc getTemp(p: BProc, t: PType, needsInit=false): TLoc -proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, n: PNode; +proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode; typ: PType) = if n == nil: return case n.kind of nkRecList: - for i in countup(0, sonsLen(n) - 1): - genTraverseProc(c, accessor, n.sons[i], typ) + for i in 0..<n.len: + genTraverseProc(c, accessor, n[i], typ) of nkRecCase: - if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc") + if (n[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc") var p = c.p - let disc = n.sons[0].sym - if disc.loc.r == nil: fillObjectFields(c.p.module, typ) + let disc = n[0].sym + if disc.loc.snippet == "": fillObjectFields(c.p.module, typ) if disc.loc.t == nil: - internalError(n.info, "genTraverseProc()") - lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r]) - for i in countup(1, sonsLen(n) - 1): - let branch = n.sons[i] + 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) @@ -49,11 +51,11 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, n: PNode; of nkSym: let field = n.sym if field.typ.kind == tyVoid: return - if field.loc.r == nil: fillObjectFields(c.p.module, typ) + if field.loc.snippet == "": fillObjectFields(c.p.module, typ) if field.loc.t == nil: - internalError(n.info, "genTraverseProc()") - genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t) - else: internalError(n.info, "genTraverseProc()") + 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: @@ -61,110 +63,128 @@ proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} = else: result = accessor -proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType) = +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: - genTraverseProc(c, accessor, lastSon(typ)) + of tyGenericInst, tyGenericBody, tyTypeDesc, tyAlias, tyDistinct, tyInferred, + tySink, tyOwned: + genTraverseProc(c, accessor, skipModifier(typ)) of tyArray: - let arraySize = lengthOrd(typ.sons[0]) - var i: TLoc - getTemp(p, getSysType(tyInt), i) - let oldCode = p.s(cpsStmts) + 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.r, arraySize.rope) + [i.snippet, arraySize]) let oldLen = p.s(cpsStmts).len - genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1]) + 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: - for i in countup(0, sonsLen(typ) - 1): - var x = typ.sons[i] - if x != nil: x = x.skipTypes(skipPtrs) - genTraverseProc(c, accessor.parentObj(c.p.module), x) + 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 in countup(0, sonsLen(typ) - 1): - genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.rope), typ.sons[i]) - of tyRef, tyString, tySequence: - lineCg(p, cpsStmts, c.visitorFrmt, accessor) + 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, c.visitorFrmt, rfmt(nil, "$1.ClE_0", accessor)) + lineCg(p, cpsStmts, visitorFrmt, [ropecg(c.p.module, "$1.ClE_0", [accessor]), c.visitorFrmt]) else: discard -proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) = +proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) = var p = c.p assert typ.kind == tySequence - var i: TLoc - getTemp(p, getSysType(tyInt), i) - let oldCode = p.s(cpsStmts) - lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n", - [i.r, accessor, rope(if c.p.module.compileToCpp: "len" else: "Sup.len")]) + 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->data[$2]" % [accessor, i.r], typ.sons[0]) + 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; - reason: TTypeInfoReason): Rope = - var c: TTraversalClosure +proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope = var p = newProc(nil, m) result = "Marker_" & getTypeName(m, origTyp, sig) - var typ = origTyp.skipTypes(abstractInst) - if typ.kind == tyOpt: typ = optLowering(typ) - - case reason - of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n" - else: assert false + 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) - let header = "static N_NIMCALL(void, $1)(void* p, NI op)" % [result] - - let t = getTypeDesc(m, typ) lineF(p, cpsLocals, "$1 a;$n", [t]) lineF(p, cpsInit, "a = ($1)p;$n", [t]) - c.p = p + 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.sons[0], typedescInst).kind == tyArray: + if skipTypes(typ.elementType, typedescInst+{tyOwned}).kind == tyArray: # C's arrays are broken beyond repair: - genTraverseProc(c, "a".rope, typ.sons[0]) + genTraverseProc(c, "a".rope, typ.elementType) else: - genTraverseProc(c, "(*a)".rope, typ.sons[0]) + genTraverseProc(c, "(*a)".rope, typ.elementType) - let generatedProc = "$1 {$n$2$3$4}$n" % + 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[cfsProcHeaders].addf("$1;\n", [header]) m.s[cfsProcs].add(generatedProc) -proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope = - discard genTypeInfo(m, s.loc.t) + 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 c: TTraversalClosure var p = newProc(nil, m) - var sLoc = s.loc.r + var sLoc = rdLoc(s.loc) result = getTempName(m) - if sfThread in s.flags and emulatedThreadVars(): + if sfThread in s.flags and emulatedThreadVars(m.config): accessThreadLocalVar(p, s) sLoc = "NimTV_->" & sLoc - c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n" - c.p = p + 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) |