// 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
}
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
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
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
if n.Func == nil {
Fatalf("inlFlood: missing Func on %v", n)
}
- if n.Func.Inl.Len() == 0 {
+ if n.Func.Inl == nil {
return
}
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
}
}
- 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
}
}
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 {
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)
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))
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
// 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
}
// 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)
}
// 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 {
}
}
}
- } else {
- dcl = fn.Func.Dcl // imported function
}
- for _, ln := range dcl {
+ for _, ln := range fn.Func.Inl.Dcl {
if ln.Op != ONAME {
continue
}
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)
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
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
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
// 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.