From 9f4dd09bf555632a39a01a4c171e713acb55fda9 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 21 Apr 2020 15:37:29 -0700 Subject: [PATCH] cmd/compile: refactor variadac call desugaring 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 TryBot-Result: Gobot Gobot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/gc/walk.go | 76 ++++++++++++++++------------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 66f4eaf40b..fb8f1873d2 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -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 -- 2.50.0