implemented marker procs for the GC resulting in huge speedups

This commit is contained in:
Araq 2012-03-21 23:10:56 +01:00
commit 03ba0f3e25
6 changed files with 169 additions and 18 deletions

121
compiler/ccgtrav.nim Normal file
View file

@ -0,0 +1,121 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# 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.
type
TTraversalClosure {.pure, final.} = object
p: BProc
visitorFrmt: string
proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType)
proc genCaseRange(p: BProc, branch: PNode)
proc getTemp(p: BProc, t: PType, result: var TLoc)
proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
if n == nil: return
case n.kind
of nkRecList:
for i in countup(0, sonsLen(n) - 1):
genTraverseProc(c, accessor, n.sons[i])
of nkRecCase:
if (n.sons[0].kind != nkSym): InternalError(n.info, "genTraverseProc")
var p = c.p
let disc = n.sons[0].sym
p.s[cpsStmts].appf("switch ($1.$2) {$n", accessor, disc.loc.r)
for i in countup(1, sonsLen(n) - 1):
let branch = n.sons[i]
assert branch.kind in {nkOfBranch, nkElse}
if branch.kind == nkOfBranch:
genCaseRange(c.p, branch)
else:
p.s[cpsStmts].appf("default:$n")
genTraverseProc(c, accessor, lastSon(branch))
p.s[cpsStmts].appf("break;$n")
p.s[cpsStmts].appf("} $n")
of nkSym:
let field = n.sym
genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t)
else: internalError(n.info, "genTraverseProc()")
proc parentObj(accessor: PRope): PRope {.inline.} =
if gCmd != cmdCompileToCpp:
result = ropef("$1.Sup", accessor)
else:
result = accessor
proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
if typ == nil: return
var p = c.p
case typ.kind
of tyGenericInst, tyGenericBody:
genTraverseProc(c, accessor, lastSon(typ))
of tyArrayConstr, tyArray:
let arraySize = lengthOrd(typ.sons[0])
var i: TLoc
getTemp(p, getSysType(tyInt), i)
appf(p.s[cpsStmts], "for ($1 = 0; $1 < $2; $1++) {$n",
i.r, arraySize.toRope)
genTraverseProc(c, ropef("$1[$2]", accessor, i.r), typ.sons[1])
appf(p.s[cpsStmts], "}$n")
of tyObject:
for i in countup(0, sonsLen(typ) - 1):
genTraverseProc(c, accessor.parentObj, typ.sons[i])
if typ.n != nil: genTraverseProc(c, accessor, typ.n)
of tyTuple:
if typ.n != nil:
genTraverseProc(c, accessor, typ.n)
else:
for i in countup(0, sonsLen(typ) - 1):
genTraverseProc(c, ropef("$1.Field$2", accessor, i.toRope), typ.sons[i])
of tyRef, tyString, tySequence:
appcg(p, cpsStmts, c.visitorFrmt, accessor)
else:
# no marker procs for closures yet
nil
proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
var p = c.p
assert typ.kind == tySequence
var i: TLoc
getTemp(p, getSysType(tyInt), i)
appf(p.s[cpsStmts], "for ($1 = 0; $1 < $2->$3; $1++) {$n",
i.r, accessor, toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len"))
genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0])
appf(p.s[cpsStmts], "}$n")
proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
var c: TTraversalClosure
var p = newProc(nil, m)
result = getGlobalTempName()
case reason
of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
else: assert false
let header = ropef("N_NIMCALL(void, $1)(void* p, NI op)", result)
let t = getTypeDesc(m, typ)
p.s[cpsLocals].appf("$1 a;$n", t)
p.s[cpsInit].appf("a = ($1)p;$n", t)
c.p = p
if typ.kind == tySequence:
genTraverseProcSeq(c, "a".toRope, typ)
else:
genTraverseProc(c, "(*a)".toRope, typ.sons[0])
let generatedProc = ropef("$1 {$n$2$3$4}$n",
[header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]])
m.s[cfsProcHeaders].appf("$1;$n", header)
m.s[cfsProcs].app(generatedProc)

View file

@ -151,7 +151,6 @@ proc ccgIntroducedPtr(s: PSym): bool =
assert skResult != s.kind
case pt.Kind
of tyObject:
# XXX quick hack floatSize*2 for the pegs module under 64bit
if (optByRef in s.options) or (getSize(pt) > platform.floatSize * 2):
result = true # requested anyway
elif (tfFinal in pt.flags) and (pt.sons[0] == nil):
@ -160,7 +159,7 @@ proc ccgIntroducedPtr(s: PSym): bool =
result = true # ordinary objects are always passed by reference,
# otherwise casting doesn't work
of tyTuple:
result = (getSize(pt) > platform.floatSize) or (optByRef in s.options)
result = (getSize(pt) > platform.floatSize*2) or (optByRef in s.options)
else: result = false
proc fillResult(param: PSym) =
@ -766,6 +765,15 @@ proc fakeClosureType(owner: PSym): PType =
r.addSon(newType(tyTuple, owner))
result.addSon(r)
type
TTypeInfoReason = enum ## for what do we need the type info?
tiNew, ## for 'new'
tiNewSeq, ## for 'newSeq'
tiNonVariantAsgn, ## for generic assignment without variants
tiVariantAsgn ## for generic assignment with variants
include ccgtrav
proc genTypeInfo(m: BModule, typ: PType): PRope =
var t = getUniqueType(typ)
# gNimDat contains all the type information nowadays:
@ -787,7 +795,12 @@ proc genTypeInfo(m: BModule, typ: PType): PRope =
genTypeInfoAuxBase(gNimDat, t, result, toRope"0")
else:
genTupleInfo(gNimDat, fakeClosureType(t.owner), result)
of tyRef, tyPtr, tySequence, tyRange: genTypeInfoAux(gNimDat, t, result)
of tySequence, tyRef:
genTypeInfoAux(gNimDat, t, result)
if optRefcGC in gGlobalOptions:
let markerProc = genTraverseProc(gNimDat, t, tiNew)
appf(gNimDat.s[cfsTypeInit3], "$1->marker = $2;$n", [result, markerProc])
of tyPtr, tyRange: genTypeInfoAux(gNimDat, t, result)
of tyArrayConstr, tyArray: genArrayInfo(gNimDat, t, result)
of tySet: genSetInfo(gNimDat, t, result)
of tyEnum: genEnumInfo(gNimDat, t, result)
@ -796,6 +809,6 @@ proc genTypeInfo(m: BModule, typ: PType): PRope =
if t.n != nil: genObjectInfo(gNimDat, t, result)
else: genTupleInfo(gNimDat, t, result)
else: InternalError("genTypeInfo(" & $t.kind & ')')
proc genTypeSection(m: BModule, n: PNode) =
nil