bugfix: MS GC acknowledges GC_ref/unref properly

This commit is contained in:
Araq 2014-04-30 00:22:45 +02:00
commit ed1927e001

View file

@ -48,12 +48,15 @@ type
# non-zero count table # non-zero count table
stackBottom: pointer stackBottom: pointer
cycleThreshold: int cycleThreshold: int
when useCellIds:
idGenerator: int
when withBitvectors: when withBitvectors:
allocated, marked: TCellSet allocated, marked: TCellSet
tempStack: TCellSeq # temporary stack for recursion elimination tempStack: TCellSeq # temporary stack for recursion elimination
recGcLock: int # prevent recursion via finalizers; no thread lock recGcLock: int # prevent recursion via finalizers; no thread lock
region: TMemRegion # garbage collected region region: TMemRegion # garbage collected region
stat: TGcStat stat: TGcStat
additionalRoots: TCellSeq # dummy roots for GC_ref/unref
var var
gch {.rtlThreadVar.}: TGcHeap gch {.rtlThreadVar.}: TGcHeap
@ -131,13 +134,26 @@ proc prepareDealloc(cell: PCell) =
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell)) (cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
dec(gch.recGcLock) dec(gch.recGcLock)
proc nimGCref(p: pointer) {.compilerProc, inline.} = proc nimGCref(p: pointer) {.compilerProc.} =
# we keep it from being collected by pretending it's not even allocated: # we keep it from being collected by pretending it's not even allocated:
when withBitvectors: excl(gch.allocated, usrToCell(p)) when false:
else: usrToCell(p).refcount = rcBlack when withBitvectors: excl(gch.allocated, usrToCell(p))
proc nimGCunref(p: pointer) {.compilerProc, inline.} = else: usrToCell(p).refcount = rcBlack
when withBitvectors: incl(gch.allocated, usrToCell(p)) add(gch.additionalRoots, usrToCell(p))
else: usrToCell(p).refcount = rcWhite
proc nimGCunref(p: pointer) {.compilerProc.} =
let cell = usrToCell(p)
var L = gch.additionalRoots.len
var i = L
let d = gch.additionalRoots.d
while i >= 0:
if d[i] == cell:
d[i] = d[L]
dec gch.additionalRoots.len
break
when false:
when withBitvectors: incl(gch.allocated, usrToCell(p))
else: usrToCell(p).refcount = rcWhite
proc initGC() = proc initGC() =
when not defined(useNimRtl): when not defined(useNimRtl):
@ -146,6 +162,7 @@ proc initGC() =
gch.stat.maxThreshold = 0 gch.stat.maxThreshold = 0
gch.stat.maxStackSize = 0 gch.stat.maxStackSize = 0
init(gch.tempStack) init(gch.tempStack)
init(gch.additionalRoots)
when withBitvectors: when withBitvectors:
Init(gch.allocated) Init(gch.allocated)
init(gch.marked) init(gch.marked)
@ -212,8 +229,16 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
res.refcount = 0 res.refcount = 0
release(gch) release(gch)
when withBitvectors: incl(gch.allocated, res) when withBitvectors: incl(gch.allocated, res)
when useCellIds:
inc gch.idGenerator
res.id = gch.idGenerator
result = cellToUsr(res) result = cellToUsr(res)
when useCellIds:
proc getCellId*[T](x: ref T): int =
let p = usrToCell(cast[pointer](x))
result = p.id
{.pop.} {.pop.}
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
@ -262,6 +287,9 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
else: else:
zeroMem(ol, sizeof(TCell)) zeroMem(ol, sizeof(TCell))
when withBitvectors: incl(gch.allocated, res) when withBitvectors: incl(gch.allocated, res)
when useCellIds:
inc gch.idGenerator
res.id = gch.idGenerator
release(gch) release(gch)
result = cellToUsr(res) result = cellToUsr(res)
when defined(memProfiler): nimProfile(newsize-oldsize) when defined(memProfiler): nimProfile(newsize-oldsize)
@ -332,8 +360,19 @@ proc sweep(gch: var TGcHeap) =
if c.refcount == rcBlack: c.refcount = rcWhite if c.refcount == rcBlack: c.refcount = rcWhite
else: freeCyclicCell(gch, c) else: freeCyclicCell(gch, c)
when false:
proc newGcInvariant*() =
for x in allObjects(gch.region):
if isCell(x):
var c = cast[PCell](x)
if c.typ == nil:
writeStackTrace()
quit 1
proc markGlobals(gch: var TGcHeap) = proc markGlobals(gch: var TGcHeap) =
for i in 0 .. < globalMarkersLen: globalMarkers[i]() for i in 0 .. < globalMarkersLen: globalMarkers[i]()
let d = gch.additionalRoots.d
for i in 0 .. < gch.additionalRoots.len: mark(gch, d[i])
proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} = proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells: # the addresses are not as cells on the stack, so turn them to cells: