/
x86_64.cr
41 lines (37 loc) · 1.33 KB
/
x86_64.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{% skip_file unless flag?(:x86_64) %}
class Fiber
# :nodoc:
def makecontext(stack_ptr, fiber_main) : Nil
# in x86-64, the context switch push/pop 6 registers + the return address
# that is left on the stack, we thus reserve space for 7 pointers:
@context.stack_top = (stack_ptr - 7).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*) # %rdi: puts `self` as first argument for `fiber_main`
end
# :nodoc:
@[NoInline]
@[Naked]
def self.swapcontext(current_context, new_context) : Nil
asm("
pushq %rdi // push 1st argument (because of initial resume)
pushq %rbx // push callee-saved registers on the stack
pushq %rbp
pushq %r12
pushq %r13
pushq %r14
pushq %r15
movq %rsp, 0($0) // current_context.stack_top = %rsp
movl $$1, 8($0) // current_context.resumable = 1
movl $$0, 8($1) // new_context.resumable = 0
movq 0($1), %rsp // %rsp = new_context.stack_top
popq %r15 // pop callee-saved registers from the stack
popq %r14
popq %r13
popq %r12
popq %rbp
popq %rbx
popq %rdi // pop 1st argument (for initial resume)
" :: "r"(current_context), "r"(new_context))
end
end