Commit 25824c96 authored by Matthew Dempsky's avatar Matthew Dempsky

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: default avatarRobert Griesemer <gri@golang.org>
parent 60e3ebb9
...@@ -191,20 +191,18 @@ func genhash(sym *types.Sym, t *types.Type) { ...@@ -191,20 +191,18 @@ func genhash(sym *types.Sym, t *types.Type) {
lineno = autogeneratedPos // less confusing than end of input lineno = autogeneratedPos // less confusing than end of input
dclcontext = PEXTERN dclcontext = PEXTERN
types.Markdcl()
// func sym(p *T, h uintptr) uintptr // func sym(p *T, h uintptr) uintptr
tfn := nod(OTFUNC, nil, nil) tfn := nod(OTFUNC, nil, nil)
n := namedfield("p", types.NewPtr(t)) tfn.List.Set2(
tfn.List.Append(n) namedfield("p", types.NewPtr(t)),
np := n.Left namedfield("h", types.Types[TUINTPTR]),
n = namedfield("h", types.Types[TUINTPTR]) )
tfn.List.Append(n) tfn.Rlist.Set1(anonfield(types.Types[TUINTPTR]))
nh := n.Left
n = anonfield(types.Types[TUINTPTR]) // return value
tfn.Rlist.Append(n)
fn := dclfunc(sym, tfn) 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 // genhash is only called for types that have equality but
// cannot be handled by the standard algorithms, // cannot be handled by the standard algorithms,
...@@ -290,12 +288,14 @@ func genhash(sym *types.Sym, t *types.Type) { ...@@ -290,12 +288,14 @@ func genhash(sym *types.Sym, t *types.Type) {
} }
funcbody() funcbody()
Curfn = fn
fn.Func.SetDupok(true) fn.Func.SetDupok(true)
fn = typecheck(fn, Etop) fn = typecheck(fn, Etop)
Curfn = fn
typecheckslice(fn.Nbody.Slice(), Etop) typecheckslice(fn.Nbody.Slice(), Etop)
Curfn = nil Curfn = nil
types.Popdcl()
if debug_dclstack != 0 { if debug_dclstack != 0 {
testdclstack() testdclstack()
} }
...@@ -358,20 +358,18 @@ func geneq(sym *types.Sym, t *types.Type) { ...@@ -358,20 +358,18 @@ func geneq(sym *types.Sym, t *types.Type) {
lineno = autogeneratedPos // less confusing than end of input lineno = autogeneratedPos // less confusing than end of input
dclcontext = PEXTERN dclcontext = PEXTERN
types.Markdcl()
// func sym(p, q *T) bool // func sym(p, q *T) bool
tfn := nod(OTFUNC, nil, nil) tfn := nod(OTFUNC, nil, nil)
n := namedfield("p", types.NewPtr(t)) tfn.List.Set2(
tfn.List.Append(n) namedfield("p", types.NewPtr(t)),
np := n.Left namedfield("q", types.NewPtr(t)),
n = namedfield("q", types.NewPtr(t)) )
tfn.List.Append(n) tfn.Rlist.Set1(anonfield(types.Types[TBOOL]))
nq := n.Left
n = anonfield(types.Types[TBOOL])
tfn.Rlist.Append(n)
fn := dclfunc(sym, tfn) 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 // geneq is only called for types that have equality but
// cannot be handled by the standard algorithms, // cannot be handled by the standard algorithms,
...@@ -474,12 +472,14 @@ func geneq(sym *types.Sym, t *types.Type) { ...@@ -474,12 +472,14 @@ func geneq(sym *types.Sym, t *types.Type) {
} }
funcbody() funcbody()
Curfn = fn
fn.Func.SetDupok(true) fn.Func.SetDupok(true)
fn = typecheck(fn, Etop) fn = typecheck(fn, Etop)
Curfn = fn
typecheckslice(fn.Nbody.Slice(), Etop) typecheckslice(fn.Nbody.Slice(), Etop)
Curfn = nil Curfn = nil
types.Popdcl()
if debug_dclstack != 0 { if debug_dclstack != 0 {
testdclstack() testdclstack()
} }
......
...@@ -91,7 +91,7 @@ func typecheckclosure(clo *Node, top int) { ...@@ -91,7 +91,7 @@ func typecheckclosure(clo *Node, top int) {
} }
xfunc.Func.Nname.Sym = closurename(Curfn) xfunc.Func.Nname.Sym = closurename(Curfn)
xfunc.Func.Nname.Sym.SetOnExportList(true) // disable export disableExport(xfunc.Func.Nname.Sym)
declare(xfunc.Func.Nname, PFUNC) declare(xfunc.Func.Nname, PFUNC)
xfunc = typecheck(xfunc, Etop) xfunc = typecheck(xfunc, Etop)
...@@ -433,59 +433,24 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node { ...@@ -433,59 +433,24 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
savecurfn := Curfn savecurfn := Curfn
Curfn = nil Curfn = nil
xtype := nod(OTFUNC, nil, nil) tfn := nod(OTFUNC, nil, nil)
var l []*Node tfn.List.Set(structargs(t0.Params(), true))
var callargs []*Node tfn.Rlist.Set(structargs(t0.Results(), false))
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)
disableExport(sym)
xfunc := dclfunc(sym, tfn)
xfunc.Func.SetDupok(true) xfunc.Func.SetDupok(true)
xfunc.Func.Nname = newfuncname(sym) xfunc.Func.SetNeedctxt(true)
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)
// Declare and initialize variable holding receiver. // Declare and initialize variable holding receiver.
xfunc.Func.SetNeedctxt(true)
cv := nod(OCLOSUREVAR, nil, nil) cv := nod(OCLOSUREVAR, nil, nil)
cv.Type = rcvrtype cv.Type = rcvrtype
cv.Xoffset = Rnd(int64(Widthptr), int64(cv.Type.Align)) cv.Xoffset = Rnd(int64(Widthptr), int64(cv.Type.Align))
ptr := newname(lookup("rcvr")) ptr := newname(lookup(".this"))
ptr.SetClass(PAUTO) declare(ptr, PAUTO)
ptr.Name.SetUsed(true) ptr.Name.SetUsed(true)
ptr.Name.Curfn = xfunc
xfunc.Func.Dcl = append(xfunc.Func.Dcl, ptr)
var body []*Node var body []*Node
if rcvrtype.IsPtr() || rcvrtype.IsInterface() { if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
ptr.Type = rcvrtype ptr.Type = rcvrtype
...@@ -496,20 +461,17 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node { ...@@ -496,20 +461,17 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
} }
call := nod(OCALL, nodSym(OXDOT, ptr, meth), nil) call := nod(OCALL, nodSym(OXDOT, ptr, meth), nil)
call.List.Set(callargs) call.List.Set(paramNnames(tfn.Type))
call.SetIsddd(ddd) call.SetIsddd(tfn.Type.IsVariadic())
if t0.NumResults() == 0 { if t0.NumResults() != 0 {
body = append(body, call) n := nod(ORETURN, nil, nil)
} else { n.List.Set1(call)
n := nod(OAS2, nil, nil) call = n
n.List.Set(retargs)
n.Rlist.Set1(call)
body = append(body, n)
n = nod(ORETURN, nil, nil)
body = append(body, n)
} }
body = append(body, call)
xfunc.Nbody.Set(body) xfunc.Nbody.Set(body)
funcbody()
xfunc = typecheck(xfunc, Etop) xfunc = typecheck(xfunc, Etop)
sym.Def = asTypesNode(xfunc) sym.Def = asTypesNode(xfunc)
......
...@@ -1026,6 +1026,12 @@ func makefuncsym(s *types.Sym) { ...@@ -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 { func dclfunc(sym *types.Sym, tfn *Node) *Node {
if tfn.Op != OTFUNC { if tfn.Op != OTFUNC {
Fatalf("expected OTFUNC node, got %v", tfn) Fatalf("expected OTFUNC node, got %v", tfn)
......
...@@ -1639,31 +1639,18 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { ...@@ -1639,31 +1639,18 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
} }
lineno = autogeneratedPos lineno = autogeneratedPos
dclcontext = PEXTERN 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) tfn := nod(OTFUNC, nil, nil)
t.List.Set(append([]*Node{this}, in...)) tfn.Left = namedfield(".this", rcvr)
t.Rlist.Set(out) tfn.List.Set(structargs(method.Type.Params(), true))
tfn.Rlist.Set(structargs(method.Type.Results(), false))
newnam.SetOnExportList(true) // prevent export; see closure.go disableExport(newnam)
fn := dclfunc(newnam, t) fn := dclfunc(newnam, tfn)
fn.Func.SetDupok(true) fn.Func.SetDupok(true)
// arg list nthis := asNode(tfn.Type.Recv().Nname)
var args []*Node
isddd := false
for _, n := range in {
args = append(args, n.Left)
isddd = n.Left.Isddd()
}
methodrcvr := method.Type.Recv().Type methodrcvr := method.Type.Recv().Type
...@@ -1671,13 +1658,13 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { ...@@ -1671,13 +1658,13 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
if rcvr.IsPtr() && rcvr.Elem() == methodrcvr { if rcvr.IsPtr() && rcvr.Elem() == methodrcvr {
// generating wrapper from *T to T. // generating wrapper from *T to T.
n := nod(OIF, nil, nil) n := nod(OIF, nil, nil)
n.Left = nod(OEQ, this.Left, nodnil()) n.Left = nod(OEQ, nthis, nodnil())
call := nod(OCALL, syslook("panicwrap"), nil) call := nod(OCALL, syslook("panicwrap"), nil)
n.Nbody.Set1(call) n.Nbody.Set1(call)
fn.Nbody.Append(n) fn.Nbody.Append(n)
} }
dot := adddot(nodSym(OXDOT, this.Left, method.Sym)) dot := adddot(nodSym(OXDOT, nthis, method.Sym))
// generate call // generate call
// It's not possible to use a tail call when dynamic linking on ppc64le. The // 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) { ...@@ -1693,21 +1680,20 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
if !dotlist[0].field.Type.IsPtr() { if !dotlist[0].field.Type.IsPtr() {
dot = nod(OADDR, dot, nil) 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 as.Right.Type = rcvr
fn.Nbody.Append(as) fn.Nbody.Append(as)
fn.Nbody.Append(nodSym(ORETJMP, nil, methodSym(methodrcvr, method.Sym))) fn.Nbody.Append(nodSym(ORETJMP, nil, methodSym(methodrcvr, method.Sym)))
} else { } else {
fn.Func.SetWrapper(true) // ignore frame for panic+recover matching fn.Func.SetWrapper(true) // ignore frame for panic+recover matching
call := nod(OCALL, dot, nil) call := nod(OCALL, dot, nil)
call.List.Set(args) call.List.Set(paramNnames(tfn.Type))
call.SetIsddd(isddd) call.SetIsddd(tfn.Type.IsVariadic())
if method.Type.NumResults() > 0 { if method.Type.NumResults() > 0 {
n := nod(ORETURN, nil, nil) n := nod(ORETURN, nil, nil)
n.List.Set1(call) n.List.Set1(call)
call = n call = n
} }
fn.Nbody.Append(call) fn.Nbody.Append(call)
} }
...@@ -1716,17 +1702,13 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { ...@@ -1716,17 +1702,13 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
} }
funcbody() funcbody()
Curfn = fn
types.Popdcl()
if debug_dclstack != 0 { if debug_dclstack != 0 {
testdclstack() 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) fn = typecheck(fn, Etop)
Curfn = fn
typecheckslice(fn.Nbody.Slice(), Etop) typecheckslice(fn.Nbody.Slice(), Etop)
inlcalls(fn) inlcalls(fn)
...@@ -1736,6 +1718,14 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { ...@@ -1736,6 +1718,14 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
funccompile(fn) 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 { func hashmem(t *types.Type) *Node {
sym := Runtimepkg.Lookup("memhash") sym := Runtimepkg.Lookup("memhash")
......
...@@ -3861,12 +3861,9 @@ func wrapCall(n *Node, init *Nodes) *Node { ...@@ -3861,12 +3861,9 @@ func wrapCall(n *Node, init *Nodes) *Node {
} }
t := nod(OTFUNC, nil, nil) t := nod(OTFUNC, nil, nil)
var args []*Node
for i, arg := range n.List.Slice() { for i, arg := range n.List.Slice() {
buf := fmt.Sprintf("a%d", i) s := lookupN("a", i)
a := namedfield(buf, arg.Type) t.List.Append(symfield(s, arg.Type))
t.List.Append(a)
args = append(args, a.Left)
} }
wrapCall_prgen++ wrapCall_prgen++
...@@ -3874,7 +3871,7 @@ func wrapCall(n *Node, init *Nodes) *Node { ...@@ -3874,7 +3871,7 @@ func wrapCall(n *Node, init *Nodes) *Node {
fn := dclfunc(sym, t) fn := dclfunc(sym, t)
a := nod(n.Op, nil, nil) a := nod(n.Op, nil, nil)
a.List.Set(args) a.List.Set(paramNnames(t.Type))
a = typecheck(a, Etop) a = typecheck(a, Etop)
fn.Nbody.Set1(a) fn.Nbody.Set1(a)
......
...@@ -710,6 +710,12 @@ func (t *Type) NumRecvs() int { return t.FuncType().Receiver.NumFields() } ...@@ -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) NumParams() int { return t.FuncType().Params.NumFields() }
func (t *Type) NumResults() int { return t.FuncType().Results.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. // Recv returns the receiver of function type t, if any.
func (t *Type) Recv() *Field { func (t *Type) Recv() *Field {
s := t.Recvs() s := t.Recvs()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment