]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: refactor Escape.tagHole
authorMatthew Dempsky <mdempsky@google.com>
Mon, 20 Apr 2020 18:14:15 +0000 (11:14 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Tue, 21 Apr 2020 20:48:43 +0000 (20:48 +0000)
This CL refactors tagHole to handle all three call situations (unknown
function; known function in same analysis batch; known function in
previous analysis batch). This will make it somewhat easier to reuse
in a followup CL.

Passes toolstash-check.

Change-Id: I764d047a333dfc593d721a881361683e94b485df
Reviewed-on: https://go-review.googlesource.com/c/go/+/229059
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/compile/internal/gc/escape.go

index 472d193efd7ecd49a2e4c4d4531a997502f91ac0..598750fd8da3195001a54fe7bcb18e5a329deb80 100644 (file)
@@ -718,8 +718,8 @@ func (e *Escape) assignHeap(src *Node, why string, where *Node) {
 // should contain the holes representing where the function callee's
 // results flows; where is the OGO/ODEFER context of the call, if any.
 func (e *Escape) call(ks []EscHole, call, where *Node) {
-       // First, pick out the function callee, its type, and receiver
-       // (if any) and normal arguments list.
+       // First, pick out the function callee (if statically known),
+       // its type, and receiver (if any) and normal arguments list.
        var fn, recv *Node
        var fntype *types.Type
        args := call.List.Slice()
@@ -730,6 +730,9 @@ func (e *Escape) call(ks []EscHole, call, where *Node) {
                        fn = fn.Func.Closure.Func.Nname
                }
                fntype = fn.Type
+               if !(fn.Op == ONAME && fn.Class() == PFUNC) {
+                       fn = nil // dynamic call
+               }
        case OCALLMETH:
                fn = asNode(call.Left.Type.FuncType().Nname)
                fntype = fn.Type
@@ -747,41 +750,22 @@ func (e *Escape) call(ks []EscHole, call, where *Node) {
                Fatalf("unexpected call op: %v", call.Op)
        }
 
-       static := fn != nil && fn.Op == ONAME && fn.Class() == PFUNC
-
        // Setup evaluation holes for each receiver/argument.
        var recvK EscHole
        var paramKs []EscHole
 
-       if static && fn.Name.Defn != nil && fn.Name.Defn.Esc < EscFuncTagged {
-               // Static call to function in same mutually recursive
-               // group; incorporate into data flow graph.
-
-               if fn.Name.Defn.Esc == EscFuncUnknown {
-                       Fatalf("graph inconsistency")
-               }
-
-               if ks != nil {
-                       for i, result := range fntype.Results().FieldSlice() {
+       if call.Op == OCALLFUNC || call.Op == OCALLMETH || call.Op == OCALLINTER {
+               if ks != nil && fn != nil && e.inMutualBatch(fn) {
+                       for i, result := range fn.Type.Results().FieldSlice() {
                                e.expr(ks[i], asNode(result.Nname))
                        }
                }
 
                if r := fntype.Recv(); r != nil {
-                       recvK = e.addr(asNode(r.Nname))
-               }
-               for _, param := range fntype.Params().FieldSlice() {
-                       paramKs = append(paramKs, e.addr(asNode(param.Nname)))
-               }
-       } else if call.Op == OCALLFUNC || call.Op == OCALLMETH || call.Op == OCALLINTER {
-               // Dynamic call, or call to previously tagged
-               // function. Setup flows to heap and/or ks according
-               // to parameter tags.
-               if r := fntype.Recv(); r != nil {
-                       recvK = e.tagHole(ks, r, static)
+                       recvK = e.tagHole(ks, fn, r)
                }
                for _, param := range fntype.Params().FieldSlice() {
-                       paramKs = append(paramKs, e.tagHole(ks, param, static))
+                       paramKs = append(paramKs, e.tagHole(ks, fn, param))
                }
        } else {
                // Handle escape analysis for builtins.
@@ -862,7 +846,7 @@ func (e *Escape) call(ks []EscHole, call, where *Node) {
                // For arguments to go:uintptrescapes, peel
                // away an unsafe.Pointer->uintptr conversion,
                // if present.
-               if static && arg.Op == OCONVNOP && arg.Type.Etype == TUINTPTR && arg.Left.Type.Etype == TUNSAFEPTR {
+               if fn != nil && arg.Op == OCONVNOP && arg.Type.Etype == TUINTPTR && arg.Left.Type.Etype == TUNSAFEPTR {
                        x := i
                        if fntype.IsVariadic() && x >= fntype.NumParams() {
                                x = fntype.NumParams() - 1
@@ -901,14 +885,19 @@ func (e *Escape) augmentParamHole(k EscHole, call, where *Node) EscHole {
 
 // tagHole returns a hole for evaluating an argument passed to param.
 // ks should contain the holes representing where the function
-// callee's results flows; static indicates whether this is a static
-// call.
-func (e *Escape) tagHole(ks []EscHole, param *types.Field, static bool) EscHole {
+// callee's results flows. fn is the statically-known callee function,
+// if any.
+func (e *Escape) tagHole(ks []EscHole, fn *Node, param *types.Field) EscHole {
        // If this is a dynamic call, we can't rely on param.Note.
-       if !static {
+       if fn == nil {
                return e.heapHole()
        }
 
+       if e.inMutualBatch(fn) {
+               return e.addr(asNode(param.Nname))
+       }
+
+       // Call to previously tagged function.
        var tagKs []EscHole
 
        esc := ParseLeaks(param.Note)
@@ -927,6 +916,21 @@ func (e *Escape) tagHole(ks []EscHole, param *types.Field, static bool) EscHole
        return e.teeHole(tagKs...)
 }
 
+// inMutualBatch reports whether function fn is in the batch of
+// mutually recursive functions being analyzed. When this is true,
+// fn has not yet been analyzed, so its parameters and results
+// should be incorporated directly into the flow graph instead of
+// relying on its escape analysis tagging.
+func (e *Escape) inMutualBatch(fn *Node) bool {
+       if fn.Name.Defn != nil && fn.Name.Defn.Esc < EscFuncTagged {
+               if fn.Name.Defn.Esc == EscFuncUnknown {
+                       Fatalf("graph inconsistency")
+               }
+               return true
+       }
+       return false
+}
+
 // An EscHole represents a context for evaluation a Go
 // expression. E.g., when evaluating p in "x = **p", we'd have a hole
 // with dst==x and derefs==2.