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:
parent
ce4e9846f0
commit
c3d1b732d6
3 changed files with 231 additions and 164 deletions
|
|
@ -68,58 +68,25 @@ proc len(stack: ptr GcStack): int =
|
|||
s = s.next
|
||||
|
||||
when defined(nimCoroutines):
|
||||
proc stackSize(stackBottom: pointer, pos: pointer=nil): int {.noinline.} =
|
||||
var sp: pointer
|
||||
if pos == nil:
|
||||
var stackTop {.volatile.}: pointer
|
||||
sp = addr(stackTop)
|
||||
else:
|
||||
sp = pos
|
||||
result = abs(cast[int](sp) - cast[int](stackBottom))
|
||||
|
||||
proc GC_addStack*(starts: pointer) {.cdecl, exportc.} =
|
||||
var sp {.volatile.}: pointer
|
||||
var stack = cast[ptr GcStack](alloc0(sizeof(GcStack)))
|
||||
stack.starts = starts
|
||||
stack.pos = addr sp
|
||||
if gch.stack == nil:
|
||||
gch.stack = stack
|
||||
else:
|
||||
stack.next = gch.stack
|
||||
gch.stack.prev = stack
|
||||
gch.stack = stack
|
||||
# c_fprintf(stdout, "[GC] added stack 0x%016X\n", starts)
|
||||
|
||||
proc GC_removeStack*(starts: pointer) {.cdecl, exportc.} =
|
||||
var stack = gch.stack
|
||||
while stack != nil:
|
||||
if stack.starts == starts:
|
||||
if stack.prev == nil:
|
||||
if stack.next != nil:
|
||||
stack.next.prev = nil
|
||||
gch.stack = stack.next
|
||||
else:
|
||||
stack.prev.next = stack.next
|
||||
if stack.next != nil:
|
||||
stack.next.prev = stack.prev
|
||||
dealloc(stack)
|
||||
# echo "[GC] removed stack ", starts.repr
|
||||
break
|
||||
proc stackSize(stack: ptr GcStack): int {.noinline.} =
|
||||
if stack.pos != nil:
|
||||
when defined(stackIncreases):
|
||||
result = cast[ByteAddress](stack.pos) -% cast[ByteAddress](stack.bottom)
|
||||
else:
|
||||
stack = stack.next
|
||||
result = cast[ByteAddress](stack.bottom) -% cast[ByteAddress](stack.pos)
|
||||
else:
|
||||
result = 0
|
||||
|
||||
proc GC_setCurrentStack*(starts: pointer) {.cdecl, exportc.} =
|
||||
var pos {.volatile.}: pointer
|
||||
pos = addr(pos)
|
||||
var stack = gch.stack
|
||||
while stack != nil:
|
||||
if stack.starts == starts:
|
||||
stack.pos = pos
|
||||
stack.maxStackSize = max(stack.maxStackSize, stackSize(stack.starts, pos))
|
||||
gch.stackActive = stack
|
||||
return
|
||||
stack = stack.next
|
||||
gcAssert(false, "Current stack position does not belong to registered stack")
|
||||
proc setPosition(stack: ptr GcStack, position: pointer) =
|
||||
stack.pos = position
|
||||
stack.maxStackSize = max(stack.maxStackSize, stack.stackSize())
|
||||
|
||||
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
|
||||
|
|
@ -180,18 +147,50 @@ elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
|
|||
else:
|
||||
const stackIncreases = false
|
||||
|
||||
{.push stack_trace: off.}
|
||||
when defined(nimCoroutines):
|
||||
proc GC_addStack(bottom: pointer) {.cdecl, exportc.} =
|
||||
# c_fprintf(stdout, "GC_addStack: %p;\n", bottom)
|
||||
var stack = gch.stack.append()
|
||||
stack.bottom = bottom
|
||||
stack.setPosition(bottom)
|
||||
|
||||
proc GC_removeStack(bottom: pointer) {.cdecl, exportc.} =
|
||||
# c_fprintf(stdout, "GC_removeStack: %p;\n", bottom)
|
||||
gch.stack.find(bottom).remove()
|
||||
|
||||
proc GC_setActiveStack(bottom: pointer) {.cdecl, exportc.} =
|
||||
## Sets active stack and updates current stack position.
|
||||
# c_fprintf(stdout, "GC_setActiveStack: %p;\n", bottom)
|
||||
var sp {.volatile.}: pointer
|
||||
gch.activeStack = gch.stack.find(bottom)
|
||||
gch.activeStack.setPosition(addr(sp))
|
||||
|
||||
when not defined(useNimRtl):
|
||||
{.push stack_trace: off.}
|
||||
proc setStackBottom(theStackBottom: pointer) =
|
||||
#c_fprintf(stdout, "stack bottom: %p;\n", theStackBottom)
|
||||
# the first init must be the one that defines the stack bottom:
|
||||
when defined(nimCoroutines):
|
||||
if gch.stack == nil:
|
||||
# `setStackBottom()` gets called multiple times from main thread.
|
||||
# Add it only once.
|
||||
GC_addStack(theStackBottom)
|
||||
GC_setCurrentStack(theStackBottom)
|
||||
else:
|
||||
when defined(nimCoroutines):
|
||||
proc setStackBottom(theStackBottom: pointer) =
|
||||
# Initializes main stack of the thread.
|
||||
if gch.stack.next == nil:
|
||||
# Main stack was not initialized yet
|
||||
gch.stack.next = addr(gch.stack)
|
||||
gch.stack.prev = addr(gch.stack)
|
||||
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) =
|
||||
#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
|
||||
|
|
@ -201,7 +200,7 @@ when not defined(useNimRtl):
|
|||
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):
|
||||
|
|
@ -272,12 +271,10 @@ else:
|
|||
proc isOnStack(p: pointer): bool =
|
||||
var stackTop {.volatile.}: pointer
|
||||
stackTop = addr(stackTop)
|
||||
for stack in items(gch.stack):
|
||||
var b = cast[ByteAddress](stack.starts)
|
||||
var a = cast[ByteAddress](stack.starts) - stack.maxStackSize
|
||||
var x = cast[ByteAddress](p)
|
||||
if a <=% x and x <=% b:
|
||||
return true
|
||||
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.
|
||||
|
|
@ -285,35 +282,38 @@ else:
|
|||
# that 'setjmp' will save registers in the C stack.
|
||||
type PStackSlice = ptr array[0..7, pointer]
|
||||
var registers {.noinit.}: C_JmpBuf
|
||||
discard c_setjmp(registers)
|
||||
gch.stackActive.pos = addr(registers)
|
||||
for stack in items(gch.stack):
|
||||
stack.maxStackSize = max(stack.maxStackSize, stackSize(stack.starts))
|
||||
var max = cast[ByteAddress](stack.starts)
|
||||
var sp = cast[ByteAddress](stack.pos)
|
||||
when defined(amd64):
|
||||
if stack == gch.stackActive:
|
||||
# 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)
|
||||
# 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)
|
||||
# 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue