]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: extract inline related fields into separate Inline type
authorMatthew Dempsky <mdempsky@google.com>
Wed, 4 Apr 2018 22:53:27 +0000 (15:53 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 5 Apr 2018 05:12:36 +0000 (05:12 +0000)
Inl, Inldcl, and InlCost are only applicable to functions with bodies
that can be inlined, so pull them out into a separate Inline type to
make understanding them easier.

A side benefit is that we can check if a function can be inlined by
just checking if n.Func.Inl is non-nil, which simplifies handling of
empty function bodies.

While here, remove some unnecessary Curfn twiddling, and make imported
functions use Inl.Dcl instead of Func.Dcl for consistency for local
functions.

Passes toolstash-check.

Change-Id: Ifd4a80349d85d9e8e4484952b38ec4a63182e81f
Reviewed-on: https://go-review.googlesource.com/104756
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/cmd/compile/internal/gc/bexport.go
src/cmd/compile/internal/gc/bimport.go
src/cmd/compile/internal/gc/inl.go
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/pgen.go
src/cmd/compile/internal/gc/sizeof_test.go
src/cmd/compile/internal/gc/syntax.go

index 982f11fb8882c02ed46f3b7f60e5ec09fe394ccf..060e7b7a677634f31b39daaf4d8ff3b6fb31e046 100644 (file)
@@ -377,11 +377,11 @@ func export(out *bufio.Writer, trace bool) int {
                        // function has inlineable body:
                        // write index and body
                        if p.trace {
-                               p.tracef("\n----\nfunc { %#v }\n", f.Inl)
+                               p.tracef("\n----\nfunc { %#v }\n", asNodes(f.Inl.Body))
                        }
                        p.int(i)
-                       p.int(int(f.InlCost))
-                       p.stmtList(f.Inl)
+                       p.int(int(f.Inl.Cost))
+                       p.stmtList(asNodes(f.Inl.Body))
                        if p.trace {
                                p.tracef("\n")
                        }
index 176da7f7590e26fe5dc5cd52731799e81717cb90..01e77ef859d66b5dca454ee1b250e2ee40d50143 100644 (file)
@@ -188,28 +188,22 @@ func Import(imp *types.Pkg, in *bufio.Reader) {
                // parameter renaming which doesn't matter if we don't have a body.
 
                inlCost := p.int()
-               if f := p.funcList[i]; f != nil && f.Func.Inl.Len() == 0 {
+               if f := p.funcList[i]; f != nil && f.Func.Inl == nil {
                        // function not yet imported - read body and set it
                        funchdr(f)
                        body := p.stmtList()
-                       if body == nil {
-                               // Make sure empty body is not interpreted as
-                               // no inlineable body (see also parser.fnbody)
-                               // (not doing so can cause significant performance
-                               // degradation due to unnecessary calls to empty
-                               // functions).
-                               body = []*Node{nod(OEMPTY, nil, nil)}
+                       funcbody()
+                       f.Func.Inl = &Inline{
+                               Cost: int32(inlCost),
+                               Body: body,
                        }
-                       f.Func.Inl.Set(body)
-                       f.Func.InlCost = int32(inlCost)
-                       if Debug['E'] > 0 && Debug['m'] > 2 && f.Func.Inl.Len() != 0 {
+                       if Debug['E'] > 0 && Debug['m'] > 2 {
                                if Debug['m'] > 3 {
-                                       fmt.Printf("inl body for %v: %+v\n", f, f.Func.Inl)
+                                       fmt.Printf("inl body for %v: %+v\n", f, asNodes(body))
                                } else {
-                                       fmt.Printf("inl body for %v: %v\n", f, f.Func.Inl)
+                                       fmt.Printf("inl body for %v: %v\n", f, asNodes(body))
                                }
                        }
-                       funcbody()
                } else {
                        // function already imported - read body but discard declarations
                        dclcontext = PDISCARD // throw away any declarations
index 54c031178cc38a66f53eb40703bc2cd15987d293..9ee6176ead4d8175f4c5bd6b1ad73a77fd557aaa 100644 (file)
@@ -70,7 +70,7 @@ func typecheckinl(fn *Node) {
        }
 
        if Debug['m'] > 2 || Debug_export != 0 {
-               fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, fn.Func.Inl)
+               fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, asNodes(fn.Func.Inl.Body))
        }
 
        save_safemode := safemode
@@ -78,9 +78,16 @@ func typecheckinl(fn *Node) {
 
        savefn := Curfn
        Curfn = fn
-       typecheckslice(fn.Func.Inl.Slice(), Etop)
+       typecheckslice(fn.Func.Inl.Body, Etop)
        Curfn = savefn
 
+       // During typechecking, declarations are added to
+       // Curfn.Func.Dcl. Move them to Inl.Dcl for consistency with
+       // how local functions behave. (Append because typecheckinl
+       // may be called multiple times.)
+       fn.Func.Inl.Dcl = append(fn.Func.Inl.Dcl, fn.Func.Dcl...)
+       fn.Func.Dcl = nil
+
        safemode = save_safemode
 
        lineno = lno
@@ -155,26 +162,21 @@ func caninl(fn *Node) {
                return
        }
 
-       savefn := Curfn
-       Curfn = fn
-
-       n.Func.Inl.Set(fn.Nbody.Slice())
-       fn.Nbody.Set(inlcopylist(n.Func.Inl.Slice()))
-       inldcl := inlcopylist(n.Name.Defn.Func.Dcl)
-       n.Func.Inldcl.Set(inldcl)
-       n.Func.InlCost = maxBudget - visitor.budget
+       n.Func.Inl = &Inline{
+               Cost: maxBudget - visitor.budget,
+               Dcl:  inlcopylist(n.Name.Defn.Func.Dcl),
+               Body: inlcopylist(fn.Nbody.Slice()),
+       }
 
        // hack, TODO, check for better way to link method nodes back to the thing with the ->inl
        // this is so export can find the body of a method
        fn.Type.FuncType().Nname = asTypesNode(n)
 
        if Debug['m'] > 1 {
-               fmt.Printf("%v: can inline %#v as: %#v { %#v }\n", fn.Line(), n, fn.Type, n.Func.Inl)
+               fmt.Printf("%v: can inline %#v as: %#v { %#v }\n", fn.Line(), n, fn.Type, asNodes(n.Func.Inl.Body))
        } else if Debug['m'] != 0 {
                fmt.Printf("%v: can inline %v\n", fn.Line(), n)
        }
-
-       Curfn = savefn
 }
 
 // inlFlood marks n's inline body for export and recursively ensures
@@ -189,7 +191,7 @@ func inlFlood(n *Node) {
        if n.Func == nil {
                Fatalf("inlFlood: missing Func on %v", n)
        }
-       if n.Func.Inl.Len() == 0 {
+       if n.Func.Inl == nil {
                return
        }
 
@@ -200,7 +202,7 @@ func inlFlood(n *Node) {
 
        typecheckinl(n)
 
-       inspectList(n.Func.Inl, func(n *Node) bool {
+       inspectList(asNodes(n.Func.Inl.Body), func(n *Node) bool {
                switch n.Op {
                case ONAME:
                        // Mark any referenced global variables or
@@ -259,13 +261,13 @@ func (v *hairyVisitor) visit(n *Node) bool {
                        }
                }
 
-               if fn := n.Left.Func; fn != nil && fn.Inl.Len() != 0 {
-                       v.budget -= fn.InlCost
+               if fn := n.Left.Func; fn != nil && fn.Inl != nil {
+                       v.budget -= fn.Inl.Cost
                        break
                }
                if n.Left.isMethodExpression() {
-                       if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl.Len() != 0 {
-                               v.budget -= d.Func.InlCost
+                       if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl != nil {
+                               v.budget -= d.Func.Inl.Cost
                                break
                        }
                }
@@ -300,8 +302,8 @@ func (v *hairyVisitor) visit(n *Node) bool {
                                break
                        }
                }
-               if inlfn := asNode(t.FuncType().Nname).Func; inlfn.Inl.Len() != 0 {
-                       v.budget -= inlfn.InlCost
+               if inlfn := asNode(t.FuncType().Nname).Func; inlfn.Inl != nil {
+                       v.budget -= inlfn.Inl.Cost
                        break
                }
                if Debug['l'] < 4 {
@@ -394,7 +396,7 @@ func inlcopy(n *Node) *Node {
 
        m := n.copy()
        if m.Func != nil {
-               m.Func.Inl.Set(nil)
+               Fatalf("unexpected Func: %v", m)
        }
        m.Left = inlcopy(n.Left)
        m.Right = inlcopy(n.Right)
@@ -583,7 +585,7 @@ func inlnode(n *Node) *Node {
                if Debug['m'] > 3 {
                        fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
                }
-               if n.Left.Func != nil && n.Left.Func.Inl.Len() != 0 && !isIntrinsicCall(n) { // normal case
+               if n.Left.Func != nil && n.Left.Func.Inl != nil && !isIntrinsicCall(n) { // normal case
                        n = mkinlcall(n, n.Left)
                } else if n.Left.isMethodExpression() && asNode(n.Left.Sym.Def) != nil {
                        n = mkinlcall(n, asNode(n.Left.Sym.Def))
@@ -647,7 +649,7 @@ func inlinableClosure(n *Node) *Node {
        c := n.Func.Closure
        caninl(c)
        f := c.Func.Nname
-       if f == nil || f.Func.Inl.Len() == 0 {
+       if f == nil || f.Func.Inl == nil {
                return nil
        }
        return f
@@ -772,7 +774,7 @@ var inlgen int
 // The result of mkinlcall1 MUST be assigned back to n, e.g.
 //     n.Left = mkinlcall1(n.Left, fn, isddd)
 func mkinlcall1(n, fn *Node) *Node {
-       if fn.Func.Inl.Len() == 0 {
+       if fn.Func.Inl == nil {
                // No inlinable body.
                return n
        }
@@ -798,7 +800,7 @@ func mkinlcall1(n, fn *Node) *Node {
 
        // We have a function node, and it has an inlineable body.
        if Debug['m'] > 1 {
-               fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, fn.Func.Inl)
+               fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, asNodes(fn.Func.Inl.Body))
        } else if Debug['m'] != 0 {
                fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
        }
@@ -814,12 +816,8 @@ func mkinlcall1(n, fn *Node) *Node {
        // record formals/locals for later post-processing
        var inlfvars []*Node
 
-       // Find declarations corresponding to inlineable body.
-       var dcl []*Node
+       // Handle captured variables when inlining closures.
        if fn.Name.Defn != nil {
-               dcl = fn.Func.Inldcl.Slice() // local function
-
-               // handle captured variables when inlining closures
                if c := fn.Name.Defn.Func.Closure; c != nil {
                        for _, v := range c.Func.Closure.Func.Cvars.Slice() {
                                if v.Op == OXXX {
@@ -854,11 +852,9 @@ func mkinlcall1(n, fn *Node) *Node {
                                }
                        }
                }
-       } else {
-               dcl = fn.Func.Dcl // imported function
        }
 
-       for _, ln := range dcl {
+       for _, ln := range fn.Func.Inl.Dcl {
                if ln.Op != ONAME {
                        continue
                }
@@ -1020,7 +1016,7 @@ func mkinlcall1(n, fn *Node) *Node {
                newInlIndex: newIndex,
        }
 
-       body := subst.list(fn.Func.Inl)
+       body := subst.list(asNodes(fn.Func.Inl.Body))
 
        lab := nod(OLABEL, retlabel, nil)
        body = append(body, lab)
index b42966229da822f81c89bc88d92962dc9e73da0a..6dd33a294441f7e7aceff644c60a1ee4fd220b43 100644 (file)
@@ -544,7 +544,7 @@ func Main(archInit func(*Arch)) {
                // Typecheck imported function bodies if debug['l'] > 1,
                // otherwise lazily when used or re-exported.
                for _, n := range importlist {
-                       if n.Func.Inl.Len() != 0 {
+                       if n.Func.Inl != nil {
                                saveerrors()
                                typecheckinl(n)
                        }
index e9271149a176240f3ab33087c16959ec407a2974..9747a0299e67274f387ef2d929da66b6e2dd6c35 100644 (file)
@@ -570,13 +570,8 @@ func createDwarfVars(fnsym *obj.LSym, fn *Func, automDecls []*Node) ([]*Node, []
 // with local vars; disregard this versioning when sorting.
 func preInliningDcls(fnsym *obj.LSym) []*Node {
        fn := Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*Node)
-       var dcl, rdcl []*Node
-       if fn.Name.Defn != nil {
-               dcl = fn.Func.Inldcl.Slice() // local function
-       } else {
-               dcl = fn.Func.Dcl // imported function
-       }
-       for _, n := range dcl {
+       var rdcl []*Node
+       for _, n := range fn.Func.Inl.Dcl {
                c := n.Sym.Name[0]
                // Avoid reporting "_" parameters, since if there are more than
                // one, it can result in a collision later on, as in #23179.
index c7104030bdc169af15b5940746a583e21ed55fe5..b1184ffbb9dbc2f8c5d742aa87cdf3f41200bf96 100644 (file)
@@ -22,7 +22,7 @@ func TestSizeof(t *testing.T) {
                _32bit uintptr     // size on 32bit platforms
                _64bit uintptr     // size on 64bit platforms
        }{
-               {Func{}, 124, 224},
+               {Func{}, 116, 208},
                {Name{}, 32, 56},
                {Param{}, 24, 48},
                {Node{}, 76, 128},
index 28befbeb857cbe94b33c2d9e1e060162046b4842..1b856b151863892a0abef7f7b8b793e9bb7d1dec 100644 (file)
@@ -461,7 +461,6 @@ type Func struct {
        Exit      Nodes
        Cvars     Nodes   // closure params
        Dcl       []*Node // autodcl for this func/closure
-       Inldcl    Nodes   // copy of dcl for use in inlining
 
        // Parents records the parent scope of each scope within a
        // function. The root scope (0) has no parent, so the i'th
@@ -484,8 +483,7 @@ type Func struct {
        Nname      *Node
        lsym       *obj.LSym
 
-       Inl     Nodes // copy of the body for use in inlining
-       InlCost int32
+       Inl *Inline
 
        Label int32 // largest auto-generated label in this function
 
@@ -502,6 +500,15 @@ type Func struct {
        nwbrCalls *[]nowritebarrierrecCallSym
 }
 
+// An Inline holds fields used for function bodies that can be inlined.
+type Inline struct {
+       Cost int32 // heuristic cost of inlining this function
+
+       // Copies of Func.Dcl and Nbody for use during inlining.
+       Dcl  []*Node
+       Body []*Node
+}
+
 // A Mark represents a scope boundary.
 type Mark struct {
        // Pos is the position of the token that marks the scope
@@ -737,6 +744,11 @@ const (
 // a slice to save space.
 type Nodes struct{ slice *[]*Node }
 
+// asNodes returns a slice of *Node as a Nodes value.
+func asNodes(s []*Node) Nodes {
+       return Nodes{&s}
+}
+
 // Slice returns the entries in Nodes as a slice.
 // Changes to the slice entries (as in s[i] = n) will be reflected in
 // the Nodes.