cmd/compile: do not clobber arguments for reflect.callReflect and callMethod's ABI wrappers

reflect.callReflect and reflect.callMethod are called from special
functions makeFuncStub and methodValueCall. The runtime expects
that it can find the first argument (ctxt) at 0(SP) in
makeFuncStub and methodValueCall's frame. Normally callReflect and
callMethod already do not modify the argument, and keep it alive.
But the compiler-generated ABI wrappers don't do that. Special
case the wrappers to not clobber its arguments.

Change-Id: I1769f49b81c38eabe452d561001c418352814d86
Reviewed-on: https://go-review.googlesource.com/c/go/+/310889
Trust: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
Cherry Zhang 2021-04-16 17:29:38 -04:00
parent b3a5640397
commit 3711ea0b5d

View file

@ -146,7 +146,8 @@ type liveness struct {
// a part of it is used, but we may not initialize all parts.
partLiveArgs map[*ir.Name]bool
doClobber bool // Whether to clobber dead stack slots in this function.
doClobber bool // Whether to clobber dead stack slots in this function.
noClobberArgs bool // Do not clobber function arguments
}
// Map maps from *ssa.Value to LivenessIndex.
@ -930,16 +931,27 @@ func (lv *liveness) enableClobber() {
// Otherwise, giant functions make this experiment generate too much code.
return
}
if lv.f.Name == "forkAndExecInChild" || lv.f.Name == "wbBufFlush" {
if lv.f.Name == "forkAndExecInChild" {
// forkAndExecInChild calls vfork on some platforms.
// The code we add here clobbers parts of the stack in the child.
// When the parent resumes, it is using the same stack frame. But the
// child has clobbered stack variables that the parent needs. Boom!
// In particular, the sys argument gets clobbered.
//
return
}
if lv.f.Name == "wbBufFlush" ||
((lv.f.Name == "callReflect" || lv.f.Name == "callMethod") && lv.fn.ABIWrapper()) {
// runtime.wbBufFlush must not modify its arguments. See the comments
// in runtime/mwbbuf.go:wbBufFlush.
return
//
// reflect.callReflect and reflect.callMethod are called from special
// functions makeFuncStub and methodValueCall. The runtime expects
// that it can find the first argument (ctxt) at 0(SP) in makeFuncStub
// and methodValueCall's frame (see runtime/traceback.go:getArgInfo).
// Normally callReflect and callMethod already do not modify the
// argument, and keep it alive. But the compiler-generated ABI wrappers
// don't do that. Special case the wrappers to not clobber its arguments.
lv.noClobberArgs = true
}
if h := os.Getenv("GOCLOBBERDEADHASH"); h != "" {
// Clobber only functions where the hash of the function name matches a pattern.
@ -1000,6 +1012,9 @@ func clobber(lv *liveness, b *ssa.Block, live bitvec.BitVec) {
// tracked dynamically.
// Also don't clobber slots that are live for defers (see
// the code setting livedefer in epilogue).
if lv.noClobberArgs && n.Class == ir.PPARAM {
continue
}
clobberVar(b, n)
}
}