github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/internal/task/task_stack_arm64.go (about)

     1  //go:build scheduler.tasks && arm64
     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_arm64.S that relies on the exact
    11  // layout of this struct.
    12  type calleeSavedRegs struct {
    13  	x19 uintptr
    14  	x20 uintptr
    15  	x21 uintptr
    16  	x22 uintptr
    17  	x23 uintptr
    18  	x24 uintptr
    19  	x25 uintptr
    20  	x26 uintptr
    21  	x27 uintptr
    22  	x28 uintptr
    23  	x29 uintptr
    24  	pc  uintptr // aka x30 aka LR
    25  
    26  	d8  uintptr
    27  	d9  uintptr
    28  	d10 uintptr
    29  	d11 uintptr
    30  	d12 uintptr
    31  	d13 uintptr
    32  	d14 uintptr
    33  	d15 uintptr
    34  }
    35  
    36  // archInit runs architecture-specific setup for the goroutine startup.
    37  func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
    38  	// Store the initial sp for the startTask function (implemented in assembly).
    39  	s.sp = uintptr(unsafe.Pointer(r))
    40  
    41  	// Initialize the registers.
    42  	// These will be popped off of the stack on the first resume of the goroutine.
    43  
    44  	// Start the function at tinygo_startTask (defined in src/internal/task/task_stack_arm64.S).
    45  	// This assembly code calls a function (passed in x19) with a single argument
    46  	// (passed in x20). After the function returns, it calls Pause().
    47  	r.pc = uintptr(unsafe.Pointer(&startTask))
    48  
    49  	// Pass the function to call in x19.
    50  	// This function is a compiler-generated wrapper which loads arguments out of a struct pointer.
    51  	// See createGoroutineStartWrapper (defined in compiler/goroutine.go) for more information.
    52  	r.x19 = fn
    53  
    54  	// Pass the pointer to the arguments struct in x20.
    55  	r.x20 = uintptr(args)
    56  }
    57  
    58  func (s *state) resume() {
    59  	swapTask(s.sp, &systemStack)
    60  }
    61  
    62  func (s *state) pause() {
    63  	newStack := systemStack
    64  	systemStack = 0
    65  	swapTask(newStack, &s.sp)
    66  }
    67  
    68  // SystemStack returns the system stack pointer when called from a task stack.
    69  // When called from the system stack, it returns 0.
    70  func SystemStack() uintptr {
    71  	return systemStack
    72  }