diff --git a/src/runtime/stkframe.go b/src/runtime/stkframe.go index 97807a038e..3ecf3a828c 100644 --- a/src/runtime/stkframe.go +++ b/src/runtime/stkframe.go @@ -93,58 +93,59 @@ func (frame *stkframe) argBytes() uintptr { // function stack object, which the caller must synthesize. func (frame *stkframe) argMapInternal() (argMap bitvector, hasReflectStackObj bool) { f := frame.fn - argMap.n = f.args / goarch.PtrSize - if f.args == _ArgsSizeUnknown { - // Extract argument bitmaps for reflect stubs from the calls they made to reflect. - switch funcname(f) { - case "reflect.makeFuncStub", "reflect.methodValueCall": - // These take a *reflect.methodValue as their - // context register and immediately save it to 0(SP). - // Get the methodValue from 0(SP). - arg0 := frame.sp + sys.MinFrameSize + if f.args != _ArgsSizeUnknown { + argMap.n = f.args / goarch.PtrSize + return + } + // Extract argument bitmaps for reflect stubs from the calls they made to reflect. + switch funcname(f) { + case "reflect.makeFuncStub", "reflect.methodValueCall": + // These take a *reflect.methodValue as their + // context register and immediately save it to 0(SP). + // Get the methodValue from 0(SP). + arg0 := frame.sp + sys.MinFrameSize - minSP := frame.fp - if !usesLR { - // The CALL itself pushes a word. - // Undo that adjustment. - minSP -= goarch.PtrSize - } - if arg0 >= minSP { - // The function hasn't started yet. - // This only happens if f was the - // start function of a new goroutine - // that hasn't run yet *and* f takes - // no arguments and has no results - // (otherwise it will get wrapped in a - // closure). In this case, we can't - // reach into its locals because it - // doesn't have locals yet, but we - // also know its argument map is - // empty. - if frame.pc != f.entry() { - print("runtime: confused by ", funcname(f), ": no frame (sp=", hex(frame.sp), " fp=", hex(frame.fp), ") at entry+", hex(frame.pc-f.entry()), "\n") - throw("reflect mismatch") - } - return bitvector{}, false // No locals, so also no stack objects - } - hasReflectStackObj = true - mv := *(**reflectMethodValue)(unsafe.Pointer(arg0)) - // Figure out whether the return values are valid. - // Reflect will update this value after it copies - // in the return values. - retValid := *(*bool)(unsafe.Pointer(arg0 + 4*goarch.PtrSize)) - if mv.fn != f.entry() { - print("runtime: confused by ", funcname(f), "\n") + minSP := frame.fp + if !usesLR { + // The CALL itself pushes a word. + // Undo that adjustment. + minSP -= goarch.PtrSize + } + if arg0 >= minSP { + // The function hasn't started yet. + // This only happens if f was the + // start function of a new goroutine + // that hasn't run yet *and* f takes + // no arguments and has no results + // (otherwise it will get wrapped in a + // closure). In this case, we can't + // reach into its locals because it + // doesn't have locals yet, but we + // also know its argument map is + // empty. + if frame.pc != f.entry() { + print("runtime: confused by ", funcname(f), ": no frame (sp=", hex(frame.sp), " fp=", hex(frame.fp), ") at entry+", hex(frame.pc-f.entry()), "\n") throw("reflect mismatch") } - argMap = *mv.stack - if !retValid { - // argMap.n includes the results, but - // those aren't valid, so drop them. - n := int32((uintptr(mv.argLen) &^ (goarch.PtrSize - 1)) / goarch.PtrSize) - if n < argMap.n { - argMap.n = n - } + return bitvector{}, false // No locals, so also no stack objects + } + hasReflectStackObj = true + mv := *(**reflectMethodValue)(unsafe.Pointer(arg0)) + // Figure out whether the return values are valid. + // Reflect will update this value after it copies + // in the return values. + retValid := *(*bool)(unsafe.Pointer(arg0 + 4*goarch.PtrSize)) + if mv.fn != f.entry() { + print("runtime: confused by ", funcname(f), "\n") + throw("reflect mismatch") + } + argMap = *mv.stack + if !retValid { + // argMap.n includes the results, but + // those aren't valid, so drop them. + n := int32((uintptr(mv.argLen) &^ (goarch.PtrSize - 1)) / goarch.PtrSize) + if n < argMap.n { + argMap.n = n } } }