even more sys assertions

This commit is contained in:
Araq 2012-01-13 12:49:06 +01:00
commit 76886432da
6 changed files with 68 additions and 33 deletions

View file

@ -95,6 +95,9 @@ proc sort*[T](a: var openArray[T],
## .. code-block:: nimrod ## .. code-block:: nimrod
## ##
## sort(myIntArray, system.cmp[int]) ## sort(myIntArray, system.cmp[int])
##
## # do not use cmp[string] here as we want to use the specialized
## # overload:
## sort(myStrArray, system.cmp) ## sort(myStrArray, system.cmp)
## ##
var n = a.len var n = a.len

View file

@ -832,10 +832,10 @@ proc quit*(errorcode: int = QuitSuccess) {.
## unless a quit procedure calls ``GC_collect``. ## unless a quit procedure calls ``GC_collect``.
template sysAssert(cond, msg: expr) = template sysAssert(cond, msg: expr) =
# change this to activate system asserts when defined(useSysAssert):
#if not cond: if not cond:
# echo "[SYSASSERT] ", msg echo "[SYSASSERT] ", msg
# quit 1 quit 1
nil nil
include "system/inclrtl" include "system/inclrtl"

View file

@ -480,7 +480,22 @@ proc getSmallChunk(a: var TMemRegion): PSmallChunk =
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
proc isAllocatedPtr(a: TMemRegion, p: pointer): bool proc isAllocatedPtr(a: TMemRegion, p: pointer): bool
proc allocInv(a: TMemRegion): bool =
## checks some (not all yet) invariants of the allocator's data structures.
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
var it = c.freeList
while it != nil:
if it.zeroField != 0: return false
it = it.next
c = c.next
result = true
proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer = proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
sysAssert(allocInv(a), "rawAlloc: begin")
sysAssert(roundup(65, 8) == 72, "rawAlloc 1") sysAssert(roundup(65, 8) == 72, "rawAlloc 1")
sysAssert requestedSize >= sizeof(TFreeCell), "rawAlloc 2" sysAssert requestedSize >= sizeof(TFreeCell), "rawAlloc 2"
var size = roundup(requestedSize, MemAlign) var size = roundup(requestedSize, MemAlign)
@ -502,6 +517,7 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
result = addr(c.data) result = addr(c.data)
sysAssert((cast[TAddress](result) and (MemAlign-1)) == 0, "rawAlloc 4") sysAssert((cast[TAddress](result) and (MemAlign-1)) == 0, "rawAlloc 4")
else: else:
sysAssert(allocInv(a), "rawAlloc: begin c != nil")
sysAssert c.next != c, "rawAlloc 5" sysAssert c.next != c, "rawAlloc 5"
#if c.size != size: #if c.size != size:
# c_fprintf(c_stdout, "csize: %lld; size %lld\n", c.size, size) # c_fprintf(c_stdout, "csize: %lld; size %lld\n", c.size, size)
@ -517,10 +533,15 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
c.freeList = c.freeList.next c.freeList = c.freeList.next
dec(c.free, size) dec(c.free, size)
sysAssert((cast[TAddress](result) and (MemAlign-1)) == 0, "rawAlloc 9") sysAssert((cast[TAddress](result) and (MemAlign-1)) == 0, "rawAlloc 9")
sysAssert(allocInv(a), "rawAlloc: end c != nil")
sysAssert(allocInv(a), "rawAlloc: before c.free < size")
if c.free < size: if c.free < size:
sysAssert(allocInv(a), "rawAlloc: before listRemove test")
ListRemove(a.freeSmallChunks[s], c) ListRemove(a.freeSmallChunks[s], c)
sysAssert(allocInv(a), "rawAlloc: end listRemove test")
sysAssert(((cast[TAddress](result) and PageMask) -% smallChunkOverhead()) %% sysAssert(((cast[TAddress](result) and PageMask) -% smallChunkOverhead()) %%
size == 0, "rawAlloc 21") size == 0, "rawAlloc 21")
sysAssert(allocInv(a), "rawAlloc: end small size")
else: else:
size = roundup(requestedSize+bigChunkOverhead(), PageSize) size = roundup(requestedSize+bigChunkOverhead(), PageSize)
# allocate a large block # allocate a large block
@ -533,12 +554,14 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
if a.root == nil: a.root = bottom if a.root == nil: a.root = bottom
add(a, a.root, cast[TAddress](result), cast[TAddress](result)+%size) add(a, a.root, cast[TAddress](result), cast[TAddress](result)+%size)
sysAssert(isAccessible(a, result), "rawAlloc 14") sysAssert(isAccessible(a, result), "rawAlloc 14")
sysAssert(allocInv(a), "rawAlloc: end")
proc rawAlloc0(a: var TMemRegion, requestedSize: int): pointer = proc rawAlloc0(a: var TMemRegion, requestedSize: int): pointer =
result = rawAlloc(a, requestedSize) result = rawAlloc(a, requestedSize)
zeroMem(result, requestedSize) zeroMem(result, requestedSize)
proc rawDealloc(a: var TMemRegion, p: pointer) = proc rawDealloc(a: var TMemRegion, p: pointer) =
sysAssert(allocInv(a), "rawDealloc: begin")
sysAssert(isAllocatedPtr(a, p), "rawDealloc: no allocated pointer!") sysAssert(isAllocatedPtr(a, p), "rawDealloc: no allocated pointer!")
var c = pageAddr(p) var c = pageAddr(p)
if isSmallChunk(c): if isSmallChunk(c):
@ -578,6 +601,7 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
a.deleted = bottom a.deleted = bottom
del(a, a.root, cast[int](addr(c.data))) del(a, a.root, cast[int](addr(c.data)))
freeBigChunk(a, c) freeBigChunk(a, c)
sysAssert(allocInv(a), "rawDealloc: end")
proc isAllocatedPtr(a: TMemRegion, p: pointer): bool = proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
if isAccessible(a, p): if isAccessible(a, p):

View file

@ -241,9 +241,13 @@ proc nimGCref(p: pointer) {.compilerProc, inline.} = incRef(usrToCell(p))
proc nimGCunref(p: pointer) {.compilerProc, inline.} = decRef(usrToCell(p)) proc nimGCunref(p: pointer) {.compilerProc, inline.} = decRef(usrToCell(p))
proc nimGCunrefNoCycle(p: pointer) {.compilerProc, inline.} = proc nimGCunrefNoCycle(p: pointer) {.compilerProc, inline.} =
sysAssert(allocInv(gch.region), "begin nimGCunrefNoCycle")
var c = usrToCell(p) var c = usrToCell(p)
sysAssert(isAllocatedPtr(gch.region, c), "nimGCunrefNoCycle: isAllocatedPtr")
if --c.refcount: if --c.refcount:
rtlAddZCT(c) rtlAddZCT(c)
sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 2")
sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 5")
proc asgnRef(dest: ppointer, src: pointer) {.compilerProc, inline.} = proc asgnRef(dest: ppointer, src: pointer) {.compilerProc, inline.} =
# the code generator calls this proc! # the code generator calls this proc!
@ -393,6 +397,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
acquire(gch) acquire(gch)
sysAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") sysAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
collectCT(gch) collectCT(gch)
sysAssert(allocInv(gch.region), "rawNewObj begin")
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell))) var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2") sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
# now it is buffered in the ZCT # now it is buffered in the ZCT
@ -409,6 +414,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
gcTrace(res, csAllocated) gcTrace(res, csAllocated)
release(gch) release(gch)
result = cellToUsr(res) result = cellToUsr(res)
sysAssert(allocInv(gch.region), "rawNewObj end")
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
result = rawNewObj(typ, size, gch) result = rawNewObj(typ, size, gch)
@ -422,10 +428,14 @@ proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
# generates a new object and sets its reference counter to 1 # generates a new object and sets its reference counter to 1
sysAssert(allocInv(gch.region), "newObjRC1 begin")
acquire(gch) acquire(gch)
sysAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") sysAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
collectCT(gch) collectCT(gch)
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell))) var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2") sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
# now it is buffered in the ZCT # now it is buffered in the ZCT
res.typ = typ res.typ = typ
@ -440,6 +450,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
release(gch) release(gch)
result = cellToUsr(res) result = cellToUsr(res)
zeroMem(result, size) zeroMem(result, size)
sysAssert(allocInv(gch.region), "newObjRC1 end")
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
result = newObjRC1(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize)) result = newObjRC1(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
@ -452,14 +463,16 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
var ol = usrToCell(old) var ol = usrToCell(old)
sysAssert(ol.typ != nil, "growObj: 1") sysAssert(ol.typ != nil, "growObj: 1")
sysAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2") sysAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell))) sysAssert(allocInv(gch.region), "growObj begin")
var res = cast[PCell](rawAlloc0(gch.region, newsize + sizeof(TCell)))
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 var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
copyMem(res, ol, oldsize + sizeof(TCell)) copyMem(res, ol, oldsize + sizeof(TCell))
zeroMem(cast[pointer](cast[TAddress](res)+% oldsize +% sizeof(TCell)), #zeroMem(cast[pointer](cast[TAddress](res)+% oldsize +% sizeof(TCell)),
newsize-oldsize) # newsize-oldsize)
sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "growObj: 3") sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
sysAssert(res.refcount shr rcShift <=% 1, "growObj: 4") sysAssert(res.refcount shr rcShift <=% 1, "growObj: 4")
#if res.refcount <% rcIncrement: #if res.refcount <% rcIncrement:
@ -486,6 +499,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
zeroMem(ol, sizeof(TCell)) zeroMem(ol, sizeof(TCell))
release(gch) release(gch)
result = cellToUsr(res) result = cellToUsr(res)
sysAssert(allocInv(gch.region), "growObj end")
proc growObj(old: pointer, newsize: int): pointer {.rtl.} = proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
result = growObj(old, newsize, gch) result = growObj(old, newsize, gch)
@ -556,6 +570,7 @@ proc collectCycles(gch: var TGcHeap) =
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:
sysAssert(allocInv(gch.region), "gcMark begin")
var cell = usrToCell(p) var cell = usrToCell(p)
var c = cast[TAddress](cell) var c = cast[TAddress](cell)
if c >% PageSize: if c >% PageSize:
@ -571,6 +586,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
# mark the cell: # mark the cell:
cell.refcount = cell.refcount +% rcIncrement cell.refcount = cell.refcount +% rcIncrement
add(gch.decStack, cell) add(gch.decStack, cell)
sysAssert(allocInv(gch.region), "gcMark end")
proc nimKeepAlive(p: PGenericSeq) {.compilerRtl, noinline.} = proc nimKeepAlive(p: PGenericSeq) {.compilerRtl, noinline.} =
var c = usrToCell(p) var c = usrToCell(p)
@ -769,6 +785,8 @@ proc collectCT(gch: var TGcHeap) =
if (gch.zct.len >= ZctThreshold or (cycleGC and if (gch.zct.len >= ZctThreshold or (cycleGC and
getOccupiedMem(gch.region) >= gch.cycleThreshold) or stressGC) and getOccupiedMem(gch.region) >= gch.cycleThreshold) or stressGC) and
gch.recGcLock == 0: gch.recGcLock == 0:
sysAssert(allocInv(gch.region), "collectCT: begin")
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize()) gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
sysAssert(gch.decStack.len == 0, "collectCT") sysAssert(gch.decStack.len == 0, "collectCT")
prepareForInteriorPointerChecking(gch.region) prepareForInteriorPointerChecking(gch.region)
@ -786,6 +804,7 @@ proc collectCT(gch: var TGcHeap) =
cycleIncrease) cycleIncrease)
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold) gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
unmarkStackAndRegisters(gch) unmarkStackAndRegisters(gch)
sysAssert(allocInv(gch.region), "collectCT: end")
when not defined(useNimRtl): when not defined(useNimRtl):
proc GC_disable() = proc GC_disable() =

