mirror of
https://github.com/golang/go
synced 2024-11-26 05:17:58 -07:00
[dev.regabi] cmd/compile: clean up Node.Func
The original meaning of type Func was "extra fields factored out of a few cases of type Node having to do with functions", but those specific cases didn't necessarily have any relation. A typical declared function is represented by an ODCLFUNC Node at its declaration and an ONAME node at its uses, and both those have a .Func field, but they are *different* Funcs. Similarly, a closure is represented both by an OCLOSURE Node for the value itself and an ODCLFUNC Node for the underlying function implementing the closure. Those too have *different* Funcs, and the Func.Closure field in one points to the other and vice versa. This has led to no end of confusion over the years. This CL elevates type Func to be the canonical identifier for a given Go function. This looks like a trivial CL but in fact is the result of a lot of scaffolding and rewriting, discarded once the result was achieved, to separate out the three different kinds of Func nodes into three separate fields, limited in use to each specific Node type, to understand which Func fields are used by which Node types and what the possible overlaps are. There were a few overlaps, most notably around closures, which led to more fields being added to type Func to keep them separate even though there is now a single Func instead of two different ones for each function. A future CL can and should change Curfn to be a *Func instead of a *Node, finally eliminating the confusion about whether Curfn is an ODCLFUNC node (as it is most of the time) or an ONAME node (as it is when type-checking an inlined function body). Although sizeof_test.go makes it look like Func is growing by two words, there are now half as many Funcs in a running compilation, so the memory footprint has actually been reduced substantially. Change-Id: I598bd96c95728093dc769a835d48f2154a406a61 Reviewed-on: https://go-review.googlesource.com/c/go/+/272253 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
8e2106327c
commit
fd11a32c92
@ -15,25 +15,25 @@ func (p *noder) funcLit(expr *syntax.FuncLit) *Node {
|
|||||||
xtype := p.typeExpr(expr.Type)
|
xtype := p.typeExpr(expr.Type)
|
||||||
ntype := p.typeExpr(expr.Type)
|
ntype := p.typeExpr(expr.Type)
|
||||||
|
|
||||||
xfunc := p.nod(expr, ODCLFUNC, nil, nil)
|
dcl := p.nod(expr, ODCLFUNC, nil, nil)
|
||||||
xfunc.Func.SetIsHiddenClosure(Curfn != nil)
|
fn := dcl.Func
|
||||||
xfunc.Func.Nname = newfuncnamel(p.pos(expr), nblank.Sym) // filled in by typecheckclosure
|
fn.SetIsHiddenClosure(Curfn != nil)
|
||||||
xfunc.Func.Nname.Name.Param.Ntype = xtype
|
fn.Nname = newfuncnamel(p.pos(expr), nblank.Sym, fn) // filled in by typecheckclosure
|
||||||
xfunc.Func.Nname.Name.Defn = xfunc
|
fn.Nname.Name.Param.Ntype = xtype
|
||||||
|
fn.Nname.Name.Defn = dcl
|
||||||
|
|
||||||
clo := p.nod(expr, OCLOSURE, nil, nil)
|
clo := p.nod(expr, OCLOSURE, nil, nil)
|
||||||
clo.Func.Ntype = ntype
|
clo.Func = fn
|
||||||
|
fn.ClosureType = ntype
|
||||||
|
fn.OClosure = clo
|
||||||
|
|
||||||
xfunc.Func.Closure = clo
|
p.funcBody(dcl, expr.Body)
|
||||||
clo.Func.Closure = xfunc
|
|
||||||
|
|
||||||
p.funcBody(xfunc, expr.Body)
|
|
||||||
|
|
||||||
// closure-specific variables are hanging off the
|
// closure-specific variables are hanging off the
|
||||||
// ordinary ones in the symbol table; see oldname.
|
// ordinary ones in the symbol table; see oldname.
|
||||||
// unhook them.
|
// unhook them.
|
||||||
// make the list of pointers for the closure call.
|
// make the list of pointers for the closure call.
|
||||||
for _, v := range xfunc.Func.Cvars.Slice() {
|
for _, v := range fn.ClosureVars.Slice() {
|
||||||
// Unlink from v1; see comment in syntax.go type Param for these fields.
|
// Unlink from v1; see comment in syntax.go type Param for these fields.
|
||||||
v1 := v.Name.Defn
|
v1 := v.Name.Defn
|
||||||
v1.Name.Param.Innermost = v.Name.Param.Outer
|
v1.Name.Param.Innermost = v.Name.Param.Outer
|
||||||
@ -77,25 +77,26 @@ func (p *noder) funcLit(expr *syntax.FuncLit) *Node {
|
|||||||
// TODO: This creation of the named function should probably really be done in a
|
// TODO: This creation of the named function should probably really be done in a
|
||||||
// separate pass from type-checking.
|
// separate pass from type-checking.
|
||||||
func typecheckclosure(clo *Node, top int) {
|
func typecheckclosure(clo *Node, top int) {
|
||||||
xfunc := clo.Func.Closure
|
fn := clo.Func
|
||||||
|
dcl := fn.Decl
|
||||||
// Set current associated iota value, so iota can be used inside
|
// Set current associated iota value, so iota can be used inside
|
||||||
// function in ConstSpec, see issue #22344
|
// function in ConstSpec, see issue #22344
|
||||||
if x := getIotaValue(); x >= 0 {
|
if x := getIotaValue(); x >= 0 {
|
||||||
xfunc.SetIota(x)
|
dcl.SetIota(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
clo.Func.Ntype = typecheck(clo.Func.Ntype, ctxType)
|
fn.ClosureType = typecheck(fn.ClosureType, ctxType)
|
||||||
clo.Type = clo.Func.Ntype.Type
|
clo.Type = fn.ClosureType.Type
|
||||||
clo.Func.Top = top
|
fn.ClosureCalled = top&ctxCallee != 0
|
||||||
|
|
||||||
// Do not typecheck xfunc twice, otherwise, we will end up pushing
|
// Do not typecheck dcl twice, otherwise, we will end up pushing
|
||||||
// xfunc to xtop multiple times, causing initLSym called twice.
|
// dcl to xtop multiple times, causing initLSym called twice.
|
||||||
// See #30709
|
// See #30709
|
||||||
if xfunc.Typecheck() == 1 {
|
if dcl.Typecheck() == 1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ln := range xfunc.Func.Cvars.Slice() {
|
for _, ln := range fn.ClosureVars.Slice() {
|
||||||
n := ln.Name.Defn
|
n := ln.Name.Defn
|
||||||
if !n.Name.Captured() {
|
if !n.Name.Captured() {
|
||||||
n.Name.SetCaptured(true)
|
n.Name.SetCaptured(true)
|
||||||
@ -111,9 +112,9 @@ func typecheckclosure(clo *Node, top int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xfunc.Func.Nname.Sym = closurename(Curfn)
|
fn.Nname.Sym = closurename(Curfn)
|
||||||
setNodeNameFunc(xfunc.Func.Nname)
|
setNodeNameFunc(fn.Nname)
|
||||||
xfunc = typecheck(xfunc, ctxStmt)
|
dcl = typecheck(dcl, ctxStmt)
|
||||||
|
|
||||||
// Type check the body now, but only if we're inside a function.
|
// Type check the body now, but only if we're inside a function.
|
||||||
// At top level (in a variable initialization: curfn==nil) we're not
|
// At top level (in a variable initialization: curfn==nil) we're not
|
||||||
@ -121,15 +122,15 @@ func typecheckclosure(clo *Node, top int) {
|
|||||||
// underlying closure function we create is added to xtop.
|
// underlying closure function we create is added to xtop.
|
||||||
if Curfn != nil && clo.Type != nil {
|
if Curfn != nil && clo.Type != nil {
|
||||||
oldfn := Curfn
|
oldfn := Curfn
|
||||||
Curfn = xfunc
|
Curfn = dcl
|
||||||
olddd := decldepth
|
olddd := decldepth
|
||||||
decldepth = 1
|
decldepth = 1
|
||||||
typecheckslice(xfunc.Nbody.Slice(), ctxStmt)
|
typecheckslice(dcl.Nbody.Slice(), ctxStmt)
|
||||||
decldepth = olddd
|
decldepth = olddd
|
||||||
Curfn = oldfn
|
Curfn = oldfn
|
||||||
}
|
}
|
||||||
|
|
||||||
xtop = append(xtop, xfunc)
|
xtop = append(xtop, dcl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// globClosgen is like Func.Closgen, but for the global scope.
|
// globClosgen is like Func.Closgen, but for the global scope.
|
||||||
@ -143,7 +144,7 @@ func closurename(outerfunc *Node) *types.Sym {
|
|||||||
gen := &globClosgen
|
gen := &globClosgen
|
||||||
|
|
||||||
if outerfunc != nil {
|
if outerfunc != nil {
|
||||||
if outerfunc.Func.Closure != nil {
|
if outerfunc.Func.OClosure != nil {
|
||||||
prefix = ""
|
prefix = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,12 +170,11 @@ var capturevarscomplete bool
|
|||||||
// by value or by reference.
|
// by value or by reference.
|
||||||
// We use value capturing for values <= 128 bytes that are never reassigned
|
// We use value capturing for values <= 128 bytes that are never reassigned
|
||||||
// after capturing (effectively constant).
|
// after capturing (effectively constant).
|
||||||
func capturevars(xfunc *Node) {
|
func capturevars(dcl *Node) {
|
||||||
lno := lineno
|
lno := lineno
|
||||||
lineno = xfunc.Pos
|
lineno = dcl.Pos
|
||||||
|
fn := dcl.Func
|
||||||
clo := xfunc.Func.Closure
|
cvars := fn.ClosureVars.Slice()
|
||||||
cvars := xfunc.Func.Cvars.Slice()
|
|
||||||
out := cvars[:0]
|
out := cvars[:0]
|
||||||
for _, v := range cvars {
|
for _, v := range cvars {
|
||||||
if v.Type == nil {
|
if v.Type == nil {
|
||||||
@ -216,21 +216,21 @@ func capturevars(xfunc *Node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
outer = typecheck(outer, ctxExpr)
|
outer = typecheck(outer, ctxExpr)
|
||||||
clo.Func.Enter.Append(outer)
|
fn.ClosureEnter.Append(outer)
|
||||||
}
|
}
|
||||||
|
|
||||||
xfunc.Func.Cvars.Set(out)
|
fn.ClosureVars.Set(out)
|
||||||
lineno = lno
|
lineno = lno
|
||||||
}
|
}
|
||||||
|
|
||||||
// transformclosure is called in a separate phase after escape analysis.
|
// transformclosure is called in a separate phase after escape analysis.
|
||||||
// It transform closure bodies to properly reference captured variables.
|
// It transform closure bodies to properly reference captured variables.
|
||||||
func transformclosure(xfunc *Node) {
|
func transformclosure(dcl *Node) {
|
||||||
lno := lineno
|
lno := lineno
|
||||||
lineno = xfunc.Pos
|
lineno = dcl.Pos
|
||||||
clo := xfunc.Func.Closure
|
fn := dcl.Func
|
||||||
|
|
||||||
if clo.Func.Top&ctxCallee != 0 {
|
if fn.ClosureCalled {
|
||||||
// If the closure is directly called, we transform it to a plain function call
|
// If the closure is directly called, we transform it to a plain function call
|
||||||
// with variables passed as args. This avoids allocation of a closure object.
|
// with variables passed as args. This avoids allocation of a closure object.
|
||||||
// Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
|
// Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
|
||||||
@ -247,12 +247,12 @@ func transformclosure(xfunc *Node) {
|
|||||||
// }(byval, &byref, 42)
|
// }(byval, &byref, 42)
|
||||||
|
|
||||||
// f is ONAME of the actual function.
|
// f is ONAME of the actual function.
|
||||||
f := xfunc.Func.Nname
|
f := fn.Nname
|
||||||
|
|
||||||
// We are going to insert captured variables before input args.
|
// We are going to insert captured variables before input args.
|
||||||
var params []*types.Field
|
var params []*types.Field
|
||||||
var decls []*Node
|
var decls []*Node
|
||||||
for _, v := range xfunc.Func.Cvars.Slice() {
|
for _, v := range fn.ClosureVars.Slice() {
|
||||||
if !v.Name.Byval() {
|
if !v.Name.Byval() {
|
||||||
// If v of type T is captured by reference,
|
// If v of type T is captured by reference,
|
||||||
// we introduce function param &v *T
|
// we introduce function param &v *T
|
||||||
@ -275,16 +275,16 @@ func transformclosure(xfunc *Node) {
|
|||||||
if len(params) > 0 {
|
if len(params) > 0 {
|
||||||
// Prepend params and decls.
|
// Prepend params and decls.
|
||||||
f.Type.Params().SetFields(append(params, f.Type.Params().FieldSlice()...))
|
f.Type.Params().SetFields(append(params, f.Type.Params().FieldSlice()...))
|
||||||
xfunc.Func.Dcl = append(decls, xfunc.Func.Dcl...)
|
fn.Dcl = append(decls, fn.Dcl...)
|
||||||
}
|
}
|
||||||
|
|
||||||
dowidth(f.Type)
|
dowidth(f.Type)
|
||||||
xfunc.Type = f.Type // update type of ODCLFUNC
|
dcl.Type = f.Type // update type of ODCLFUNC
|
||||||
} else {
|
} else {
|
||||||
// The closure is not called, so it is going to stay as closure.
|
// The closure is not called, so it is going to stay as closure.
|
||||||
var body []*Node
|
var body []*Node
|
||||||
offset := int64(Widthptr)
|
offset := int64(Widthptr)
|
||||||
for _, v := range xfunc.Func.Cvars.Slice() {
|
for _, v := range fn.ClosureVars.Slice() {
|
||||||
// cv refers to the field inside of closure OSTRUCTLIT.
|
// cv refers to the field inside of closure OSTRUCTLIT.
|
||||||
cv := nod(OCLOSUREVAR, nil, nil)
|
cv := nod(OCLOSUREVAR, nil, nil)
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ func transformclosure(xfunc *Node) {
|
|||||||
if v.Name.Byval() && v.Type.Width <= int64(2*Widthptr) {
|
if v.Name.Byval() && v.Type.Width <= int64(2*Widthptr) {
|
||||||
// If it is a small variable captured by value, downgrade it to PAUTO.
|
// If it is a small variable captured by value, downgrade it to PAUTO.
|
||||||
v.SetClass(PAUTO)
|
v.SetClass(PAUTO)
|
||||||
xfunc.Func.Dcl = append(xfunc.Func.Dcl, v)
|
fn.Dcl = append(fn.Dcl, v)
|
||||||
body = append(body, nod(OAS, v, cv))
|
body = append(body, nod(OAS, v, cv))
|
||||||
} else {
|
} else {
|
||||||
// Declare variable holding addresses taken from closure
|
// Declare variable holding addresses taken from closure
|
||||||
@ -308,8 +308,8 @@ func transformclosure(xfunc *Node) {
|
|||||||
addr.Type = types.NewPtr(v.Type)
|
addr.Type = types.NewPtr(v.Type)
|
||||||
addr.SetClass(PAUTO)
|
addr.SetClass(PAUTO)
|
||||||
addr.Name.SetUsed(true)
|
addr.Name.SetUsed(true)
|
||||||
addr.Name.Curfn = xfunc
|
addr.Name.Curfn = dcl
|
||||||
xfunc.Func.Dcl = append(xfunc.Func.Dcl, addr)
|
fn.Dcl = append(fn.Dcl, addr)
|
||||||
v.Name.Param.Heapaddr = addr
|
v.Name.Param.Heapaddr = addr
|
||||||
if v.Name.Byval() {
|
if v.Name.Byval() {
|
||||||
cv = nod(OADDR, cv, nil)
|
cv = nod(OADDR, cv, nil)
|
||||||
@ -320,8 +320,8 @@ func transformclosure(xfunc *Node) {
|
|||||||
|
|
||||||
if len(body) > 0 {
|
if len(body) > 0 {
|
||||||
typecheckslice(body, ctxStmt)
|
typecheckslice(body, ctxStmt)
|
||||||
xfunc.Func.Enter.Set(body)
|
fn.Enter.Set(body)
|
||||||
xfunc.Func.SetNeedctxt(true)
|
fn.SetNeedctxt(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,19 +331,17 @@ func transformclosure(xfunc *Node) {
|
|||||||
// hasemptycvars reports whether closure clo has an
|
// hasemptycvars reports whether closure clo has an
|
||||||
// empty list of captured vars.
|
// empty list of captured vars.
|
||||||
func hasemptycvars(clo *Node) bool {
|
func hasemptycvars(clo *Node) bool {
|
||||||
xfunc := clo.Func.Closure
|
return clo.Func.ClosureVars.Len() == 0
|
||||||
return xfunc.Func.Cvars.Len() == 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// closuredebugruntimecheck applies boilerplate checks for debug flags
|
// closuredebugruntimecheck applies boilerplate checks for debug flags
|
||||||
// and compiling runtime
|
// and compiling runtime
|
||||||
func closuredebugruntimecheck(clo *Node) {
|
func closuredebugruntimecheck(clo *Node) {
|
||||||
if Debug_closure > 0 {
|
if Debug_closure > 0 {
|
||||||
xfunc := clo.Func.Closure
|
|
||||||
if clo.Esc == EscHeap {
|
if clo.Esc == EscHeap {
|
||||||
Warnl(clo.Pos, "heap closure, captured vars = %v", xfunc.Func.Cvars)
|
Warnl(clo.Pos, "heap closure, captured vars = %v", clo.Func.ClosureVars)
|
||||||
} else {
|
} else {
|
||||||
Warnl(clo.Pos, "stack closure, captured vars = %v", xfunc.Func.Cvars)
|
Warnl(clo.Pos, "stack closure, captured vars = %v", clo.Func.ClosureVars)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if compiling_runtime && clo.Esc == EscHeap {
|
if compiling_runtime && clo.Esc == EscHeap {
|
||||||
@ -371,7 +369,7 @@ func closureType(clo *Node) *types.Type {
|
|||||||
fields := []*Node{
|
fields := []*Node{
|
||||||
namedfield(".F", types.Types[TUINTPTR]),
|
namedfield(".F", types.Types[TUINTPTR]),
|
||||||
}
|
}
|
||||||
for _, v := range clo.Func.Closure.Func.Cvars.Slice() {
|
for _, v := range clo.Func.ClosureVars.Slice() {
|
||||||
typ := v.Type
|
typ := v.Type
|
||||||
if !v.Name.Byval() {
|
if !v.Name.Byval() {
|
||||||
typ = types.NewPtr(typ)
|
typ = types.NewPtr(typ)
|
||||||
@ -384,14 +382,14 @@ func closureType(clo *Node) *types.Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func walkclosure(clo *Node, init *Nodes) *Node {
|
func walkclosure(clo *Node, init *Nodes) *Node {
|
||||||
xfunc := clo.Func.Closure
|
fn := clo.Func
|
||||||
|
|
||||||
// If no closure vars, don't bother wrapping.
|
// If no closure vars, don't bother wrapping.
|
||||||
if hasemptycvars(clo) {
|
if hasemptycvars(clo) {
|
||||||
if Debug_closure > 0 {
|
if Debug_closure > 0 {
|
||||||
Warnl(clo.Pos, "closure converted to global")
|
Warnl(clo.Pos, "closure converted to global")
|
||||||
}
|
}
|
||||||
return xfunc.Func.Nname
|
return fn.Nname
|
||||||
}
|
}
|
||||||
closuredebugruntimecheck(clo)
|
closuredebugruntimecheck(clo)
|
||||||
|
|
||||||
@ -399,7 +397,7 @@ func walkclosure(clo *Node, init *Nodes) *Node {
|
|||||||
|
|
||||||
clos := nod(OCOMPLIT, nil, typenod(typ))
|
clos := nod(OCOMPLIT, nil, typenod(typ))
|
||||||
clos.Esc = clo.Esc
|
clos.Esc = clo.Esc
|
||||||
clos.List.Set(append([]*Node{nod(OCFUNC, xfunc.Func.Nname, nil)}, clo.Func.Enter.Slice()...))
|
clos.List.Set(append([]*Node{nod(OCFUNC, fn.Nname, nil)}, fn.ClosureEnter.Slice()...))
|
||||||
|
|
||||||
clos = nod(OADDR, clos, nil)
|
clos = nod(OADDR, clos, nil)
|
||||||
clos.Esc = clo.Esc
|
clos.Esc = clo.Esc
|
||||||
@ -419,8 +417,8 @@ func walkclosure(clo *Node, init *Nodes) *Node {
|
|||||||
return walkexpr(clos, init)
|
return walkexpr(clos, init)
|
||||||
}
|
}
|
||||||
|
|
||||||
func typecheckpartialcall(fn *Node, sym *types.Sym) {
|
func typecheckpartialcall(dot *Node, sym *types.Sym) {
|
||||||
switch fn.Op {
|
switch dot.Op {
|
||||||
case ODOTINTER, ODOTMETH:
|
case ODOTINTER, ODOTMETH:
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -429,19 +427,19 @@ func typecheckpartialcall(fn *Node, sym *types.Sym) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create top-level function.
|
// Create top-level function.
|
||||||
xfunc := makepartialcall(fn, fn.Type, sym)
|
dcl := makepartialcall(dot, dot.Type, sym)
|
||||||
fn.Func = xfunc.Func
|
dcl.Func.SetWrapper(true)
|
||||||
fn.Func.SetWrapper(true)
|
dot.Op = OCALLPART
|
||||||
fn.Right = newname(sym)
|
dot.Right = newname(sym)
|
||||||
fn.Op = OCALLPART
|
dot.Type = dcl.Type
|
||||||
fn.Type = xfunc.Type
|
dot.Func = dcl.Func
|
||||||
fn.SetOpt(nil) // clear types.Field from ODOTMETH
|
dot.SetOpt(nil) // clear types.Field from ODOTMETH
|
||||||
}
|
}
|
||||||
|
|
||||||
// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
|
// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
|
||||||
// for partial calls.
|
// for partial calls.
|
||||||
func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
|
func makepartialcall(dot *Node, t0 *types.Type, meth *types.Sym) *Node {
|
||||||
rcvrtype := fn.Left.Type
|
rcvrtype := dot.Left.Type
|
||||||
sym := methodSymSuffix(rcvrtype, meth, "-fm")
|
sym := methodSymSuffix(rcvrtype, meth, "-fm")
|
||||||
|
|
||||||
if sym.Uniq() {
|
if sym.Uniq() {
|
||||||
@ -468,9 +466,10 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
|
|||||||
tfn.List.Set(structargs(t0.Params(), true))
|
tfn.List.Set(structargs(t0.Params(), true))
|
||||||
tfn.Rlist.Set(structargs(t0.Results(), false))
|
tfn.Rlist.Set(structargs(t0.Results(), false))
|
||||||
|
|
||||||
xfunc := dclfunc(sym, tfn)
|
dcl := dclfunc(sym, tfn)
|
||||||
xfunc.Func.SetDupok(true)
|
fn := dcl.Func
|
||||||
xfunc.Func.SetNeedctxt(true)
|
fn.SetDupok(true)
|
||||||
|
fn.SetNeedctxt(true)
|
||||||
|
|
||||||
tfn.Type.SetPkg(t0.Pkg())
|
tfn.Type.SetPkg(t0.Pkg())
|
||||||
|
|
||||||
@ -502,20 +501,20 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
|
|||||||
}
|
}
|
||||||
body = append(body, call)
|
body = append(body, call)
|
||||||
|
|
||||||
xfunc.Nbody.Set(body)
|
dcl.Nbody.Set(body)
|
||||||
funcbody()
|
funcbody()
|
||||||
|
|
||||||
xfunc = typecheck(xfunc, ctxStmt)
|
dcl = typecheck(dcl, ctxStmt)
|
||||||
// Need to typecheck the body of the just-generated wrapper.
|
// Need to typecheck the body of the just-generated wrapper.
|
||||||
// typecheckslice() requires that Curfn is set when processing an ORETURN.
|
// typecheckslice() requires that Curfn is set when processing an ORETURN.
|
||||||
Curfn = xfunc
|
Curfn = dcl
|
||||||
typecheckslice(xfunc.Nbody.Slice(), ctxStmt)
|
typecheckslice(dcl.Nbody.Slice(), ctxStmt)
|
||||||
sym.Def = asTypesNode(xfunc)
|
sym.Def = asTypesNode(dcl)
|
||||||
xtop = append(xtop, xfunc)
|
xtop = append(xtop, dcl)
|
||||||
Curfn = savecurfn
|
Curfn = savecurfn
|
||||||
lineno = saveLineNo
|
lineno = saveLineNo
|
||||||
|
|
||||||
return xfunc
|
return dcl
|
||||||
}
|
}
|
||||||
|
|
||||||
// partialCallType returns the struct type used to hold all the information
|
// partialCallType returns the struct type used to hold all the information
|
||||||
|
@ -206,11 +206,13 @@ func newnoname(s *types.Sym) *Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newfuncnamel generates a new name node for a function or method.
|
// newfuncnamel generates a new name node for a function or method.
|
||||||
// TODO(rsc): Use an ODCLFUNC node instead. See comment in CL 7360.
|
func newfuncnamel(pos src.XPos, s *types.Sym, fn *Func) *Node {
|
||||||
func newfuncnamel(pos src.XPos, s *types.Sym) *Node {
|
if fn.Nname != nil {
|
||||||
|
Fatalf("newfuncnamel - already have name")
|
||||||
|
}
|
||||||
n := newnamel(pos, s)
|
n := newnamel(pos, s)
|
||||||
n.Func = new(Func)
|
n.Func = fn
|
||||||
n.Func.SetIsHiddenClosure(Curfn != nil)
|
fn.Nname = n
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,7 +289,7 @@ func oldname(s *types.Sym) *Node {
|
|||||||
c.Name.Param.Outer = n.Name.Param.Innermost
|
c.Name.Param.Outer = n.Name.Param.Innermost
|
||||||
n.Name.Param.Innermost = c
|
n.Name.Param.Innermost = c
|
||||||
|
|
||||||
Curfn.Func.Cvars.Append(c)
|
Curfn.Func.ClosureVars.Append(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// return ref to closure var, not original
|
// return ref to closure var, not original
|
||||||
@ -388,10 +390,8 @@ func funchdr(n *Node) {
|
|||||||
|
|
||||||
types.Markdcl()
|
types.Markdcl()
|
||||||
|
|
||||||
if n.Func.Nname != nil {
|
if n.Func.Nname != nil && n.Func.Nname.Name.Param.Ntype != nil {
|
||||||
funcargs(n.Func.Nname.Name.Param.Ntype)
|
funcargs(n.Func.Nname.Name.Param.Ntype)
|
||||||
} else if n.Func.Ntype != nil {
|
|
||||||
funcargs(n.Func.Ntype)
|
|
||||||
} else {
|
} else {
|
||||||
funcargs2(n.Type)
|
funcargs2(n.Type)
|
||||||
}
|
}
|
||||||
@ -973,7 +973,7 @@ func dclfunc(sym *types.Sym, tfn *Node) *Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn := nod(ODCLFUNC, nil, nil)
|
fn := nod(ODCLFUNC, nil, nil)
|
||||||
fn.Func.Nname = newfuncnamel(lineno, sym)
|
fn.Func.Nname = newfuncnamel(lineno, sym, fn.Func)
|
||||||
fn.Func.Nname.Name.Defn = fn
|
fn.Func.Nname.Name.Defn = fn
|
||||||
fn.Func.Nname.Name.Param.Ntype = tfn
|
fn.Func.Nname.Name.Param.Ntype = tfn
|
||||||
setNodeNameFunc(fn.Func.Nname)
|
setNodeNameFunc(fn.Func.Nname)
|
||||||
@ -1043,7 +1043,7 @@ func (c *nowritebarrierrecChecker) findExtraCalls(n *Node) bool {
|
|||||||
case ONAME:
|
case ONAME:
|
||||||
callee = arg.Name.Defn
|
callee = arg.Name.Defn
|
||||||
case OCLOSURE:
|
case OCLOSURE:
|
||||||
callee = arg.Func.Closure
|
callee = arg.Func.Decl
|
||||||
default:
|
default:
|
||||||
Fatalf("expected ONAME or OCLOSURE node, got %+v", arg)
|
Fatalf("expected ONAME or OCLOSURE node, got %+v", arg)
|
||||||
}
|
}
|
||||||
|
@ -259,8 +259,9 @@ func addrescapes(n *Node) {
|
|||||||
// heap in f, not in the inner closure. Flip over to f before calling moveToHeap.
|
// heap in f, not in the inner closure. Flip over to f before calling moveToHeap.
|
||||||
oldfn := Curfn
|
oldfn := Curfn
|
||||||
Curfn = n.Name.Curfn
|
Curfn = n.Name.Curfn
|
||||||
if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
|
if Curfn.Op == OCLOSURE {
|
||||||
Curfn = Curfn.Func.Closure
|
Curfn = Curfn.Func.Decl
|
||||||
|
panic("can't happen")
|
||||||
}
|
}
|
||||||
ln := lineno
|
ln := lineno
|
||||||
lineno = Curfn.Pos
|
lineno = Curfn.Pos
|
||||||
|
@ -623,7 +623,7 @@ func (e *Escape) exprSkipInit(k EscHole, n *Node) {
|
|||||||
k = e.spill(k, n)
|
k = e.spill(k, n)
|
||||||
|
|
||||||
// Link addresses of captured variables to closure.
|
// Link addresses of captured variables to closure.
|
||||||
for _, v := range n.Func.Closure.Func.Cvars.Slice() {
|
for _, v := range n.Func.ClosureVars.Slice() {
|
||||||
if v.Op == OXXX { // unnamed out argument; see dcl.go:/^funcargs
|
if v.Op == OXXX { // unnamed out argument; see dcl.go:/^funcargs
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -810,7 +810,7 @@ func (e *Escape) call(ks []EscHole, call, where *Node) {
|
|||||||
case v.Op == ONAME && v.Class() == PFUNC:
|
case v.Op == ONAME && v.Class() == PFUNC:
|
||||||
fn = v
|
fn = v
|
||||||
case v.Op == OCLOSURE:
|
case v.Op == OCLOSURE:
|
||||||
fn = v.Func.Closure.Func.Nname
|
fn = v.Func.Nname
|
||||||
}
|
}
|
||||||
case OCALLMETH:
|
case OCALLMETH:
|
||||||
fn = call.Left.MethodName()
|
fn = call.Left.MethodName()
|
||||||
@ -1358,7 +1358,7 @@ func (e *Escape) outlives(l, other *EscLocation) bool {
|
|||||||
//
|
//
|
||||||
// var u int // okay to stack allocate
|
// var u int // okay to stack allocate
|
||||||
// *(func() *int { return &u }()) = 42
|
// *(func() *int { return &u }()) = 42
|
||||||
if containsClosure(other.curfn, l.curfn) && l.curfn.Func.Closure.Func.Top&ctxCallee != 0 {
|
if containsClosure(other.curfn, l.curfn) && l.curfn.Func.ClosureCalled {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1417,7 +1417,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
|
|||||||
mode.Fprintf(s, "%v { %v }", n.Type, n.Nbody)
|
mode.Fprintf(s, "%v { %v }", n.Type, n.Nbody)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mode.Fprintf(s, "%v { %v }", n.Type, n.Func.Closure.Nbody)
|
mode.Fprintf(s, "%v { %v }", n.Type, n.Func.Decl.Nbody)
|
||||||
|
|
||||||
case OCOMPLIT:
|
case OCOMPLIT:
|
||||||
if mode == FErr {
|
if mode == FErr {
|
||||||
@ -1717,8 +1717,8 @@ func (n *Node) nodedump(s fmt.State, flag FmtFlag, mode fmtMode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Op == OCLOSURE && n.Func.Closure != nil && n.Func.Closure.Func.Nname.Sym != nil {
|
if n.Op == OCLOSURE && n.Func.Decl != nil && n.Func.Nname.Sym != nil {
|
||||||
mode.Fprintf(s, " fnName %v", n.Func.Closure.Func.Nname.Sym)
|
mode.Fprintf(s, " fnName %v", n.Func.Nname.Sym)
|
||||||
}
|
}
|
||||||
if n.Sym != nil && n.Op != ONAME {
|
if n.Sym != nil && n.Op != ONAME {
|
||||||
mode.Fprintf(s, " %v", n.Sym)
|
mode.Fprintf(s, " %v", n.Sym)
|
||||||
@ -1735,12 +1735,12 @@ func (n *Node) nodedump(s fmt.State, flag FmtFlag, mode fmtMode) {
|
|||||||
if n.Right != nil {
|
if n.Right != nil {
|
||||||
mode.Fprintf(s, "%v", n.Right)
|
mode.Fprintf(s, "%v", n.Right)
|
||||||
}
|
}
|
||||||
if n.Func != nil && n.Func.Closure != nil && n.Func.Closure.Nbody.Len() != 0 {
|
if n.Op == OCLOSURE && n.Func != nil && n.Func.Decl != nil && n.Func.Decl.Nbody.Len() != 0 {
|
||||||
indent(s)
|
indent(s)
|
||||||
// The function associated with a closure
|
// The function associated with a closure
|
||||||
mode.Fprintf(s, "%v-clofunc%v", n.Op, n.Func.Closure)
|
mode.Fprintf(s, "%v-clofunc%v", n.Op, n.Func.Decl)
|
||||||
}
|
}
|
||||||
if n.Func != nil && n.Func.Dcl != nil && len(n.Func.Dcl) != 0 {
|
if n.Op == ODCLFUNC && n.Func != nil && n.Func.Dcl != nil && len(n.Func.Dcl) != 0 {
|
||||||
indent(s)
|
indent(s)
|
||||||
// The dcls for a func or closure
|
// The dcls for a func or closure
|
||||||
mode.Fprintf(s, "%v-dcl%v", n.Op, asNodes(n.Func.Dcl))
|
mode.Fprintf(s, "%v-dcl%v", n.Op, asNodes(n.Func.Dcl))
|
||||||
|
@ -54,7 +54,7 @@ func tempAt(pos src.XPos, curfn *Node, t *types.Type) *Node {
|
|||||||
if curfn == nil {
|
if curfn == nil {
|
||||||
Fatalf("no curfn for tempAt")
|
Fatalf("no curfn for tempAt")
|
||||||
}
|
}
|
||||||
if curfn.Func.Closure != nil && curfn.Op == OCLOSURE {
|
if curfn.Op == OCLOSURE {
|
||||||
Dump("tempAt", curfn)
|
Dump("tempAt", curfn)
|
||||||
Fatalf("adding tempAt to wrong closure function")
|
Fatalf("adding tempAt to wrong closure function")
|
||||||
}
|
}
|
||||||
|
@ -329,7 +329,7 @@ func (r *importReader) doDecl(n *Node) {
|
|||||||
recv := r.param()
|
recv := r.param()
|
||||||
mtyp := r.signature(recv)
|
mtyp := r.signature(recv)
|
||||||
|
|
||||||
m := newfuncnamel(mpos, methodSym(recv.Type, msym))
|
m := newfuncnamel(mpos, methodSym(recv.Type, msym), new(Func))
|
||||||
m.Type = mtyp
|
m.Type = mtyp
|
||||||
m.SetClass(PFUNC)
|
m.SetClass(PFUNC)
|
||||||
// methodSym already marked m.Sym as a function.
|
// methodSym already marked m.Sym as a function.
|
||||||
|
@ -285,7 +285,7 @@ func (d *initDeps) visit(n *Node) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case OCLOSURE:
|
case OCLOSURE:
|
||||||
d.inspectList(n.Func.Closure.Nbody)
|
d.inspectList(n.Func.Decl.Nbody)
|
||||||
|
|
||||||
case ODOTMETH, OCALLPART:
|
case ODOTMETH, OCALLPART:
|
||||||
d.foundDep(n.MethodName())
|
d.foundDep(n.MethodName())
|
||||||
|
@ -722,7 +722,7 @@ func inlCallee(fn *Node) *Node {
|
|||||||
}
|
}
|
||||||
return fn
|
return fn
|
||||||
case fn.Op == OCLOSURE:
|
case fn.Op == OCLOSURE:
|
||||||
c := fn.Func.Closure
|
c := fn.Func.Decl
|
||||||
caninl(c)
|
caninl(c)
|
||||||
return c.Func.Nname
|
return c.Func.Nname
|
||||||
}
|
}
|
||||||
@ -806,7 +806,7 @@ func reassigned(n *Node) (bool, *Node) {
|
|||||||
// We need to walk the function body to check for reassignments so we follow the
|
// We need to walk the function body to check for reassignments so we follow the
|
||||||
// linkage to the ODCLFUNC node as that is where body is held.
|
// linkage to the ODCLFUNC node as that is where body is held.
|
||||||
if f.Op == OCLOSURE {
|
if f.Op == OCLOSURE {
|
||||||
f = f.Func.Closure
|
f = f.Func.Decl
|
||||||
}
|
}
|
||||||
v := reassignVisitor{name: n}
|
v := reassignVisitor{name: n}
|
||||||
a := v.visitList(f.Nbody)
|
a := v.visitList(f.Nbody)
|
||||||
@ -976,8 +976,8 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
|||||||
|
|
||||||
// Handle captured variables when inlining closures.
|
// Handle captured variables when inlining closures.
|
||||||
if fn.Name.Defn != nil {
|
if fn.Name.Defn != nil {
|
||||||
if c := fn.Name.Defn.Func.Closure; c != nil {
|
if c := fn.Name.Defn.Func.OClosure; c != nil {
|
||||||
for _, v := range c.Func.Closure.Func.Cvars.Slice() {
|
for _, v := range c.Func.ClosureVars.Slice() {
|
||||||
if v.Op == OXXX {
|
if v.Op == OXXX {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -987,7 +987,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
|||||||
// NB: if we enabled inlining of functions containing OCLOSURE or refined
|
// NB: if we enabled inlining of functions containing OCLOSURE or refined
|
||||||
// the reassigned check via some sort of copy propagation this would most
|
// the reassigned check via some sort of copy propagation this would most
|
||||||
// likely need to be changed to a loop to walk up to the correct Param
|
// likely need to be changed to a loop to walk up to the correct Param
|
||||||
if o == nil || (o.Name.Curfn != Curfn && o.Name.Curfn.Func.Closure != Curfn) {
|
if o == nil || (o.Name.Curfn != Curfn && o.Name.Curfn.Func.OClosure != Curfn) {
|
||||||
Fatalf("%v: unresolvable capture %v %v\n", n.Line(), fn, v)
|
Fatalf("%v: unresolvable capture %v %v\n", n.Line(), fn, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,7 +651,7 @@ func Main(archInit func(*Arch)) {
|
|||||||
// because variables captured by value do not escape.
|
// because variables captured by value do not escape.
|
||||||
timings.Start("fe", "capturevars")
|
timings.Start("fe", "capturevars")
|
||||||
for _, n := range xtop {
|
for _, n := range xtop {
|
||||||
if n.Op == ODCLFUNC && n.Func.Closure != nil {
|
if n.Op == ODCLFUNC && n.Func.OClosure != nil {
|
||||||
Curfn = n
|
Curfn = n
|
||||||
capturevars(n)
|
capturevars(n)
|
||||||
}
|
}
|
||||||
@ -724,7 +724,7 @@ func Main(archInit func(*Arch)) {
|
|||||||
// before walk reaches a call of a closure.
|
// before walk reaches a call of a closure.
|
||||||
timings.Start("fe", "xclosures")
|
timings.Start("fe", "xclosures")
|
||||||
for _, n := range xtop {
|
for _, n := range xtop {
|
||||||
if n.Op == ODCLFUNC && n.Func.Closure != nil {
|
if n.Op == ODCLFUNC && n.Func.OClosure != nil {
|
||||||
Curfn = n
|
Curfn = n
|
||||||
transformclosure(n)
|
transformclosure(n)
|
||||||
}
|
}
|
||||||
@ -829,7 +829,7 @@ func Main(archInit func(*Arch)) {
|
|||||||
func numNonClosures(list []*Node) int {
|
func numNonClosures(list []*Node) int {
|
||||||
count := 0
|
count := 0
|
||||||
for _, n := range list {
|
for _, n := range list {
|
||||||
if n.Func.Closure == nil {
|
if n.Func.OClosure == nil {
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -537,7 +537,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
|
|||||||
name = nblank.Sym // filled in by typecheckfunc
|
name = nblank.Sym // filled in by typecheckfunc
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Func.Nname = newfuncnamel(p.pos(fun.Name), name)
|
f.Func.Nname = newfuncnamel(p.pos(fun.Name), name, f.Func)
|
||||||
f.Func.Nname.Name.Defn = f
|
f.Func.Nname.Name.Defn = f
|
||||||
f.Func.Nname.Name.Param.Ntype = t
|
f.Func.Nname.Name.Param.Ntype = t
|
||||||
|
|
||||||
|
@ -1256,7 +1256,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case OCLOSURE:
|
case OCLOSURE:
|
||||||
if n.Transient() && n.Func.Closure.Func.Cvars.Len() > 0 {
|
if n.Transient() && n.Func.ClosureVars.Len() > 0 {
|
||||||
prealloc[n] = o.newTemp(closureType(n), false)
|
prealloc[n] = o.newTemp(closureType(n), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,8 +404,36 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Back when there were two different *Funcs for a function, this code
|
||||||
|
// was not consistent about whether a particular *Node being processed
|
||||||
|
// was an ODCLFUNC or ONAME node. Partly this is because inlined function
|
||||||
|
// bodies have no ODCLFUNC node, which was it's own inconsistency.
|
||||||
|
// In any event, the handling of the two different nodes for DWARF purposes
|
||||||
|
// was subtly different, likely in unintended ways. CL 272253 merged the
|
||||||
|
// two nodes' Func fields, so that code sees the same *Func whether it is
|
||||||
|
// holding the ODCLFUNC or the ONAME. This resulted in changes in the
|
||||||
|
// DWARF output. To preserve the existing DWARF output and leave an
|
||||||
|
// intentional change for a future CL, this code does the following when
|
||||||
|
// fn.Op == ONAME:
|
||||||
|
//
|
||||||
|
// 1. Disallow use of createComplexVars in createDwarfVars.
|
||||||
|
// It was not possible to reach that code for an ONAME before,
|
||||||
|
// because the DebugInfo was set only on the ODCLFUNC Func.
|
||||||
|
// Calling into it in the ONAME case causes an index out of bounds panic.
|
||||||
|
//
|
||||||
|
// 2. Do not populate apdecls. fn.Func.Dcl was in the ODCLFUNC Func,
|
||||||
|
// not the ONAME Func. Populating apdecls for the ONAME case results
|
||||||
|
// in selected being populated after createSimpleVars is called in
|
||||||
|
// createDwarfVars, and then that causes the loop to skip all the entries
|
||||||
|
// in dcl, meaning that the RecordAutoType calls don't happen.
|
||||||
|
//
|
||||||
|
// These two adjustments keep toolstash -cmp working for now.
|
||||||
|
// Deciding the right answer is, as they say, future work.
|
||||||
|
isODCLFUNC := fn.Op == ODCLFUNC
|
||||||
|
|
||||||
var apdecls []*Node
|
var apdecls []*Node
|
||||||
// Populate decls for fn.
|
// Populate decls for fn.
|
||||||
|
if isODCLFUNC {
|
||||||
for _, n := range fn.Func.Dcl {
|
for _, n := range fn.Func.Dcl {
|
||||||
if n.Op != ONAME { // might be OTYPE or OLITERAL
|
if n.Op != ONAME { // might be OTYPE or OLITERAL
|
||||||
continue
|
continue
|
||||||
@ -426,8 +454,9 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
|
|||||||
apdecls = append(apdecls, n)
|
apdecls = append(apdecls, n)
|
||||||
fnsym.Func().RecordAutoType(ngotype(n).Linksym())
|
fnsym.Func().RecordAutoType(ngotype(n).Linksym())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
decls, dwarfVars := createDwarfVars(fnsym, fn.Func, apdecls)
|
decls, dwarfVars := createDwarfVars(fnsym, isODCLFUNC, fn.Func, apdecls)
|
||||||
|
|
||||||
// For each type referenced by the functions auto vars but not
|
// For each type referenced by the functions auto vars but not
|
||||||
// already referenced by a dwarf var, attach a dummy relocation to
|
// already referenced by a dwarf var, attach a dummy relocation to
|
||||||
@ -575,12 +604,12 @@ func createComplexVars(fnsym *obj.LSym, fn *Func) ([]*Node, []*dwarf.Var, map[*N
|
|||||||
|
|
||||||
// createDwarfVars process fn, returning a list of DWARF variables and the
|
// createDwarfVars process fn, returning a list of DWARF variables and the
|
||||||
// Nodes they represent.
|
// Nodes they represent.
|
||||||
func createDwarfVars(fnsym *obj.LSym, fn *Func, apDecls []*Node) ([]*Node, []*dwarf.Var) {
|
func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *Func, apDecls []*Node) ([]*Node, []*dwarf.Var) {
|
||||||
// Collect a raw list of DWARF vars.
|
// Collect a raw list of DWARF vars.
|
||||||
var vars []*dwarf.Var
|
var vars []*dwarf.Var
|
||||||
var decls []*Node
|
var decls []*Node
|
||||||
var selected map[*Node]bool
|
var selected map[*Node]bool
|
||||||
if Ctxt.Flag_locationlists && Ctxt.Flag_optimize && fn.DebugInfo != nil {
|
if Ctxt.Flag_locationlists && Ctxt.Flag_optimize && fn.DebugInfo != nil && complexOK {
|
||||||
decls, vars, selected = createComplexVars(fnsym, fn)
|
decls, vars, selected = createComplexVars(fnsym, fn)
|
||||||
} else {
|
} else {
|
||||||
decls, vars, selected = createSimpleVars(fnsym, apDecls)
|
decls, vars, selected = createSimpleVars(fnsym, apDecls)
|
||||||
|
@ -101,7 +101,7 @@ func (v *bottomUpVisitor) visit(n *Node) uint32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case OCLOSURE:
|
case OCLOSURE:
|
||||||
if m := v.visit(n.Func.Closure); m < min {
|
if m := v.visit(n.Func.Decl); m < min {
|
||||||
min = m
|
min = m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,7 +261,7 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
|
|||||||
}
|
}
|
||||||
// Closures with no captured variables are globals,
|
// Closures with no captured variables are globals,
|
||||||
// so the assignment can be done at link time.
|
// so the assignment can be done at link time.
|
||||||
pfuncsym(l, r.Func.Closure.Func.Nname)
|
pfuncsym(l, r.Func.Nname)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
closuredebugruntimecheck(r)
|
closuredebugruntimecheck(r)
|
||||||
|
@ -20,7 +20,7 @@ func TestSizeof(t *testing.T) {
|
|||||||
_32bit uintptr // size on 32bit platforms
|
_32bit uintptr // size on 32bit platforms
|
||||||
_64bit uintptr // size on 64bit platforms
|
_64bit uintptr // size on 64bit platforms
|
||||||
}{
|
}{
|
||||||
{Func{}, 124, 224},
|
{Func{}, 132, 240},
|
||||||
{Name{}, 32, 56},
|
{Name{}, 32, 56},
|
||||||
{Param{}, 24, 48},
|
{Param{}, 24, 48},
|
||||||
{Node{}, 76, 128},
|
{Node{}, 76, 128},
|
||||||
|
@ -139,13 +139,14 @@ func nod(op Op, nleft, nright *Node) *Node {
|
|||||||
func nodl(pos src.XPos, op Op, nleft, nright *Node) *Node {
|
func nodl(pos src.XPos, op Op, nleft, nright *Node) *Node {
|
||||||
var n *Node
|
var n *Node
|
||||||
switch op {
|
switch op {
|
||||||
case OCLOSURE, ODCLFUNC:
|
case ODCLFUNC:
|
||||||
var x struct {
|
var x struct {
|
||||||
n Node
|
n Node
|
||||||
f Func
|
f Func
|
||||||
}
|
}
|
||||||
n = &x.n
|
n = &x.n
|
||||||
n.Func = &x.f
|
n.Func = &x.f
|
||||||
|
n.Func.Decl = n
|
||||||
case ONAME:
|
case ONAME:
|
||||||
Fatalf("use newname instead")
|
Fatalf("use newname instead")
|
||||||
case OLABEL, OPACK:
|
case OLABEL, OPACK:
|
||||||
|
@ -578,62 +578,66 @@ func (p *Param) SetEmbedFiles(list []string) {
|
|||||||
*(*p.Extra).(*embedFileList) = list
|
*(*p.Extra).(*embedFileList) = list
|
||||||
}
|
}
|
||||||
|
|
||||||
// Functions
|
// A Func corresponds to a single function in a Go program
|
||||||
|
// (and vice versa: each function is denoted by exactly one *Func).
|
||||||
//
|
//
|
||||||
// A simple function declaration is represented as an ODCLFUNC node f
|
// There are multiple nodes that represent a Func in the IR.
|
||||||
// and an ONAME node n. They're linked to one another through
|
|
||||||
// f.Func.Nname == n and n.Name.Defn == f. When functions are
|
|
||||||
// referenced by name in an expression, the function's ONAME node is
|
|
||||||
// used directly.
|
|
||||||
//
|
//
|
||||||
// Function names have n.Class() == PFUNC. This distinguishes them
|
// The ONAME node (Func.Name) is used for plain references to it.
|
||||||
// from variables of function type.
|
// The ODCLFUNC node (Func.Decl) is used for its declaration code.
|
||||||
|
// The OCLOSURE node (Func.Closure) is used for a reference to a
|
||||||
|
// function literal.
|
||||||
//
|
//
|
||||||
// Confusingly, n.Func and f.Func both exist, but commonly point to
|
// A Func for an imported function will have only an ONAME node.
|
||||||
// different Funcs. (Exception: an OCALLPART's Func does point to its
|
// A declared function or method has an ONAME and an ODCLFUNC.
|
||||||
// ODCLFUNC's Func.)
|
// A function literal is represented directly by an OCLOSURE, but it also
|
||||||
|
// has an ODCLFUNC (and a matching ONAME) representing the compiled
|
||||||
|
// underlying form of the closure, which accesses the captured variables
|
||||||
|
// using a special data structure passed in a register.
|
||||||
//
|
//
|
||||||
// A method declaration is represented like functions, except n.Sym
|
// A method declaration is represented like functions, except f.Sym
|
||||||
// will be the qualified method name (e.g., "T.m") and
|
// will be the qualified method name (e.g., "T.m") and
|
||||||
// f.Func.Shortname is the bare method name (e.g., "m").
|
// f.Func.Shortname is the bare method name (e.g., "m").
|
||||||
//
|
//
|
||||||
// Method expressions are represented as ONAME/PFUNC nodes like
|
// A method expression (T.M) is represented as an ONAME node
|
||||||
// function names, but their Left and Right fields still point to the
|
// like a function name would be, but n.Left and n.Right point to
|
||||||
// type and method, respectively. They can be distinguished from
|
// the type and method, respectively. A method expression can
|
||||||
// normal functions with isMethodExpression. Also, unlike function
|
// be distinguished from a normal function ONAME by checking
|
||||||
// name nodes, method expression nodes exist for each method
|
// n.IsMethodExpression. Unlike ordinary ONAME nodes, each
|
||||||
// expression. The declaration ONAME can be accessed with
|
// distinct mention of a method expression in the source code
|
||||||
// x.Type.Nname(), where x is the method expression ONAME node.
|
// constructs a fresh ONAME node.
|
||||||
|
// TODO(rsc): Method expressions deserve their own opcode
|
||||||
|
// instead of violating invariants of ONAME.
|
||||||
//
|
//
|
||||||
// Method values are represented by ODOTMETH/ODOTINTER when called
|
// A method value (t.M) is represented by ODOTMETH/ODOTINTER
|
||||||
// immediately, and OCALLPART otherwise. They are like method
|
// when it is called directly and by OCALLPART otherwise.
|
||||||
// expressions, except that for ODOTMETH/ODOTINTER the method name is
|
// These are like method expressions, except that for ODOTMETH/ODOTINTER,
|
||||||
// stored in Sym instead of Right.
|
// the method name is stored in Sym instead of Right.
|
||||||
//
|
// Each OCALLPART ends up being implemented as a new
|
||||||
// Closures are represented by OCLOSURE node c. They link back and
|
// function, a bit like a closure, with its own ODCLFUNC.
|
||||||
// forth with the ODCLFUNC via Func.Closure; that is, c.Func.Closure
|
// The OCALLPART has uses n.Func to record the linkage to
|
||||||
// == f and f.Func.Closure == c.
|
// the generated ODCLFUNC (as n.Func.Decl), but there is no
|
||||||
//
|
// pointer from the Func back to the OCALLPART.
|
||||||
// Function bodies are stored in f.Nbody, and inline function bodies
|
|
||||||
// are stored in n.Func.Inl. Pragmas are stored in f.Func.Pragma.
|
|
||||||
//
|
|
||||||
// Imported functions skip the ODCLFUNC, so n.Name.Defn is nil. They
|
|
||||||
// also use Dcl instead of Inldcl.
|
|
||||||
|
|
||||||
// Func holds Node fields used only with function-like nodes.
|
|
||||||
type Func struct {
|
type Func struct {
|
||||||
|
Nname *Node // ONAME node
|
||||||
|
Decl *Node // ODCLFUNC node
|
||||||
|
OClosure *Node // OCLOSURE node
|
||||||
|
|
||||||
Shortname *types.Sym
|
Shortname *types.Sym
|
||||||
|
|
||||||
// Extra entry code for the function. For example, allocate and initialize
|
// Extra entry code for the function. For example, allocate and initialize
|
||||||
// memory for escaping parameters. However, just for OCLOSURE, Enter is a
|
// memory for escaping parameters.
|
||||||
// list of ONAME nodes of captured variables
|
|
||||||
Enter Nodes
|
Enter Nodes
|
||||||
Exit Nodes
|
Exit Nodes
|
||||||
// ONAME nodes for closure params, each should have closurevar set
|
|
||||||
Cvars Nodes
|
|
||||||
// ONAME nodes for all params/locals for this func/closure, does NOT
|
// ONAME nodes for all params/locals for this func/closure, does NOT
|
||||||
// include closurevars until transformclosure runs.
|
// include closurevars until transformclosure runs.
|
||||||
Dcl []*Node
|
Dcl []*Node
|
||||||
|
|
||||||
|
ClosureEnter Nodes // list of ONAME nodes of captured variables
|
||||||
|
ClosureType *Node // closure representation type
|
||||||
|
ClosureCalled bool // closure is only immediately called
|
||||||
|
ClosureVars Nodes // closure params; each has closurevar set
|
||||||
|
|
||||||
// Parents records the parent scope of each scope within a
|
// Parents records the parent scope of each scope within a
|
||||||
// function. The root scope (0) has no parent, so the i'th
|
// function. The root scope (0) has no parent, so the i'th
|
||||||
// scope's parent is stored at Parents[i-1].
|
// scope's parent is stored at Parents[i-1].
|
||||||
@ -649,10 +653,6 @@ type Func struct {
|
|||||||
|
|
||||||
FieldTrack map[*types.Sym]struct{}
|
FieldTrack map[*types.Sym]struct{}
|
||||||
DebugInfo *ssa.FuncDebug
|
DebugInfo *ssa.FuncDebug
|
||||||
Ntype *Node // signature
|
|
||||||
Top int // top context (ctxCallee, etc)
|
|
||||||
Closure *Node // OCLOSURE <-> ODCLFUNC (see header comment above)
|
|
||||||
Nname *Node // The ONAME node associated with an ODCLFUNC (both have same Type)
|
|
||||||
lsym *obj.LSym
|
lsym *obj.LSym
|
||||||
|
|
||||||
Inl *Inline
|
Inl *Inline
|
||||||
|
@ -562,12 +562,11 @@ opswitch:
|
|||||||
// transformclosure already did all preparation work.
|
// transformclosure already did all preparation work.
|
||||||
|
|
||||||
// Prepend captured variables to argument list.
|
// Prepend captured variables to argument list.
|
||||||
n.List.Prepend(n.Left.Func.Enter.Slice()...)
|
n.List.Prepend(n.Left.Func.ClosureEnter.Slice()...)
|
||||||
|
n.Left.Func.ClosureEnter.Set(nil)
|
||||||
n.Left.Func.Enter.Set(nil)
|
|
||||||
|
|
||||||
// Replace OCLOSURE with ONAME/PFUNC.
|
// Replace OCLOSURE with ONAME/PFUNC.
|
||||||
n.Left = n.Left.Func.Closure.Func.Nname
|
n.Left = n.Left.Func.Nname
|
||||||
|
|
||||||
// Update type of OCALLFUNC node.
|
// Update type of OCALLFUNC node.
|
||||||
// Output arguments had not changed, but their offsets could.
|
// Output arguments had not changed, but their offsets could.
|
||||||
|
Loading…
Reference in New Issue
Block a user