Reworked gc support for coroutines. Nim now bootstraps with -d:nimCoroutines

Added gc test to coro.nim
Lots of misc improvements and comments in coro.nim
This commit is contained in:
Rokas Kupstys 2017-02-13 19:42:47 +02:00
commit c3d1b732d6
3 changed files with 231 additions and 164 deletions

View file

@ -63,18 +63,18 @@ type
cycleTableSize: int # max entries in cycle table
maxPause: int64 # max measured GC pause in nanoseconds
GcStack {.final.} = object
GcStack {.final, pure.} = object
prev: ptr GcStack
next: ptr GcStack
starts: pointer
bottom: pointer
pos: pointer
maxStackSize: int
GcHeap {.final, pure.} = object # this contains the zero count and
# non-zero count table
when defined(nimCoroutines):
stack: ptr GcStack
stackActive: ptr GcStack
stack: GcStack
activeStack: ptr GcStack
else:
stackBottom: pointer
cycleThreshold: int
@ -120,6 +120,53 @@ 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
@ -823,7 +870,10 @@ proc collectCTBody(gch: var GcHeap) =
let t0 = getticks()
sysAssert(allocInv(gch.region), "collectCT: begin")
when not defined(nimCoroutines):
when defined(nimCoroutines):
for stack in gch.stack.items():
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stack.stackSize())
else:
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
sysAssert(gch.decStack.len == 0, "collectCT")
prepareForInteriorPointerChecking(gch.region)
@ -849,19 +899,11 @@ 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):
proc currentStackSizes(): int =
for stack in items(gch.stack):
result = result + stackSize(stack.starts, stack.pos)
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):
let stackMarkCosts = max(currentStackSizes() div (16*sizeof(int)), ZctThreshold)
else:
let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold)
let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold)
if (gch.zct.len >= stackMarkCosts or (cycleGC and
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
gch.recGcLock == 0:
@ -946,7 +988,7 @@ when not defined(useNimRtl):
when defined(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 " & cast[pointer](stack.maxStackSize).repr & "\n"
else:
result = result & "[GC] max stack size: " & $gch.stat.maxStackSize & "\n"
GC_enable()