diff options
-rw-r--r-- | lib/system/gc.nim | 114 | ||||
-rw-r--r-- | lib/system/gc2.nim | 66 | ||||
-rw-r--r-- | lib/system/gc_common.nim | 279 | ||||
-rw-r--r-- | lib/system/gc_ms.nim | 30 |
4 files changed, 214 insertions, 275 deletions
diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 515aa9851..551dae459 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -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() = diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim index ce2bfc2ae..083c06fe3 100644 --- a/lib/system/gc2.nim +++ b/lib/system/gc2.nim @@ -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 = 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 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() diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index c5714eef6..70fd3412f 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -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 + + 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 - var s = stack - result = 1 - while s.next != nil: - inc(result) - s = s.next +proc stackSize(stack: ptr GcStack): int {.noinline.} = + when defined(nimCoroutines): + var pos = stack.pos + else: + var pos {.volatile.}: pointer + pos = addr(pos) -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) + if pos != nil: + when defined(stackIncreases): + result = cast[ByteAddress](pos) -% cast[ByteAddress](stack.bottom) else: - result = 0 + 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 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: diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index f927575dd..5896af88e 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -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() |