View file

@ -25,46 +25,35 @@ proc bubbleSort[T](a: var openArray[T],
when isMainModule: when isMainModule:
proc main() = proc main() =
const order = Ascending const order = Ascending
var data: seq[string] = @[] var data: seq[string]
for i in 0..10_000: for i in 0..10_000:
var L = 59 #random(59) var L = random(59)
setLen(data, L) newSeq(data, L)
for j in 0 .. L-1: for j in 0 .. L-1:
data[j] = "" #$(math.random(90) - 10) data[j] = $(math.random(90) - 10)
when false: var copy = data
#var copy = data bubblesort(data, system.cmp, order)
var copy: seq[string]
newSeq(copy, data.len)
for i in 0..data.high: copy[i] = data[i]
bubblesort(data, cmp, order)
if not sorted(data, order): if not sorted(data, order):
#for x in items(data): echo x quit "bubblesort failed"
break sort(copy, cmp, order)
else:
echo "SUCCESS!"
bubblesort(copy, cmp, order)
if copy.len != data.len: if copy.len != data.len:
quit "lengths differ!" quit "lengths differ!"
for i in 0 .. copy.high: for i in 0 .. copy.high:
if copy[i] != data[i]: if copy[i] != data[i]:
quit "algorithms differ!" quit "algorithms differ!"
when false: for i in 0..10_000:
for i in 0..10_000: var data: seq[int]
var data: seq[int] = @[]
var L = random(59) var L = random(59)
setLen(data, L) newSeq(data, L)
for j in 0 .. L-1: for j in 0 .. L-1:
data[j] = (math.random(90) - 10) data[j] = (math.random(90) - 10)
var copy = data var copy = data
sort(data, cmp[int], order) sort(data, cmp[int], order)
if not sorted(data, order): if not sorted(data, order):
#for x in items(data): echo x quit "sort for seq[int] failed"
break bubblesort(copy, system.cmp[int], order)
else:
echo "SUCCESS!"
bubblesort(copy, cmp[int])
if copy.len != data.len: if copy.len != data.len:
quit "lengths differ!" quit "lengths differ!"
for i in 0 .. copy.high: for i in 0 .. copy.high:

View file

@ -1,7 +1,6 @@
version 0.8.14 version 0.8.14
============== ==============
- fix tsortdev bugs
- fix line info in assertions - fix line info in assertions
version 0.9.0 version 0.9.0
@ -46,6 +45,7 @@ Bugs
without ``-d:release`` leaks memory; good way to figure out how a without ``-d:release`` leaks memory; good way to figure out how a
fixed amount of stack can hold an arbitrary number of GC roots! fixed amount of stack can hold an arbitrary number of GC roots!
- BUG: temp2.nim triggers weird compiler and except.nim bug - BUG: temp2.nim triggers weird compiler and except.nim bug
- bug: tsortdev does not run
version 0.9.XX version 0.9.XX