proper color flipping

This commit is contained in:
Araq 2015-12-01 00:48:37 +01:00
commit af29ea1ea2

View file

@ -39,9 +39,9 @@ iterToProc(allObjects, ptr ObjectSpaceIter, allObjectsAsProc)
const const
rcIncrement = 0b1000 # so that lowest 3 bits are not touched rcIncrement = 0b1000 # so that lowest 3 bits are not touched
rcBlack = 0b000 rcBlackOrig = 0b000
rcGrey = 0b001 # traditional color for incremental mark&sweep rcWhiteOrig = 0b001
rcWhite = 0b010 rcGrey = 0b010 # traditional color for incremental mark&sweep
rcUnused = 0b011 rcUnused = 0b011
ZctFlag = 0b100 # in ZCT ZctFlag = 0b100 # in ZCT
rcShift = 3 # shift by rcShift to get the reference counter rcShift = 3 # shift by rcShift to get the reference counter
@ -76,6 +76,7 @@ type
GcHeap = object # this contains the zero count and GcHeap = object # this contains the zero count and
# non-zero count table # non-zero count table
black: int # either 0 or 1.
stack: ptr GcStack stack: ptr GcStack
stackBottom: pointer stackBottom: pointer
phase: Phase phase: Phase
@ -153,9 +154,6 @@ when BitsPerPage mod (sizeof(int)*8) != 0:
template color(c): expr = c.refCount and colorMask template color(c): expr = c.refCount and colorMask
template setColor(c, col) = template setColor(c, col) =
when col == rcBlack:
c.refcount = c.refcount and not colorMask
else:
c.refcount = c.refcount and not colorMask or col c.refcount = c.refcount and not colorMask or col
proc writeCell(msg: cstring, c: PCell) = proc writeCell(msg: cstring, c: PCell) =
@ -236,7 +234,7 @@ proc nimGCunref(p: pointer) {.compilerProc.} =
dec(i) dec(i)
template markGrey(x: PCell) = template markGrey(x: PCell) =
if x.color == rcWhite and gch.phase == Phase.Marking: if x.color == 1-gch.black and gch.phase == Phase.Marking:
x.setColor(rcGrey) x.setColor(rcGrey)
add(gch.greyStack, x) add(gch.greyStack, x)
@ -425,7 +423,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
res.filename = framePtr.prev.filename res.filename = framePtr.prev.filename
res.line = framePtr.prev.line res.line = framePtr.prev.line
# refcount is zero, color is black, but mark it to be in the ZCT # refcount is zero, color is black, but mark it to be in the ZCT
res.refcount = ZctFlag res.refcount = ZctFlag or gch.black
sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3") sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3")
# its refcount is zero, so add it to the ZCT: # its refcount is zero, so add it to the ZCT:
addNewObjToZCT(res, gch) addNewObjToZCT(res, gch)
@ -472,7 +470,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
if framePtr != nil and framePtr.prev != nil: if framePtr != nil and framePtr.prev != nil:
res.filename = framePtr.prev.filename res.filename = framePtr.prev.filename
res.line = framePtr.prev.line res.line = framePtr.prev.line
res.refcount = rcIncrement # refcount is 1 res.refcount = rcIncrement or gch.black # refcount is 1
sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3") sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3")
when logGC: writeCell("new cell", res) when logGC: writeCell("new cell", res)
gcTrace(res, csAllocated) gcTrace(res, csAllocated)
@ -504,9 +502,9 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
var elemSize = 1 var elemSize = 1
if ol.typ.kind != tyString: elemSize = ol.typ.base.size if ol.typ.kind != tyString: elemSize = ol.typ.base.size
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize let oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
copyMem(res, ol, oldsize + sizeof(Cell)) copyMem(res, ol, oldsize + sizeof(Cell))
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)), zeroMem(cast[pointer](cast[ByteAddress](res) +% oldsize +% sizeof(Cell)),
newsize-oldsize) newsize-oldsize)
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
# This can be wrong for intermediate temps that are nevertheless on the # This can be wrong for intermediate temps that are nevertheless on the
@ -536,7 +534,7 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
# A better fix would be to emit the location specific write barrier for # A better fix would be to emit the location specific write barrier for
# 'growObj', but this is lots of more work and who knows what new problems # 'growObj', but this is lots of more work and who knows what new problems
# this would create. # this would create.
res.refcount = rcIncrement res.refcount = rcIncrement or gch.black
decRef(ol) decRef(ol)
else: else:
sysAssert(ol.typ != nil, "growObj: 5") sysAssert(ol.typ != nil, "growObj: 5")
@ -603,6 +601,7 @@ proc freeCyclicCell(gch: var GcHeap, c: PCell) =
proc sweep(gch: var GcHeap): bool = proc sweep(gch: var GcHeap): bool =
takeStartTime(100) takeStartTime(100)
echo "loop start" echo "loop start"
let black = gch.black
while true: while true:
let x = allObjectsAsProc(gch.region, addr gch.spaceIter) let x = allObjectsAsProc(gch.region, addr gch.spaceIter)
if gch.spaceIter.state < 0: break if gch.spaceIter.state < 0: break
@ -611,31 +610,22 @@ proc sweep(gch: var GcHeap): bool =
# cast to PCell is correct here: # cast to PCell is correct here:
var c = cast[PCell](x) var c = cast[PCell](x)
gcAssert c.color != rcGrey, "cell is still grey?" gcAssert c.color != rcGrey, "cell is still grey?"
if c.color == rcWhite: freeCyclicCell(gch, c) if c.color != black: freeCyclicCell(gch, c)
#else: c.setColor(rcWhite) # Since this is incremental, we MUST not set the object to 'white' here.
# We could set all the remaining objects to white after the 'sweep'
# completed but instead we flip the meaning of black/white to save one
# traversal over the heap!
checkTime() checkTime()
# prepare for next iteration: # prepare for next iteration:
echo "loop end" echo "loop end"
gch.spaceIter = ObjectSpaceIter() gch.spaceIter = ObjectSpaceIter()
result = true result = true
proc markS(gch: var GcHeap, c: PCell) = proc markRoot(gch: var GcHeap, c: PCell) =
# since we start with 'black' cells, we need to mark them here too: # since we start with 'black' cells, we need to mark them here too:
if c.color != rcGrey: if c.color != rcGrey:
c.setColor(rcGrey) c.setColor(rcGrey)
add(gch.greyStack, c) add(gch.greyStack, c)
when false:
# since we start with 'black' cells, we need to mark them unconditionally
# here. But this means that we mark too much. Duplicate roots (which can
# often happen for stack slots) lead to somewhat duplicate marking.
# XXX We could maybe prevent this somehow?
if c.color == rcWhite:
c.setColor(rcGrey)
add(gch.greyStack, c)
#elif c.color == rcBlack:
# echo "cell is black?!"
#forAllChildren(c, waMarkGrey)
#x.setColor(rcBlack)
proc markIncremental(gch: var GcHeap): bool = proc markIncremental(gch: var GcHeap): bool =
var L = addr(gch.greyStack.len) var L = addr(gch.greyStack.len)
@ -647,7 +637,7 @@ proc markIncremental(gch: var GcHeap): bool =
dec(L[]) dec(L[])
takeTime() takeTime()
if c.color == rcGrey: if c.color == rcGrey:
c.setColor(rcBlack) c.setColor(gch.black)
forAllChildren(c, waMarkGrey) forAllChildren(c, waMarkGrey)
checkTime() checkTime()
gcAssert gch.greyStack.len == 0, "markIncremental: greystack not empty " gcAssert gch.greyStack.len == 0, "markIncremental: greystack not empty "
@ -660,7 +650,7 @@ proc markLocals(gch: var GcHeap) =
var d = gch.decStack.d var d = gch.decStack.d
for i in 0 .. < gch.decStack.len: for i in 0 .. < gch.decStack.len:
sysAssert isAllocatedPtr(gch.region, d[i]), "markLocals" sysAssert isAllocatedPtr(gch.region, d[i]), "markLocals"
markS(gch, d[i]) markRoot(gch, d[i])
when logGC: when logGC:
var var
@ -704,11 +694,11 @@ proc doOperation(p: pointer, op: WalkOp) =
when hasThreadSupport: when hasThreadSupport:
# could point to a cell which we don't own and don't want to touch/trace # could point to a cell which we don't own and don't want to touch/trace
if isAllocatedPtr(gch.region, c): if isAllocatedPtr(gch.region, c):
markS(gch, c) markRoot(gch, c)
else: else:
markS(gch, c) markRoot(gch, c)
of waMarkGrey: of waMarkGrey:
if c.color == rcWhite: if c.color == 1-gch.black:
c.setColor(rcGrey) c.setColor(rcGrey)
add(gch.greyStack, c) add(gch.greyStack, c)
#of waDebug: debugGraph(c) #of waDebug: debugGraph(c)
@ -723,15 +713,18 @@ proc collectCycles(gch: var GcHeap): bool =
while gch.zct.len > 0: discard collectZCT(gch) while gch.zct.len > 0: discard collectZCT(gch)
case gch.phase case gch.phase
of Phase.None, Phase.Marking: of Phase.None, Phase.Marking:
#if gch.phase == Phase.None:
gch.phase = Phase.Marking
markGlobals(gch) markGlobals(gch)
markLocals(gch) markLocals(gch)
gch.phase = Phase.Marking
if markIncremental(gch): if markIncremental(gch):
gch.phase = Phase.Sweeping gch.phase = Phase.Sweeping
of Phase.Sweeping: of Phase.Sweeping:
gcAssert gch.greyStack.len == 0, "greystack not empty" gcAssert gch.greyStack.len == 0, "greystack not empty"
if sweep(gch): if sweep(gch):
gch.phase = Phase.None gch.phase = Phase.None
# flip black/white meanings:
gch.black = 1 - gch.black
result = true result = true
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} = proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =