Cleanup of gc code

Cleanups
This commit is contained in:
Rokas Kupstys
2017-02-18 17:05:29 +02:00
parent d69b701dde
commit 9f8863169a
4 changed files with 214 additions and 275 deletions

View File

@@ -64,21 +64,23 @@ type
maxPause: int64 # max measured GC pause in nanoseconds
GcStack {.final, pure.} = object
prev: ptr GcStack
next: ptr GcStack
when defined(nimCoroutines):
prev: ptr GcStack
next: ptr GcStack
maxStackSize: int # Used to track statistics because we can not use
# GcStat.maxStackSize when multiple stacks exist.
bottom: pointer
when withRealTime or defined(nimCoroutines):
pos: pointer # Used with `withRealTime` only for code clarity, see GC_Step().
when withRealTime:
bottomSaved: pointer
pos: pointer
maxStackSize: int
GcHeap {.final, pure.} = object # this contains the zero count and
# non-zero count table
# non-zero count table
stack: GcStack
when defined(nimCoroutines):
stack: GcStack
activeStack: ptr GcStack
else:
stackBottom: pointer
activeStack: ptr GcStack # current executing coroutine stack.
cycleThreshold: int
when useCellIds:
idGenerator: int
@@ -122,53 +124,6 @@ template gcAssert(cond: bool, msg: string) =
#echo x[]
quit 1
when defined(nimCoroutines):
iterator items(first: var GcStack): ptr GcStack =
var item = addr(first)
while true:
yield item
item = item.next
if item == addr(first):
break
proc append(first: var GcStack, stack: ptr GcStack) =
## Append stack to the ring of stacks.
first.prev.next = stack
stack.prev = first.prev
first.prev = stack
stack.next = addr(first)
proc append(first: var GcStack): ptr GcStack =
## Allocate new GcStack object, append it to the ring of stacks and return it.
result = cast[ptr GcStack](alloc0(sizeof(GcStack)))
first.append(result)
proc remove(first: var GcStack, stack: ptr GcStack) =
## Remove stack from ring of stacks.
gcAssert(addr(first) != stack, "Main application stack can not be removed")
if addr(first) == stack or stack == nil:
return
stack.prev.next = stack.next
stack.next.prev = stack.prev
dealloc(stack)
proc remove(stack: ptr GcStack) =
gch.stack.remove(stack)
proc find(first: var GcStack, bottom: pointer): ptr GcStack =
## Find stack struct based on bottom pointer. If `bottom` is nil then main
## thread stack is is returned.
if bottom == nil:
return addr(gch.stack)
for stack in first.items():
if stack.bottom == bottom:
return stack
proc len(stack: var GcStack): int =
for _ in stack.items():
result = result + 1
proc addZCT(s: var CellSeq, c: PCell) {.noinline.} =
if (c.refcount and ZctFlag) == 0:
c.refcount = c.refcount or ZctFlag
@@ -931,40 +886,25 @@ when withRealTime:
collectCTBody(gch)
release(gch)
when defined(nimCoroutines):
proc GC_step*(us: int, strongAdvice = false, stackSize = -1) {.noinline.} =
if stackSize >= 0:
var stackTop {.volatile.}: pointer
gch.activeStack.pos = addr(stackTop)
for stack in gch.stack.items():
stack.bottomSaved = stack.bottom
when stackIncreases:
stack.bottom = cast[pointer](
cast[ByteAddress](stack.pos) - sizeof(pointer) * 6 - stackSize)
else:
stack.bottom = cast[pointer](
cast[ByteAddress](stack.pos) + sizeof(pointer) * 6 + stackSize)
GC_step(gch, us, strongAdvice)
if stackSize >= 0:
for stack in gch.stack.items():
stack.bottom = stack.bottomSaved
else:
proc GC_step*(us: int, strongAdvice = false, stackSize = -1) {.noinline.} =
proc GC_step*(us: int, strongAdvice = false, stackSize = -1) {.noinline.} =
if stackSize >= 0:
var stackTop {.volatile.}: pointer
let prevStackBottom = gch.stackBottom
if stackSize >= 0:
stackTop = addr(stackTop)
gch.getActiveStack().pos = addr(stackTop)
for stack in gch.stack.items():
stack.bottomSaved = stack.bottom
when stackIncreases:
gch.stackBottom = cast[pointer](
cast[ByteAddress](stackTop) - sizeof(pointer) * 6 - stackSize)
stack.bottom = cast[pointer](
cast[ByteAddress](stack.pos) - sizeof(pointer) * 6 - stackSize)
else:
gch.stackBottom = cast[pointer](
cast[ByteAddress](stackTop) + sizeof(pointer) * 6 + stackSize)
GC_step(gch, us, strongAdvice)
gch.stackBottom = prevStackBottom
stack.bottom = cast[pointer](
cast[ByteAddress](stack.pos) + sizeof(pointer) * 6 + stackSize)
GC_step(gch, us, strongAdvice)
if stackSize >= 0:
for stack in gch.stack.items():
stack.bottom = stack.bottomSaved
when not defined(useNimRtl):
proc GC_disable() =

View File

@@ -15,9 +15,6 @@
# XXX Ensure by smart color masking that the object is not in the ZCT.
when defined(nimCoroutines):
import arch
{.push profiler:off.}
const
@@ -72,19 +69,26 @@ type
maxStackCells: int # max stack cells in ``decStack``
cycleTableSize: int # max entries in cycle table
maxPause: int64 # max measured GC pause in nanoseconds
GcStack {.final, pure.} = object
when nimCoroutines:
prev: ptr GcStack
next: ptr GcStack
maxStackSize: int # Used to track statistics because we can not use
# GcStat.maxStackSize when multiple stacks exist.
bottom: pointer
GcStack = object
prev: ptr GcStack
next: ptr GcStack
starts: pointer
pos: pointer
maxStackSize: int
when withRealTime or nimCoroutines:
pos: pointer # Used with `withRealTime` only for code clarity, see GC_Step().
when withRealTime:
bottomSaved: pointer
GcHeap = object # this contains the zero count and
# non-zero count table
black, red: int # either 0 or 1.
stack: ptr GcStack
stackBottom: pointer
stack: GcStack
when nimCoroutines:
activeStack: ptr GcStack # current executing coroutine stack.
phase: Phase
cycleThreshold: int
when useCellIds:
@@ -913,7 +917,7 @@ proc collectCTBody(gch: var GcHeap) =
let t0 = getticks()
sysAssert(allocInv(gch.region), "collectCT: begin")
when not defined(nimCoroutines):
when not nimCoroutines:
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
sysAssert(gch.decStack.len == 0, "collectCT")
prepareForInteriorPointerChecking(gch.region)
@@ -938,16 +942,16 @@ proc collectCTBody(gch: var GcHeap) =
if gch.maxPause > 0 and duration > gch.maxPause:
c_fprintf(stdout, "[GC] missed deadline: %ld\n", duration)
when defined(nimCoroutines):
when nimCoroutines:
proc currentStackSizes(): int =
for stack in items(gch.stack):
result = result + stackSize(stack.starts, stack.pos)
result = result + stack.stackSize()
proc collectCT(gch: var GcHeap) =
# stackMarkCosts prevents some pathological behaviour: Stack marking
# becomes more expensive with large stacks and large stacks mean that
# cells with RC=0 are more likely to be kept alive by the stack.
when defined(nimCoroutines):
when nimCoroutines:
let stackMarkCosts = max(currentStackSizes() div (16*sizeof(int)), ZctThreshold)
else:
let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold)
@@ -971,18 +975,24 @@ when withRealTime:
collectCTBody(gch)
proc GC_step*(us: int, strongAdvice = false, stackSize = -1) {.noinline.} =
var stackTop {.volatile.}: pointer
let prevStackBottom = gch.stackBottom
if stackSize >= 0:
stackTop = addr(stackTop)
when stackIncreases:
gch.stackBottom = cast[pointer](
cast[ByteAddress](stackTop) - sizeof(pointer) * 6 - stackSize)
else:
gch.stackBottom = cast[pointer](
cast[ByteAddress](stackTop) + sizeof(pointer) * 6 + stackSize)
var stackTop {.volatile.}: pointer
gch.getActiveStack().pos = addr(stackTop)
for stack in gch.stack.items():
stack.bottomSaved = stack.bottom
when stackIncreases:
stack.bottom = cast[pointer](
cast[ByteAddress](stack.pos) - sizeof(pointer) * 6 - stackSize)
else:
stack.bottom = cast[pointer](
cast[ByteAddress](stack.pos) + sizeof(pointer) * 6 + stackSize)
GC_step(gch, us, strongAdvice)
gch.stackBottom = prevStackBottom
if stackSize >= 0:
for stack in gch.stack.items():
stack.bottom = stack.bottomSaved
when not defined(useNimRtl):
proc GC_disable() =
@@ -1024,10 +1034,10 @@ when not defined(useNimRtl):
"[GC] zct capacity: " & $gch.zct.cap & "\n" &
"[GC] max cycle table size: " & $gch.stat.cycleTableSize & "\n" &
"[GC] max pause time [ms]: " & $(gch.stat.maxPause div 1000_000)
when defined(nimCoroutines):
when nimCoroutines:
result = result & "[GC] number of stacks: " & $gch.stack.len & "\n"
for stack in items(gch.stack):
result = result & "[GC] stack " & stack.starts.repr & "[GC] max stack size " & $stack.maxStackSize & "\n"
result = result & "[GC] stack " & stack.bottom.repr & "[GC] max stack size " & $stack.maxStackSize & "\n"
else:
result = result & "[GC] max stack size: " & $gch.stat.maxStackSize & "\n"
GC_enable()

View File

@@ -57,26 +57,77 @@ proc isNotForeign*(x: ForeignCell): bool =
## No deep copy has to be performed then.
x.owner == addr(gch)
proc len(stack: ptr GcStack): int =
if stack == nil:
return 0
when nimCoroutines:
iterator items(first: var GcStack): ptr GcStack =
var item = addr(first)
while true:
yield item
item = item.next
if item == addr(first):
break
var s = stack
result = 1
while s.next != nil:
inc(result)
s = s.next
proc append(first: var GcStack, stack: ptr GcStack) =
## Append stack to the ring of stacks.
first.prev.next = stack
stack.prev = first.prev
first.prev = stack
stack.next = addr(first)
proc append(first: var GcStack): ptr GcStack =
## Allocate new GcStack object, append it to the ring of stacks and return it.
result = cast[ptr GcStack](alloc0(sizeof(GcStack)))
first.append(result)
proc remove(first: var GcStack, stack: ptr GcStack) =
## Remove stack from ring of stacks.
gcAssert(addr(first) != stack, "Main application stack can not be removed")
if addr(first) == stack or stack == nil:
return
stack.prev.next = stack.next
stack.next.prev = stack.prev
dealloc(stack)
proc remove(stack: ptr GcStack) =
gch.stack.remove(stack)
proc find(first: var GcStack, bottom: pointer): ptr GcStack =
## Find stack struct based on bottom pointer. If `bottom` is nil then main
## thread stack is is returned.
if bottom == nil:
return addr(gch.stack)
for stack in first.items():
if stack.bottom == bottom:
return stack
proc len(stack: var GcStack): int =
for _ in stack.items():
result = result + 1
else:
# This iterator gets optimized out in forEachStackSlot().
iterator items(first: var GcStack): ptr GcStack = yield addr(first)
proc len(stack: var GcStack): int = 1
proc stackSize(stack: ptr GcStack): int {.noinline.} =
when defined(nimCoroutines):
var pos = stack.pos
else:
var pos {.volatile.}: pointer
pos = addr(pos)
if pos != nil:
when defined(stackIncreases):
result = cast[ByteAddress](pos) -% cast[ByteAddress](stack.bottom)
else:
result = cast[ByteAddress](stack.bottom) -% cast[ByteAddress](pos)
else:
result = 0
proc stackSize(): int {.noinline.} =
for stack in gch.stack.items():
result = result + stack.stackSize()
when defined(nimCoroutines):
proc stackSize(stack: ptr GcStack): int {.noinline.} =
if stack.pos != nil:
when defined(stackIncreases):
result = cast[ByteAddress](stack.pos) -% cast[ByteAddress](stack.bottom)
else:
result = cast[ByteAddress](stack.bottom) -% cast[ByteAddress](stack.pos)
else:
result = 0
proc setPosition(stack: ptr GcStack, position: pointer) =
stack.pos = position
stack.maxStackSize = max(stack.maxStackSize, stack.stackSize())
@@ -84,19 +135,18 @@ when defined(nimCoroutines):
proc setPosition(stack: var GcStack, position: pointer) =
setPosition(addr(stack), position)
proc stackSize(): int {.noinline.} =
for stack in gch.stack.items():
result = result + stack.stackSize()
else:
proc stackSize(): int {.noinline.} =
var stackTop {.volatile.}: pointer
result = abs(cast[int](addr(stackTop)) - cast[int](gch.stackBottom))
proc getActiveStack(gch: var GcHeap): ptr GcStack =
return gch.activeStack
iterator items(stack: ptr GcStack): ptr GcStack =
var s = stack
while not isNil(s):
yield s
s = s.next
proc isActiveStack(stack: ptr GcStack): bool =
return gch.activeStack == stack
else:
# Stack positions do not need to be tracked if coroutines are not used.
proc setPosition(stack: ptr GcStack, position: pointer) = discard
proc setPosition(stack: var GcStack, position: pointer) = discard
# There is just one stack - main stack of the thread. It is active always.
proc getActiveStack(gch: var GcHeap): ptr GcStack = addr(gch.stack)
proc isActiveStack(stack: ptr GcStack): bool = true
when declared(threadType):
proc setupForeignThreadGc*() {.gcsafe.} =
@@ -167,9 +217,9 @@ when defined(nimCoroutines):
gch.activeStack.setPosition(addr(sp))
when not defined(useNimRtl):
when defined(nimCoroutines):
proc setStackBottom(theStackBottom: pointer) =
# Initializes main stack of the thread.
proc setStackBottom(theStackBottom: pointer) =
# Initializes main stack of the thread.
when defined(nimCoroutines):
if gch.stack.next == nil:
# Main stack was not initialized yet
gch.stack.next = addr(gch.stack)
@@ -177,43 +227,39 @@ when not defined(useNimRtl):
gch.stack.bottom = theStackBottom
gch.stack.maxStackSize = 0
gch.activeStack = addr(gch.stack)
else:
var a = cast[ByteAddress](theStackBottom) # and not PageMask - PageSize*2
var b = cast[ByteAddress](gch.stack.bottom)
#c_fprintf(stdout, "old: %p new: %p;\n",gch.stackBottom,theStackBottom)
when stackIncreases:
gch.stack.bottom = cast[pointer](min(a, b))
else:
gch.stack.bottom = cast[pointer](max(a, b))
gch.stack.setPosition(theStackBottom)
else:
proc setStackBottom(theStackBottom: pointer) =
if gch.stack.bottom == nil:
# This branch will not be called when -d:nimCoroutines - it is fine,
# because same thing is done just above.
#c_fprintf(stdout, "stack bottom: %p;\n", theStackBottom)
# the first init must be the one that defines the stack bottom:
if gch.stackBottom == nil: gch.stackBottom = theStackBottom
gch.stack.bottom = theStackBottom
elif theStackBottom != gch.stack.bottom:
var a = cast[ByteAddress](theStackBottom) # and not PageMask - PageSize*2
var b = cast[ByteAddress](gch.stack.bottom)
#c_fprintf(stdout, "old: %p new: %p;\n",gch.stack.bottom,theStackBottom)
when stackIncreases:
gch.stack.bottom = cast[pointer](min(a, b))
else:
var a = cast[ByteAddress](theStackBottom) # and not PageMask - PageSize*2
var b = cast[ByteAddress](gch.stackBottom)
#c_fprintf(stdout, "old: %p new: %p;\n",gch.stackBottom,theStackBottom)
when stackIncreases:
gch.stackBottom = cast[pointer](min(a, b))
else:
gch.stackBottom = cast[pointer](max(a, b))
gch.stack.bottom = cast[pointer](max(a, b))
gch.stack.setPosition(theStackBottom)
{.pop.}
proc isOnStack(p: pointer): bool =
var stackTop {.volatile.}: pointer
stackTop = addr(stackTop)
var a = cast[ByteAddress](gch.getActiveStack().bottom)
var b = cast[ByteAddress](stackTop)
when not stackIncreases:
swap(a, b)
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
when defined(sparc): # For SPARC architecture.
when defined(nimCoroutines):
{.error: "Nim coroutines are not supported on this platform."}
proc isOnStack(p: pointer): bool =
var stackTop {.volatile.}: pointer
stackTop = addr(stackTop)
var b = cast[ByteAddress](gch.stackBottom)
var a = cast[ByteAddress](stackTop)
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
template forEachStackSlot(gch, gcMark: untyped) {.dirty.} =
when defined(sparcv9):
asm """"flushw \n" """
@@ -221,7 +267,7 @@ when defined(sparc): # For SPARC architecture.
asm """"ta 0x3 ! ST_FLUSH_WINDOWS\n" """
var
max = gch.stackBottom
max = gch.stack.bottom
sp: PPointer
stackTop: array[0..1, pointer]
sp = addr(stackTop[0])
@@ -237,16 +283,6 @@ elif stackIncreases:
# ---------------------------------------------------------------------------
# Generic code for architectures where addresses increase as the stack grows.
# ---------------------------------------------------------------------------
when defined(nimCoroutines):
{.error: "Nim coroutines are not supported on this platform."}
proc isOnStack(p: pointer): bool =
var stackTop {.volatile.}: pointer
stackTop = addr(stackTop)
var a = cast[ByteAddress](gch.stackBottom)
var b = cast[ByteAddress](stackTop)
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
var
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
# a little hack to get the size of a JmpBuf in the generated C code
@@ -254,91 +290,42 @@ elif stackIncreases:
template forEachStackSlot(gch, gcMark: untyped) {.dirty.} =
var registers {.noinit.}: C_JmpBuf
# sp will traverse the JMP_BUF as well (jmp_buf size is added,
# otherwise sp would be below the registers structure).
var regAddr = addr(registers) +% jmpbufSize
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
var max = cast[ByteAddress](gch.stackBottom)
var sp = cast[ByteAddress](addr(registers)) +% jmpbufSize -% sizeof(pointer)
# sp will traverse the JMP_BUF as well (jmp_buf size is added,
# otherwise sp would be below the registers structure).
while sp >=% max:
gcMark(gch, cast[PPointer](sp)[])
sp = sp -% sizeof(pointer)
for stack in gch.stack.items():
var max = cast[ByteAddress](gch.stack.bottom)
var sp = cast[ByteAddress](addr(registers)) -% sizeof(pointer)
while sp >=% max:
gcMark(gch, cast[PPointer](sp)[])
sp = sp -% sizeof(pointer)
else:
# ---------------------------------------------------------------------------
# Generic code for architectures where addresses decrease as the stack grows.
# ---------------------------------------------------------------------------
when defined(nimCoroutines):
proc isOnStack(p: pointer): bool =
var stackTop {.volatile.}: pointer
stackTop = addr(stackTop)
var b = cast[ByteAddress](gch.activeStack.bottom)
var a = cast[ByteAddress](stackTop)
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
template forEachStackSlot(gch, gcMark: untyped) {.dirty.} =
# We use a jmp_buf buffer that is in the C stack.
# Used to traverse the stack and registers assuming
# that 'setjmp' will save registers in the C stack.
type PStackSlice = ptr array[0..7, pointer]
var registers {.noinit.}: C_JmpBuf
# Update position of stack gc is executing in.
gch.activeStack.setPosition(addr(registers))
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
for stack in gch.stack.items():
var max = cast[ByteAddress](stack.bottom)
var sp = cast[ByteAddress](addr(registers))
when defined(amd64):
if stack == gch.activeStack:
# words within the jmp_buf structure may not be properly aligned.
let regEnd = sp +% sizeof(registers)
while sp <% regEnd:
gcMark(gch, cast[PPointer](sp)[])
gcMark(gch, cast[PPointer](sp +% sizeof(pointer) div 2)[])
sp = sp +% sizeof(pointer)
# Make sure sp is word-aligned
sp = sp and not (sizeof(pointer) - 1)
# loop unrolled:
while sp <% max - 8*sizeof(pointer):
gcMark(gch, cast[PStackSlice](sp)[0])
gcMark(gch, cast[PStackSlice](sp)[1])
gcMark(gch, cast[PStackSlice](sp)[2])
gcMark(gch, cast[PStackSlice](sp)[3])
gcMark(gch, cast[PStackSlice](sp)[4])
gcMark(gch, cast[PStackSlice](sp)[5])
gcMark(gch, cast[PStackSlice](sp)[6])
gcMark(gch, cast[PStackSlice](sp)[7])
sp = sp +% sizeof(pointer)*8
# last few entries:
while sp <=% max:
gcMark(gch, cast[PPointer](sp)[])
sp = sp +% sizeof(pointer)
else:
proc isOnStack(p: pointer): bool =
var stackTop {.volatile.}: pointer
stackTop = addr(stackTop)
var b = cast[ByteAddress](gch.stackBottom)
var a = cast[ByteAddress](stackTop)
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
template forEachStackSlot(gch, gcMark: untyped) {.dirty.} =
# We use a jmp_buf buffer that is in the C stack.
# Used to traverse the stack and registers assuming
# that 'setjmp' will save registers in the C stack.
type PStackSlice = ptr array[0..7, pointer]
var registers {.noinit.}: C_JmpBuf
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
var max = cast[ByteAddress](gch.stackBottom)
template forEachStackSlot(gch, gcMark: untyped) {.dirty.} =
# We use a jmp_buf buffer that is in the C stack.
# Used to traverse the stack and registers assuming
# that 'setjmp' will save registers in the C stack.
type PStackSlice = ptr array[0..7, pointer]
var registers {.noinit.}: C_JmpBuf
# Update position of stack gc is executing in.
gch.getActiveStack().setPosition(addr(registers))
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
for stack in gch.stack.items():
var max = cast[ByteAddress](stack.bottom)
var sp = cast[ByteAddress](addr(registers))
when defined(amd64):
# words within the jmp_buf structure may not be properly aligned.
let regEnd = sp +% sizeof(registers)
while sp <% regEnd:
gcMark(gch, cast[PPointer](sp)[])
gcMark(gch, cast[PPointer](sp +% sizeof(pointer) div 2)[])
sp = sp +% sizeof(pointer)
if stack.isActiveStack():
# words within the jmp_buf structure may not be properly aligned.
let regEnd = sp +% sizeof(registers)
while sp <% regEnd:
gcMark(gch, cast[PPointer](sp)[])
gcMark(gch, cast[PPointer](sp +% sizeof(pointer) div 2)[])
sp = sp +% sizeof(pointer)
# Make sure sp is word-aligned
sp = sp and not (sizeof(pointer) - 1)
# loop unrolled:

View File

@@ -10,9 +10,6 @@
# A simple mark&sweep garbage collector for Nim. Define the
# symbol ``gcUseBitvectors`` to generate a variant of this GC.
when defined(nimCoroutines):
import arch
{.push profiler:off.}
const
@@ -51,17 +48,22 @@ type
maxStackSize: int # max stack size
freedObjects: int # max entries in cycle table
GcStack {.final.} = object
prev: ptr GcStack
next: ptr GcStack
starts: pointer
pos: pointer
maxStackSize: int
GcStack {.final, pure.} = object
when nimCoroutines:
prev: ptr GcStack
next: ptr GcStack
maxStackSize: int # Used to track statistics because we can not use
# GcStat.maxStackSize when multiple stacks exist.
bottom: pointer
when nimCoroutines:
pos: pointer
GcHeap = object # this contains the zero count and
# non-zero count table
stack: ptr GcStack
stackBottom: pointer
stack: GcStack
when nimCoroutines:
activeStack: ptr GcStack # current executing coroutine stack.
cycleThreshold: int
when useCellIds:
idGenerator: int
@@ -423,7 +425,7 @@ proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
forEachStackSlot(gch, gcMark)
proc collectCTBody(gch: var GcHeap) =
when not defined(nimCoroutines):
when not nimCoroutines:
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
prepareForInteriorPointerChecking(gch.region)
markStackAndRegisters(gch)
@@ -479,10 +481,10 @@ when not defined(useNimRtl):
"[GC] collections: " & $gch.stat.collections & "\n" &
"[GC] max threshold: " & $gch.stat.maxThreshold & "\n" &
"[GC] freed objects: " & $gch.stat.freedObjects & "\n"
when defined(nimCoroutines):
when nimCoroutines:
result = result & "[GC] number of stacks: " & $gch.stack.len & "\n"
for stack in items(gch.stack):
result = result & "[GC] stack " & stack.starts.repr & "[GC] max stack size " & $stack.maxStackSize & "\n"
result = result & "[GC] stack " & stack.bottom.repr & "[GC] max stack size " & $stack.maxStackSize & "\n"
else:
result = result & "[GC] max stack size: " & $gch.stat.maxStackSize & "\n"
GC_enable()