]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: do not clobber arguments for reflect.callReflect and callMethod's ABI...
authorCherry Zhang <cherryyz@google.com>
Fri, 16 Apr 2021 21:29:38 +0000 (17:29 -0400)
committerCherry Zhang <cherryyz@google.com>
Mon, 19 Apr 2021 23:17:10 +0000 (23:17 +0000)
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>
src/cmd/compile/internal/liveness/plive.go

index 9eca05b040afec7e6d29992e7ddaddf82eab63dd..424d2485905ca643fff8183e7fa67269e732a70c 100644 (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)
                }
        }