diff options
-rw-r--r-- | doc/gc.txt | 2 | ||||
-rw-r--r-- | lib/system/alloc.nim | 15 | ||||
-rw-r--r-- | lib/system/gc.nim | 21 | ||||
-rw-r--r-- | lib/system/mmdisp.nim | 1 |
4 files changed, 30 insertions, 9 deletions
diff --git a/doc/gc.txt b/doc/gc.txt index 854f9ce2a..13498afaa 100644 --- a/doc/gc.txt +++ b/doc/gc.txt @@ -13,7 +13,7 @@ Introduction This document describes how the GC works and how to tune it for (soft) `realtime systems`:idx:. -The basic algorithm is *Deferrent Reference Counting* with cycle detection. +The basic algorithm is *Deferred Reference Counting* with cycle detection. References on the stack are not counted for better performance (and easier C code generation). The GC **never** scans the whole heap but it may scan the delta-subgraph of the heap that changed since its last run. diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 744c26d36..2bab79212 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -520,11 +520,18 @@ proc allocInv(a: TMemRegion): bool = for s in low(a.freeSmallChunks)..high(a.freeSmallChunks): var c = a.freeSmallChunks[s] while c != nil: - if c.next == c: return false - if c.size != s * MemAlign: return false + if c.next == c: + echo "[SYSASSERT] c.next == c" + return false + if c.size != s * MemAlign: + echo "[SYSASSERT] c.size != s * MemAlign" + return false var it = c.freeList while it != nil: - if it.zeroField != 0: return false + if it.zeroField != 0: + echo "[SYSASSERT] it.zeroField != 0" + cprintf("%ld %p\n", it.zeroField, it) + return false it = it.next c = c.next result = true @@ -591,6 +598,7 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer = add(a, a.root, cast[TAddress](result), cast[TAddress](result)+%size) sysAssert(isAccessible(a, result), "rawAlloc 14") sysAssert(allocInv(a), "rawAlloc: end") + when logAlloc: cprintf("rawAlloc: %ld %p\n", requestedSize, result) proc rawAlloc0(a: var TMemRegion, requestedSize: int): pointer = result = rawAlloc(a, requestedSize) @@ -638,6 +646,7 @@ proc rawDealloc(a: var TMemRegion, p: pointer) = del(a, a.root, cast[int](addr(c.data))) freeBigChunk(a, c) sysAssert(allocInv(a), "rawDealloc: end") + when logAlloc: cprintf("rawDealloc: %p\n", p) proc isAllocatedPtr(a: TMemRegion, p: pointer): bool = if isAccessible(a, p): diff --git a/lib/system/gc.nim b/lib/system/gc.nim index c5d4d2aa2..48705db96 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -9,7 +9,7 @@ # Garbage Collector # -# The basic algorithm is *Deferrent Reference Counting* with cycle detection. +# The basic algorithm is *Deferred Reference Counting* with cycle detection. # This is achieved by combining a Deutsch-Bobrow garbage collector # together with Christoper's partial mark-sweep garbage collector. # @@ -407,12 +407,17 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} = return add(gch.zct, res) +{.push stackTrace: off, profiler:off.} +proc gcInvariant*(msg: string) = + sysAssert(allocInv(gch.region), msg) +{.pop.} + proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer = # generates a new object and sets its reference counter to 0 + sysAssert(allocInv(gch.region), "rawNewObj begin") acquire(gch) gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") collectCT(gch) - sysAssert(allocInv(gch.region), "rawNewObj begin") var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell))) gcAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2") # now it is buffered in the ZCT @@ -517,7 +522,9 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer = writeCell("growObj new cell", res) gcTrace(ol, csZctFreed) gcTrace(res, csAllocated) - when reallyDealloc: rawDealloc(gch.region, ol) + when reallyDealloc: + sysAssert(allocInv(gch.region), "growObj before dealloc") + rawDealloc(gch.region, ol) else: sysAssert(ol.typ != nil, "growObj: 5") zeroMem(ol, sizeof(TCell)) @@ -537,7 +544,9 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) = prepareDealloc(c) gcTrace(c, csCycFreed) when logGC: writeCell("cycle collector dealloc cell", c) - when reallyDealloc: rawDealloc(gch.region, c) + when reallyDealloc: + sysAssert(allocInv(gch.region), "free cyclic cell") + rawDealloc(gch.region, c) else: gcAssert(c.typ != nil, "freeCyclicCell") zeroMem(c, sizeof(TCell)) @@ -910,7 +919,9 @@ proc collectZCT(gch: var TGcHeap): bool = # access invalid memory. This is done by prepareDealloc(): prepareDealloc(c) forAllChildren(c, waZctDecRef) - when reallyDealloc: rawDealloc(gch.region, c) + when reallyDealloc: + sysAssert(allocInv(gch.region), "collectZCT: rawDealloc") + rawDealloc(gch.region, c) else: sysAssert(c.typ != nil, "collectZCT 2") zeroMem(c, sizeof(TCell)) diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index c9801abad..118272ee3 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -28,6 +28,7 @@ const reallyOsDealloc = true coalescRight = true coalescLeft = true + logAlloc = false type PPointer = ptr pointer |