mark and sweep without bitvectors

This commit is contained in:
Araq
2013-02-19 17:31:54 +01:00
parent 4a51209e9f
commit a4d47664d6
2 changed files with 77 additions and 29 deletions

View File

@@ -303,7 +303,32 @@ iterator elements(t: TIntSet): int {.inline.} =
w = w shr 1
inc(i)
r = r.next
proc isSmallChunk(c: PChunk): bool {.inline.} =
return c.size <= SmallChunkSize-smallChunkOverhead()
proc chunkUnused(c: PChunk): bool {.inline.} =
result = not c.used
iterator allObjects(m: TMemRegion): pointer {.inline.} =
for s in elements(m.chunkStarts):
let c = cast[PChunk](s shl PageShift)
if not chunkUnused(c):
if isSmallChunk(c):
var c = cast[PSmallChunk](c)
let size = c.size
var a = cast[TAddress](addr(c.data))
while a <% c.acc:
yield cast[pointer](a)
a = a +% size
else:
let c = cast[PBigChunk](c)
yield addr(c.data)
proc isCell(p: pointer): bool {.inline.} =
result = cast[ptr TFreeCell](p).zeroField >% 1
# ------------- chunk management ----------------------------------------------
proc pageIndex(c: PChunk): int {.inline.} =
result = cast[TAddress](c) shr PageShift
@@ -398,12 +423,6 @@ proc ListRemove[T](head: var T, c: T) {.inline.} =
c.next = nil
c.prev = nil
proc isSmallChunk(c: PChunk): bool {.inline.} =
return c.size <= SmallChunkSize-smallChunkOverhead()
proc chunkUnused(c: PChunk): bool {.inline.} =
result = not c.used
proc updatePrevSize(a: var TMemRegion, c: PBigChunk,
prevSize: int) {.inline.} =
var ri = cast[PChunk](cast[TAddress](c) +% c.size)

View File

@@ -7,11 +7,16 @@
# distribution, for details about the copyright.
#
# A simple mark&sweep garbage collector for Nimrod.
# A simple mark&sweep garbage collector for Nimrod. Define the
# symbol ``gcUseBitvectors`` to generate a variant of this GC.
{.push profiler:off.}
const
InitialThreshold = 4*1024*1024 # X MB because marking&sweeping is slow
withBitvectors = defined(gcUseBitvectors)
rcWhite = 0
rcGrey = 1 # unused
rcBlack = 2
template mulThreshold(x): expr {.immediate.} = x * 2
@@ -41,7 +46,8 @@ type
# non-zero count table
stackBottom: pointer
cycleThreshold: int
allocated, marked: TCellSet
when withBitvectors:
allocated, marked: TCellSet
tempStack: TCellSeq # temporary stack for recursion elimination
recGcLock: int # prevent recursion via finalizers; no thread lock
region: TMemRegion # garbage collected region
@@ -125,9 +131,11 @@ proc prepareDealloc(cell: PCell) =
proc nimGCref(p: pointer) {.compilerProc, inline.} =
# we keep it from being collected by pretending it's not even allocated:
excl(gch.allocated, usrToCell(p))
when withBitvectors: excl(gch.allocated, usrToCell(p))
else: usrToCell(p).refcount = rcBlack
proc nimGCunref(p: pointer) {.compilerProc, inline.} =
incl(gch.allocated, usrToCell(p))
when withBitvectors: incl(gch.allocated, usrToCell(p))
else: usrToCell(p).refcount = rcWhite
proc initGC() =
when not defined(useNimRtl):
@@ -136,8 +144,9 @@ proc initGC() =
gch.stat.maxThreshold = 0
gch.stat.maxStackSize = 0
init(gch.tempStack)
Init(gch.allocated)
init(gch.marked)
when withBitvectors:
Init(gch.allocated)
init(gch.marked)
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
var d = cast[TAddress](dest)
@@ -200,7 +209,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
res.line = framePtr.prev.line
res.refcount = 0
release(gch)
incl(gch.allocated, res)
when withBitvectors: incl(gch.allocated, res)
result = cellToUsr(res)
{.pop.}
@@ -246,11 +255,11 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
zeroMem(cast[pointer](cast[TAddress](res)+% oldsize +% sizeof(TCell)),
newsize-oldsize)
sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
excl(gch.allocated, ol)
when withBitvectors: excl(gch.allocated, ol)
when reallyDealloc: rawDealloc(gch.region, ol)
else:
zeroMem(ol, sizeof(TCell))
incl(gch.allocated, res)
when withBitvectors: incl(gch.allocated, res)
release(gch)
result = cellToUsr(res)
when defined(memProfiler): nimProfile(newsize-oldsize)
@@ -263,14 +272,25 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
# ----------------- collector -----------------------------------------------
proc mark(gch: var TGcHeap, c: PCell) =
incl(gch.marked, c)
gcAssert gch.tempStack.len == 0, "stack not empty!"
forAllChildren(c, waMarkPrecise)
while gch.tempStack.len > 0:
dec gch.tempStack.len
var d = gch.tempStack.d[gch.tempStack.len]
if not containsOrIncl(gch.marked, d):
forAllChildren(d, waMarkPrecise)
when withBitvectors:
incl(gch.marked, c)
gcAssert gch.tempStack.len == 0, "stack not empty!"
forAllChildren(c, waMarkPrecise)
while gch.tempStack.len > 0:
dec gch.tempStack.len
var d = gch.tempStack.d[gch.tempStack.len]
if not containsOrIncl(gch.marked, d):
forAllChildren(d, waMarkPrecise)
else:
c.refCount = rcBlack
gcAssert gch.tempStack.len == 0, "stack not empty!"
forAllChildren(c, waMarkPrecise)
while gch.tempStack.len > 0:
dec gch.tempStack.len
var d = gch.tempStack.d[gch.tempStack.len]
if d.refcount == rcWhite:
d.refCount = rcBlack
forAllChildren(d, waMarkPrecise)
proc doOperation(p: pointer, op: TWalkOp) =
if p == nil: return
@@ -298,9 +318,17 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
zeroMem(c, sizeof(TCell))
proc sweep(gch: var TGcHeap) =
for c in gch.allocated.elementsExcept(gch.marked):
gch.allocated.excl(c)
freeCyclicCell(gch, c)
when withBitvectors:
for c in gch.allocated.elementsExcept(gch.marked):
gch.allocated.excl(c)
freeCyclicCell(gch, c)
else:
for x in allObjects(gch.region):
if isCell(x):
# cast to PCell is correct here:
var c = cast[PCell](x)
if c.refcount == rcBlack: c.refcount = rcWhite
else: freeCyclicCell(gch, c)
proc markGlobals(gch: var TGcHeap) =
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
@@ -451,8 +479,9 @@ proc collectCTBody(gch: var TGcHeap) =
sweep(gch)
inc(gch.stat.collections)
deinit(gch.marked)
init(gch.marked)
when withBitvectors:
deinit(gch.marked)
init(gch.marked)
gch.cycleThreshold = max(InitialThreshold, getOccupiedMem().mulThreshold)
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
sysAssert(allocInv(gch.region), "collectCT: end")