Cleanup of gc code
Cleanups
This commit is contained in:
parent
d69b701dde
commit
9f8863169a
4 changed files with 214 additions and 275 deletions
|
|
@ -64,21 +64,23 @@ type
|
||||||
maxPause: int64 # max measured GC pause in nanoseconds
|
maxPause: int64 # max measured GC pause in nanoseconds
|
||||||
|
|
||||||
GcStack {.final, pure.} = object
|
GcStack {.final, pure.} = object
|
||||||
|
when defined(nimCoroutines):
|
||||||
prev: ptr GcStack
|
prev: ptr GcStack
|
||||||
next: ptr GcStack
|
next: ptr GcStack
|
||||||
|
maxStackSize: int # Used to track statistics because we can not use
|
||||||
|
# GcStat.maxStackSize when multiple stacks exist.
|
||||||
bottom: pointer
|
bottom: pointer
|
||||||
|
|
||||||
|
when withRealTime or defined(nimCoroutines):
|
||||||
|
pos: pointer # Used with `withRealTime` only for code clarity, see GC_Step().
|
||||||
when withRealTime:
|
when withRealTime:
|
||||||
bottomSaved: pointer
|
bottomSaved: pointer
|
||||||
pos: pointer
|
|
||||||
maxStackSize: int
|
|
||||||
|
|
||||||
GcHeap {.final, pure.} = object # this contains the zero count and
|
GcHeap {.final, pure.} = object # this contains the zero count and
|
||||||
# non-zero count table
|
# non-zero count table
|
||||||
when defined(nimCoroutines):
|
|
||||||
stack: GcStack
|
stack: GcStack
|
||||||
activeStack: ptr GcStack
|
when defined(nimCoroutines):
|
||||||
else:
|
activeStack: ptr GcStack # current executing coroutine stack.
|
||||||
stackBottom: pointer
|
|
||||||
cycleThreshold: int
|
cycleThreshold: int
|
||||||
when useCellIds:
|
when useCellIds:
|
||||||
idGenerator: int
|
idGenerator: int
|
||||||
|
|
@ -122,53 +124,6 @@ template gcAssert(cond: bool, msg: string) =
|
||||||
#echo x[]
|
#echo x[]
|
||||||
quit 1
|
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.} =
|
proc addZCT(s: var CellSeq, c: PCell) {.noinline.} =
|
||||||
if (c.refcount and ZctFlag) == 0:
|
if (c.refcount and ZctFlag) == 0:
|
||||||
c.refcount = c.refcount or ZctFlag
|
c.refcount = c.refcount or ZctFlag
|
||||||
|
|
@ -931,11 +886,10 @@ when withRealTime:
|
||||||
collectCTBody(gch)
|
collectCTBody(gch)
|
||||||
release(gch)
|
release(gch)
|
||||||
|
|
||||||
when defined(nimCoroutines):
|
|
||||||
proc GC_step*(us: int, strongAdvice = false, stackSize = -1) {.noinline.} =
|
proc GC_step*(us: int, strongAdvice = false, stackSize = -1) {.noinline.} =
|
||||||
if stackSize >= 0:
|
if stackSize >= 0:
|
||||||
var stackTop {.volatile.}: pointer
|
var stackTop {.volatile.}: pointer
|
||||||
gch.activeStack.pos = addr(stackTop)
|
gch.getActiveStack().pos = addr(stackTop)
|
||||||
|
|
||||||
for stack in gch.stack.items():
|
for stack in gch.stack.items():
|
||||||
stack.bottomSaved = stack.bottom
|
stack.bottomSaved = stack.bottom
|
||||||
|
|
@ -951,20 +905,6 @@ when withRealTime:
|
||||||
if stackSize >= 0:
|
if stackSize >= 0:
|
||||||
for stack in gch.stack.items():
|
for stack in gch.stack.items():
|
||||||
stack.bottom = stack.bottomSaved
|
stack.bottom = stack.bottomSaved
|
||||||
else:
|
|
||||||
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)
|
|
||||||
GC_step(gch, us, strongAdvice)
|
|
||||||
gch.stackBottom = prevStackBottom
|
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
proc GC_disable() =
|
proc GC_disable() =
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,6 @@
|
||||||
|
|
||||||
# XXX Ensure by smart color masking that the object is not in the ZCT.
|
# XXX Ensure by smart color masking that the object is not in the ZCT.
|
||||||
|
|
||||||
when defined(nimCoroutines):
|
|
||||||
import arch
|
|
||||||
|
|
||||||
{.push profiler:off.}
|
{.push profiler:off.}
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -73,18 +70,25 @@ type
|
||||||
cycleTableSize: int # max entries in cycle table
|
cycleTableSize: int # max entries in cycle table
|
||||||
maxPause: int64 # max measured GC pause in nanoseconds
|
maxPause: int64 # max measured GC pause in nanoseconds
|
||||||
|
|
||||||
GcStack = object
|
GcStack {.final, pure.} = object
|
||||||
|
when nimCoroutines:
|
||||||
prev: ptr GcStack
|
prev: ptr GcStack
|
||||||
next: ptr GcStack
|
next: ptr GcStack
|
||||||
starts: pointer
|
maxStackSize: int # Used to track statistics because we can not use
|
||||||
pos: pointer
|
# GcStat.maxStackSize when multiple stacks exist.
|
||||||
maxStackSize: int
|
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
|
GcHeap = object # this contains the zero count and
|
||||||
# non-zero count table
|
# non-zero count table
|
||||||
black, red: int # either 0 or 1.
|
black, red: int # either 0 or 1.
|
||||||
stack: ptr GcStack
|
stack: GcStack
|
||||||
stackBottom: pointer
|
when nimCoroutines:
|
||||||
|
activeStack: ptr GcStack # current executing coroutine stack.
|
||||||
phase: Phase
|
phase: Phase
|
||||||
cycleThreshold: int
|
cycleThreshold: int
|
||||||
when useCellIds:
|
when useCellIds:
|
||||||
|
|
@ -913,7 +917,7 @@ proc collectCTBody(gch: var GcHeap) =
|
||||||
let t0 = getticks()
|
let t0 = getticks()
|
||||||
sysAssert(allocInv(gch.region), "collectCT: begin")
|
sysAssert(allocInv(gch.region), "collectCT: begin")
|
||||||
|
|
||||||
when not defined(nimCoroutines):
|
when not nimCoroutines:
|
||||||
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
|
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
|
||||||
sysAssert(gch.decStack.len == 0, "collectCT")
|
sysAssert(gch.decStack.len == 0, "collectCT")
|
||||||
prepareForInteriorPointerChecking(gch.region)
|
prepareForInteriorPointerChecking(gch.region)
|
||||||
|
|
@ -938,16 +942,16 @@ proc collectCTBody(gch: var GcHeap) =
|
||||||
if gch.maxPause > 0 and duration > gch.maxPause:
|
if gch.maxPause > 0 and duration > gch.maxPause:
|
||||||
c_fprintf(stdout, "[GC] missed deadline: %ld\n", duration)
|
c_fprintf(stdout, "[GC] missed deadline: %ld\n", duration)
|
||||||
|
|
||||||
when defined(nimCoroutines):
|
when nimCoroutines:
|
||||||
proc currentStackSizes(): int =
|
proc currentStackSizes(): int =
|
||||||
for stack in items(gch.stack):
|
for stack in items(gch.stack):
|
||||||
result = result + stackSize(stack.starts, stack.pos)
|
result = result + stack.stackSize()
|
||||||
|
|
||||||
proc collectCT(gch: var GcHeap) =
|
proc collectCT(gch: var GcHeap) =
|
||||||
# stackMarkCosts prevents some pathological behaviour: Stack marking
|
# stackMarkCosts prevents some pathological behaviour: Stack marking
|
||||||
# becomes more expensive with large stacks and large stacks mean that
|
# 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.
|
# 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)
|
let stackMarkCosts = max(currentStackSizes() div (16*sizeof(int)), ZctThreshold)
|
||||||
else:
|
else:
|
||||||
let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold)
|
let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold)
|
||||||
|
|
@ -971,18 +975,24 @@ when withRealTime:
|
||||||
collectCTBody(gch)
|
collectCTBody(gch)
|
||||||
|
|
||||||
proc GC_step*(us: int, strongAdvice = false, stackSize = -1) {.noinline.} =
|
proc GC_step*(us: int, strongAdvice = false, stackSize = -1) {.noinline.} =
|
||||||
var stackTop {.volatile.}: pointer
|
|
||||||
let prevStackBottom = gch.stackBottom
|
|
||||||
if stackSize >= 0:
|
if stackSize >= 0:
|
||||||
stackTop = addr(stackTop)
|
var stackTop {.volatile.}: pointer
|
||||||
|
gch.getActiveStack().pos = addr(stackTop)
|
||||||
|
|
||||||
|
for stack in gch.stack.items():
|
||||||
|
stack.bottomSaved = stack.bottom
|
||||||
when stackIncreases:
|
when stackIncreases:
|
||||||
gch.stackBottom = cast[pointer](
|
stack.bottom = cast[pointer](
|
||||||
cast[ByteAddress](stackTop) - sizeof(pointer) * 6 - stackSize)
|
cast[ByteAddress](stack.pos) - sizeof(pointer) * 6 - stackSize)
|
||||||
else:
|
else:
|
||||||
gch.stackBottom = cast[pointer](
|
stack.bottom = cast[pointer](
|
||||||
cast[ByteAddress](stackTop) + sizeof(pointer) * 6 + stackSize)
|
cast[ByteAddress](stack.pos) + sizeof(pointer) * 6 + stackSize)
|
||||||
|
|
||||||
GC_step(gch, us, strongAdvice)
|
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):
|
when not defined(useNimRtl):
|
||||||
proc GC_disable() =
|
proc GC_disable() =
|
||||||
|
|
@ -1024,10 +1034,10 @@ when not defined(useNimRtl):
|
||||||
"[GC] zct capacity: " & $gch.zct.cap & "\n" &
|
"[GC] zct capacity: " & $gch.zct.cap & "\n" &
|
||||||
"[GC] max cycle table size: " & $gch.stat.cycleTableSize & "\n" &
|
"[GC] max cycle table size: " & $gch.stat.cycleTableSize & "\n" &
|
||||||
"[GC] max pause time [ms]: " & $(gch.stat.maxPause div 1000_000)
|
"[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"
|
result = result & "[GC] number of stacks: " & $gch.stack.len & "\n"
|
||||||
for stack in items(gch.stack):
|
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:
|
else:
|
||||||
result = result & "[GC] max stack size: " & $gch.stat.maxStackSize & "\n"
|
result = result & "[GC] max stack size: " & $gch.stat.maxStackSize & "\n"
|
||||||
GC_enable()
|
GC_enable()
|
||||||
|
|
|
||||||
|
|
@ -57,26 +57,77 @@ proc isNotForeign*(x: ForeignCell): bool =
|
||||||
## No deep copy has to be performed then.
|
## No deep copy has to be performed then.
|
||||||
x.owner == addr(gch)
|
x.owner == addr(gch)
|
||||||
|
|
||||||
proc len(stack: ptr GcStack): int =
|
when nimCoroutines:
|
||||||
if stack == nil:
|
iterator items(first: var GcStack): ptr GcStack =
|
||||||
return 0
|
var item = addr(first)
|
||||||
|
while true:
|
||||||
|
yield item
|
||||||
|
item = item.next
|
||||||
|
if item == addr(first):
|
||||||
|
break
|
||||||
|
|
||||||
var s = stack
|
proc append(first: var GcStack, stack: ptr GcStack) =
|
||||||
result = 1
|
## Append stack to the ring of stacks.
|
||||||
while s.next != nil:
|
first.prev.next = stack
|
||||||
inc(result)
|
stack.prev = first.prev
|
||||||
s = s.next
|
first.prev = stack
|
||||||
|
stack.next = addr(first)
|
||||||
|
|
||||||
when defined(nimCoroutines):
|
proc append(first: var GcStack): ptr GcStack =
|
||||||
proc stackSize(stack: ptr GcStack): int {.noinline.} =
|
## Allocate new GcStack object, append it to the ring of stacks and return it.
|
||||||
if stack.pos != nil:
|
result = cast[ptr GcStack](alloc0(sizeof(GcStack)))
|
||||||
when defined(stackIncreases):
|
first.append(result)
|
||||||
result = cast[ByteAddress](stack.pos) -% cast[ByteAddress](stack.bottom)
|
|
||||||
|
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:
|
else:
|
||||||
result = cast[ByteAddress](stack.bottom) -% cast[ByteAddress](stack.pos)
|
# 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:
|
else:
|
||||||
result = 0
|
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) =
|
proc setPosition(stack: ptr GcStack, position: pointer) =
|
||||||
stack.pos = position
|
stack.pos = position
|
||||||
stack.maxStackSize = max(stack.maxStackSize, stack.stackSize())
|
stack.maxStackSize = max(stack.maxStackSize, stack.stackSize())
|
||||||
|
|
@ -84,19 +135,18 @@ when defined(nimCoroutines):
|
||||||
proc setPosition(stack: var GcStack, position: pointer) =
|
proc setPosition(stack: var GcStack, position: pointer) =
|
||||||
setPosition(addr(stack), position)
|
setPosition(addr(stack), position)
|
||||||
|
|
||||||
proc stackSize(): int {.noinline.} =
|
proc getActiveStack(gch: var GcHeap): ptr GcStack =
|
||||||
for stack in gch.stack.items():
|
return gch.activeStack
|
||||||
result = result + stack.stackSize()
|
|
||||||
else:
|
|
||||||
proc stackSize(): int {.noinline.} =
|
|
||||||
var stackTop {.volatile.}: pointer
|
|
||||||
result = abs(cast[int](addr(stackTop)) - cast[int](gch.stackBottom))
|
|
||||||
|
|
||||||
iterator items(stack: ptr GcStack): ptr GcStack =
|
proc isActiveStack(stack: ptr GcStack): bool =
|
||||||
var s = stack
|
return gch.activeStack == stack
|
||||||
while not isNil(s):
|
else:
|
||||||
yield s
|
# Stack positions do not need to be tracked if coroutines are not used.
|
||||||
s = s.next
|
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):
|
when declared(threadType):
|
||||||
proc setupForeignThreadGc*() {.gcsafe.} =
|
proc setupForeignThreadGc*() {.gcsafe.} =
|
||||||
|
|
@ -167,9 +217,9 @@ when defined(nimCoroutines):
|
||||||
gch.activeStack.setPosition(addr(sp))
|
gch.activeStack.setPosition(addr(sp))
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
when defined(nimCoroutines):
|
|
||||||
proc setStackBottom(theStackBottom: pointer) =
|
proc setStackBottom(theStackBottom: pointer) =
|
||||||
# Initializes main stack of the thread.
|
# Initializes main stack of the thread.
|
||||||
|
when defined(nimCoroutines):
|
||||||
if gch.stack.next == nil:
|
if gch.stack.next == nil:
|
||||||
# Main stack was not initialized yet
|
# Main stack was not initialized yet
|
||||||
gch.stack.next = addr(gch.stack)
|
gch.stack.next = addr(gch.stack)
|
||||||
|
|
@ -177,43 +227,39 @@ when not defined(useNimRtl):
|
||||||
gch.stack.bottom = theStackBottom
|
gch.stack.bottom = theStackBottom
|
||||||
gch.stack.maxStackSize = 0
|
gch.stack.maxStackSize = 0
|
||||||
gch.activeStack = addr(gch.stack)
|
gch.activeStack = addr(gch.stack)
|
||||||
else:
|
|
||||||
|
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:
|
||||||
|
gch.stack.bottom = theStackBottom
|
||||||
|
elif theStackBottom != gch.stack.bottom:
|
||||||
var a = cast[ByteAddress](theStackBottom) # and not PageMask - PageSize*2
|
var a = cast[ByteAddress](theStackBottom) # and not PageMask - PageSize*2
|
||||||
var b = cast[ByteAddress](gch.stack.bottom)
|
var b = cast[ByteAddress](gch.stack.bottom)
|
||||||
#c_fprintf(stdout, "old: %p new: %p;\n",gch.stackBottom,theStackBottom)
|
#c_fprintf(stdout, "old: %p new: %p;\n",gch.stack.bottom,theStackBottom)
|
||||||
when stackIncreases:
|
when stackIncreases:
|
||||||
gch.stack.bottom = cast[pointer](min(a, b))
|
gch.stack.bottom = cast[pointer](min(a, b))
|
||||||
else:
|
else:
|
||||||
gch.stack.bottom = cast[pointer](max(a, b))
|
gch.stack.bottom = cast[pointer](max(a, b))
|
||||||
|
|
||||||
gch.stack.setPosition(theStackBottom)
|
gch.stack.setPosition(theStackBottom)
|
||||||
|
|
||||||
else:
|
|
||||||
proc setStackBottom(theStackBottom: pointer) =
|
|
||||||
#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
|
|
||||||
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))
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
when defined(sparc): # For SPARC architecture.
|
|
||||||
when defined(nimCoroutines):
|
|
||||||
{.error: "Nim coroutines are not supported on this platform."}
|
|
||||||
|
|
||||||
proc isOnStack(p: pointer): bool =
|
proc isOnStack(p: pointer): bool =
|
||||||
var stackTop {.volatile.}: pointer
|
var stackTop {.volatile.}: pointer
|
||||||
stackTop = addr(stackTop)
|
stackTop = addr(stackTop)
|
||||||
var b = cast[ByteAddress](gch.stackBottom)
|
var a = cast[ByteAddress](gch.getActiveStack().bottom)
|
||||||
var a = cast[ByteAddress](stackTop)
|
var b = cast[ByteAddress](stackTop)
|
||||||
|
when not stackIncreases:
|
||||||
|
swap(a, b)
|
||||||
var x = cast[ByteAddress](p)
|
var x = cast[ByteAddress](p)
|
||||||
result = a <=% x and x <=% b
|
result = a <=% x and x <=% b
|
||||||
|
|
||||||
|
when defined(sparc): # For SPARC architecture.
|
||||||
|
when defined(nimCoroutines):
|
||||||
|
{.error: "Nim coroutines are not supported on this platform."}
|
||||||
|
|
||||||
template forEachStackSlot(gch, gcMark: untyped) {.dirty.} =
|
template forEachStackSlot(gch, gcMark: untyped) {.dirty.} =
|
||||||
when defined(sparcv9):
|
when defined(sparcv9):
|
||||||
asm """"flushw \n" """
|
asm """"flushw \n" """
|
||||||
|
|
@ -221,7 +267,7 @@ when defined(sparc): # For SPARC architecture.
|
||||||
asm """"ta 0x3 ! ST_FLUSH_WINDOWS\n" """
|
asm """"ta 0x3 ! ST_FLUSH_WINDOWS\n" """
|
||||||
|
|
||||||
var
|
var
|
||||||
max = gch.stackBottom
|
max = gch.stack.bottom
|
||||||
sp: PPointer
|
sp: PPointer
|
||||||
stackTop: array[0..1, pointer]
|
stackTop: array[0..1, pointer]
|
||||||
sp = addr(stackTop[0])
|
sp = addr(stackTop[0])
|
||||||
|
|
@ -237,16 +283,6 @@ elif stackIncreases:
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Generic code for architectures where addresses increase as the stack grows.
|
# 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
|
var
|
||||||
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
|
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
|
||||||
# a little hack to get the size of a JmpBuf in the generated C code
|
# a little hack to get the size of a JmpBuf in the generated C code
|
||||||
|
|
@ -254,11 +290,14 @@ elif stackIncreases:
|
||||||
|
|
||||||
template forEachStackSlot(gch, gcMark: untyped) {.dirty.} =
|
template forEachStackSlot(gch, gcMark: untyped) {.dirty.} =
|
||||||
var registers {.noinit.}: C_JmpBuf
|
var registers {.noinit.}: C_JmpBuf
|
||||||
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,
|
# sp will traverse the JMP_BUF as well (jmp_buf size is added,
|
||||||
# otherwise sp would be below the registers structure).
|
# 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.
|
||||||
|
for stack in gch.stack.items():
|
||||||
|
var max = cast[ByteAddress](gch.stack.bottom)
|
||||||
|
var sp = cast[ByteAddress](addr(registers)) -% sizeof(pointer)
|
||||||
while sp >=% max:
|
while sp >=% max:
|
||||||
gcMark(gch, cast[PPointer](sp)[])
|
gcMark(gch, cast[PPointer](sp)[])
|
||||||
sp = sp -% sizeof(pointer)
|
sp = sp -% sizeof(pointer)
|
||||||
|
|
@ -267,15 +306,6 @@ else:
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Generic code for architectures where addresses decrease as the stack grows.
|
# 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.} =
|
template forEachStackSlot(gch, gcMark: untyped) {.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
|
||||||
|
|
@ -283,56 +313,13 @@ else:
|
||||||
type PStackSlice = ptr array[0..7, pointer]
|
type PStackSlice = ptr array[0..7, pointer]
|
||||||
var registers {.noinit.}: C_JmpBuf
|
var registers {.noinit.}: C_JmpBuf
|
||||||
# Update position of stack gc is executing in.
|
# Update position of stack gc is executing in.
|
||||||
gch.activeStack.setPosition(addr(registers))
|
gch.getActiveStack().setPosition(addr(registers))
|
||||||
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.
|
||||||
for stack in gch.stack.items():
|
for stack in gch.stack.items():
|
||||||
var max = cast[ByteAddress](stack.bottom)
|
var max = cast[ByteAddress](stack.bottom)
|
||||||
var sp = cast[ByteAddress](addr(registers))
|
var sp = cast[ByteAddress](addr(registers))
|
||||||
when defined(amd64):
|
when defined(amd64):
|
||||||
if stack == gch.activeStack:
|
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:
|
|
||||||
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)
|
|
||||||
var sp = cast[ByteAddress](addr(registers))
|
|
||||||
when defined(amd64):
|
|
||||||
# words within the jmp_buf structure may not be properly aligned.
|
# words within the jmp_buf structure may not be properly aligned.
|
||||||
let regEnd = sp +% sizeof(registers)
|
let regEnd = sp +% sizeof(registers)
|
||||||
while sp <% regEnd:
|
while sp <% regEnd:
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,6 @@
|
||||||
# A simple mark&sweep garbage collector for Nim. Define the
|
# A simple mark&sweep garbage collector for Nim. Define the
|
||||||
# symbol ``gcUseBitvectors`` to generate a variant of this GC.
|
# symbol ``gcUseBitvectors`` to generate a variant of this GC.
|
||||||
|
|
||||||
when defined(nimCoroutines):
|
|
||||||
import arch
|
|
||||||
|
|
||||||
{.push profiler:off.}
|
{.push profiler:off.}
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -51,17 +48,22 @@ type
|
||||||
maxStackSize: int # max stack size
|
maxStackSize: int # max stack size
|
||||||
freedObjects: int # max entries in cycle table
|
freedObjects: int # max entries in cycle table
|
||||||
|
|
||||||
GcStack {.final.} = object
|
GcStack {.final, pure.} = object
|
||||||
|
when nimCoroutines:
|
||||||
prev: ptr GcStack
|
prev: ptr GcStack
|
||||||
next: ptr GcStack
|
next: ptr GcStack
|
||||||
starts: pointer
|
maxStackSize: int # Used to track statistics because we can not use
|
||||||
|
# GcStat.maxStackSize when multiple stacks exist.
|
||||||
|
bottom: pointer
|
||||||
|
|
||||||
|
when nimCoroutines:
|
||||||
pos: pointer
|
pos: pointer
|
||||||
maxStackSize: int
|
|
||||||
|
|
||||||
GcHeap = object # this contains the zero count and
|
GcHeap = object # this contains the zero count and
|
||||||
# non-zero count table
|
# non-zero count table
|
||||||
stack: ptr GcStack
|
stack: GcStack
|
||||||
stackBottom: pointer
|
when nimCoroutines:
|
||||||
|
activeStack: ptr GcStack # current executing coroutine stack.
|
||||||
cycleThreshold: int
|
cycleThreshold: int
|
||||||
when useCellIds:
|
when useCellIds:
|
||||||
idGenerator: int
|
idGenerator: int
|
||||||
|
|
@ -423,7 +425,7 @@ proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
|
||||||
forEachStackSlot(gch, gcMark)
|
forEachStackSlot(gch, gcMark)
|
||||||
|
|
||||||
proc collectCTBody(gch: var GcHeap) =
|
proc collectCTBody(gch: var GcHeap) =
|
||||||
when not defined(nimCoroutines):
|
when not nimCoroutines:
|
||||||
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
|
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
|
||||||
prepareForInteriorPointerChecking(gch.region)
|
prepareForInteriorPointerChecking(gch.region)
|
||||||
markStackAndRegisters(gch)
|
markStackAndRegisters(gch)
|
||||||
|
|
@ -479,10 +481,10 @@ when not defined(useNimRtl):
|
||||||
"[GC] collections: " & $gch.stat.collections & "\n" &
|
"[GC] collections: " & $gch.stat.collections & "\n" &
|
||||||
"[GC] max threshold: " & $gch.stat.maxThreshold & "\n" &
|
"[GC] max threshold: " & $gch.stat.maxThreshold & "\n" &
|
||||||
"[GC] freed objects: " & $gch.stat.freedObjects & "\n"
|
"[GC] freed objects: " & $gch.stat.freedObjects & "\n"
|
||||||
when defined(nimCoroutines):
|
when nimCoroutines:
|
||||||
result = result & "[GC] number of stacks: " & $gch.stack.len & "\n"
|
result = result & "[GC] number of stacks: " & $gch.stack.len & "\n"
|
||||||
for stack in items(gch.stack):
|
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:
|
else:
|
||||||
result = result & "[GC] max stack size: " & $gch.stat.maxStackSize & "\n"
|
result = result & "[GC] max stack size: " & $gch.stat.maxStackSize & "\n"
|
||||||
GC_enable()
|
GC_enable()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue