github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/internal/task/task_stack_amd64.go (about) 1 //go:build scheduler.tasks && amd64 && !windows 2 3 package task 4 5 import "unsafe" 6 7 var systemStack uintptr 8 9 // calleeSavedRegs is the list of registers that must be saved and restored when 10 // switching between tasks. Also see task_stack_amd64.S that relies on the exact 11 // layout of this struct. 12 type calleeSavedRegs struct { 13 rbx uintptr 14 rbp uintptr 15 r12 uintptr 16 r13 uintptr 17 r14 uintptr 18 r15 uintptr 19 20 pc uintptr 21 } 22 23 // archInit runs architecture-specific setup for the goroutine startup. 24 func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) { 25 // Store the initial sp for the startTask function (implemented in assembly). 26 s.sp = uintptr(unsafe.Pointer(r)) 27 28 // Initialize the registers. 29 // These will be popped off of the stack on the first resume of the goroutine. 30 31 // Start the function at tinygo_startTask (defined in 32 // src/internal/task/task_stack_amd64.S). This assembly code calls a 33 // function (passed in r12) with a single argument (passed in r13). After 34 // the function returns, it calls Pause(). 35 r.pc = uintptr(unsafe.Pointer(&startTask)) 36 37 // Pass the function to call in r12. 38 // This function is a compiler-generated wrapper which loads arguments out 39 // of a struct pointer. See createGoroutineStartWrapper (defined in 40 // compiler/goroutine.go) for more information. 41 r.r12 = fn 42 43 // Pass the pointer to the arguments struct in r13. 44 r.r13 = uintptr(args) 45 } 46 47 func (s *state) resume() { 48 swapTask(s.sp, &systemStack) 49 } 50 51 func (s *state) pause() { 52 newStack := systemStack 53 systemStack = 0 54 swapTask(newStack, &s.sp) 55 } 56 57 // SystemStack returns the system stack pointer when called from a task stack. 58 // When called from the system stack, it returns 0. 59 func SystemStack() uintptr { 60 return systemStack 61 }