// a stack pointer to an escaping argument. debugCallV1 cannot check
// this invariant.
TEXT runtime·debugCallV1(SB),NOSPLIT,$152-0
- // Save all registers that may contain pointers in GC register
- // map order (see ssa.registersAMD64). This makes it possible
- // to copy the stack while updating pointers currently held in
- // registers, and for the GC to find roots in registers.
+ // Save all registers that may contain pointers so they can be
+ // conservatively scanned.
//
// We can't do anything that might clobber any of these
// registers before this.
// the calling goroutine. On the goroutine, it prepares to recover
// panics from the debug call, and then calls the call dispatching
// function at PC dispatch.
+//
+// This must be deeply nosplit because there are untyped values on the
+// stack from debugCallV1.
+//
+//go:nosplit
func debugCallWrap(dispatch uintptr) {
var lockedm bool
var lockedExt uint32
gp.lockedm = 0
}
+ // Mark the calling goroutine as being at an async
+ // safe-point, since it has a few conservative frames
+ // at the bottom of the stack. This also prevents
+ // stack shrinks.
+ gp.asyncSafePoint = true
+
// Stash newg away so we can execute it below (mcall's
// closure can't capture anything).
gp.schedlink.set(newg)
mp.lockedg.set(gp)
gp.lockedm.set(mp)
}
+
+ gp.asyncSafePoint = false
}
// debugCallWrap1 is the continuation of debugCallWrap on the callee
}
isAsyncPreempt := frame.fn.valid() && frame.fn.funcID == funcID_asyncPreempt
- if state.conservative || isAsyncPreempt {
+ isDebugCall := frame.fn.valid() && frame.fn.funcID == funcID_debugCallV1
+ if state.conservative || isAsyncPreempt || isDebugCall {
if debugScanConservative {
println("conservatively scanning function", funcname(frame.fn), "at PC", hex(frame.continpc))
}
scanConservative(frame.argp, frame.arglen, nil, gcw, state)
}
- if isAsyncPreempt {
+ if isAsyncPreempt || isDebugCall {
// This function's frame contained the
// registers for the asynchronously stopped
// parent frame. Scan the parent
minsize = sys.MinFrameSize
}
if size > minsize {
- var stkmap *stackmap
stackid := pcdata
- if f.funcID != funcID_debugCallV1 {
- stkmap = (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
- } else {
- // debugCallV1's stack map is the register map
- // at its call site.
- callerPC := frame.lr
- caller := findfunc(callerPC)
- if !caller.valid() {
- println("runtime: debugCallV1 called by unknown caller", hex(callerPC))
- throw("bad debugCallV1")
- }
- stackid = int32(-1)
- if callerPC != caller.entry {
- callerPC--
- stackid = pcdatavalue(caller, _PCDATA_RegMapIndex, callerPC, cache)
- }
- if stackid == -1 {
- stackid = 0 // in prologue
- }
- stkmap = (*stackmap)(funcdata(caller, _FUNCDATA_RegPointerMaps))
- }
+ stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
if stkmap == nil || stkmap.n <= 0 {
print("runtime: frame ", funcname(f), " untyped locals ", hex(frame.varp-size), "+", hex(size), "\n")
throw("missing stackmap")