gc_stack_portable.mx raw

   1  //go:build (gc.conservative || gc.custom || gc.precise || gc.boehm) && moxie.wasm
   2  
   3  package runtime
   4  
   5  import (
   6  	"internal/task"
   7  	"runtime/volatile"
   8  	"unsafe"
   9  )
  10  
  11  func gcMarkReachable() {
  12  	markStack()
  13  	findGlobals(markRoots)
  14  }
  15  
  16  //go:extern runtime.stackChainStart
  17  var stackChainStart *stackChainObject
  18  
  19  type stackChainObject struct {
  20  	parent   *stackChainObject
  21  	numSlots uintptr
  22  }
  23  
  24  // markStack marks all root pointers found on the stack.
  25  //
  26  //   - Goroutine stacks are heap allocated and always reachable in some way
  27  //     (for example through internal/task.currentTask) so they will always be
  28  //     scanned.
  29  //   - The system stack (aka startup stack) is not heap allocated, so even
  30  //     though it may be referenced it will not be scanned by default.
  31  //
  32  // The compiler also inserts code to store all globals in a chain via
  33  // stackChainStart. Luckily we don't need to scan these, as these globals are
  34  // stored on the goroutine stack and are therefore already getting scanned.
  35  func markStack() {
  36  	// Hack to force LLVM to consider stackChainStart to be live.
  37  	// Without this hack, loads and stores may be considered dead and objects on
  38  	// the stack might not be correctly tracked. With this volatile load, LLVM
  39  	// is forced to consider stackChainStart (and everything it points to) as
  40  	// live.
  41  	volatile.LoadUint32((*uint32)(unsafe.Pointer(&stackChainStart)))
  42  
  43  	// Scan the system stack.
  44  	var sysSP uintptr
  45  	if task.OnSystemStack() {
  46  		// We are on the system stack.
  47  		// Use the current stack pointer.
  48  		sysSP = getCurrentStackPointer()
  49  	} else {
  50  		// We are in a goroutine.
  51  		// Use the saved stack pointer.
  52  		sysSP = savedStackPointer
  53  	}
  54  	markRoots(sysSP, stackTop)
  55  }
  56  
  57  // trackPointer is a stub function call inserted by the compiler during IR
  58  // construction. Calls to it are later replaced with regular stack bookkeeping
  59  // code.
  60  func trackPointer(ptr, alloca unsafe.Pointer)
  61  
  62  // swapStackChain swaps the stack chain.
  63  // This is called from internal/task when switching goroutines.
  64  func swapStackChain(dst **stackChainObject) {
  65  	*dst, stackChainStart = stackChainStart, *dst
  66  }
  67  
  68  func gcResumeWorld() {
  69  	// Nothing to do here (single threaded).
  70  }
  71