]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: refactor variadac call desugaring
authorMatthew Dempsky <mdempsky@google.com>
Tue, 21 Apr 2020 22:37:29 +0000 (15:37 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 23 Apr 2020 06:24:40 +0000 (06:24 +0000)
In mid-Walk, we rewrite calls to variadic functions to use explicit
slice literals; e.g., rewriting f(a,b,c) into f([]T{a,b,c}...).
However, it would be useful to do that rewrite much earlier in the
compiler, so that other compiler passes can be simplified.

This CL refactors the rewrite logic into a new fixVariadicCall
function, which subsequent CLs can more easily move into earlier
compiler passes.

Passes toolstash-check -race.

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

index 66f4eaf40b574cd361d2868d6c8d22a8b0732635..fb8f1873d2300b67f5941c0dcb98f63d80268eca 100644 (file)
@@ -1717,57 +1717,65 @@ func ascompatet(nl Nodes, nr *types.Type) []*Node {
 }
 
 // package all the arguments that match a ... T parameter into a []T.
-func mkdotargslice(typ *types.Type, args []*Node, init *Nodes, ddd *Node) *Node {
-       esc := uint16(EscUnknown)
-       if ddd != nil {
-               esc = ddd.Esc
-       }
+func mkdotargslice(typ *types.Type, args []*Node) *Node {
+       var n *Node
        if len(args) == 0 {
-               n := nodnil()
+               n = nodnil()
                n.Type = typ
-               return n
+       } else {
+               n = nod(OCOMPLIT, nil, typenod(typ))
+               n.List.Append(args...)
        }
 
-       n := nod(OCOMPLIT, nil, typenod(typ))
-       if ddd != nil && prealloc[ddd] != nil {
-               prealloc[n] = prealloc[ddd] // temporary to use
-       }
-       n.List.Set(args)
-       n.Esc = esc
        n = typecheck(n, ctxExpr)
        if n.Type == nil {
                Fatalf("mkdotargslice: typecheck failed")
        }
-       n = walkexpr(n, init)
        return n
 }
 
+// fixVariadicCall rewrites calls to variadic functions to use an
+// explicit ... argument if one is not already present.
+func fixVariadicCall(call *Node, init *Nodes) {
+       fntype := call.Left.Type
+       if !fntype.IsVariadic() || call.IsDDD() {
+               return
+       }
+
+       vi := fntype.NumParams() - 1
+       vt := fntype.Params().Field(vi).Type
+
+       args := call.List.Slice()
+       extra := args[vi:]
+       slice := mkdotargslice(vt, extra)
+       for i := range extra {
+               extra[i] = nil // allow GC
+       }
+
+       if ddd := call.Right; ddd != nil && slice.Op == OSLICELIT {
+               slice.Esc = ddd.Esc
+               if prealloc[ddd] != nil {
+                       prealloc[slice] = prealloc[ddd] // temporary to use
+               }
+       }
+
+       slice = walkexpr(slice, init)
+
+       call.List.Set(append(args[:vi], slice))
+       call.SetIsDDD(true)
+}
+
 func walkCall(n *Node, init *Nodes) {
        if n.Rlist.Len() != 0 {
                return // already walked
        }
+
        n.Left = walkexpr(n.Left, init)
        walkexprlist(n.List.Slice(), init)
+       fixVariadicCall(n, init)
 
        params := n.Left.Type.Params()
        args := n.List.Slice()
-       // If there's a ... parameter (which is only valid as the final
-       // parameter) and this is not a ... call expression,
-       // then assign the remaining arguments as a slice.
-       if nf := params.NumFields(); nf > 0 {
-               if last := params.Field(nf - 1); last.IsDDD() && !n.IsDDD() {
-                       // The callsite does not use a ..., but the called function is declared
-                       // with a final argument that has a ... . Build the slice that we will
-                       // pass as the ... argument.
-                       tail := args[nf-1:]
-                       slice := mkdotargslice(last.Type, tail, init, n.Right)
-                       // Allow immediate GC.
-                       for i := range tail {
-                               tail[i] = nil
-                       }
-                       args = append(args[:nf-1], slice)
-               }
-       }
 
        // If this is a method call, add the receiver at the beginning of the args.
        if n.Op == OCALLMETH {
@@ -3979,10 +3987,8 @@ func walkCheckPtrArithmetic(n *Node, init *Nodes) *Node {
 
        n = cheapexpr(n, init)
 
-       ddd := nodl(n.Pos, ODDDARG, nil, nil)
-       ddd.Type = types.NewPtr(types.NewArray(types.Types[TUNSAFEPTR], int64(len(originals))))
-       ddd.Esc = EscNone
-       slice := mkdotargslice(types.NewSlice(types.Types[TUNSAFEPTR]), originals, init, ddd)
+       slice := mkdotargslice(types.NewSlice(types.Types[TUNSAFEPTR]), originals)
+       slice.Esc = EscNone
 
        init.Append(mkcall("checkptrArithmetic", nil, init, convnop(n, types.Types[TUNSAFEPTR]), slice))
        // TODO(khr): Mark backing store of slice as dead. This will allow us to reuse