Merge branch 'rbehrends-gc-fixes' into devel

This commit is contained in:
Araq
2015-10-12 19:59:18 +02:00
4 changed files with 86 additions and 45 deletions

View File

@@ -1260,6 +1260,15 @@ const
hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
taintMode = compileOption("taintmode")
when defined(boehmgc):
when defined(windows):
const boehmLib = "boehmgc.dll"
elif defined(macosx):
const boehmLib = "libgc.dylib"
else:
const boehmLib = "libgc.so.1"
{.pragma: boehmGC, noconv, dynlib: boehmLib.}
when taintMode:
type TaintedString* = distinct string ## a distinct string type that
## is `tainted`:idx:. It is an alias for

View File

@@ -66,41 +66,34 @@ proc raiseOutOfMem() {.noinline.} =
quit(1)
when defined(boehmgc):
when defined(windows):
const boehmLib = "boehmgc.dll"
elif defined(macosx):
const boehmLib = "libgc.dylib"
else:
const boehmLib = "libgc.so.1"
proc boehmGCinit {.importc: "GC_init", dynlib: boehmLib.}
proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.}
proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.}
proc boehmGCinit {.importc: "GC_init", boehmGC.}
proc boehmGC_disable {.importc: "GC_disable", boehmGC.}
proc boehmGC_enable {.importc: "GC_enable", boehmGC.}
proc boehmGCincremental {.
importc: "GC_enable_incremental", dynlib: boehmLib.}
proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}
proc boehmAlloc(size: int): pointer {.
importc: "GC_malloc", dynlib: boehmLib.}
importc: "GC_enable_incremental", boehmGC.}
proc boehmGCfullCollect {.importc: "GC_gcollect", boehmGC.}
proc boehmAlloc(size: int): pointer {.importc: "GC_malloc", boehmGC.}
proc boehmAllocAtomic(size: int): pointer {.
importc: "GC_malloc_atomic", dynlib: boehmLib.}
importc: "GC_malloc_atomic", boehmGC.}
proc boehmRealloc(p: pointer, size: int): pointer {.
importc: "GC_realloc", dynlib: boehmLib.}
proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.}
importc: "GC_realloc", boehmGC.}
proc boehmDealloc(p: pointer) {.importc: "GC_free", boehmGC.}
when hasThreadSupport:
proc boehmGC_allow_register_threads {.
importc: "GC_allow_register_threads", boehmGC.}
proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", dynlib: boehmLib.}
proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", boehmGC.}
## Return the number of bytes in the heap. Excludes collector private
## data structures. Includes empty blocks and fragmentation loss.
## Includes some pages that were allocated but never written.
proc boehmGetFreeBytes: int {.importc: "GC_get_free_bytes", dynlib: boehmLib.}
proc boehmGetFreeBytes: int {.importc: "GC_get_free_bytes", boehmGC.}
## Return a lower bound on the number of free bytes in the heap.
proc boehmGetBytesSinceGC: int {.importc: "GC_get_bytes_since_gc",
dynlib: boehmLib.}
proc boehmGetBytesSinceGC: int {.importc: "GC_get_bytes_since_gc", boehmGC.}
## Return the number of bytes allocated since the last collection.
proc boehmGetTotalBytes: int {.importc: "GC_get_total_bytes",
dynlib: boehmLib.}
proc boehmGetTotalBytes: int {.importc: "GC_get_total_bytes", boehmGC.}
## Return the total number of bytes allocated in this process.
## Never decreases.
@@ -157,7 +150,9 @@ when defined(boehmgc):
proc setStackBottom(theStackBottom: pointer) = discard
proc initGC() =
when defined(macosx): boehmGCinit()
boehmGCinit()
when hasThreadSupport:
boehmGC_allow_register_threads()
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
if ntfNoRefs in typ.flags: result = allocAtomic(size)
@@ -204,9 +199,6 @@ elif defined(gogc):
else:
const goLib = "libgo.so"
proc `div`[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.}
proc `-`[T: SomeUnsignedInt](x, y: T): T {.magic: "SubU", noSideEffect.}
proc roundup(x, v: int): int {.inline.} =
result = (x + (v-1)) and not (v-1)

View File

