From 25824c96dc34c0634dffb3860c3e01c666628606 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 18 Apr 2018 23:22:26 -0700 Subject: [PATCH] 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 TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/alg.go | 44 ++++++++-------- src/cmd/compile/internal/gc/closure.go | 72 ++++++-------------------- src/cmd/compile/internal/gc/dcl.go | 6 +++ src/cmd/compile/internal/gc/subr.go | 54 ++++++++----------- src/cmd/compile/internal/gc/walk.go | 9 ++-- src/cmd/compile/internal/types/type.go | 6 +++ 6 files changed, 76 insertions(+), 115 deletions(-) diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go index b17cab68bd..b7d88531fd 100644 --- a/src/cmd/compile/internal/gc/alg.go +++ b/src/cmd/compile/internal/gc/alg.go @@ -191,20 +191,18 @@ func genhash(sym *types.Sym, t *types.Type) { 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 @@ func genhash(sym *types.Sym, t *types.Type) { } 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 @@ func geneq(sym *types.Sym, t *types.Type) { 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 @@ func geneq(sym *types.Sym, t *types.Type) { } 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 6a05bef3aa..a0bf1e8cb9 100644 --- a/src/cmd/compile/internal/gc/closure.go +++ b/src/cmd/compile/internal/gc/closure.go @@ -91,7 +91,7 @@ func typecheckclosure(clo *Node, top int) { } 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 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node { 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 - } - - 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) + tfn := nod(OTFUNC, nil, nil) + tfn.List.Set(structargs(t0.Params(), true)) + tfn.Rlist.Set(structargs(t0.Results(), false)) + 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 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node { } 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 5db2c67d7f..0bb3c530f1 100644 --- a/src/cmd/compile/internal/gc/dcl.go +++ b/src/cmd/compile/internal/gc/dcl.go @@ -1026,6 +1026,12 @@ func makefuncsym(s *types.Sym) { } } +// 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 2f8f92271e..4d87f0da26 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -1639,31 +1639,18 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { } 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) - t := nod(OTFUNC, nil, nil) - t.List.Set(append([]*Node{this}, in...)) - t.Rlist.Set(out) + 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)) - 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 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { 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 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { 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 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { } 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 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { 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 c7c39232f4..3ad18a17e3 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -3861,12 +3861,9 @@ func wrapCall(n *Node, init *Nodes) *Node { } 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 @@ func wrapCall(n *Node, init *Nodes) *Node { 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 f5e9237b81..55d0930ceb 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -710,6 +710,12 @@ func (t *Type) NumRecvs() int { return t.FuncType().Receiver.NumFields() } 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() -- 2.48.1