Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions src/fiber/context/x86_64-microsoft.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@ class Fiber
# :nodoc:
def makecontext(stack_ptr, fiber_main) : Nil
# A great explanation on stack contexts for win32:
# https://cfsamson.gitbook.io/green-threads-explained-in-200-lines-of-rust/supporting-windows
# https://web.archive.org/web/20220527113808/https://cfsamson.gitbook.io/green-threads-explained-in-200-lines-of-rust/supporting-windows

# 8 registers + 2 qwords for NT_TIB + 1 parameter + 10 128bit XMM registers
@context.stack_top = (stack_ptr - (11 + 10*2)).as(Void*)
# 8 registers + 3 qwords for NT_TIB + 1 parameter + 10 128bit XMM registers
@context.stack_top = (stack_ptr - (12 + 10*2)).as(Void*)
@context.resumable = 1

stack_ptr[0] = fiber_main.pointer # %rbx: Initial `resume` will `ret` to this address
stack_ptr[-1] = self.as(Void*) # %rcx: puts `self` as first argument for `fiber_main`

# The following two values are stored in the Thread Information Block (NT_TIB)
# The following three values are stored in the Thread Information Block (NT_TIB)
# and are used by Windows to track the current stack limits
stack_ptr[-2] = @stack # %gs:0x10: Stack Limit
stack_ptr[-3] = @stack_bottom # %gs:0x08: Stack Base
stack_ptr[-2] = @stack # %gs:0x1478: Win32 DeallocationStack
stack_ptr[-3] = @stack # %gs:0x10: Stack Limit
stack_ptr[-4] = @stack_bottom # %gs:0x08: Stack Base
end

# :nodoc:
Expand All @@ -27,6 +28,7 @@ class Fiber
# %rcx , %rdx
asm("
pushq %rcx
pushq %gs:0x1478 // Thread Information Block: Win32 DeallocationStack
pushq %gs:0x10 // Thread Information Block: Stack Limit
pushq %gs:0x08 // Thread Information Block: Stack Base
pushq %rdi // push 1st argument (because of initial resume)
Expand Down Expand Up @@ -73,13 +75,15 @@ class Fiber
popq %rdi // pop 1st argument (for initial resume)
popq %gs:0x08
popq %gs:0x10
popq %gs:0x1478
popq %rcx
")
{% else %}
# On LLVM < 9.0 using the previous code emits some additional
# instructions that breaks the context switching.
asm("
pushq %rcx
pushq %gs:0x1478 // Thread Information Block: Win32 DeallocationStack
pushq %gs:0x10 // Thread Information Block: Stack Limit
pushq %gs:0x08 // Thread Information Block: Stack Base
pushq %rdi // push 1st argument (because of initial resume)
Expand Down Expand Up @@ -126,6 +130,7 @@ class Fiber
popq %rdi // pop 1st argument (for initial resume)
popq %gs:0x08
popq %gs:0x10
popq %gs:0x1478
popq %rcx
" :: "r"(current_context), "r"(new_context))
{% end %}
Expand Down