]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: refactor escape analysis of calls
authorMatthew Dempsky <mdempsky@google.com>
Wed, 23 Jun 2021 03:53:14 +0000 (20:53 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Wed, 23 Jun 2021 05:31:38 +0000 (05:31 +0000)
This CL is a prep refactoring for an upcoming CL to move go/defer
wrapping into escape analysis. That CL is unfortunately unavoidably
complex and subtle, so this CL takes care of some more mundane
refactoring details.

Change-Id: Ifbefe1d522a8d57066646be09536437f42e7082c
Reviewed-on: https://go-review.googlesource.com/c/go/+/330251
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
src/cmd/compile/internal/escape/call.go
src/cmd/compile/internal/escape/expr.go
src/cmd/compile/internal/escape/stmt.go

index 28a3b679a5681328baabb72005a1bbc809319dfe..8511259d47bd779e984946e16b2708ab184e5ae7 100644 (file)
@@ -13,26 +13,24 @@ import (
 
 // call evaluates a call expressions, including builtin calls. ks
 // 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 []hole, call, where ir.Node) {
-       topLevelDefer := where != nil && where.Op() == ir.ODEFER && e.loopDepth == 1
-       if topLevelDefer {
-               // force stack allocation of defer record, unless
-               // open-coded defers are used (see ssa.go)
-               where.SetEsc(ir.EscNever)
-       }
+// results flows.
+func (e *escape) call(ks []hole, call ir.Node) {
+       e.callCommon(ks, call, nil)
+}
 
-       argument := func(k hole, arg ir.Node) {
-               if topLevelDefer {
-                       // Top level defers arguments don't escape to
-                       // heap, but they do need to last until end of
-                       // function.
-                       k = e.later(k)
-               } else if where != nil {
-                       k = e.heapHole()
+func (e *escape) callCommon(ks []hole, call ir.Node, where *ir.GoDeferStmt) {
+       argument := func(k hole, argp *ir.Node) {
+               if where != nil {
+                       if where.Esc() == ir.EscNever {
+                               // Top-level defers arguments don't escape to heap,
+                               // but they do need to last until end of function.
+                               k = e.later(k)
+                       } else {
+                               k = e.heapHole()
+                       }
                }
 
-               e.expr(k.note(call, "call parameter"), arg)
+               e.expr(k.note(call, "call parameter"), *argp)
        }
 
        switch call.Op() {
@@ -70,15 +68,15 @@ func (e *escape) call(ks []hole, call, where ir.Node) {
                }
 
                if r := fntype.Recv(); r != nil {
-                       argument(e.tagHole(ks, fn, r), call.X.(*ir.SelectorExpr).X)
+                       argument(e.tagHole(ks, fn, r), &call.X.(*ir.SelectorExpr).X)
                } else {
                        // Evaluate callee function expression.
-                       argument(e.discardHole(), call.X)
+                       argument(e.discardHole(), &call.X)
                }
 
                args := call.Args
                for i, param := range fntype.Params().FieldSlice() {
-                       argument(e.tagHole(ks, fn, param), args[i])
+                       argument(e.tagHole(ks, fn, param), &args[i])
                }
 
        case ir.OAPPEND:
@@ -93,54 +91,66 @@ func (e *escape) call(ks []hole, call, where ir.Node) {
                if args[0].Type().Elem().HasPointers() {
                        appendeeK = e.teeHole(appendeeK, e.heapHole().deref(call, "appendee slice"))
                }
-               argument(appendeeK, args[0])
+               argument(appendeeK, &args[0])
 
                if call.IsDDD {
                        appendedK := e.discardHole()
                        if args[1].Type().IsSlice() && args[1].Type().Elem().HasPointers() {
                                appendedK = e.heapHole().deref(call, "appended slice...")
                        }
-                       argument(appendedK, args[1])
+                       argument(appendedK, &args[1])
                } else {
-                       for _, arg := range args[1:] {
-                               argument(e.heapHole(), arg)
+                       for i := 1; i < len(args); i++ {
+                               argument(e.heapHole(), &args[i])
                        }
                }
 
        case ir.OCOPY:
                call := call.(*ir.BinaryExpr)
-               argument(e.discardHole(), call.X)
+               argument(e.discardHole(), &call.X)
 
                copiedK := e.discardHole()
                if call.Y.Type().IsSlice() && call.Y.Type().Elem().HasPointers() {
                        copiedK = e.heapHole().deref(call, "copied slice")
                }
-               argument(copiedK, call.Y)
+               argument(copiedK, &call.Y)
 
        case ir.OPANIC:
                call := call.(*ir.UnaryExpr)
-               argument(e.heapHole(), call.X)
+               argument(e.heapHole(), &call.X)
 
        case ir.OCOMPLEX:
                call := call.(*ir.BinaryExpr)
-               argument(e.discardHole(), call.X)
-               argument(e.discardHole(), call.Y)
+               argument(e.discardHole(), &call.X)
+               argument(e.discardHole(), &call.Y)
        case ir.ODELETE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
                call := call.(*ir.CallExpr)
-               for _, arg := range call.Args {
-                       argument(e.discardHole(), arg)
+               for i := range call.Args {
+                       argument(e.discardHole(), &call.Args[i])
                }
        case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
                call := call.(*ir.UnaryExpr)
-               argument(e.discardHole(), call.X)
+               argument(e.discardHole(), &call.X)
 
        case ir.OUNSAFEADD, ir.OUNSAFESLICE:
                call := call.(*ir.BinaryExpr)
-               argument(ks[0], call.X)
-               argument(e.discardHole(), call.Y)
+               argument(ks[0], &call.X)
+               argument(e.discardHole(), &call.Y)
        }
 }
 
+func (e *escape) goDeferStmt(n *ir.GoDeferStmt) {
+       topLevelDefer := n.Op() == ir.ODEFER && e.loopDepth == 1
+       if topLevelDefer {
+               // force stack allocation of defer record, unless
+               // open-coded defers are used (see ssa.go)
+               n.SetEsc(ir.EscNever)
+       }
+
+       e.stmts(n.Call.Init())
+       e.callCommon(nil, n.Call, n)
+}
+
 // tagHole returns a hole for evaluating an argument passed to param.
 // ks should contain the holes representing where the function
 // callee's results flows. fn is the statically-known callee function,
index 5b280c76f1fcffff51056b5d33a96ab72b1e8b29..cb95221dd5154741b1383ed3a8f9beca2c36e659 100644 (file)
@@ -139,7 +139,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
                e.discard(n.X)
 
        case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE:
-               e.call([]hole{k}, n, nil)
+               e.call([]hole{k}, n)
 
        case ir.ONEW:
                n := n.(*ir.UnaryExpr)
index d3e47290d378d0d9e33a47b40a5cbf64e794f032..0bdb07b27844a981c56036509601075c95c3654d 100644 (file)
@@ -163,7 +163,7 @@ func (e *escape) stmt(n ir.Node) {
                n := n.(*ir.AssignListStmt)
                e.stmts(n.Rhs[0].Init())
                ks := e.addrs(n.Lhs)
-               e.call(ks, n.Rhs[0], nil)
+               e.call(ks, n.Rhs[0])
                e.reassigned(ks, n)
        case ir.ORETURN:
                n := n.(*ir.ReturnStmt)
@@ -174,11 +174,10 @@ func (e *escape) stmt(n ir.Node) {
                }
                e.assignList(dsts, n.Results, "return", n)
        case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OCLOSE, ir.OCOPY, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
-               e.call(nil, n, nil)
+               e.call(nil, n)
        case ir.OGO, ir.ODEFER:
                n := n.(*ir.GoDeferStmt)
-               e.stmts(n.Call.Init())
-               e.call(nil, n.Call, n)
+               e.goDeferStmt(n)
 
        case ir.OTAILCALL:
                // TODO(mdempsky): Treat like a normal call? esc.go used to just ignore it.