cmd/compile: make generated function code more consistent

There are a bunch of places where we generate functions: equality and
hash functions; method expression and promoted method wrappers; and
print/delete wrappers for defer/go statements.

This CL brings them in sync by:

1) Always using dclfunc and funcbody. Most were already using this,
but makepartialcall needed some changes.

2) Removing duplicate types.Markdcl/types.Popdcl calls. These are
already handled by dclfunc and funcbody.

3) Using structargs (already used by genwrapper) to construct new
param/result lists from existing types.

4) Always accessing the parameter ONAME nodes through Field.Nname
instead of poking into the ODCLFIELD. Also, since creating a slice of
the entire parameter list is common, extract this out into a
paramNnames helper function.

5) Add a Type.IsVariadic method to simplify identifying variadic
function types.

Passes toolstash-check -gcflags=-dwarf=false. DWARF output changes
because using structargs in makepartialcall changes the generated
parameter names.

Change-Id: I6661d3699afdbe7852ad60db5a4ec6eeb2b696e4
Reviewed-on: https://go-review.googlesource.com/108216
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
index b17cab6..b7d8853 100644
--- a/src/cmd/compile/internal/gc/alg.go
+++ b/src/cmd/compile/internal/gc/alg.go
@@ -191,20 +191,18 @@
 
 	lineno = autogeneratedPos // less confusing than end of input
 	dclcontext = PEXTERN
-	types.Markdcl()
 
 	// func sym(p *T, h uintptr) uintptr
 	tfn := nod(OTFUNC, nil, nil)
-	n := namedfield("p", types.NewPtr(t))
-	tfn.List.Append(n)
-	np := n.Left
-	n = namedfield("h", types.Types[TUINTPTR])
-	tfn.List.Append(n)
-	nh := n.Left
-	n = anonfield(types.Types[TUINTPTR]) // return value
-	tfn.Rlist.Append(n)
+	tfn.List.Set2(
+		namedfield("p", types.NewPtr(t)),
+		namedfield("h", types.Types[TUINTPTR]),
+	)
+	tfn.Rlist.Set1(anonfield(types.Types[TUINTPTR]))
 
 	fn := dclfunc(sym, tfn)
+	np := asNode(tfn.Type.Params().Field(0).Nname)
+	nh := asNode(tfn.Type.Params().Field(1).Nname)
 
 	// genhash is only called for types that have equality but
 	// cannot be handled by the standard algorithms,
@@ -290,12 +288,14 @@
 	}
 
 	funcbody()
-	Curfn = fn
+
 	fn.Func.SetDupok(true)
 	fn = typecheck(fn, Etop)
+
+	Curfn = fn
 	typecheckslice(fn.Nbody.Slice(), Etop)
 	Curfn = nil
-	types.Popdcl()
+
 	if debug_dclstack != 0 {
 		testdclstack()
 	}
@@ -358,20 +358,18 @@
 
 	lineno = autogeneratedPos // less confusing than end of input
 	dclcontext = PEXTERN
-	types.Markdcl()
 
 	// func sym(p, q *T) bool
 	tfn := nod(OTFUNC, nil, nil)
-	n := namedfield("p", types.NewPtr(t))
-	tfn.List.Append(n)
-	np := n.Left
-	n = namedfield("q", types.NewPtr(t))
-	tfn.List.Append(n)
-	nq := n.Left
-	n = anonfield(types.Types[TBOOL])
-	tfn.Rlist.Append(n)
+	tfn.List.Set2(
+		namedfield("p", types.NewPtr(t)),
+		namedfield("q", types.NewPtr(t)),
+	)
+	tfn.Rlist.Set1(anonfield(types.Types[TBOOL]))
 
 	fn := dclfunc(sym, tfn)
+	np := asNode(tfn.Type.Params().Field(0).Nname)
+	nq := asNode(tfn.Type.Params().Field(1).Nname)
 
 	// geneq is only called for types that have equality but
 	// cannot be handled by the standard algorithms,
@@ -474,12 +472,14 @@
 	}
 
 	funcbody()
-	Curfn = fn
+
 	fn.Func.SetDupok(true)
 	fn = typecheck(fn, Etop)
+
+	Curfn = fn
 	typecheckslice(fn.Nbody.Slice(), Etop)
 	Curfn = nil
-	types.Popdcl()
+
 	if debug_dclstack != 0 {
 		testdclstack()
 	}
diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
index 6a05bef..a0bf1e8 100644
--- a/src/cmd/compile/internal/gc/closure.go
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -91,7 +91,7 @@
 	}
 
 	xfunc.Func.Nname.Sym = closurename(Curfn)
-	xfunc.Func.Nname.Sym.SetOnExportList(true) // disable export
+	disableExport(xfunc.Func.Nname.Sym)
 	declare(xfunc.Func.Nname, PFUNC)
 	xfunc = typecheck(xfunc, Etop)
 
@@ -433,59 +433,24 @@
 	savecurfn := Curfn
 	Curfn = nil
 
-	xtype := nod(OTFUNC, nil, nil)
-	var l []*Node
-	var callargs []*Node
-	ddd := false
-	xfunc := nod(ODCLFUNC, nil, nil)
-	Curfn = xfunc
-	for i, t := range t0.Params().Fields().Slice() {
-		n := newname(lookupN("a", i))
-		n.SetClass(PPARAM)
-		xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
-		callargs = append(callargs, n)
-		fld := nod(ODCLFIELD, n, typenod(t.Type))
-		if t.Isddd() {
-			fld.SetIsddd(true)
-			ddd = true
-		}
+	tfn := nod(OTFUNC, nil, nil)
+	tfn.List.Set(structargs(t0.Params(), true))
+	tfn.Rlist.Set(structargs(t0.Results(), false))
 
-		l = append(l, fld)
-	}
-
-	xtype.List.Set(l)
-	l = nil
-	var retargs []*Node
-	for i, t := range t0.Results().Fields().Slice() {
-		n := newname(lookupN("r", i))
-		n.SetClass(PPARAMOUT)
-		xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
-		retargs = append(retargs, n)
-		l = append(l, nod(ODCLFIELD, n, typenod(t.Type)))
-	}
-
-	xtype.Rlist.Set(l)
-
+	disableExport(sym)
+	xfunc := dclfunc(sym, tfn)
 	xfunc.Func.SetDupok(true)
-	xfunc.Func.Nname = newfuncname(sym)
-	xfunc.Func.Nname.Sym.SetOnExportList(true) // disable export
-	xfunc.Func.Nname.Name.Param.Ntype = xtype
-	xfunc.Func.Nname.Name.Defn = xfunc
-	declare(xfunc.Func.Nname, PFUNC)
+	xfunc.Func.SetNeedctxt(true)
 
 	// Declare and initialize variable holding receiver.
 
-	xfunc.Func.SetNeedctxt(true)
-
 	cv := nod(OCLOSUREVAR, nil, nil)
 	cv.Type = rcvrtype
 	cv.Xoffset = Rnd(int64(Widthptr), int64(cv.Type.Align))
 
-	ptr := newname(lookup("rcvr"))
-	ptr.SetClass(PAUTO)
+	ptr := newname(lookup(".this"))
+	declare(ptr, PAUTO)
 	ptr.Name.SetUsed(true)
-	ptr.Name.Curfn = xfunc
-	xfunc.Func.Dcl = append(xfunc.Func.Dcl, ptr)
 	var body []*Node
 	if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
 		ptr.Type = rcvrtype
@@ -496,20 +461,17 @@
 	}
 
 	call := nod(OCALL, nodSym(OXDOT, ptr, meth), nil)
-	call.List.Set(callargs)
-	call.SetIsddd(ddd)
-	if t0.NumResults() == 0 {
-		body = append(body, call)
-	} else {
-		n := nod(OAS2, nil, nil)
-		n.List.Set(retargs)
-		n.Rlist.Set1(call)
-		body = append(body, n)
-		n = nod(ORETURN, nil, nil)
-		body = append(body, n)
+	call.List.Set(paramNnames(tfn.Type))
+	call.SetIsddd(tfn.Type.IsVariadic())
+	if t0.NumResults() != 0 {
+		n := nod(ORETURN, nil, nil)
+		n.List.Set1(call)
+		call = n
 	}
+	body = append(body, call)
 
 	xfunc.Nbody.Set(body)
+	funcbody()
 
 	xfunc = typecheck(xfunc, Etop)
 	sym.Def = asTypesNode(xfunc)
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
index 5db2c67..0bb3c53 100644
--- a/src/cmd/compile/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -1026,6 +1026,12 @@
 	}
 }
 
+// disableExport prevents sym from being included in package export
+// data. To be effectual, it must be called before declare.
+func disableExport(sym *types.Sym) {
+	sym.SetOnExportList(true)
+}
+
 func dclfunc(sym *types.Sym, tfn *Node) *Node {
 	if tfn.Op != OTFUNC {
 		Fatalf("expected OTFUNC node, got %v", tfn)
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 2f8f922..4d87f0d 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -1639,31 +1639,18 @@
 	}
 
 	lineno = autogeneratedPos
-
 	dclcontext = PEXTERN
-	types.Markdcl()
 
-	this := namedfield(".this", rcvr)
-	this.Left.Name.Param.Ntype = this.Right
-	in := structargs(method.Type.Params(), true)
-	out := structargs(method.Type.Results(), false)
+	tfn := nod(OTFUNC, nil, nil)
+	tfn.Left = namedfield(".this", rcvr)
+	tfn.List.Set(structargs(method.Type.Params(), true))
+	tfn.Rlist.Set(structargs(method.Type.Results(), false))
 
-	t := nod(OTFUNC, nil, nil)
-	t.List.Set(append([]*Node{this}, in...))
-	t.Rlist.Set(out)
-
-	newnam.SetOnExportList(true) // prevent export; see closure.go
-	fn := dclfunc(newnam, t)
+	disableExport(newnam)
+	fn := dclfunc(newnam, tfn)
 	fn.Func.SetDupok(true)
 
-	// arg list
-	var args []*Node
-
-	isddd := false
-	for _, n := range in {
-		args = append(args, n.Left)
-		isddd = n.Left.Isddd()
-	}
+	nthis := asNode(tfn.Type.Recv().Nname)
 
 	methodrcvr := method.Type.Recv().Type
 
@@ -1671,13 +1658,13 @@
 	if rcvr.IsPtr() && rcvr.Elem() == methodrcvr {
 		// generating wrapper from *T to T.
 		n := nod(OIF, nil, nil)
-		n.Left = nod(OEQ, this.Left, nodnil())
+		n.Left = nod(OEQ, nthis, nodnil())
 		call := nod(OCALL, syslook("panicwrap"), nil)
 		n.Nbody.Set1(call)
 		fn.Nbody.Append(n)
 	}
 
-	dot := adddot(nodSym(OXDOT, this.Left, method.Sym))
+	dot := adddot(nodSym(OXDOT, nthis, method.Sym))
 
 	// generate call
 	// It's not possible to use a tail call when dynamic linking on ppc64le. The
@@ -1693,21 +1680,20 @@
 		if !dotlist[0].field.Type.IsPtr() {
 			dot = nod(OADDR, dot, nil)
 		}
-		as := nod(OAS, this.Left, nod(OCONVNOP, dot, nil))
+		as := nod(OAS, nthis, nod(OCONVNOP, dot, nil))
 		as.Right.Type = rcvr
 		fn.Nbody.Append(as)
 		fn.Nbody.Append(nodSym(ORETJMP, nil, methodSym(methodrcvr, method.Sym)))
 	} else {
 		fn.Func.SetWrapper(true) // ignore frame for panic+recover matching
 		call := nod(OCALL, dot, nil)
-		call.List.Set(args)
-		call.SetIsddd(isddd)
+		call.List.Set(paramNnames(tfn.Type))
+		call.SetIsddd(tfn.Type.IsVariadic())
 		if method.Type.NumResults() > 0 {
 			n := nod(ORETURN, nil, nil)
 			n.List.Set1(call)
 			call = n
 		}
-
 		fn.Nbody.Append(call)
 	}
 
@@ -1716,17 +1702,13 @@
 	}
 
 	funcbody()
-	Curfn = fn
-	types.Popdcl()
 	if debug_dclstack != 0 {
 		testdclstack()
 	}
 
-	// wrappers where T is anonymous (struct or interface) can be duplicated.
-	if rcvr.IsStruct() || rcvr.IsInterface() || rcvr.IsPtr() && rcvr.Elem().IsStruct() {
-		fn.Func.SetDupok(true)
-	}
 	fn = typecheck(fn, Etop)
+
+	Curfn = fn
 	typecheckslice(fn.Nbody.Slice(), Etop)
 
 	inlcalls(fn)
@@ -1736,6 +1718,14 @@
 	funccompile(fn)
 }
 
+func paramNnames(ft *types.Type) []*Node {
+	args := make([]*Node, ft.NumParams())
+	for i, f := range ft.Params().FieldSlice() {
+		args[i] = asNode(f.Nname)
+	}
+	return args
+}
+
 func hashmem(t *types.Type) *Node {
 	sym := Runtimepkg.Lookup("memhash")
 
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index c7c3923..3ad18a1 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -3861,12 +3861,9 @@
 	}
 
 	t := nod(OTFUNC, nil, nil)
-	var args []*Node
 	for i, arg := range n.List.Slice() {
-		buf := fmt.Sprintf("a%d", i)
-		a := namedfield(buf, arg.Type)
-		t.List.Append(a)
-		args = append(args, a.Left)
+		s := lookupN("a", i)
+		t.List.Append(symfield(s, arg.Type))
 	}
 
 	wrapCall_prgen++
@@ -3874,7 +3871,7 @@
 	fn := dclfunc(sym, t)
 
 	a := nod(n.Op, nil, nil)
-	a.List.Set(args)
+	a.List.Set(paramNnames(t.Type))
 	a = typecheck(a, Etop)
 	fn.Nbody.Set1(a)
 
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index f5e9237..55d0930 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -710,6 +710,12 @@
 func (t *Type) NumParams() int  { return t.FuncType().Params.NumFields() }
 func (t *Type) NumResults() int { return t.FuncType().Results.NumFields() }
 
+// IsVariadic reports whether function type t is variadic.
+func (t *Type) IsVariadic() bool {
+	n := t.NumParams()
+	return n > 0 && t.Params().Field(n-1).Isddd()
+}
+
 // Recv returns the receiver of function type t, if any.
 func (t *Type) Recv() *Field {
 	s := t.Recvs()