Merge branch 'gc-fixes' of https://github.com/rbehrends/Nim into rbehrends-gc-fixes

This commit is contained in:
Araq 2015-10-12 17:34:44 +02:00
commit 967c20743a
4 changed files with 83 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 hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
taintMode = compileOption("taintmode") 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: when taintMode:
type TaintedString* = distinct string ## a distinct string type that type TaintedString* = distinct string ## a distinct string type that
## is `tainted`:idx:. It is an alias for ## is `tainted`:idx:. It is an alias for

View file

@ -66,41 +66,34 @@ proc raiseOutOfMem() {.noinline.} =
quit(1) quit(1)
when defined(boehmgc): when defined(boehmgc):
when defined(windows): proc boehmGCinit {.importc: "GC_init", boehmGC.}
const boehmLib = "boehmgc.dll" proc boehmGC_disable {.importc: "GC_disable", boehmGC.}
elif defined(macosx): proc boehmGC_enable {.importc: "GC_enable", boehmGC.}
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 boehmGCincremental {. proc boehmGCincremental {.
importc: "GC_enable_incremental", dynlib: boehmLib.} importc: "GC_enable_incremental", boehmGC.}
proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.} proc boehmGCfullCollect {.importc: "GC_gcollect", boehmGC.}
proc boehmAlloc(size: int): pointer {. proc boehmAlloc(size: int): pointer {.importc: "GC_malloc", boehmGC.}
importc: "GC_malloc", dynlib: boehmLib.}
proc boehmAllocAtomic(size: int): pointer {. proc boehmAllocAtomic(size: int): pointer {.
importc: "GC_malloc_atomic", dynlib: boehmLib.} importc: "GC_malloc_atomic", boehmGC.}
proc boehmRealloc(p: pointer, size: int): pointer {. proc boehmRealloc(p: pointer, size: int): pointer {.
importc: "GC_realloc", dynlib: boehmLib.} importc: "GC_realloc", boehmGC.}
proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.} 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 ## Return the number of bytes in the heap. Excludes collector private
## data structures. Includes empty blocks and fragmentation loss. ## data structures. Includes empty blocks and fragmentation loss.
## Includes some pages that were allocated but never written. ## 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. ## Return a lower bound on the number of free bytes in the heap.
proc boehmGetBytesSinceGC: int {.importc: "GC_get_bytes_since_gc", proc boehmGetBytesSinceGC: int {.importc: "GC_get_bytes_since_gc", boehmGC.}
dynlib: boehmLib.}
## Return the number of bytes allocated since the last collection. ## Return the number of bytes allocated since the last collection.
proc boehmGetTotalBytes: int {.importc: "GC_get_total_bytes", proc boehmGetTotalBytes: int {.importc: "GC_get_total_bytes", boehmGC.}
dynlib: boehmLib.}
## Return the total number of bytes allocated in this process. ## Return the total number of bytes allocated in this process.
## Never decreases. ## Never decreases.
@ -157,7 +150,9 @@ when defined(boehmgc):
proc setStackBottom(theStackBottom: pointer) = discard proc setStackBottom(theStackBottom: pointer) = discard
proc initGC() = proc initGC() =
when defined(macosx): boehmGCinit() boehmGCinit()
when hasThreadSupport:
boehmGC_allow_register_threads()
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
if ntfNoRefs in typ.flags: result = allocAtomic(size) if ntfNoRefs in typ.flags: result = allocAtomic(size)
@ -204,9 +199,6 @@ elif defined(gogc):
else: else:
const goLib = "libgo.so" 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.} = proc roundup(x, v: int): int {.inline.} =
result = (x + (v-1)) and not (v-1) 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): when not defined(boehmgc) and not hasSharedHeap and not defined(gogc):
proc deallocOsPages() 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.} = template threadProcWrapperBody(closure: expr) {.immediate.} =
when declared(globalsSlot): threadVarSetValue(globalsSlot, closure) when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
var t = cast[ptr Thread[TArg]](closure) var thrd = cast[ptr Thread[TArg]](closure)
when useStackMaskHack: threadProcWrapStackFrame(thrd)
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()
# Since an unhandled exception terminates the whole process (!), there is # Since an unhandled exception terminates the whole process (!), there is
# no need for a ``try finally`` here, nor would it be correct: The current # 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``! # exception is tried to be re-raised by the code-gen after the ``finally``!
@ -327,7 +358,7 @@ template threadProcWrapperBody(closure: expr) {.immediate.} =
# page! # page!
# mark as not running anymore: # mark as not running anymore:
t.dataFn = nil thrd.dataFn = nil
{.push stack_trace:off.} {.push stack_trace:off.}
when defined(windows): when defined(windows):

View file

@ -117,12 +117,18 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
testSpec r, makeTest("tests/gc" / filename, options & testSpec r, makeTest("tests/gc" / filename, options &
" -d:release -d:useRealtimeGC", cat, actionRun) " -d:release -d:useRealtimeGC", cat, actionRun)
template test(filename: expr): stmt = template testWithoutBoehm(filename: expr): stmt =
testWithoutMs filename testWithoutMs filename
testSpec r, makeTest("tests/gc" / filename, options & testSpec r, makeTest("tests/gc" / filename, options &
" --gc:markAndSweep", cat, actionRun) " --gc:markAndSweep", cat, actionRun)
testSpec r, makeTest("tests/gc" / filename, options & testSpec r, makeTest("tests/gc" / filename, options &
" -d:release --gc:markAndSweep", cat, actionRun) " -d:release --gc:markAndSweep", cat, actionRun)
template test(filename: expr): stmt =
testWithoutBoehm filename
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 "gcemscripten"
test "growobjcrash" test "growobjcrash"
@ -134,9 +140,9 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
test "gcleak4" test "gcleak4"
# Disabled because it works and takes too long to run: # Disabled because it works and takes too long to run:
#test "gcleak5" #test "gcleak5"
test "weakrefs" testWithoutBoehm "weakrefs"
test "cycleleak" test "cycleleak"
test "closureleak" testWithoutBoehm "closureleak"
testWithoutMs "refarrayleak" testWithoutMs "refarrayleak"
test "stackrefleak" test "stackrefleak"