@@ -304,22 +304,53 @@ type
when not defined(boehmgc) and not hasSharedHeap and not defined(gogc):
proc deallocOsPages()
when defined(boehmgc):
type GCStackBaseProc = proc(sb: pointer, t: pointer) {.noconv.}
proc boehmGC_call_with_stack_base(sbp: GCStackBaseProc, p: pointer)
{.importc: "GC_call_with_stack_base", boehmGC.}
proc boehmGC_register_my_thread(sb: pointer)
{.importc: "GC_register_my_thread", boehmGC.}
proc boehmGC_unregister_my_thread()
{.importc: "GC_unregister_my_thread", boehmGC.}
proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv.} =
boehmGC_register_my_thread(sb)
let thrd = cast[ptr Thread[TArg]](thrd)
when TArg is void:
thrd.dataFn()
else:
thrd.dataFn(thrd.data)
boehmGC_unregister_my_thread()
else:
proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) =
when TArg is void:
thrd.dataFn()
else:
thrd.dataFn(thrd.data)
proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) =
when defined(boehmgc):
boehmGC_call_with_stack_base(threadProcWrapDispatch[TArg], thrd)
elif not defined(nogc) and not defined(gogc):
var p {.volatile.}: proc(a: ptr Thread[TArg]) {.nimcall.} =
threadProcWrapDispatch[TArg]
when not hasSharedHeap:
# init the GC for refc/markandsweep
setStackBottom(addr(p))
initGC()
when declared(registerThread):
thrd.stackBottom = addr(thrd)
registerThread(thrd)
p(thrd)
when declared(registerThread): unregisterThread(thrd)
when declared(deallocOsPages): deallocOsPages()
else:
threadProcWrapDispatch(thrd)
template threadProcWrapperBody(closure: expr) {.immediate.} =
when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
var t = cast[ptr Thread[TArg]](closure)
when useStackMaskHack:
var tls: ThreadLocalStorage
when not defined(boehmgc) and not defined(gogc) and not defined(nogc) and not hasSharedHeap:
# init the GC for this thread:
setStackBottom(addr(t))
initGC()
when declared(registerThread):
t.stackBottom = addr(t)
registerThread(t)
when TArg is void: t.dataFn()
else: t.dataFn(t.data)
when declared(registerThread): unregisterThread(t)
when declared(deallocOsPages): deallocOsPages()
var thrd = cast[ptr Thread[TArg]](closure)
threadProcWrapStackFrame(thrd)
# Since an unhandled exception terminates the whole process (!), there is
# no need for a ``try finally`` here, nor would it be correct: The current
# exception is tried to be re-raised by the code-gen after the ``finally``!
@@ -327,7 +358,7 @@ template threadProcWrapperBody(closure: expr) {.immediate.} =
# page!
# mark as not running anymore:
t.dataFn = nil
thrd.dataFn = nil
{.push stack_trace:off.}
when defined(windows):

View File

@@ -117,12 +117,21 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
testSpec r, makeTest("tests/gc" / filename, options &
" -d:release -d:useRealtimeGC", cat, actionRun)
template test(filename: expr): stmt =
template testWithoutBoehm(filename: expr): stmt =
testWithoutMs filename
testSpec r, makeTest("tests/gc" / filename, options &
" --gc:markAndSweep", cat, actionRun)
testSpec r, makeTest("tests/gc" / filename, options &
" -d:release --gc:markAndSweep", cat, actionRun)
template test(filename: expr): stmt =
testWithoutBoehm filename
when not defined(windows):
# AR: cannot find any boehm.dll on the net, right now, so disabled
# for windows:
testSpec r, makeTest("tests/gc" / filename, options &
" --gc:boehm", cat, actionRun)
testSpec r, makeTest("tests/gc" / filename, options &
" -d:release --gc:boehm", cat, actionRun)
test "gcemscripten"
test "growobjcrash"
@@ -134,9 +143,9 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
test "gcleak4"
# Disabled because it works and takes too long to run:
#test "gcleak5"
test "weakrefs"
testWithoutBoehm "weakrefs"
test "cycleleak"
test "closureleak"
testWithoutBoehm "closureleak"
testWithoutMs "refarrayleak"
test "stackrefleak"