mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/internal/gc: separate func-only Node fields
Nodes dominate gc's memory usage, but many fields are only used for a subset of kinds of nodes. This change pulls out fields used only for func-like Nodes. This reduces the size of the Node struct on a 64-bit machine from 504 bytes to 416 bytes (-17%). Compiling the runtime, 1.5% of nodes have a non-nil Func. In html/template, 2.7% of nodes have a non-nil Func. This change introduces an extra alloc and associated GC overhead when Func is non-nil. However, when Func is nil, as it almost always is, it spares the garbage collector scanning some Node fields. Empirically, this change appears to be roughly neutral with regard to GC. To keep the diff readable, this CL uses an embedded Func field. A subsequent CL will unembed the field. Passes toolstash -cmp. Change-Id: Ide86aa954b097fb8e6154f0811d3691497477004 Reviewed-on: https://go-review.googlesource.com/7360 Reviewed-by: Russ Cox <rsc@golang.org> Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
9fd87bd501
commit
57279ba752
8 changed files with 98 additions and 75 deletions
|
|
@ -191,7 +191,7 @@ func makeclosure(func_ *Node) *Node {
|
||||||
// create the function
|
// create the function
|
||||||
xfunc := Nod(ODCLFUNC, nil, nil)
|
xfunc := Nod(ODCLFUNC, nil, nil)
|
||||||
|
|
||||||
xfunc.Nname = newname(closurename(func_))
|
xfunc.Nname = newfuncname(closurename(func_))
|
||||||
xfunc.Nname.Sym.Flags |= SymExported // disable export
|
xfunc.Nname.Sym.Flags |= SymExported // disable export
|
||||||
xfunc.Nname.Ntype = xtype
|
xfunc.Nname.Ntype = xtype
|
||||||
xfunc.Nname.Defn = xfunc
|
xfunc.Nname.Defn = xfunc
|
||||||
|
|
@ -581,7 +581,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
|
||||||
xtype.Rlist = l
|
xtype.Rlist = l
|
||||||
|
|
||||||
xfunc.Dupok = true
|
xfunc.Dupok = true
|
||||||
xfunc.Nname = newname(sym)
|
xfunc.Nname = newfuncname(sym)
|
||||||
xfunc.Nname.Sym.Flags |= SymExported // disable export
|
xfunc.Nname.Sym.Flags |= SymExported // disable export
|
||||||
xfunc.Nname.Ntype = xtype
|
xfunc.Nname.Ntype = xtype
|
||||||
xfunc.Nname.Defn = xfunc
|
xfunc.Nname.Defn = xfunc
|
||||||
|
|
|
||||||
|
|
@ -373,6 +373,14 @@ func newname(s *Sym) *Node {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newfuncname generates a new name node for a function or method.
|
||||||
|
// TODO(rsc): Use an ODCLFUNC node instead. See comment in CL 7360.
|
||||||
|
func newfuncname(s *Sym) *Node {
|
||||||
|
n := newname(s)
|
||||||
|
n.Func = new(Func)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this generates a new name node for a name
|
* this generates a new name node for a name
|
||||||
* being declared.
|
* being declared.
|
||||||
|
|
@ -542,6 +550,7 @@ func ifacedcl(n *Node) {
|
||||||
Yyerror("methods must have a unique non-blank name")
|
Yyerror("methods must have a unique non-blank name")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n.Func = new(Func)
|
||||||
dclcontext = PPARAM
|
dclcontext = PPARAM
|
||||||
markdcl()
|
markdcl()
|
||||||
Funcdepth++
|
Funcdepth++
|
||||||
|
|
@ -1312,7 +1321,7 @@ func methodname1(n *Node, t *Node) *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Sym == nil || isblank(n) {
|
if t.Sym == nil || isblank(n) {
|
||||||
return newname(n.Sym)
|
return newfuncname(n.Sym)
|
||||||
}
|
}
|
||||||
|
|
||||||
var p string
|
var p string
|
||||||
|
|
@ -1323,9 +1332,9 @@ func methodname1(n *Node, t *Node) *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
if exportname(t.Sym.Name) {
|
if exportname(t.Sym.Name) {
|
||||||
n = newname(Lookup(p))
|
n = newfuncname(Lookup(p))
|
||||||
} else {
|
} else {
|
||||||
n = newname(Pkglookup(p, t.Sym.Pkg))
|
n = newfuncname(Pkglookup(p, t.Sym.Pkg))
|
||||||
}
|
}
|
||||||
|
|
||||||
return n
|
return n
|
||||||
|
|
@ -1476,7 +1485,7 @@ func funcsym(s *Sym) *Sym {
|
||||||
|
|
||||||
s1 := Pkglookup(s.Name+"·f", s.Pkg)
|
s1 := Pkglookup(s.Name+"·f", s.Pkg)
|
||||||
if s1.Def == nil {
|
if s1.Def == nil {
|
||||||
s1.Def = newname(s1)
|
s1.Def = newfuncname(s1)
|
||||||
s1.Def.Shortname = newname(s)
|
s1.Def.Shortname = newname(s)
|
||||||
funcsyms = list(funcsyms, s1.Def)
|
funcsyms = list(funcsyms, s1.Def)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,7 @@ func dumpexportvar(s *Sym) {
|
||||||
dumpexporttype(t)
|
dumpexporttype(t)
|
||||||
|
|
||||||
if t.Etype == TFUNC && n.Class == PFUNC {
|
if t.Etype == TFUNC && n.Class == PFUNC {
|
||||||
if n.Inl != nil {
|
if n.Func != nil && n.Inl != nil {
|
||||||
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
|
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
|
||||||
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
|
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
|
||||||
if Debug['l'] < 2 {
|
if Debug['l'] < 2 {
|
||||||
|
|
|
||||||
|
|
@ -1358,7 +1358,7 @@ fndcl:
|
||||||
t.Rlist = $5;
|
t.Rlist = $5;
|
||||||
|
|
||||||
$$ = Nod(ODCLFUNC, nil, nil);
|
$$ = Nod(ODCLFUNC, nil, nil);
|
||||||
$$.Nname = newname($1);
|
$$.Nname = newfuncname($1);
|
||||||
$$.Nname.Defn = $$;
|
$$.Nname.Defn = $$;
|
||||||
$$.Nname.Ntype = t; // TODO: check if nname already has an ntype
|
$$.Nname.Ntype = t; // TODO: check if nname already has an ntype
|
||||||
declare($$.Nname, PFUNC);
|
declare($$.Nname, PFUNC);
|
||||||
|
|
@ -1392,7 +1392,7 @@ fndcl:
|
||||||
t.Rlist = $8;
|
t.Rlist = $8;
|
||||||
|
|
||||||
$$ = Nod(ODCLFUNC, nil, nil);
|
$$ = Nod(ODCLFUNC, nil, nil);
|
||||||
$$.Shortname = newname($4);
|
$$.Shortname = newfuncname($4);
|
||||||
$$.Nname = methodname1($$.Shortname, rcvr.Right);
|
$$.Nname = methodname1($$.Shortname, rcvr.Right);
|
||||||
$$.Nname.Defn = $$;
|
$$.Nname.Defn = $$;
|
||||||
$$.Nname.Ntype = t;
|
$$.Nname.Ntype = t;
|
||||||
|
|
@ -1422,7 +1422,7 @@ hidden_fndcl:
|
||||||
Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", Sconv(s, 0), Tconv(s.Def.Type, 0), Tconv(t, 0));
|
Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", Sconv(s, 0), Tconv(s.Def.Type, 0), Tconv(t, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
$$ = newname(s);
|
$$ = newfuncname(s);
|
||||||
$$.Type = t;
|
$$.Type = t;
|
||||||
declare($$, PFUNC);
|
declare($$, PFUNC);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ func ishairy(n *Node, budget *int) bool {
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
// Call is okay if inlinable and we have the budget for the body.
|
// Call is okay if inlinable and we have the budget for the body.
|
||||||
case OCALLFUNC:
|
case OCALLFUNC:
|
||||||
if n.Left.Inl != nil {
|
if n.Left.Func != nil && n.Left.Inl != nil {
|
||||||
*budget -= int(n.Left.InlCost)
|
*budget -= int(n.Left.InlCost)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -247,7 +247,9 @@ func inlcopy(n *Node) *Node {
|
||||||
|
|
||||||
m := Nod(OXXX, nil, nil)
|
m := Nod(OXXX, nil, nil)
|
||||||
*m = *n
|
*m = *n
|
||||||
m.Inl = nil
|
if m.Func != nil {
|
||||||
|
m.Inl = nil
|
||||||
|
}
|
||||||
m.Left = inlcopy(n.Left)
|
m.Left = inlcopy(n.Left)
|
||||||
m.Right = inlcopy(n.Right)
|
m.Right = inlcopy(n.Right)
|
||||||
m.List = inlcopylist(n.List)
|
m.List = inlcopylist(n.List)
|
||||||
|
|
@ -457,7 +459,7 @@ func inlnode(np **Node) {
|
||||||
if Debug['m'] > 3 {
|
if Debug['m'] > 3 {
|
||||||
fmt.Printf("%v:call to func %v\n", n.Line(), Nconv(n.Left, obj.FmtSign))
|
fmt.Printf("%v:call to func %v\n", n.Line(), Nconv(n.Left, obj.FmtSign))
|
||||||
}
|
}
|
||||||
if n.Left.Inl != nil { // normal case
|
if n.Left.Func != nil && n.Left.Inl != nil { // normal case
|
||||||
mkinlcall(np, n.Left, n.Isddd)
|
mkinlcall(np, n.Left, n.Isddd)
|
||||||
} else if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
|
} else if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
|
||||||
if n.Left.Sym.Def != nil {
|
if n.Left.Sym.Def != nil {
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,10 @@ func Nod(op int, nleft *Node, nright *Node) *Node {
|
||||||
n.Xoffset = BADWIDTH
|
n.Xoffset = BADWIDTH
|
||||||
n.Orig = n
|
n.Orig = n
|
||||||
n.Curfn = Curfn
|
n.Curfn = Curfn
|
||||||
|
switch op {
|
||||||
|
case OCLOSURE, ODCLFUNC:
|
||||||
|
n.Func = new(Func)
|
||||||
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,58 +23,45 @@ type Node struct {
|
||||||
List *NodeList
|
List *NodeList
|
||||||
Rlist *NodeList
|
Rlist *NodeList
|
||||||
|
|
||||||
Op uint8
|
Op uint8
|
||||||
Nointerface bool
|
Nointerface bool
|
||||||
Ullman uint8 // sethi/ullman number
|
Ullman uint8 // sethi/ullman number
|
||||||
Addable uint8 // type of addressability - 0 is not addressable
|
Addable uint8 // type of addressability - 0 is not addressable
|
||||||
Etype uint8 // op for OASOP, etype for OTYPE, exclam for export
|
Etype uint8 // op for OASOP, etype for OTYPE, exclam for export
|
||||||
Bounded bool // bounds check unnecessary
|
Bounded bool // bounds check unnecessary
|
||||||
Class uint8 // PPARAM, PAUTO, PEXTERN, etc
|
Class uint8 // PPARAM, PAUTO, PEXTERN, etc
|
||||||
Method uint8 // OCALLMETH name
|
Method uint8 // OCALLMETH name
|
||||||
Embedded uint8 // ODCLFIELD embedded type
|
Embedded uint8 // ODCLFIELD embedded type
|
||||||
Colas uint8 // OAS resulting from :=
|
Colas uint8 // OAS resulting from :=
|
||||||
Diag uint8 // already printed error about this
|
Diag uint8 // already printed error about this
|
||||||
Noescape bool // func arguments do not escape
|
Noescape bool // func arguments do not escape; TODO(rsc): move Noescape to Func struct (see CL 7360)
|
||||||
Nosplit bool // func should not execute on separate stack
|
Walkdef uint8
|
||||||
Nowritebarrier bool // emit compiler error instead of write barrier
|
Typecheck uint8
|
||||||
Walkdef uint8
|
Local bool
|
||||||
Typecheck uint8
|
Dodata uint8
|
||||||
Local bool
|
Initorder uint8
|
||||||
Dodata uint8
|
Used bool
|
||||||
Initorder uint8
|
Isddd bool // is the argument variadic
|
||||||
Used bool
|
Readonly bool
|
||||||
Isddd bool // is the argument variadic
|
Implicit bool
|
||||||
Readonly bool
|
Addrtaken bool // address taken, even if not moved to heap
|
||||||
Implicit bool
|
Assigned bool // is the variable ever assigned to
|
||||||
Addrtaken bool // address taken, even if not moved to heap
|
Captured bool // is the variable captured by a closure
|
||||||
Assigned bool // is the variable ever assigned to
|
Byval bool // is the variable captured by value or by reference
|
||||||
Captured bool // is the variable captured by a closure
|
Reslice bool // this is a reslice x = x[0:y] or x = append(x, ...)
|
||||||
Byval bool // is the variable captured by value or by reference
|
Likely int8 // likeliness of if statement
|
||||||
Dupok bool // duplicate definitions ok (for func)
|
Hasbreak bool // has break statement
|
||||||
Wrapper bool // is method wrapper (for func)
|
Needzero bool // if it contains pointers, needs to be zeroed on function entry
|
||||||
Reslice bool // this is a reslice x = x[0:y] or x = append(x, ...)
|
Esc uint8 // EscXXX
|
||||||
Likely int8 // likeliness of if statement
|
Funcdepth int32
|
||||||
Hasbreak bool // has break statement
|
|
||||||
Needzero bool // if it contains pointers, needs to be zeroed on function entry
|
|
||||||
Needctxt bool // function uses context register (has closure variables)
|
|
||||||
Esc uint8 // EscXXX
|
|
||||||
Funcdepth int32
|
|
||||||
|
|
||||||
// most nodes
|
// most nodes
|
||||||
Type *Type
|
Type *Type
|
||||||
Orig *Node // original form, for printing, and tracking copies of ONAMEs
|
Orig *Node // original form, for printing, and tracking copies of ONAMEs
|
||||||
|
Nname *Node
|
||||||
|
|
||||||
// func
|
// func
|
||||||
Nname *Node
|
*Func
|
||||||
Shortname *Node
|
|
||||||
Enter *NodeList
|
|
||||||
Exit *NodeList
|
|
||||||
Cvars *NodeList // closure params
|
|
||||||
Dcl *NodeList // autodcl for this func/closure
|
|
||||||
Inl *NodeList // copy of the body for use in inlining
|
|
||||||
Inldcl *NodeList // copy of dcl for use in inlining
|
|
||||||
Closgen int
|
|
||||||
Outerfunc *Node
|
|
||||||
|
|
||||||
// OLITERAL/OREGISTER
|
// OLITERAL/OREGISTER
|
||||||
Val Val
|
Val Val
|
||||||
|
|
@ -112,18 +99,39 @@ type Node struct {
|
||||||
Escretval *NodeList // on OCALLxxx, list of dummy return values
|
Escretval *NodeList // on OCALLxxx, list of dummy return values
|
||||||
Escloopdepth int // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
|
Escloopdepth int // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
|
||||||
|
|
||||||
Sym *Sym // various
|
Sym *Sym // various
|
||||||
InlCost int32 // unique name for OTYPE/ONAME
|
Vargen int32 // unique name for OTYPE/ONAME
|
||||||
Vargen int32
|
Lineno int32
|
||||||
Lineno int32
|
Xoffset int64
|
||||||
|
Stkdelta int64 // offset added by stack frame compaction phase.
|
||||||
|
Ostk int32 // 6g only
|
||||||
|
Iota int32
|
||||||
|
Walkgen uint32
|
||||||
|
Esclevel int32
|
||||||
|
Opt interface{} // for optimization passes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Func holds Node fields used only with function-like nodes.
|
||||||
|
type Func struct {
|
||||||
|
Shortname *Node
|
||||||
|
Enter *NodeList
|
||||||
|
Exit *NodeList
|
||||||
|
Cvars *NodeList // closure params
|
||||||
|
Dcl *NodeList // autodcl for this func/closure
|
||||||
|
Inldcl *NodeList // copy of dcl for use in inlining
|
||||||
|
Closgen int
|
||||||
|
Outerfunc *Node
|
||||||
|
|
||||||
|
Inl *NodeList // copy of the body for use in inlining
|
||||||
|
InlCost int32
|
||||||
|
|
||||||
Endlineno int32
|
Endlineno int32
|
||||||
Xoffset int64
|
|
||||||
Stkdelta int64 // offset added by stack frame compaction phase.
|
Nosplit bool // func should not execute on separate stack
|
||||||
Ostk int32
|
Nowritebarrier bool // emit compiler error instead of write barrier
|
||||||
Iota int32
|
Dupok bool // duplicate definitions ok
|
||||||
Walkgen uint32
|
Wrapper bool // is method wrapper
|
||||||
Esclevel int32
|
Needctxt bool // function uses context register (has closure variables)
|
||||||
Opt interface{} // for optimization passes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node ops.
|
// Node ops.
|
||||||
|
|
|
||||||
|
|
@ -2523,7 +2523,7 @@ yydefault:
|
||||||
t.Rlist = yyDollar[5].list
|
t.Rlist = yyDollar[5].list
|
||||||
|
|
||||||
yyVAL.node = Nod(ODCLFUNC, nil, nil)
|
yyVAL.node = Nod(ODCLFUNC, nil, nil)
|
||||||
yyVAL.node.Nname = newname(yyDollar[1].sym)
|
yyVAL.node.Nname = newfuncname(yyDollar[1].sym)
|
||||||
yyVAL.node.Nname.Defn = yyVAL.node
|
yyVAL.node.Nname.Defn = yyVAL.node
|
||||||
yyVAL.node.Nname.Ntype = t // TODO: check if nname already has an ntype
|
yyVAL.node.Nname.Ntype = t // TODO: check if nname already has an ntype
|
||||||
declare(yyVAL.node.Nname, PFUNC)
|
declare(yyVAL.node.Nname, PFUNC)
|
||||||
|
|
@ -2559,7 +2559,7 @@ yydefault:
|
||||||
t.Rlist = yyDollar[8].list
|
t.Rlist = yyDollar[8].list
|
||||||
|
|
||||||
yyVAL.node = Nod(ODCLFUNC, nil, nil)
|
yyVAL.node = Nod(ODCLFUNC, nil, nil)
|
||||||
yyVAL.node.Shortname = newname(yyDollar[4].sym)
|
yyVAL.node.Shortname = newfuncname(yyDollar[4].sym)
|
||||||
yyVAL.node.Nname = methodname1(yyVAL.node.Shortname, rcvr.Right)
|
yyVAL.node.Nname = methodname1(yyVAL.node.Shortname, rcvr.Right)
|
||||||
yyVAL.node.Nname.Defn = yyVAL.node
|
yyVAL.node.Nname.Defn = yyVAL.node
|
||||||
yyVAL.node.Nname.Ntype = t
|
yyVAL.node.Nname.Ntype = t
|
||||||
|
|
@ -2589,7 +2589,7 @@ yydefault:
|
||||||
Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", Sconv(s, 0), Tconv(s.Def.Type, 0), Tconv(t, 0))
|
Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", Sconv(s, 0), Tconv(s.Def.Type, 0), Tconv(t, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
yyVAL.node = newname(s)
|
yyVAL.node = newfuncname(s)
|
||||||
yyVAL.node.Type = t
|
yyVAL.node.Type = t
|
||||||
declare(yyVAL.node, PFUNC)
|
declare(yyVAL.node, PFUNC)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue