github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/internal/task/task_stack_amd64_windows.go (about) 1 //go:build scheduler.tasks && amd64 && windows 2 3 package task 4 5 // This is almost the same as task_stack_amd64.go, but with the extra rdi and 6 // rsi registers saved: Windows has a slightly different calling convention. 7 8 import "unsafe" 9 10 var systemStack uintptr 11 12 // calleeSavedRegs is the list of registers that must be saved and restored when 13 // switching between tasks. Also see task_stack_amd64_windows.S that relies on 14 // the exact layout of this struct. 15 // The calling convention is described here: 16 // https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170 17 // Most importantly, these are the registers we need to save/restore: 18 // 19 // > The x64 ABI considers registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, 20 // > R15, and XMM6-XMM15 nonvolatile. They must be saved and restored by a 21 // > function that uses them. 22 type calleeSavedRegs struct { 23 // Note: rbx is placed here so that the stack is correctly aligned when 24 // loading/storing the xmm registers. 25 rbx uintptr 26 xmm15 [2]uint64 27 xmm14 [2]uint64 28 xmm13 [2]uint64 29 xmm12 [2]uint64 30 xmm11 [2]uint64 31 xmm10 [2]uint64 32 xmm9 [2]uint64 33 xmm8 [2]uint64 34 xmm7 [2]uint64 35 xmm6 [2]uint64 36 rbp uintptr 37 rdi uintptr 38 rsi uintptr 39 r12 uintptr 40 r13 uintptr 41 r14 uintptr 42 r15 uintptr 43 44 pc uintptr 45 } 46 47 // archInit runs architecture-specific setup for the goroutine startup. 48 func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) { 49 // Store the initial sp for the startTask function (implemented in assembly). 50 s.sp = uintptr(unsafe.Pointer(r)) 51 52 // Initialize the registers. 53 // These will be popped off of the stack on the first resume of the goroutine. 54 55 // Start the function at tinygo_startTask (defined in 56 // src/internal/task/task_stack_amd64_windows.S). This assembly code calls a 57 // function (passed in r12) with a single argument (passed in r13). After 58 // the function returns, it calls Pause(). 59 r.pc = uintptr(unsafe.Pointer(&startTask)) 60 61 // Pass the function to call in r12. 62 // This function is a compiler-generated wrapper which loads arguments out 63 // of a struct pointer. See createGoroutineStartWrapper (defined in 64 // compiler/goroutine.go) for more information. 65 r.r12 = fn 66 67 // Pass the pointer to the arguments struct in r13. 68 r.r13 = uintptr(args) 69 } 70 71 func (s *state) resume() { 72 swapTask(s.sp, &systemStack) 73 } 74 75 func (s *state) pause() { 76 newStack := systemStack 77 systemStack = 0 78 swapTask(newStack, &s.sp) 79 } 80 81 // SystemStack returns the system stack pointer when called from a task stack. 82 // When called from the system stack, it returns 0. 83 func SystemStack() uintptr { 84 return systemStack 85 }