Merge branch 'gc-fixes' of https://github.com/rbehrends/Nim into rbehrends-gc-fixes
This commit is contained in:
commit
967c20743a
4 changed files with 83 additions and 45 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue