Files
tinygo/src/internal/task/task_stack_amd64.S
T
Ayke van Laethem 95ee572b4d internal/task: rename tinygo_pause to tinygo_task_exit
This is more descriptive: the call is to exit a task, not to pause it.
This also makes it more obvious that there's an optimization
opportunity: to free the stack explicitly after the goroutine returns
(or to keep it as a cache for the next stack allocation).
2025-04-12 13:34:57 +02:00

80 lines
2.1 KiB
ArmAsm

#ifdef __MACH__ // Darwin
.global _tinygo_startTask
_tinygo_startTask:
#else // Linux etc
.section .text.tinygo_startTask
.global tinygo_startTask
tinygo_startTask:
#endif
.cfi_startproc
// Small assembly stub for starting a goroutine. This is already run on the
// new stack, with the callee-saved registers already loaded.
// Most importantly, r12 contain the pc of the to-be-started function and
// r13 contain the only argument it is given. Multiple arguments are packed
// into one by storing them in a new allocation.
// Indicate to the unwinder that there is nothing to unwind, this is the
// root frame. It avoids bogus extra frames in GDB like here:
// #10 0x00000000004277b6 in <goroutine wrapper> () at [...]
// #11 0x00000000004278f3 in tinygo_startTask () at [...]
// #12 0x0000000000002030 in ?? ()
// #13 0x0000000000000071 in ?? ()
.cfi_undefined rip
// Set the first argument of the goroutine start wrapper, which contains all
// the arguments.
movq %r13, %rdi
// Branch to the "goroutine start" function.
callq *%r12
// After return, exit this goroutine. This is a tail call.
#ifdef __MACH__
jmp _tinygo_task_exit
#else
jmp tinygo_task_exit
#endif
.cfi_endproc
#ifdef __MACH__ // Darwin
.global _tinygo_swapTask
_tinygo_swapTask:
#else // Linux etc
.global tinygo_swapTask
.section .text.tinygo_swapTask
tinygo_swapTask:
#endif
// This function gets the following parameters:
// %rdi = newStack uintptr
// %rsi = oldStack *uintptr
// Save all callee-saved registers:
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbp
pushq %rbx
// Save the current stack pointer in oldStack.
movq %rsp, (%rsi)
// Switch to the new stack pointer.
movq %rdi, %rsp
// Load saved register from the new stack.
popq %rbx
popq %rbp
popq %r12
popq %r13
popq %r14
popq %r15
// Return into the new task, as if tinygo_swapTask was a regular call.
ret
#ifdef __MACH__ // Darwin
// allow these symbols to stripped as dead code
.subsections_via_symbols
#endif