first version of the debug GC; doesn't work yet
This commit is contained in:
parent
7a2fad1e35
commit
1a792d46d0
5 changed files with 136 additions and 39 deletions
|
|
@ -55,6 +55,10 @@ proc overwriteFiles*() =
|
||||||
except EIO:
|
except EIO:
|
||||||
rawMessage(errCannotOpenFile, newFile)
|
rawMessage(errCannotOpenFile, newFile)
|
||||||
|
|
||||||
|
proc `=~`(s: string, a: openArray[string]): bool =
|
||||||
|
for x in a:
|
||||||
|
if s.startsWith(x): return true
|
||||||
|
|
||||||
proc beautifyName(s: string, k: TSymKind): string =
|
proc beautifyName(s: string, k: TSymKind): string =
|
||||||
result = newStringOfCap(s.len)
|
result = newStringOfCap(s.len)
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
@ -64,7 +68,13 @@ proc beautifyName(s: string, k: TSymKind): string =
|
||||||
when removeTP:
|
when removeTP:
|
||||||
if s[0] == 'T' and s[1] in {'A'..'Z'}:
|
if s[0] == 'T' and s[1] in {'A'..'Z'}:
|
||||||
i = 1
|
i = 1
|
||||||
result.add toUpper(s[i])
|
if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
|
||||||
|
"char", "byte", "bool", "openArray", "seq", "array", "void",
|
||||||
|
"pointer", "float", "csize", "cdouble", "cchar", "cschar",
|
||||||
|
"cshort", "cu"]:
|
||||||
|
result.add s[i]
|
||||||
|
else:
|
||||||
|
result.add toUpper(s[i])
|
||||||
of skConst, skEnumField:
|
of skConst, skEnumField:
|
||||||
# for 'const' we keep how it's spelt; either upper case or lower case:
|
# for 'const' we keep how it's spelt; either upper case or lower case:
|
||||||
result.add s[0]
|
result.add s[0]
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,11 @@
|
||||||
## of sockets. Sockets are buffered by default meaning that data will be
|
## of sockets. Sockets are buffered by default meaning that data will be
|
||||||
## received in ``BufferSize`` (4000) sized chunks, buffering
|
## received in ``BufferSize`` (4000) sized chunks, buffering
|
||||||
## behaviour can be disabled by setting the ``buffered`` parameter when calling
|
## behaviour can be disabled by setting the ``buffered`` parameter when calling
|
||||||
## the ``socket`` function to `False`. Be aware that some functions may not yet
|
## the ``socket`` function to `false`. Be aware that some functions may not yet
|
||||||
## support buffered sockets (mainly the recvFrom function).
|
## support buffered sockets (mainly the recvFrom function).
|
||||||
##
|
##
|
||||||
## Most procedures raise EOS on error, but some may return ``-1`` or a boolean
|
## Most procedures raise EOS on error, but some may return ``-1`` or a boolean
|
||||||
## ``False``.
|
## ``false``.
|
||||||
##
|
##
|
||||||
## SSL is supported through the OpenSSL library. This support can be activated
|
## SSL is supported through the OpenSSL library. This support can be activated
|
||||||
## by compiling with the ``-d:ssl`` switch. When an SSL socket is used it will
|
## by compiling with the ``-d:ssl`` switch. When an SSL socket is used it will
|
||||||
|
|
|
||||||
|
|
@ -77,17 +77,6 @@ type
|
||||||
|
|
||||||
TNumber* = TInteger|TReal
|
TNumber* = TInteger|TReal
|
||||||
## type class matching all number types
|
## type class matching all number types
|
||||||
|
|
||||||
type
|
|
||||||
## helper types for writing implicitly generic procs
|
|
||||||
T1* = expr
|
|
||||||
T2* = expr
|
|
||||||
T3* = expr
|
|
||||||
T4* = expr
|
|
||||||
T5* = expr
|
|
||||||
type1* = typedesc
|
|
||||||
type2* = typedesc
|
|
||||||
type3* = typedesc
|
|
||||||
|
|
||||||
proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.}
|
proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.}
|
||||||
## Special compile-time procedure that checks whether `x` is
|
## Special compile-time procedure that checks whether `x` is
|
||||||
|
|
@ -2509,7 +2498,7 @@ proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.}
|
||||||
## converts the AST of `x` into a string representation. This is very useful
|
## converts the AST of `x` into a string representation. This is very useful
|
||||||
## for debugging.
|
## for debugging.
|
||||||
|
|
||||||
proc InstantiationInfo*(index = -1, fullPaths = false): tuple[
|
proc instantiationInfo*(index = -1, fullPaths = false): tuple[
|
||||||
filename: string, line: int] {. magic: "InstantiationInfo", noSideEffect.}
|
filename: string, line: int] {. magic: "InstantiationInfo", noSideEffect.}
|
||||||
## provides access to the compiler's instantiation stack line information.
|
## provides access to the compiler's instantiation stack line information.
|
||||||
##
|
##
|
||||||
|
|
@ -2540,7 +2529,7 @@ proc InstantiationInfo*(index = -1, fullPaths = false): tuple[
|
||||||
## testException(EInvalidIndex, tester(1))
|
## testException(EInvalidIndex, tester(1))
|
||||||
## # --> Test failure at example.nim:20 with 'tester(1)'
|
## # --> Test failure at example.nim:20 with 'tester(1)'
|
||||||
|
|
||||||
template CurrentSourcePath*: string = InstantiationInfo(-1, true).filename
|
template currentSourcePath*: string = instantiationInfo(-1, true).filename
|
||||||
## returns the full file-system path of the current source
|
## returns the full file-system path of the current source
|
||||||
|
|
||||||
proc raiseAssert*(msg: string) {.noinline.} =
|
proc raiseAssert*(msg: string) {.noinline.} =
|
||||||
|
|
@ -2560,7 +2549,7 @@ template assert*(cond: bool, msg = "") =
|
||||||
## raises an ``EAssertionFailure`` exception. However, the compiler may
|
## raises an ``EAssertionFailure`` exception. However, the compiler may
|
||||||
## not generate any code at all for ``assert`` if it is advised to do so.
|
## not generate any code at all for ``assert`` if it is advised to do so.
|
||||||
## Use ``assert`` for debugging purposes only.
|
## Use ``assert`` for debugging purposes only.
|
||||||
bind InstantiationInfo, hiddenRaiseAssert
|
bind instantiationInfo, hiddenRaiseAssert
|
||||||
when compileOption("assertions"):
|
when compileOption("assertions"):
|
||||||
{.line.}:
|
{.line.}:
|
||||||
if not cond:
|
if not cond:
|
||||||
|
|
@ -2569,8 +2558,8 @@ template assert*(cond: bool, msg = "") =
|
||||||
template doAssert*(cond: bool, msg = "") =
|
template doAssert*(cond: bool, msg = "") =
|
||||||
## same as `assert` but is always turned on and not affected by the
|
## same as `assert` but is always turned on and not affected by the
|
||||||
## ``--assertions`` command line switch.
|
## ``--assertions`` command line switch.
|
||||||
bind InstantiationInfo
|
bind instantiationInfo
|
||||||
{.line: InstantiationInfo().}:
|
{.line: instantiationInfo().}:
|
||||||
if not cond:
|
if not cond:
|
||||||
raiseAssert(astToStr(cond) & ' ' & msg)
|
raiseAssert(astToStr(cond) & ' ' & msg)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,10 @@ const
|
||||||
# reaches this threshold
|
# reaches this threshold
|
||||||
# this seems to be a good value
|
# this seems to be a good value
|
||||||
withRealTime = defined(useRealtimeGC)
|
withRealTime = defined(useRealtimeGC)
|
||||||
|
useMarkForDebug = defined(gcGenerational)
|
||||||
|
useBackupGc = false # use a simple M&S GC to collect
|
||||||
|
# cycles instead of the complex
|
||||||
|
# algorithm
|
||||||
|
|
||||||
when withRealTime and not defined(getTicks):
|
when withRealTime and not defined(getTicks):
|
||||||
include "system/timers"
|
include "system/timers"
|
||||||
|
|
@ -43,7 +47,9 @@ const
|
||||||
type
|
type
|
||||||
TWalkOp = enum
|
TWalkOp = enum
|
||||||
waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
|
waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
|
||||||
waCollectWhite
|
waCollectWhite,
|
||||||
|
waMarkGlobal, # part of the backup/debug mark&sweep
|
||||||
|
waMarkPrecise, # part of the backup/debug mark&sweep
|
||||||
|
|
||||||
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall.}
|
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall.}
|
||||||
# A ref type can have a finalizer that is called before the object's
|
# A ref type can have a finalizer that is called before the object's
|
||||||
|
|
@ -71,6 +77,8 @@ type
|
||||||
maxPause: TNanos # max allowed pause in nanoseconds; active if > 0
|
maxPause: TNanos # max allowed pause in nanoseconds; active if > 0
|
||||||
region: TMemRegion # garbage collected region
|
region: TMemRegion # garbage collected region
|
||||||
stat: TGcStat
|
stat: TGcStat
|
||||||
|
when useMarkForDebug or useBackupGc:
|
||||||
|
marked: TCellSet
|
||||||
|
|
||||||
var
|
var
|
||||||
gch {.rtlThreadVar.}: TGcHeap
|
gch {.rtlThreadVar.}: TGcHeap
|
||||||
|
|
@ -80,7 +88,7 @@ when not defined(useNimRtl):
|
||||||
|
|
||||||
template acquire(gch: TGcHeap) =
|
template acquire(gch: TGcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
AcquireSys(HeapLock)
|
acquireSys(HeapLock)
|
||||||
|
|
||||||
template release(gch: TGcHeap) =
|
template release(gch: TGcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
|
|
@ -128,7 +136,7 @@ template setColor(c, col) =
|
||||||
else:
|
else:
|
||||||
c.refcount = c.refCount and not colorMask or col
|
c.refcount = c.refCount and not colorMask or col
|
||||||
|
|
||||||
proc writeCell(msg: CString, c: PCell) =
|
proc writeCell(msg: cstring, c: PCell) =
|
||||||
var kind = -1
|
var kind = -1
|
||||||
if c.typ != nil: kind = ord(c.typ.kind)
|
if c.typ != nil: kind = ord(c.typ.kind)
|
||||||
when leakDetector:
|
when leakDetector:
|
||||||
|
|
@ -159,6 +167,8 @@ else:
|
||||||
template `++`(x: expr): stmt = Inc(x, rcIncrement)
|
template `++`(x: expr): stmt = Inc(x, rcIncrement)
|
||||||
|
|
||||||
proc prepareDealloc(cell: PCell) =
|
proc prepareDealloc(cell: PCell) =
|
||||||
|
when useMarkForDebug:
|
||||||
|
gcAssert(cell notin gch.marked, "Cell still alive!")
|
||||||
if cell.typ.finalizer != nil:
|
if cell.typ.finalizer != nil:
|
||||||
# the finalizer could invoke something that
|
# the finalizer could invoke something that
|
||||||
# allocates memory; this could trigger a garbage
|
# allocates memory; this could trigger a garbage
|
||||||
|
|
@ -172,21 +182,21 @@ proc prepareDealloc(cell: PCell) =
|
||||||
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
|
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
|
||||||
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
AcquireSys(HeapLock)
|
acquireSys(HeapLock)
|
||||||
when cycleGC:
|
when cycleGC:
|
||||||
if c.color != rcPurple:
|
if c.color != rcPurple:
|
||||||
c.setColor(rcPurple)
|
c.setColor(rcPurple)
|
||||||
incl(gch.cycleRoots, c)
|
incl(gch.cycleRoots, c)
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
ReleaseSys(HeapLock)
|
releaseSys(HeapLock)
|
||||||
|
|
||||||
proc rtlAddZCT(c: PCell) {.rtl, inl.} =
|
proc rtlAddZCT(c: PCell) {.rtl, inl.} =
|
||||||
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
AcquireSys(HeapLock)
|
acquireSys(HeapLock)
|
||||||
addZCT(gch.zct, c)
|
addZCT(gch.zct, c)
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
ReleaseSys(HeapLock)
|
releaseSys(HeapLock)
|
||||||
|
|
||||||
proc decRef(c: PCell) {.inline.} =
|
proc decRef(c: PCell) {.inline.} =
|
||||||
gcAssert(isAllocatedPtr(gch.region, c), "decRef: interiorPtr")
|
gcAssert(isAllocatedPtr(gch.region, c), "decRef: interiorPtr")
|
||||||
|
|
@ -249,7 +259,7 @@ proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerProc.} =
|
||||||
# unsureAsgnRef updates the reference counters only if dest is not on the
|
# unsureAsgnRef updates the reference counters only if dest is not on the
|
||||||
# stack. It is used by the code generator if it cannot decide wether a
|
# stack. It is used by the code generator if it cannot decide wether a
|
||||||
# reference is in the stack or not (this can happen for var parameters).
|
# reference is in the stack or not (this can happen for var parameters).
|
||||||
if not IsOnStack(dest):
|
if not isOnStack(dest):
|
||||||
if src != nil: incRef(usrToCell(src))
|
if src != nil: incRef(usrToCell(src))
|
||||||
# XXX finally use assembler for the stack checking instead!
|
# XXX finally use assembler for the stack checking instead!
|
||||||
# the test for '!= nil' is correct, but I got tired of the segfaults
|
# the test for '!= nil' is correct, but I got tired of the segfaults
|
||||||
|
|
@ -277,6 +287,27 @@ proc initGC() =
|
||||||
init(gch.tempStack)
|
init(gch.tempStack)
|
||||||
init(gch.cycleRoots)
|
init(gch.cycleRoots)
|
||||||
init(gch.decStack)
|
init(gch.decStack)
|
||||||
|
when useMarkForDebug or useBackupGc:
|
||||||
|
init(gch.marked)
|
||||||
|
|
||||||
|
when useMarkForDebug or useBackupGc:
|
||||||
|
type
|
||||||
|
TGlobalMarkerProc = proc () {.nimcall.}
|
||||||
|
var
|
||||||
|
globalMarkersLen: int
|
||||||
|
globalMarkers: array[0.. 7_000, TGlobalMarkerProc]
|
||||||
|
|
||||||
|
proc nimRegisterGlobalMarker(markerProc: TGlobalMarkerProc) {.compilerProc.} =
|
||||||
|
if globalMarkersLen <= high(globalMarkers):
|
||||||
|
globalMarkers[globalMarkersLen] = markerProc
|
||||||
|
inc globalMarkersLen
|
||||||
|
else:
|
||||||
|
echo "[GC] cannot register global variable; too many global variables"
|
||||||
|
quit 1
|
||||||
|
|
||||||
|
proc cellsetReset(s: var TCellSet) =
|
||||||
|
deinit(s)
|
||||||
|
init(s)
|
||||||
|
|
||||||
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
|
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
|
||||||
var d = cast[TAddress](dest)
|
var d = cast[TAddress](dest)
|
||||||
|
|
@ -534,7 +565,7 @@ proc collectWhite(s: PCell) =
|
||||||
forAllChildren(s, waCollectWhite)
|
forAllChildren(s, waCollectWhite)
|
||||||
freeCyclicCell(gch, s)
|
freeCyclicCell(gch, s)
|
||||||
|
|
||||||
proc MarkRoots(gch: var TGcHeap) =
|
proc markRoots(gch: var TGcHeap) =
|
||||||
var tabSize = 0
|
var tabSize = 0
|
||||||
for s in elements(gch.cycleRoots):
|
for s in elements(gch.cycleRoots):
|
||||||
#writeCell("markRoot", s)
|
#writeCell("markRoot", s)
|
||||||
|
|
@ -548,6 +579,38 @@ proc MarkRoots(gch: var TGcHeap) =
|
||||||
freeCyclicCell(gch, s)
|
freeCyclicCell(gch, s)
|
||||||
gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, tabSize)
|
gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, tabSize)
|
||||||
|
|
||||||
|
when useBackupGc:
|
||||||
|
proc sweep(gch: var TGcHeap) =
|
||||||
|
for x in allObjects(gch.region):
|
||||||
|
if isCell(x):
|
||||||
|
# cast to PCell is correct here:
|
||||||
|
var c = cast[PCell](x)
|
||||||
|
if c notin gch.marked: freeCyclicCell(gch, c)
|
||||||
|
|
||||||
|
when useMarkForDebug or useBackupGc:
|
||||||
|
proc markS(gch: var TGcHeap, c: PCell) =
|
||||||
|
incl(gch.marked, c)
|
||||||
|
gcAssert gch.tempStack.len == 0, "stack not empty!"
|
||||||
|
forAllChildren(c, waMarkPrecise)
|
||||||
|
while gch.tempStack.len > 0:
|
||||||
|
dec gch.tempStack.len
|
||||||
|
var d = gch.tempStack.d[gch.tempStack.len]
|
||||||
|
if not containsOrIncl(gch.marked, d):
|
||||||
|
forAllChildren(d, waMarkPrecise)
|
||||||
|
|
||||||
|
proc markGlobals(gch: var TGcHeap) =
|
||||||
|
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
|
||||||
|
|
||||||
|
proc stackMarkS(gch: var TGcHeap, p: pointer) {.inline.} =
|
||||||
|
# the addresses are not as cells on the stack, so turn them to cells:
|
||||||
|
var cell = usrToCell(p)
|
||||||
|
var c = cast[TAddress](cell)
|
||||||
|
if c >% PageSize:
|
||||||
|
# fast check: does it look like a cell?
|
||||||
|
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
|
||||||
|
if objStart != nil:
|
||||||
|
markS(gch, objStart)
|
||||||
|
|
||||||
proc doOperation(p: pointer, op: TWalkOp) =
|
proc doOperation(p: pointer, op: TWalkOp) =
|
||||||
if p == nil: return
|
if p == nil: return
|
||||||
var c: PCell = usrToCell(p)
|
var c: PCell = usrToCell(p)
|
||||||
|
|
@ -580,12 +643,26 @@ proc doOperation(p: pointer, op: TWalkOp) =
|
||||||
if c.color != rcBlack:
|
if c.color != rcBlack:
|
||||||
scanBlack(c)
|
scanBlack(c)
|
||||||
of waCollectWhite: collectWhite(c)
|
of waCollectWhite: collectWhite(c)
|
||||||
|
of waMarkGlobal:
|
||||||
|
when useMarkForDebug or useBackupGc:
|
||||||
|
when hasThreadSupport:
|
||||||
|
# could point to a cell which we don't own and don't want to touch/trace
|
||||||
|
if isAllocatedPtr(gch.region, c):
|
||||||
|
markS(gch, c)
|
||||||
|
else:
|
||||||
|
markS(gch, c)
|
||||||
|
of waMarkPrecise:
|
||||||
|
when useMarkForDebug or useBackupGc:
|
||||||
|
add(gch.tempStack, c)
|
||||||
|
|
||||||
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
|
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
|
||||||
doOperation(d, TWalkOp(op))
|
doOperation(d, TWalkOp(op))
|
||||||
|
|
||||||
proc CollectZCT(gch: var TGcHeap): bool
|
proc CollectZCT(gch: var TGcHeap): bool
|
||||||
|
|
||||||
|
when useMarkForDebug or useBackupGc:
|
||||||
|
proc markStackAndRegistersForSweep(gch: var TGcHeap) {.noinline, cdecl.}
|
||||||
|
|
||||||
proc collectRoots(gch: var TGcHeap) =
|
proc collectRoots(gch: var TGcHeap) =
|
||||||
for s in elements(gch.cycleRoots):
|
for s in elements(gch.cycleRoots):
|
||||||
excl(gch.cycleRoots, s)
|
excl(gch.cycleRoots, s)
|
||||||
|
|
@ -594,13 +671,18 @@ proc collectRoots(gch: var TGcHeap) =
|
||||||
proc collectCycles(gch: var TGcHeap) =
|
proc collectCycles(gch: var TGcHeap) =
|
||||||
# ensure the ZCT 'color' is not used:
|
# ensure the ZCT 'color' is not used:
|
||||||
while gch.zct.len > 0: discard collectZCT(gch)
|
while gch.zct.len > 0: discard collectZCT(gch)
|
||||||
markRoots(gch)
|
when useBackupGc:
|
||||||
# scanRoots:
|
cellsetReset(gch.marked)
|
||||||
for s in elements(gch.cycleRoots): scan(s)
|
markStackAndRegistersForSweep(gch)
|
||||||
collectRoots(gch)
|
markGlobals(gch)
|
||||||
|
sweep(gch)
|
||||||
|
else:
|
||||||
|
markRoots(gch)
|
||||||
|
# scanRoots:
|
||||||
|
for s in elements(gch.cycleRoots): scan(s)
|
||||||
|
collectRoots(gch)
|
||||||
|
|
||||||
Deinit(gch.cycleRoots)
|
cellsetReset(gch.cycleRoots)
|
||||||
Init(gch.cycleRoots)
|
|
||||||
# alive cycles need to be kept in 'cycleRoots' if they are referenced
|
# alive cycles need to be kept in 'cycleRoots' if they are referenced
|
||||||
# from the stack; otherwise the write barrier will add the cycle root again
|
# from the stack; otherwise the write barrier will add the cycle root again
|
||||||
# anyway:
|
# anyway:
|
||||||
|
|
@ -695,7 +777,7 @@ when defined(sparc): # For SPARC architecture.
|
||||||
var x = cast[TAddress](p)
|
var x = cast[TAddress](p)
|
||||||
result = a <=% x and x <=% b
|
result = a <=% x and x <=% b
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
|
||||||
when defined(sparcv9):
|
when defined(sparcv9):
|
||||||
asm """"flushw \n" """
|
asm """"flushw \n" """
|
||||||
else:
|
else:
|
||||||
|
|
@ -731,7 +813,7 @@ elif stackIncreases:
|
||||||
# a little hack to get the size of a TJmpBuf in the generated C code
|
# a little hack to get the size of a TJmpBuf in the generated C code
|
||||||
# in a platform independant way
|
# in a platform independant way
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
|
||||||
var registers: C_JmpBuf
|
var registers: C_JmpBuf
|
||||||
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
|
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
|
||||||
var max = cast[TAddress](gch.stackBottom)
|
var max = cast[TAddress](gch.stackBottom)
|
||||||
|
|
@ -754,7 +836,7 @@ else:
|
||||||
var x = cast[TAddress](p)
|
var x = cast[TAddress](p)
|
||||||
result = a <=% x and x <=% b
|
result = a <=% x and x <=% b
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
|
||||||
# We use a jmp_buf buffer that is in the C stack.
|
# We use a jmp_buf buffer that is in the C stack.
|
||||||
# Used to traverse the stack and registers assuming
|
# Used to traverse the stack and registers assuming
|
||||||
# that 'setjmp' will save registers in the C stack.
|
# that 'setjmp' will save registers in the C stack.
|
||||||
|
|
@ -778,12 +860,19 @@ else:
|
||||||
while sp <=% max:
|
while sp <=% max:
|
||||||
gcMark(gch, cast[ppointer](sp)[])
|
gcMark(gch, cast[ppointer](sp)[])
|
||||||
sp = sp +% sizeof(pointer)
|
sp = sp +% sizeof(pointer)
|
||||||
|
|
||||||
|
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
||||||
|
forEachStackSlot(gch, gcMark)
|
||||||
|
|
||||||
|
when useMarkForDebug or useBackupGc:
|
||||||
|
proc markStackAndRegistersForSweep(gch: var TGcHeap) =
|
||||||
|
forEachStackSlot(gch, stackMarkS)
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# end of non-portable code
|
# end of non-portable code
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
proc CollectZCT(gch: var TGcHeap): bool =
|
proc collectZCT(gch: var TGcHeap): bool =
|
||||||
# Note: Freeing may add child objects to the ZCT! So essentially we do
|
# Note: Freeing may add child objects to the ZCT! So essentially we do
|
||||||
# deep freeing, which is bad for incremental operation. In order to
|
# deep freeing, which is bad for incremental operation. In order to
|
||||||
# avoid a deep stack, we move objects to keep the ZCT small.
|
# avoid a deep stack, we move objects to keep the ZCT small.
|
||||||
|
|
@ -880,10 +969,19 @@ proc collectCTBody(gch: var TGcHeap) =
|
||||||
if gch.maxPause > 0 and duration > gch.maxPause:
|
if gch.maxPause > 0 and duration > gch.maxPause:
|
||||||
c_fprintf(c_stdout, "[GC] missed deadline: %ld\n", duration)
|
c_fprintf(c_stdout, "[GC] missed deadline: %ld\n", duration)
|
||||||
|
|
||||||
|
when useMarkForDebug or useBackupGc:
|
||||||
|
proc markForDebug(gch: var TGcHeap) =
|
||||||
|
markStackAndRegistersForSweep(gch)
|
||||||
|
markGlobals(gch)
|
||||||
|
|
||||||
proc collectCT(gch: var TGcHeap) =
|
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 alwaysGC) and
|
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
|
||||||
gch.recGcLock == 0:
|
gch.recGcLock == 0:
|
||||||
|
when useMarkForDebug:
|
||||||
|
prepareForInteriorPointerChecking(gch.region)
|
||||||
|
cellsetReset(gch.marked)
|
||||||
|
markForDebug(gch)
|
||||||
collectCTBody(gch)
|
collectCTBody(gch)
|
||||||
|
|
||||||
when withRealtime:
|
when withRealtime:
|
||||||
|
|
|
||||||
|
|
@ -313,7 +313,7 @@ else:
|
||||||
# XXX use 'compileOption' here
|
# XXX use 'compileOption' here
|
||||||
include "system/gc_ms"
|
include "system/gc_ms"
|
||||||
elif defined(gcGenerational):
|
elif defined(gcGenerational):
|
||||||
include "system/gc_genms"
|
include "system/gc"
|
||||||
else:
|
else:
|
||||||
include "system/gc"
|
include "system/gc"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue