]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/gc: separate func-only Node fields
authorJosh Bleecher Snyder <josharian@gmail.com>
Wed, 11 Mar 2015 04:37:13 +0000 (21:37 -0700)
committerJosh Bleecher Snyder <josharian@gmail.com>
Wed, 1 Apr 2015 18:00:20 +0000 (18:00 +0000)
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>

src/cmd/internal/gc/closure.go
src/cmd/internal/gc/dcl.go
src/cmd/internal/gc/export.go
src/cmd/internal/gc/go.y
src/cmd/internal/gc/inl.go
src/cmd/internal/gc/subr.go
src/cmd/internal/gc/syntax.go
src/cmd/internal/gc/y.go

index 4b1e92964269e3c015d763968808a02cc039a2fd..7cee6309c30cf70cf4367053a3d30d6bcce45fdc 100644 (file)
@@ -191,7 +191,7 @@ func makeclosure(func_ *Node) *Node {
        // create the function
        xfunc := Nod(ODCLFUNC, nil, nil)
 
-       xfunc.Nname = newname(closurename(func_))
+       xfunc.Nname = newfuncname(closurename(func_))
        xfunc.Nname.Sym.Flags |= SymExported // disable export
        xfunc.Nname.Ntype = xtype
        xfunc.Nname.Defn = xfunc
@@ -581,7 +581,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
        xtype.Rlist = l
 
        xfunc.Dupok = true
-       xfunc.Nname = newname(sym)
+       xfunc.Nname = newfuncname(sym)
        xfunc.Nname.Sym.Flags |= SymExported // disable export
        xfunc.Nname.Ntype = xtype
        xfunc.Nname.Defn = xfunc
index 64be3e7119351d7e9cc5e1bef641f8bd7e97dbe4..4e298a3038fe0ceb90c64662c25f2e526a07f9d1 100644 (file)
@@ -373,6 +373,14 @@ func newname(s *Sym) *Node {
        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
  * being declared.
@@ -542,6 +550,7 @@ func ifacedcl(n *Node) {
                Yyerror("methods must have a unique non-blank name")
        }
 
+       n.Func = new(Func)
        dclcontext = PPARAM
        markdcl()
        Funcdepth++
@@ -1312,7 +1321,7 @@ func methodname1(n *Node, t *Node) *Node {
        }
 
        if t.Sym == nil || isblank(n) {
-               return newname(n.Sym)
+               return newfuncname(n.Sym)
        }
 
        var p string
@@ -1323,9 +1332,9 @@ func methodname1(n *Node, t *Node) *Node {
        }
 
        if exportname(t.Sym.Name) {
-               n = newname(Lookup(p))
+               n = newfuncname(Lookup(p))
        } else {
-               n = newname(Pkglookup(p, t.Sym.Pkg))
+               n = newfuncname(Pkglookup(p, t.Sym.Pkg))
        }
 
        return n
@@ -1476,7 +1485,7 @@ func funcsym(s *Sym) *Sym {
 
        s1 := Pkglookup(s.Name+"·f", s.Pkg)
        if s1.Def == nil {
-               s1.Def = newname(s1)
+               s1.Def = newfuncname(s1)
                s1.Def.Shortname = newname(s)
                funcsyms = list(funcsyms, s1.Def)
        }
index e36ea76080ab5ccfe8d9d88026ce5e9abb31d71c..dae891292479687d8c91f548c42a8a6a1d0ee693 100644 (file)
@@ -239,7 +239,7 @@ func dumpexportvar(s *Sym) {
        dumpexporttype(t)
 
        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.
                        // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
                        if Debug['l'] < 2 {
index bfdf781519d27d379992baf5ced4d5ce1919dc29..6777d7a361bdc8480323026b32c6a2ffed599d58 100644 (file)
@@ -1358,7 +1358,7 @@ fndcl:
                t.Rlist = $5;
 
                $$ = Nod(ODCLFUNC, nil, nil);
-               $$.Nname = newname($1);
+               $$.Nname = newfuncname($1);
                $$.Nname.Defn = $$;
                $$.Nname.Ntype = t;             // TODO: check if nname already has an ntype
                declare($$.Nname, PFUNC);
@@ -1392,7 +1392,7 @@ fndcl:
                t.Rlist = $8;
 
                $$ = Nod(ODCLFUNC, nil, nil);
-               $$.Shortname = newname($4);
+               $$.Shortname = newfuncname($4);
                $$.Nname = methodname1($$.Shortname, rcvr.Right);
                $$.Nname.Defn = $$;
                $$.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));
                }
 
-               $$ = newname(s);
+               $$ = newfuncname(s);
                $$.Type = t;
                declare($$, PFUNC);
 
index 5e5cb6d3f0b6c8978ea9b71e46c977248468fd0a..0e8ef710ffd76d41da91b7b7fcb83d134dee3777 100644 (file)
@@ -169,7 +169,7 @@ func ishairy(n *Node, budget *int) bool {
        switch n.Op {
        // Call is okay if inlinable and we have the budget for the body.
        case OCALLFUNC:
-               if n.Left.Inl != nil {
+               if n.Left.Func != nil && n.Left.Inl != nil {
                        *budget -= int(n.Left.InlCost)
                        break
                }
@@ -247,7 +247,9 @@ func inlcopy(n *Node) *Node {
 
        m := Nod(OXXX, nil, nil)
        *m = *n
-       m.Inl = nil
+       if m.Func != nil {
+               m.Inl = nil
+       }
        m.Left = inlcopy(n.Left)
        m.Right = inlcopy(n.Right)
        m.List = inlcopylist(n.List)
@@ -457,7 +459,7 @@ func inlnode(np **Node) {
                if Debug['m'] > 3 {
                        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)
                } 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 {
index 8d199a296d798e3154b0c219562d406fe839a08d..17ee1d3c0a85a997331c3afde6d5f5ddec1ce7a4 100644 (file)
@@ -394,6 +394,10 @@ func Nod(op int, nleft *Node, nright *Node) *Node {
        n.Xoffset = BADWIDTH
        n.Orig = n
        n.Curfn = Curfn
+       switch op {
+       case OCLOSURE, ODCLFUNC:
+               n.Func = new(Func)
+       }
        return n
 }
 
index 1c84aa196b51a39037139763e7caaa2048487b0d..593e81e3dc37a9839f6a67f36c5fd9dbd42a9146 100644 (file)
@@ -23,58 +23,45 @@ type Node struct {
        List  *NodeList
        Rlist *NodeList
 
-       Op             uint8
-       Nointerface    bool
-       Ullman         uint8 // sethi/ullman number
-       Addable        uint8 // type of addressability - 0 is not addressable
-       Etype          uint8 // op for OASOP, etype for OTYPE, exclam for export
-       Bounded        bool  // bounds check unnecessary
-       Class          uint8 // PPARAM, PAUTO, PEXTERN, etc
-       Method         uint8 // OCALLMETH name
-       Embedded       uint8 // ODCLFIELD embedded type
-       Colas          uint8 // OAS resulting from :=
-       Diag           uint8 // already printed error about this
-       Noescape       bool  // func arguments do not escape
-       Nosplit        bool  // func should not execute on separate stack
-       Nowritebarrier bool  // emit compiler error instead of write barrier
-       Walkdef        uint8
-       Typecheck      uint8
-       Local          bool
-       Dodata         uint8
-       Initorder      uint8
-       Used           bool
-       Isddd          bool // is the argument variadic
-       Readonly       bool
-       Implicit       bool
-       Addrtaken      bool  // address taken, even if not moved to heap
-       Assigned       bool  // is the variable ever assigned to
-       Captured       bool  // is the variable captured by a closure
-       Byval          bool  // is the variable captured by value or by reference
-       Dupok          bool  // duplicate definitions ok (for func)
-       Wrapper        bool  // is method wrapper (for func)
-       Reslice        bool  // this is a reslice x = x[0:y] or x = append(x, ...)
-       Likely         int8  // likeliness of if statement
-       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
+       Op          uint8
+       Nointerface bool
+       Ullman      uint8 // sethi/ullman number
+       Addable     uint8 // type of addressability - 0 is not addressable
+       Etype       uint8 // op for OASOP, etype for OTYPE, exclam for export
+       Bounded     bool  // bounds check unnecessary
+       Class       uint8 // PPARAM, PAUTO, PEXTERN, etc
+       Method      uint8 // OCALLMETH name
+       Embedded    uint8 // ODCLFIELD embedded type
+       Colas       uint8 // OAS resulting from :=
+       Diag        uint8 // already printed error about this
+       Noescape    bool  // func arguments do not escape; TODO(rsc): move Noescape to Func struct (see CL 7360)
+       Walkdef     uint8
+       Typecheck   uint8
+       Local       bool
+       Dodata      uint8
+       Initorder   uint8
+       Used        bool
+       Isddd       bool // is the argument variadic
+       Readonly    bool
+       Implicit    bool
+       Addrtaken   bool  // address taken, even if not moved to heap
+       Assigned    bool  // is the variable ever assigned to
+       Captured    bool  // is the variable captured by a closure
+       Byval       bool  // is the variable captured by value or by reference
+       Reslice     bool  // this is a reslice x = x[0:y] or x = append(x, ...)
+       Likely      int8  // likeliness of if statement
+       Hasbreak    bool  // has break statement
+       Needzero    bool  // if it contains pointers, needs to be zeroed on function entry
+       Esc         uint8 // EscXXX
+       Funcdepth   int32
 
        // most nodes
-       Type *Type
-       Orig *Node // original form, for printing, and tracking copies of ONAMEs
+       Type  *Type
+       Orig  *Node // original form, for printing, and tracking copies of ONAMEs
+       Nname *Node
 
        // func
-       Nname     *Node
-       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
+       *Func
 
        // OLITERAL/OREGISTER
        Val Val
@@ -112,18 +99,39 @@ type Node struct {
        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
 
-       Sym       *Sym  // various
-       InlCost   int32 // unique name for OTYPE/ONAME
-       Vargen    int32
-       Lineno    int32
+       Sym      *Sym  // various
+       Vargen   int32 // unique name for OTYPE/ONAME
+       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
-       Xoffset   int64
-       Stkdelta  int64 // offset added by stack frame compaction phase.
-       Ostk      int32
-       Iota      int32
-       Walkgen   uint32
-       Esclevel  int32
-       Opt       interface{} // for optimization passes
+
+       Nosplit        bool // func should not execute on separate stack
+       Nowritebarrier bool // emit compiler error instead of write barrier
+       Dupok          bool // duplicate definitions ok
+       Wrapper        bool // is method wrapper
+       Needctxt       bool // function uses context register (has closure variables)
 }
 
 // Node ops.
index 4f97439b22b9af063aea2e608cd6441a43eba3bb..4e3f8b1a1adace38766cf51733e15ccc99322da9 100644 (file)
@@ -2523,7 +2523,7 @@ yydefault:
                        t.Rlist = yyDollar[5].list
 
                        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.Ntype = t // TODO: check if nname already has an ntype
                        declare(yyVAL.node.Nname, PFUNC)
@@ -2559,7 +2559,7 @@ yydefault:
                        t.Rlist = yyDollar[8].list
 
                        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.Defn = yyVAL.node
                        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))
                        }
 
-                       yyVAL.node = newname(s)
+                       yyVAL.node = newfuncname(s)
                        yyVAL.node.Type = t
                        declare(yyVAL.node, PFUNC)