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  }