simplifying the yield procedure and allowing a void* userdata
Closed this issue · 1 comments
ratchetfreak commented
You don't need to save the rip separately, you can instead put that on the stack. Then once you exchange the stack pointer you can then return from yield. Even for the first time into the entry point.
You can allow the entry point to take a void* userdata by adding rdi to the saved context and in void coroutine_go(void (*f)(void*), void*); you take the second parameter and save that to be restored into rdi for when you jump into the entry point for the first time.
Making these changes in coroutine_go the sequence will then become
mov rax, [stacks_end] ;; rax contains the rsp of the new
;; routine
sub QWORD [stacks_end], STACK_CAPACITY
sub rax, 8
mov QWORD [rax], coroutine_finish
sub rax, 8
mov QWORD [rax], rdi ;;save the function pointer on the stack
mov [contexts_rsp+rbx*8], rax
mov QWORD [contexts_rbp+rbx*8], 0
mov [contexts_rdi+rbx*8], rsi ;; save second argument user_data
retcoroutine_yield then becomes:
coroutine_yield:
mov rbx, [contexts_current]
mov [contexts_rsp+rbx*8], rsp
mov [contexts_rbp+rbx*8], rbp
mov [contexts_rdi+rbx*8], rdi ;; technically not needed
;; mov rbx, [contexts_next]
mov rsp, [contexts_rsp+rbx*8]
mov rbp, [contexts_rbp+rbx*8]
mov rdi, [contexts_rdi+rbx*8] ;; on first time this will be the user_data
ret ;; on first time this will pop the entrypoint pointer
;; and leave coroutine_finish on top as return target