Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/inline/inl.go

Documentation: cmd/compile/internal/inline

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  //
     5  // The inlining facility makes 2 passes: first caninl determines which
     6  // functions are suitable for inlining, and for those that are it
     7  // saves a copy of the body. Then InlineCalls walks each function body to
     8  // expand calls to inlinable functions.
     9  //
    10  // The Debug.l flag controls the aggressiveness. Note that main() swaps level 0 and 1,
    11  // making 1 the default and -l disable. Additional levels (beyond -l) may be buggy and
    12  // are not supported.
    13  //      0: disabled
    14  //      1: 80-nodes leaf functions, oneliners, panic, lazy typechecking (default)
    15  //      2: (unassigned)
    16  //      3: (unassigned)
    17  //      4: allow non-leaf functions
    18  //
    19  // At some point this may get another default and become switch-offable with -N.
    20  //
    21  // The -d typcheckinl flag enables early typechecking of all imported bodies,
    22  // which is useful to flush out bugs.
    23  //
    24  // The Debug.m flag enables diagnostic output.  a single -m is useful for verifying
    25  // which calls get inlined or not, more is for debugging, and may go away at any point.
    26  
    27  package inline
    28  
    29  import (
    30  	"fmt"
    31  	"go/constant"
    32  	"strings"
    33  
    34  	"cmd/compile/internal/base"
    35  	"cmd/compile/internal/ir"
    36  	"cmd/compile/internal/logopt"
    37  	"cmd/compile/internal/typecheck"
    38  	"cmd/compile/internal/types"
    39  	"cmd/internal/obj"
    40  	"cmd/internal/src"
    41  )
    42  
    43  // Inlining budget parameters, gathered in one place
    44  const (
    45  	inlineMaxBudget       = 80
    46  	inlineExtraAppendCost = 0
    47  	// default is to inline if there's at most one call. -l=4 overrides this by using 1 instead.
    48  	inlineExtraCallCost  = 57              // 57 was benchmarked to provided most benefit with no bad surprises; see https://github.com/golang/go/issues/19348#issuecomment-439370742
    49  	inlineExtraPanicCost = 1               // do not penalize inlining panics.
    50  	inlineExtraThrowCost = inlineMaxBudget // with current (2018-05/1.11) code, inlining runtime.throw does not help.
    51  
    52  	inlineBigFunctionNodes   = 5000 // Functions with this many nodes are considered "big".
    53  	inlineBigFunctionMaxCost = 20   // Max cost of inlinee when inlining into a "big" function.
    54  )
    55  
    56  // InlinePackage finds functions that can be inlined and clones them before walk expands them.
    57  func InlinePackage() {
    58  	ir.VisitFuncsBottomUp(typecheck.Target.Decls, func(list []*ir.Func, recursive bool) {
    59  		numfns := numNonClosures(list)
    60  		for _, n := range list {
    61  			if !recursive || numfns > 1 {
    62  				// We allow inlining if there is no
    63  				// recursion, or the recursion cycle is
    64  				// across more than one function.
    65  				CanInline(n)
    66  			} else {
    67  				if base.Flag.LowerM > 1 {
    68  					fmt.Printf("%v: cannot inline %v: recursive\n", ir.Line(n), n.Nname)
    69  				}
    70  			}
    71  			InlineCalls(n)
    72  		}
    73  	})
    74  }
    75  
    76  // CanInline determines whether fn is inlineable.
    77  // If so, CanInline saves copies of fn.Body and fn.Dcl in fn.Inl.
    78  // fn and fn.Body will already have been typechecked.
    79  func CanInline(fn *ir.Func) {
    80  	if fn.Nname == nil {
    81  		base.Fatalf("CanInline no nname %+v", fn)
    82  	}
    83  
    84  	var reason string // reason, if any, that the function was not inlined
    85  	if base.Flag.LowerM > 1 || logopt.Enabled() {
    86  		defer func() {
    87  			if reason != "" {
    88  				if base.Flag.LowerM > 1 {
    89  					fmt.Printf("%v: cannot inline %v: %s\n", ir.Line(fn), fn.Nname, reason)
    90  				}
    91  				if logopt.Enabled() {
    92  					logopt.LogOpt(fn.Pos(), "cannotInlineFunction", "inline", ir.FuncName(fn), reason)
    93  				}
    94  			}
    95  		}()
    96  	}
    97  
    98  	// If marked "go:noinline", don't inline
    99  	if fn.Pragma&ir.Noinline != 0 {
   100  		reason = "marked go:noinline"
   101  		return
   102  	}
   103  
   104  	// If marked "go:norace" and -race compilation, don't inline.
   105  	if base.Flag.Race && fn.Pragma&ir.Norace != 0 {
   106  		reason = "marked go:norace with -race compilation"
   107  		return
   108  	}
   109  
   110  	// If marked "go:nocheckptr" and -d checkptr compilation, don't inline.
   111  	if base.Debug.Checkptr != 0 && fn.Pragma&ir.NoCheckPtr != 0 {
   112  		reason = "marked go:nocheckptr"
   113  		return
   114  	}
   115  
   116  	// If marked "go:cgo_unsafe_args", don't inline, since the
   117  	// function makes assumptions about its argument frame layout.
   118  	if fn.Pragma&ir.CgoUnsafeArgs != 0 {
   119  		reason = "marked go:cgo_unsafe_args"
   120  		return
   121  	}
   122  
   123  	// If marked as "go:uintptrescapes", don't inline, since the
   124  	// escape information is lost during inlining.
   125  	if fn.Pragma&ir.UintptrEscapes != 0 {
   126  		reason = "marked as having an escaping uintptr argument"
   127  		return
   128  	}
   129  
   130  	// The nowritebarrierrec checker currently works at function
   131  	// granularity, so inlining yeswritebarrierrec functions can
   132  	// confuse it (#22342). As a workaround, disallow inlining
   133  	// them for now.
   134  	if fn.Pragma&ir.Yeswritebarrierrec != 0 {
   135  		reason = "marked go:yeswritebarrierrec"
   136  		return
   137  	}
   138  
   139  	// If fn has no body (is defined outside of Go), cannot inline it.
   140  	if len(fn.Body) == 0 {
   141  		reason = "no function body"
   142  		return
   143  	}
   144  
   145  	if fn.Typecheck() == 0 {
   146  		base.Fatalf("CanInline on non-typechecked function %v", fn)
   147  	}
   148  
   149  	n := fn.Nname
   150  	if n.Func.InlinabilityChecked() {
   151  		return
   152  	}
   153  	defer n.Func.SetInlinabilityChecked(true)
   154  
   155  	cc := int32(inlineExtraCallCost)
   156  	if base.Flag.LowerL == 4 {
   157  		cc = 1 // this appears to yield better performance than 0.
   158  	}
   159  
   160  	// At this point in the game the function we're looking at may
   161  	// have "stale" autos, vars that still appear in the Dcl list, but
   162  	// which no longer have any uses in the function body (due to
   163  	// elimination by deadcode). We'd like to exclude these dead vars
   164  	// when creating the "Inline.Dcl" field below; to accomplish this,
   165  	// the hairyVisitor below builds up a map of used/referenced
   166  	// locals, and we use this map to produce a pruned Inline.Dcl
   167  	// list. See issue 25249 for more context.
   168  
   169  	visitor := hairyVisitor{
   170  		budget:        inlineMaxBudget,
   171  		extraCallCost: cc,
   172  	}
   173  	if visitor.tooHairy(fn) {
   174  		reason = visitor.reason
   175  		return
   176  	}
   177  
   178  	n.Func.Inl = &ir.Inline{
   179  		Cost: inlineMaxBudget - visitor.budget,
   180  		Dcl:  pruneUnusedAutos(n.Defn.(*ir.Func).Dcl, &visitor),
   181  		Body: inlcopylist(fn.Body),
   182  	}
   183  
   184  	if base.Flag.LowerM > 1 {
   185  		fmt.Printf("%v: can inline %v with cost %d as: %v { %v }\n", ir.Line(fn), n, inlineMaxBudget-visitor.budget, fn.Type(), ir.Nodes(n.Func.Inl.Body))
   186  	} else if base.Flag.LowerM != 0 {
   187  		fmt.Printf("%v: can inline %v\n", ir.Line(fn), n)
   188  	}
   189  	if logopt.Enabled() {
   190  		logopt.LogOpt(fn.Pos(), "canInlineFunction", "inline", ir.FuncName(fn), fmt.Sprintf("cost: %d", inlineMaxBudget-visitor.budget))
   191  	}
   192  }
   193  
   194  // Inline_Flood marks n's inline body for export and recursively ensures
   195  // all called functions are marked too.
   196  func Inline_Flood(n *ir.Name, exportsym func(*ir.Name)) {
   197  	if n == nil {
   198  		return
   199  	}
   200  	if n.Op() != ir.ONAME || n.Class != ir.PFUNC {
   201  		base.Fatalf("Inline_Flood: unexpected %v, %v, %v", n, n.Op(), n.Class)
   202  	}
   203  	fn := n.Func
   204  	if fn == nil {
   205  		base.Fatalf("Inline_Flood: missing Func on %v", n)
   206  	}
   207  	if fn.Inl == nil {
   208  		return
   209  	}
   210  
   211  	if fn.ExportInline() {
   212  		return
   213  	}
   214  	fn.SetExportInline(true)
   215  
   216  	typecheck.ImportedBody(fn)
   217  
   218  	var doFlood func(n ir.Node)
   219  	doFlood = func(n ir.Node) {
   220  		switch n.Op() {
   221  		case ir.OMETHEXPR, ir.ODOTMETH:
   222  			Inline_Flood(ir.MethodExprName(n), exportsym)
   223  
   224  		case ir.ONAME:
   225  			n := n.(*ir.Name)
   226  			switch n.Class {
   227  			case ir.PFUNC:
   228  				Inline_Flood(n, exportsym)
   229  				exportsym(n)
   230  			case ir.PEXTERN:
   231  				exportsym(n)
   232  			}
   233  
   234  		case ir.OCALLPART:
   235  			// Okay, because we don't yet inline indirect
   236  			// calls to method values.
   237  		case ir.OCLOSURE:
   238  			// VisitList doesn't visit closure bodies, so force a
   239  			// recursive call to VisitList on the body of the closure.
   240  			ir.VisitList(n.(*ir.ClosureExpr).Func.Body, doFlood)
   241  		}
   242  	}
   243  
   244  	// Recursively identify all referenced functions for
   245  	// reexport. We want to include even non-called functions,
   246  	// because after inlining they might be callable.
   247  	ir.VisitList(ir.Nodes(fn.Inl.Body), doFlood)
   248  }
   249  
   250  // hairyVisitor visits a function body to determine its inlining
   251  // hairiness and whether or not it can be inlined.
   252  type hairyVisitor struct {
   253  	budget        int32
   254  	reason        string
   255  	extraCallCost int32
   256  	usedLocals    ir.NameSet
   257  	do            func(ir.Node) bool
   258  }
   259  
   260  func (v *hairyVisitor) tooHairy(fn *ir.Func) bool {
   261  	v.do = v.doNode // cache closure
   262  	if ir.DoChildren(fn, v.do) {
   263  		return true
   264  	}
   265  	if v.budget < 0 {
   266  		v.reason = fmt.Sprintf("function too complex: cost %d exceeds budget %d", inlineMaxBudget-v.budget, inlineMaxBudget)
   267  		return true
   268  	}
   269  	return false
   270  }
   271  
   272  func (v *hairyVisitor) doNode(n ir.Node) bool {
   273  	if n == nil {
   274  		return false
   275  	}
   276  	switch n.Op() {
   277  	// Call is okay if inlinable and we have the budget for the body.
   278  	case ir.OCALLFUNC:
   279  		n := n.(*ir.CallExpr)
   280  		// Functions that call runtime.getcaller{pc,sp} can not be inlined
   281  		// because getcaller{pc,sp} expect a pointer to the caller's first argument.
   282  		//
   283  		// runtime.throw is a "cheap call" like panic in normal code.
   284  		if n.X.Op() == ir.ONAME {
   285  			name := n.X.(*ir.Name)
   286  			if name.Class == ir.PFUNC && types.IsRuntimePkg(name.Sym().Pkg) {
   287  				fn := name.Sym().Name
   288  				if fn == "getcallerpc" || fn == "getcallersp" {
   289  					v.reason = "call to " + fn
   290  					return true
   291  				}
   292  				if fn == "throw" {
   293  					v.budget -= inlineExtraThrowCost
   294  					break
   295  				}
   296  			}
   297  		}
   298  
   299  		if ir.IsIntrinsicCall(n) {
   300  			// Treat like any other node.
   301  			break
   302  		}
   303  
   304  		if fn := inlCallee(n.X); fn != nil && fn.Inl != nil {
   305  			v.budget -= fn.Inl.Cost
   306  			break
   307  		}
   308  
   309  		// Call cost for non-leaf inlining.
   310  		v.budget -= v.extraCallCost
   311  
   312  	// Call is okay if inlinable and we have the budget for the body.
   313  	case ir.OCALLMETH:
   314  		n := n.(*ir.CallExpr)
   315  		t := n.X.Type()
   316  		if t == nil {
   317  			base.Fatalf("no function type for [%p] %+v\n", n.X, n.X)
   318  		}
   319  		fn := ir.MethodExprName(n.X).Func
   320  		if types.IsRuntimePkg(fn.Sym().Pkg) && fn.Sym().Name == "heapBits.nextArena" {
   321  			// Special case: explicitly allow
   322  			// mid-stack inlining of
   323  			// runtime.heapBits.next even though
   324  			// it calls slow-path
   325  			// runtime.heapBits.nextArena.
   326  			break
   327  		}
   328  		if fn.Inl != nil {
   329  			v.budget -= fn.Inl.Cost
   330  			break
   331  		}
   332  		// Call cost for non-leaf inlining.
   333  		v.budget -= v.extraCallCost
   334  
   335  	// Things that are too hairy, irrespective of the budget
   336  	case ir.OCALL, ir.OCALLINTER:
   337  		// Call cost for non-leaf inlining.
   338  		v.budget -= v.extraCallCost
   339  
   340  	case ir.OPANIC:
   341  		n := n.(*ir.UnaryExpr)
   342  		if n.X.Op() == ir.OCONVIFACE && n.X.(*ir.ConvExpr).Implicit() {
   343  			// Hack to keep reflect.flag.mustBe inlinable for TestIntendedInlining.
   344  			// Before CL 284412, these conversions were introduced later in the
   345  			// compiler, so they didn't count against inlining budget.
   346  			v.budget++
   347  		}
   348  		v.budget -= inlineExtraPanicCost
   349  
   350  	case ir.ORECOVER:
   351  		// recover matches the argument frame pointer to find
   352  		// the right panic value, so it needs an argument frame.
   353  		v.reason = "call to recover"
   354  		return true
   355  
   356  	case ir.OCLOSURE:
   357  		if base.Debug.InlFuncsWithClosures == 0 {
   358  			v.reason = "not inlining functions with closures"
   359  			return true
   360  		}
   361  
   362  		// TODO(danscales): Maybe make budget proportional to number of closure
   363  		// variables, e.g.:
   364  		//v.budget -= int32(len(n.(*ir.ClosureExpr).Func.ClosureVars) * 3)
   365  		v.budget -= 15
   366  		// Scan body of closure (which DoChildren doesn't automatically
   367  		// do) to check for disallowed ops in the body and include the
   368  		// body in the budget.
   369  		if doList(n.(*ir.ClosureExpr).Func.Body, v.do) {
   370  			return true
   371  		}
   372  
   373  	case ir.ORANGE,
   374  		ir.OSELECT,
   375  		ir.OGO,
   376  		ir.ODEFER,
   377  		ir.ODCLTYPE, // can't print yet
   378  		ir.OTAILCALL:
   379  		v.reason = "unhandled op " + n.Op().String()
   380  		return true
   381  
   382  	case ir.OAPPEND:
   383  		v.budget -= inlineExtraAppendCost
   384  
   385  	case ir.ODEREF:
   386  		// *(*X)(unsafe.Pointer(&x)) is low-cost
   387  		n := n.(*ir.StarExpr)
   388  
   389  		ptr := n.X
   390  		for ptr.Op() == ir.OCONVNOP {
   391  			ptr = ptr.(*ir.ConvExpr).X
   392  		}
   393  		if ptr.Op() == ir.OADDR {
   394  			v.budget += 1 // undo half of default cost of ir.ODEREF+ir.OADDR
   395  		}
   396  
   397  	case ir.OCONVNOP:
   398  		// This doesn't produce code, but the children might.
   399  		v.budget++ // undo default cost
   400  
   401  	case ir.ODCLCONST, ir.OFALL:
   402  		// These nodes don't produce code; omit from inlining budget.
   403  		return false
   404  
   405  	case ir.OFOR, ir.OFORUNTIL:
   406  		n := n.(*ir.ForStmt)
   407  		if n.Label != nil {
   408  			v.reason = "labeled control"
   409  			return true
   410  		}
   411  	case ir.OSWITCH:
   412  		n := n.(*ir.SwitchStmt)
   413  		if n.Label != nil {
   414  			v.reason = "labeled control"
   415  			return true
   416  		}
   417  	// case ir.ORANGE, ir.OSELECT in "unhandled" above
   418  
   419  	case ir.OBREAK, ir.OCONTINUE:
   420  		n := n.(*ir.BranchStmt)
   421  		if n.Label != nil {
   422  			// Should have short-circuited due to labeled control error above.
   423  			base.Fatalf("unexpected labeled break/continue: %v", n)
   424  		}
   425  
   426  	case ir.OIF:
   427  		n := n.(*ir.IfStmt)
   428  		if ir.IsConst(n.Cond, constant.Bool) {
   429  			// This if and the condition cost nothing.
   430  			// TODO(rsc): It seems strange that we visit the dead branch.
   431  			return doList(n.Init(), v.do) ||
   432  				doList(n.Body, v.do) ||
   433  				doList(n.Else, v.do)
   434  		}
   435  
   436  	case ir.ONAME:
   437  		n := n.(*ir.Name)
   438  		if n.Class == ir.PAUTO {
   439  			v.usedLocals.Add(n)
   440  		}
   441  
   442  	case ir.OBLOCK:
   443  		// The only OBLOCK we should see at this point is an empty one.
   444  		// In any event, let the visitList(n.List()) below take care of the statements,
   445  		// and don't charge for the OBLOCK itself. The ++ undoes the -- below.
   446  		v.budget++
   447  
   448  	case ir.OCALLPART, ir.OSLICELIT:
   449  		v.budget-- // Hack for toolstash -cmp.
   450  
   451  	case ir.OMETHEXPR:
   452  		v.budget++ // Hack for toolstash -cmp.
   453  	}
   454  
   455  	v.budget--
   456  
   457  	// When debugging, don't stop early, to get full cost of inlining this function
   458  	if v.budget < 0 && base.Flag.LowerM < 2 && !logopt.Enabled() {
   459  		v.reason = "too expensive"
   460  		return true
   461  	}
   462  
   463  	return ir.DoChildren(n, v.do)
   464  }
   465  
   466  func isBigFunc(fn *ir.Func) bool {
   467  	budget := inlineBigFunctionNodes
   468  	return ir.Any(fn, func(n ir.Node) bool {
   469  		budget--
   470  		return budget <= 0
   471  	})
   472  }
   473  
   474  // inlcopylist (together with inlcopy) recursively copies a list of nodes, except
   475  // that it keeps the same ONAME, OTYPE, and OLITERAL nodes. It is used for copying
   476  // the body and dcls of an inlineable function.
   477  func inlcopylist(ll []ir.Node) []ir.Node {
   478  	s := make([]ir.Node, len(ll))
   479  	for i, n := range ll {
   480  		s[i] = inlcopy(n)
   481  	}
   482  	return s
   483  }
   484  
   485  // inlcopy is like DeepCopy(), but does extra work to copy closures.
   486  func inlcopy(n ir.Node) ir.Node {
   487  	var edit func(ir.Node) ir.Node
   488  	edit = func(x ir.Node) ir.Node {
   489  		switch x.Op() {
   490  		case ir.ONAME, ir.OTYPE, ir.OLITERAL, ir.ONIL:
   491  			return x
   492  		}
   493  		m := ir.Copy(x)
   494  		ir.EditChildren(m, edit)
   495  		if x.Op() == ir.OCLOSURE {
   496  			x := x.(*ir.ClosureExpr)
   497  			// Need to save/duplicate x.Func.Nname,
   498  			// x.Func.Nname.Ntype, x.Func.Dcl, x.Func.ClosureVars, and
   499  			// x.Func.Body for iexport and local inlining.
   500  			oldfn := x.Func
   501  			newfn := ir.NewFunc(oldfn.Pos())
   502  			if oldfn.ClosureCalled() {
   503  				newfn.SetClosureCalled(true)
   504  			}
   505  			m.(*ir.ClosureExpr).Func = newfn
   506  			newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), oldfn.Nname.Sym())
   507  			// XXX OK to share fn.Type() ??
   508  			newfn.Nname.SetType(oldfn.Nname.Type())
   509  			// Ntype can be nil for -G=3 mode.
   510  			if oldfn.Nname.Ntype != nil {
   511  				newfn.Nname.Ntype = inlcopy(oldfn.Nname.Ntype).(ir.Ntype)
   512  			}
   513  			newfn.Body = inlcopylist(oldfn.Body)
   514  			// Make shallow copy of the Dcl and ClosureVar slices
   515  			newfn.Dcl = append([]*ir.Name(nil), oldfn.Dcl...)
   516  			newfn.ClosureVars = append([]*ir.Name(nil), oldfn.ClosureVars...)
   517  		}
   518  		return m
   519  	}
   520  	return edit(n)
   521  }
   522  
   523  // InlineCalls/inlnode walks fn's statements and expressions and substitutes any
   524  // calls made to inlineable functions. This is the external entry point.
   525  func InlineCalls(fn *ir.Func) {
   526  	savefn := ir.CurFunc
   527  	ir.CurFunc = fn
   528  	maxCost := int32(inlineMaxBudget)
   529  	if isBigFunc(fn) {
   530  		maxCost = inlineBigFunctionMaxCost
   531  	}
   532  	// Map to keep track of functions that have been inlined at a particular
   533  	// call site, in order to stop inlining when we reach the beginning of a
   534  	// recursion cycle again. We don't inline immediately recursive functions,
   535  	// but allow inlining if there is a recursion cycle of many functions.
   536  	// Most likely, the inlining will stop before we even hit the beginning of
   537  	// the cycle again, but the map catches the unusual case.
   538  	inlMap := make(map[*ir.Func]bool)
   539  	var edit func(ir.Node) ir.Node
   540  	edit = func(n ir.Node) ir.Node {
   541  		return inlnode(n, maxCost, inlMap, edit)
   542  	}
   543  	ir.EditChildren(fn, edit)
   544  	ir.CurFunc = savefn
   545  }
   546  
   547  // Turn an OINLCALL into a statement.
   548  func inlconv2stmt(inlcall *ir.InlinedCallExpr) ir.Node {
   549  	n := ir.NewBlockStmt(inlcall.Pos(), nil)
   550  	n.List = inlcall.Init()
   551  	n.List.Append(inlcall.Body.Take()...)
   552  	return n
   553  }
   554  
   555  // Turn an OINLCALL into a single valued expression.
   556  // The result of inlconv2expr MUST be assigned back to n, e.g.
   557  // 	n.Left = inlconv2expr(n.Left)
   558  func inlconv2expr(n *ir.InlinedCallExpr) ir.Node {
   559  	r := n.ReturnVars[0]
   560  	return ir.InitExpr(append(n.Init(), n.Body...), r)
   561  }
   562  
   563  // Turn the rlist (with the return values) of the OINLCALL in
   564  // n into an expression list lumping the ninit and body
   565  // containing the inlined statements on the first list element so
   566  // order will be preserved. Used in return, oas2func and call
   567  // statements.
   568  func inlconv2list(n *ir.InlinedCallExpr) []ir.Node {
   569  	if n.Op() != ir.OINLCALL || len(n.ReturnVars) == 0 {
   570  		base.Fatalf("inlconv2list %+v\n", n)
   571  	}
   572  
   573  	s := n.ReturnVars
   574  	s[0] = ir.InitExpr(append(n.Init(), n.Body...), s[0])
   575  	return s
   576  }
   577  
   578  // inlnode recurses over the tree to find inlineable calls, which will
   579  // be turned into OINLCALLs by mkinlcall. When the recursion comes
   580  // back up will examine left, right, list, rlist, ninit, ntest, nincr,
   581  // nbody and nelse and use one of the 4 inlconv/glue functions above
   582  // to turn the OINLCALL into an expression, a statement, or patch it
   583  // in to this nodes list or rlist as appropriate.
   584  // NOTE it makes no sense to pass the glue functions down the
   585  // recursion to the level where the OINLCALL gets created because they
   586  // have to edit /this/ n, so you'd have to push that one down as well,
   587  // but then you may as well do it here.  so this is cleaner and
   588  // shorter and less complicated.
   589  // The result of inlnode MUST be assigned back to n, e.g.
   590  // 	n.Left = inlnode(n.Left)
   591  func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.Node) ir.Node) ir.Node {
   592  	if n == nil {
   593  		return n
   594  	}
   595  
   596  	switch n.Op() {
   597  	case ir.ODEFER, ir.OGO:
   598  		n := n.(*ir.GoDeferStmt)
   599  		switch call := n.Call; call.Op() {
   600  		case ir.OCALLFUNC, ir.OCALLMETH:
   601  			call := call.(*ir.CallExpr)
   602  			call.NoInline = true
   603  		}
   604  
   605  	// TODO do them here (or earlier),
   606  	// so escape analysis can avoid more heapmoves.
   607  	case ir.OCLOSURE:
   608  		return n
   609  	case ir.OCALLMETH:
   610  		// Prevent inlining some reflect.Value methods when using checkptr,
   611  		// even when package reflect was compiled without it (#35073).
   612  		n := n.(*ir.CallExpr)
   613  		if s := ir.MethodExprName(n.X).Sym(); base.Debug.Checkptr != 0 && types.IsReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
   614  			return n
   615  		}
   616  	}
   617  
   618  	lno := ir.SetPos(n)
   619  
   620  	ir.EditChildren(n, edit)
   621  
   622  	if as := n; as.Op() == ir.OAS2FUNC {
   623  		as := as.(*ir.AssignListStmt)
   624  		if as.Rhs[0].Op() == ir.OINLCALL {
   625  			as.Rhs = inlconv2list(as.Rhs[0].(*ir.InlinedCallExpr))
   626  			as.SetOp(ir.OAS2)
   627  			as.SetTypecheck(0)
   628  			n = typecheck.Stmt(as)
   629  		}
   630  	}
   631  
   632  	// with all the branches out of the way, it is now time to
   633  	// transmogrify this node itself unless inhibited by the
   634  	// switch at the top of this function.
   635  	switch n.Op() {
   636  	case ir.OCALLFUNC, ir.OCALLMETH:
   637  		n := n.(*ir.CallExpr)
   638  		if n.NoInline {
   639  			return n
   640  		}
   641  	}
   642  
   643  	var call *ir.CallExpr
   644  	switch n.Op() {
   645  	case ir.OCALLFUNC:
   646  		call = n.(*ir.CallExpr)
   647  		if base.Flag.LowerM > 3 {
   648  			fmt.Printf("%v:call to func %+v\n", ir.Line(n), call.X)
   649  		}
   650  		if ir.IsIntrinsicCall(call) {
   651  			break
   652  		}
   653  		if fn := inlCallee(call.X); fn != nil && fn.Inl != nil {
   654  			n = mkinlcall(call, fn, maxCost, inlMap, edit)
   655  		}
   656  
   657  	case ir.OCALLMETH:
   658  		call = n.(*ir.CallExpr)
   659  		if base.Flag.LowerM > 3 {
   660  			fmt.Printf("%v:call to meth %v\n", ir.Line(n), call.X.(*ir.SelectorExpr).Sel)
   661  		}
   662  
   663  		// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
   664  		if call.X.Type() == nil {
   665  			base.Fatalf("no function type for [%p] %+v\n", call.X, call.X)
   666  		}
   667  
   668  		n = mkinlcall(call, ir.MethodExprName(call.X).Func, maxCost, inlMap, edit)
   669  	}
   670  
   671  	base.Pos = lno
   672  
   673  	if n.Op() == ir.OINLCALL {
   674  		ic := n.(*ir.InlinedCallExpr)
   675  		switch call.Use {
   676  		default:
   677  			ir.Dump("call", call)
   678  			base.Fatalf("call missing use")
   679  		case ir.CallUseExpr:
   680  			n = inlconv2expr(ic)
   681  		case ir.CallUseStmt:
   682  			n = inlconv2stmt(ic)
   683  		case ir.CallUseList:
   684  			// leave for caller to convert
   685  		}
   686  	}
   687  
   688  	return n
   689  }
   690  
   691  // inlCallee takes a function-typed expression and returns the underlying function ONAME
   692  // that it refers to if statically known. Otherwise, it returns nil.
   693  func inlCallee(fn ir.Node) *ir.Func {
   694  	fn = ir.StaticValue(fn)
   695  	switch fn.Op() {
   696  	case ir.OMETHEXPR:
   697  		fn := fn.(*ir.SelectorExpr)
   698  		n := ir.MethodExprName(fn)
   699  		// Check that receiver type matches fn.X.
   700  		// TODO(mdempsky): Handle implicit dereference
   701  		// of pointer receiver argument?
   702  		if n == nil || !types.Identical(n.Type().Recv().Type, fn.X.Type()) {
   703  			return nil
   704  		}
   705  		return n.Func
   706  	case ir.ONAME:
   707  		fn := fn.(*ir.Name)
   708  		if fn.Class == ir.PFUNC {
   709  			return fn.Func
   710  		}
   711  	case ir.OCLOSURE:
   712  		fn := fn.(*ir.ClosureExpr)
   713  		c := fn.Func
   714  		CanInline(c)
   715  		return c
   716  	}
   717  	return nil
   718  }
   719  
   720  func inlParam(t *types.Field, as ir.InitNode, inlvars map[*ir.Name]*ir.Name) ir.Node {
   721  	if t.Nname == nil {
   722  		return ir.BlankNode
   723  	}
   724  	n := t.Nname.(*ir.Name)
   725  	if ir.IsBlank(n) {
   726  		return ir.BlankNode
   727  	}
   728  	inlvar := inlvars[n]
   729  	if inlvar == nil {
   730  		base.Fatalf("missing inlvar for %v", n)
   731  	}
   732  	as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, inlvar))
   733  	inlvar.Name().Defn = as
   734  	return inlvar
   735  }
   736  
   737  var inlgen int
   738  
   739  // SSADumpInline gives the SSA back end a chance to dump the function
   740  // when producing output for debugging the compiler itself.
   741  var SSADumpInline = func(*ir.Func) {}
   742  
   743  // If n is a call node (OCALLFUNC or OCALLMETH), and fn is an ONAME node for a
   744  // function with an inlinable body, return an OINLCALL node that can replace n.
   745  // The returned node's Ninit has the parameter assignments, the Nbody is the
   746  // inlined function body, and (List, Rlist) contain the (input, output)
   747  // parameters.
   748  // The result of mkinlcall MUST be assigned back to n, e.g.
   749  // 	n.Left = mkinlcall(n.Left, fn, isddd)
   750  func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.Node) ir.Node) ir.Node {
   751  	if fn.Inl == nil {
   752  		if logopt.Enabled() {
   753  			logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(ir.CurFunc),
   754  				fmt.Sprintf("%s cannot be inlined", ir.PkgFuncName(fn)))
   755  		}
   756  		return n
   757  	}
   758  	if fn.Inl.Cost > maxCost {
   759  		// The inlined function body is too big. Typically we use this check to restrict
   760  		// inlining into very big functions.  See issue 26546 and 17566.
   761  		if logopt.Enabled() {
   762  			logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(ir.CurFunc),
   763  				fmt.Sprintf("cost %d of %s exceeds max large caller cost %d", fn.Inl.Cost, ir.PkgFuncName(fn), maxCost))
   764  		}
   765  		return n
   766  	}
   767  
   768  	if fn == ir.CurFunc {
   769  		// Can't recursively inline a function into itself.
   770  		if logopt.Enabled() {
   771  			logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to %s", ir.FuncName(ir.CurFunc)))
   772  		}
   773  		return n
   774  	}
   775  
   776  	if base.Flag.Cfg.Instrumenting && types.IsRuntimePkg(fn.Sym().Pkg) {
   777  		// Runtime package must not be instrumented.
   778  		// Instrument skips runtime package. However, some runtime code can be
   779  		// inlined into other packages and instrumented there. To avoid this,
   780  		// we disable inlining of runtime functions when instrumenting.
   781  		// The example that we observed is inlining of LockOSThread,
   782  		// which lead to false race reports on m contents.
   783  		return n
   784  	}
   785  
   786  	if inlMap[fn] {
   787  		if base.Flag.LowerM > 1 {
   788  			fmt.Printf("%v: cannot inline %v into %v: repeated recursive cycle\n", ir.Line(n), fn, ir.FuncName(ir.CurFunc))
   789  		}
   790  		return n
   791  	}
   792  	inlMap[fn] = true
   793  	defer func() {
   794  		inlMap[fn] = false
   795  	}()
   796  	if base.Debug.TypecheckInl == 0 {
   797  		typecheck.ImportedBody(fn)
   798  	}
   799  
   800  	// We have a function node, and it has an inlineable body.
   801  	if base.Flag.LowerM > 1 {
   802  		fmt.Printf("%v: inlining call to %v %v { %v }\n", ir.Line(n), fn.Sym(), fn.Type(), ir.Nodes(fn.Inl.Body))
   803  	} else if base.Flag.LowerM != 0 {
   804  		fmt.Printf("%v: inlining call to %v\n", ir.Line(n), fn)
   805  	}
   806  	if base.Flag.LowerM > 2 {
   807  		fmt.Printf("%v: Before inlining: %+v\n", ir.Line(n), n)
   808  	}
   809  
   810  	SSADumpInline(fn)
   811  
   812  	ninit := n.Init()
   813  
   814  	// For normal function calls, the function callee expression
   815  	// may contain side effects (e.g., added by addinit during
   816  	// inlconv2expr or inlconv2list). Make sure to preserve these,
   817  	// if necessary (#42703).
   818  	if n.Op() == ir.OCALLFUNC {
   819  		callee := n.X
   820  		for callee.Op() == ir.OCONVNOP {
   821  			conv := callee.(*ir.ConvExpr)
   822  			ninit.Append(ir.TakeInit(conv)...)
   823  			callee = conv.X
   824  		}
   825  		if callee.Op() != ir.ONAME && callee.Op() != ir.OCLOSURE && callee.Op() != ir.OMETHEXPR {
   826  			base.Fatalf("unexpected callee expression: %v", callee)
   827  		}
   828  	}
   829  
   830  	// Make temp names to use instead of the originals.
   831  	inlvars := make(map[*ir.Name]*ir.Name)
   832  
   833  	// record formals/locals for later post-processing
   834  	var inlfvars []*ir.Name
   835  
   836  	for _, ln := range fn.Inl.Dcl {
   837  		if ln.Op() != ir.ONAME {
   838  			continue
   839  		}
   840  		if ln.Class == ir.PPARAMOUT { // return values handled below.
   841  			continue
   842  		}
   843  		inlf := typecheck.Expr(inlvar(ln)).(*ir.Name)
   844  		inlvars[ln] = inlf
   845  		if base.Flag.GenDwarfInl > 0 {
   846  			if ln.Class == ir.PPARAM {
   847  				inlf.Name().SetInlFormal(true)
   848  			} else {
   849  				inlf.Name().SetInlLocal(true)
   850  			}
   851  			inlf.SetPos(ln.Pos())
   852  			inlfvars = append(inlfvars, inlf)
   853  		}
   854  	}
   855  
   856  	// We can delay declaring+initializing result parameters if:
   857  	// (1) there's exactly one "return" statement in the inlined function;
   858  	// (2) it's not an empty return statement (#44355); and
   859  	// (3) the result parameters aren't named.
   860  	delayretvars := true
   861  
   862  	nreturns := 0
   863  	ir.VisitList(ir.Nodes(fn.Inl.Body), func(n ir.Node) {
   864  		if n, ok := n.(*ir.ReturnStmt); ok {
   865  			nreturns++
   866  			if len(n.Results) == 0 {
   867  				delayretvars = false // empty return statement (case 2)
   868  			}
   869  		}
   870  	})
   871  
   872  	if nreturns != 1 {
   873  		delayretvars = false // not exactly one return statement (case 1)
   874  	}
   875  
   876  	// temporaries for return values.
   877  	var retvars []ir.Node
   878  	for i, t := range fn.Type().Results().Fields().Slice() {
   879  		var m *ir.Name
   880  		if nn := t.Nname; nn != nil && !ir.IsBlank(nn.(*ir.Name)) && !strings.HasPrefix(nn.Sym().Name, "~r") {
   881  			n := nn.(*ir.Name)
   882  			m = inlvar(n)
   883  			m = typecheck.Expr(m).(*ir.Name)
   884  			inlvars[n] = m
   885  			delayretvars = false // found a named result parameter (case 3)
   886  		} else {
   887  			// anonymous return values, synthesize names for use in assignment that replaces return
   888  			m = retvar(t, i)
   889  		}
   890  
   891  		if base.Flag.GenDwarfInl > 0 {
   892  			// Don't update the src.Pos on a return variable if it
   893  			// was manufactured by the inliner (e.g. "~R2"); such vars
   894  			// were not part of the original callee.
   895  			if !strings.HasPrefix(m.Sym().Name, "~R") {
   896  				m.Name().SetInlFormal(true)
   897  				m.SetPos(t.Pos)
   898  				inlfvars = append(inlfvars, m)
   899  			}
   900  		}
   901  
   902  		retvars = append(retvars, m)
   903  	}
   904  
   905  	// Assign arguments to the parameters' temp names.
   906  	as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
   907  	as.Def = true
   908  	if n.Op() == ir.OCALLMETH {
   909  		sel := n.X.(*ir.SelectorExpr)
   910  		if sel.X == nil {
   911  			base.Fatalf("method call without receiver: %+v", n)
   912  		}
   913  		as.Rhs.Append(sel.X)
   914  	}
   915  	as.Rhs.Append(n.Args...)
   916  
   917  	// For non-dotted calls to variadic functions, we assign the
   918  	// variadic parameter's temp name separately.
   919  	var vas *ir.AssignStmt
   920  
   921  	if recv := fn.Type().Recv(); recv != nil {
   922  		as.Lhs.Append(inlParam(recv, as, inlvars))
   923  	}
   924  	for _, param := range fn.Type().Params().Fields().Slice() {
   925  		// For ordinary parameters or variadic parameters in
   926  		// dotted calls, just add the variable to the
   927  		// assignment list, and we're done.
   928  		if !param.IsDDD() || n.IsDDD {
   929  			as.Lhs.Append(inlParam(param, as, inlvars))
   930  			continue
   931  		}
   932  
   933  		// Otherwise, we need to collect the remaining values
   934  		// to pass as a slice.
   935  
   936  		x := len(as.Lhs)
   937  		for len(as.Lhs) < len(as.Rhs) {
   938  			as.Lhs.Append(argvar(param.Type, len(as.Lhs)))
   939  		}
   940  		varargs := as.Lhs[x:]
   941  
   942  		vas = ir.NewAssignStmt(base.Pos, nil, nil)
   943  		vas.X = inlParam(param, vas, inlvars)
   944  		if len(varargs) == 0 {
   945  			vas.Y = typecheck.NodNil()
   946  			vas.Y.SetType(param.Type)
   947  		} else {
   948  			lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(param.Type), nil)
   949  			lit.List = varargs
   950  			vas.Y = lit
   951  		}
   952  	}
   953  
   954  	if len(as.Rhs) != 0 {
   955  		ninit.Append(typecheck.Stmt(as))
   956  	}
   957  
   958  	if vas != nil {
   959  		ninit.Append(typecheck.Stmt(vas))
   960  	}
   961  
   962  	if !delayretvars {
   963  		// Zero the return parameters.
   964  		for _, n := range retvars {
   965  			ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
   966  			ras := ir.NewAssignStmt(base.Pos, n, nil)
   967  			ninit.Append(typecheck.Stmt(ras))
   968  		}
   969  	}
   970  
   971  	retlabel := typecheck.AutoLabel(".i")
   972  
   973  	inlgen++
   974  
   975  	parent := -1
   976  	if b := base.Ctxt.PosTable.Pos(n.Pos()).Base(); b != nil {
   977  		parent = b.InliningIndex()
   978  	}
   979  
   980  	sym := fn.Linksym()
   981  	newIndex := base.Ctxt.InlTree.Add(parent, n.Pos(), sym)
   982  
   983  	// Add an inline mark just before the inlined body.
   984  	// This mark is inline in the code so that it's a reasonable spot
   985  	// to put a breakpoint. Not sure if that's really necessary or not
   986  	// (in which case it could go at the end of the function instead).
   987  	// Note issue 28603.
   988  	inlMark := ir.NewInlineMarkStmt(base.Pos, types.BADWIDTH)
   989  	inlMark.SetPos(n.Pos().WithIsStmt())
   990  	inlMark.Index = int64(newIndex)
   991  	ninit.Append(inlMark)
   992  
   993  	if base.Flag.GenDwarfInl > 0 {
   994  		if !sym.WasInlined() {
   995  			base.Ctxt.DwFixups.SetPrecursorFunc(sym, fn)
   996  			sym.Set(obj.AttrWasInlined, true)
   997  		}
   998  	}
   999  
  1000  	subst := inlsubst{
  1001  		retlabel:     retlabel,
  1002  		retvars:      retvars,
  1003  		delayretvars: delayretvars,
  1004  		inlvars:      inlvars,
  1005  		defnMarker:   ir.NilExpr{},
  1006  		bases:        make(map[*src.PosBase]*src.PosBase),
  1007  		newInlIndex:  newIndex,
  1008  		fn:           fn,
  1009  	}
  1010  	subst.edit = subst.node
  1011  
  1012  	body := subst.list(ir.Nodes(fn.Inl.Body))
  1013  
  1014  	lab := ir.NewLabelStmt(base.Pos, retlabel)
  1015  	body = append(body, lab)
  1016  
  1017  	if !typecheck.Go117ExportTypes {
  1018  		typecheck.Stmts(body)
  1019  	}
  1020  
  1021  	if base.Flag.GenDwarfInl > 0 {
  1022  		for _, v := range inlfvars {
  1023  			v.SetPos(subst.updatedPos(v.Pos()))
  1024  		}
  1025  	}
  1026  
  1027  	//dumplist("ninit post", ninit);
  1028  
  1029  	call := ir.NewInlinedCallExpr(base.Pos, nil, nil)
  1030  	*call.PtrInit() = ninit
  1031  	call.Body = body
  1032  	call.ReturnVars = retvars
  1033  	call.SetType(n.Type())
  1034  	call.SetTypecheck(1)
  1035  
  1036  	// transitive inlining
  1037  	// might be nice to do this before exporting the body,
  1038  	// but can't emit the body with inlining expanded.
  1039  	// instead we emit the things that the body needs
  1040  	// and each use must redo the inlining.
  1041  	// luckily these are small.
  1042  	ir.EditChildren(call, edit)
  1043  
  1044  	if base.Flag.LowerM > 2 {
  1045  		fmt.Printf("%v: After inlining %+v\n\n", ir.Line(call), call)
  1046  	}
  1047  
  1048  	return call
  1049  }
  1050  
  1051  // Every time we expand a function we generate a new set of tmpnames,
  1052  // PAUTO's in the calling functions, and link them off of the
  1053  // PPARAM's, PAUTOS and PPARAMOUTs of the called function.
  1054  func inlvar(var_ *ir.Name) *ir.Name {
  1055  	if base.Flag.LowerM > 3 {
  1056  		fmt.Printf("inlvar %+v\n", var_)
  1057  	}
  1058  
  1059  	n := typecheck.NewName(var_.Sym())
  1060  	n.SetType(var_.Type())
  1061  	n.Class = ir.PAUTO
  1062  	n.SetUsed(true)
  1063  	n.Curfn = ir.CurFunc // the calling function, not the called one
  1064  	n.SetAddrtaken(var_.Addrtaken())
  1065  
  1066  	ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
  1067  	return n
  1068  }
  1069  
  1070  // Synthesize a variable to store the inlined function's results in.
  1071  func retvar(t *types.Field, i int) *ir.Name {
  1072  	n := typecheck.NewName(typecheck.LookupNum("~R", i))
  1073  	n.SetType(t.Type)
  1074  	n.Class = ir.PAUTO
  1075  	n.SetUsed(true)
  1076  	n.Curfn = ir.CurFunc // the calling function, not the called one
  1077  	ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
  1078  	return n
  1079  }
  1080  
  1081  // Synthesize a variable to store the inlined function's arguments
  1082  // when they come from a multiple return call.
  1083  func argvar(t *types.Type, i int) ir.Node {
  1084  	n := typecheck.NewName(typecheck.LookupNum("~arg", i))
  1085  	n.SetType(t.Elem())
  1086  	n.Class = ir.PAUTO
  1087  	n.SetUsed(true)
  1088  	n.Curfn = ir.CurFunc // the calling function, not the called one
  1089  	ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
  1090  	return n
  1091  }
  1092  
  1093  // The inlsubst type implements the actual inlining of a single
  1094  // function call.
  1095  type inlsubst struct {
  1096  	// Target of the goto substituted in place of a return.
  1097  	retlabel *types.Sym
  1098  
  1099  	// Temporary result variables.
  1100  	retvars []ir.Node
  1101  
  1102  	// Whether result variables should be initialized at the
  1103  	// "return" statement.
  1104  	delayretvars bool
  1105  
  1106  	inlvars map[*ir.Name]*ir.Name
  1107  	// defnMarker is used to mark a Node for reassignment.
  1108  	// inlsubst.clovar set this during creating new ONAME.
  1109  	// inlsubst.node will set the correct Defn for inlvar.
  1110  	defnMarker ir.NilExpr
  1111  
  1112  	// bases maps from original PosBase to PosBase with an extra
  1113  	// inlined call frame.
  1114  	bases map[*src.PosBase]*src.PosBase
  1115  
  1116  	// newInlIndex is the index of the inlined call frame to
  1117  	// insert for inlined nodes.
  1118  	newInlIndex int
  1119  
  1120  	edit func(ir.Node) ir.Node // cached copy of subst.node method value closure
  1121  
  1122  	// If non-nil, we are inside a closure inside the inlined function, and
  1123  	// newclofn is the Func of the new inlined closure.
  1124  	newclofn *ir.Func
  1125  
  1126  	fn *ir.Func // For debug -- the func that is being inlined
  1127  
  1128  	// If true, then don't update source positions during substitution
  1129  	// (retain old source positions).
  1130  	noPosUpdate bool
  1131  }
  1132  
  1133  // list inlines a list of nodes.
  1134  func (subst *inlsubst) list(ll ir.Nodes) []ir.Node {
  1135  	s := make([]ir.Node, 0, len(ll))
  1136  	for _, n := range ll {
  1137  		s = append(s, subst.node(n))
  1138  	}
  1139  	return s
  1140  }
  1141  
  1142  // fields returns a list of the fields of a struct type representing receiver,
  1143  // params, or results, after duplicating the field nodes and substituting the
  1144  // Nname nodes inside the field nodes.
  1145  func (subst *inlsubst) fields(oldt *types.Type) []*types.Field {
  1146  	oldfields := oldt.FieldSlice()
  1147  	newfields := make([]*types.Field, len(oldfields))
  1148  	for i := range oldfields {
  1149  		newfields[i] = oldfields[i].Copy()
  1150  		if oldfields[i].Nname != nil {
  1151  			newfields[i].Nname = subst.node(oldfields[i].Nname.(*ir.Name))
  1152  		}
  1153  	}
  1154  	return newfields
  1155  }
  1156  
  1157  // clovar creates a new ONAME node for a local variable or param of a closure
  1158  // inside a function being inlined.
  1159  func (subst *inlsubst) clovar(n *ir.Name) *ir.Name {
  1160  	// TODO(danscales): want to get rid of this shallow copy, with code like the
  1161  	// following, but it is hard to copy all the necessary flags in a maintainable way.
  1162  	// m := ir.NewNameAt(n.Pos(), n.Sym())
  1163  	// m.Class = n.Class
  1164  	// m.SetType(n.Type())
  1165  	// m.SetTypecheck(1)
  1166  	//if n.IsClosureVar() {
  1167  	//	m.SetIsClosureVar(true)
  1168  	//}
  1169  	m := &ir.Name{}
  1170  	*m = *n
  1171  	m.Curfn = subst.newclofn
  1172  
  1173  	switch defn := n.Defn.(type) {
  1174  	case nil:
  1175  		// ok
  1176  	case *ir.Name:
  1177  		if !n.IsClosureVar() {
  1178  			base.FatalfAt(n.Pos(), "want closure variable, got: %+v", n)
  1179  		}
  1180  		if n.Sym().Pkg != types.LocalPkg {
  1181  			// If the closure came from inlining a function from
  1182  			// another package, must change package of captured
  1183  			// variable to localpkg, so that the fields of the closure
  1184  			// struct are local package and can be accessed even if
  1185  			// name is not exported. If you disable this code, you can
  1186  			// reproduce the problem by running 'go test
  1187  			// go/internal/srcimporter'. TODO(mdempsky) - maybe change
  1188  			// how we create closure structs?
  1189  			m.SetSym(types.LocalPkg.Lookup(n.Sym().Name))
  1190  		}
  1191  		// Make sure any inlvar which is the Defn
  1192  		// of an ONAME closure var is rewritten
  1193  		// during inlining. Don't substitute
  1194  		// if Defn node is outside inlined function.
  1195  		if subst.inlvars[n.Defn.(*ir.Name)] != nil {
  1196  			m.Defn = subst.node(n.Defn)
  1197  		}
  1198  	case *ir.AssignStmt, *ir.AssignListStmt:
  1199  		// Mark node for reassignment at the end of inlsubst.node.
  1200  		m.Defn = &subst.defnMarker
  1201  	case *ir.TypeSwitchGuard:
  1202  		// TODO(mdempsky): Set m.Defn properly. See discussion on #45743.
  1203  	default:
  1204  		base.FatalfAt(n.Pos(), "unexpected Defn: %+v", defn)
  1205  	}
  1206  
  1207  	if n.Outer != nil {
  1208  		// Either the outer variable is defined in function being inlined,
  1209  		// and we will replace it with the substituted variable, or it is
  1210  		// defined outside the function being inlined, and we should just
  1211  		// skip the outer variable (the closure variable of the function
  1212  		// being inlined).
  1213  		s := subst.node(n.Outer).(*ir.Name)
  1214  		if s == n.Outer {
  1215  			s = n.Outer.Outer
  1216  		}
  1217  		m.Outer = s
  1218  	}
  1219  	return m
  1220  }
  1221  
  1222  // closure does the necessary substitions for a ClosureExpr n and returns the new
  1223  // closure node.
  1224  func (subst *inlsubst) closure(n *ir.ClosureExpr) ir.Node {
  1225  	m := ir.Copy(n)
  1226  
  1227  	// Prior to the subst edit, set a flag in the inlsubst to
  1228  	// indicated that we don't want to update the source positions in
  1229  	// the new closure. If we do this, it will appear that the closure
  1230  	// itself has things inlined into it, which is not the case. See
  1231  	// issue #46234 for more details.
  1232  	defer func(prev bool) { subst.noPosUpdate = prev }(subst.noPosUpdate)
  1233  	subst.noPosUpdate = true
  1234  	ir.EditChildren(m, subst.edit)
  1235  
  1236  	//fmt.Printf("Inlining func %v with closure into %v\n", subst.fn, ir.FuncName(ir.CurFunc))
  1237  
  1238  	// The following is similar to funcLit
  1239  	oldfn := n.Func
  1240  	newfn := ir.NewFunc(oldfn.Pos())
  1241  	// These three lines are not strictly necessary, but just to be clear
  1242  	// that new function needs to redo typechecking and inlinability.
  1243  	newfn.SetTypecheck(0)
  1244  	newfn.SetInlinabilityChecked(false)
  1245  	newfn.Inl = nil
  1246  	newfn.SetIsHiddenClosure(true)
  1247  	newfn.Nname = ir.NewNameAt(n.Pos(), ir.BlankNode.Sym())
  1248  	newfn.Nname.Func = newfn
  1249  	// Ntype can be nil for -G=3 mode.
  1250  	if oldfn.Nname.Ntype != nil {
  1251  		newfn.Nname.Ntype = subst.node(oldfn.Nname.Ntype).(ir.Ntype)
  1252  	}
  1253  	newfn.Nname.Defn = newfn
  1254  
  1255  	m.(*ir.ClosureExpr).Func = newfn
  1256  	newfn.OClosure = m.(*ir.ClosureExpr)
  1257  
  1258  	if subst.newclofn != nil {
  1259  		//fmt.Printf("Inlining a closure with a nested closure\n")
  1260  	}
  1261  	prevxfunc := subst.newclofn
  1262  
  1263  	// Mark that we are now substituting within a closure (within the
  1264  	// inlined function), and create new nodes for all the local
  1265  	// vars/params inside this closure.
  1266  	subst.newclofn = newfn
  1267  	newfn.Dcl = nil
  1268  	newfn.ClosureVars = nil
  1269  	for _, oldv := range oldfn.Dcl {
  1270  		newv := subst.clovar(oldv)
  1271  		subst.inlvars[oldv] = newv
  1272  		newfn.Dcl = append(newfn.Dcl, newv)
  1273  	}
  1274  	for _, oldv := range oldfn.ClosureVars {
  1275  		newv := subst.clovar(oldv)
  1276  		subst.inlvars[oldv] = newv
  1277  		newfn.ClosureVars = append(newfn.ClosureVars, newv)
  1278  	}
  1279  
  1280  	// Need to replace ONAME nodes in
  1281  	// newfn.Type().FuncType().Receiver/Params/Results.FieldSlice().Nname
  1282  	oldt := oldfn.Type()
  1283  	newrecvs := subst.fields(oldt.Recvs())
  1284  	var newrecv *types.Field
  1285  	if len(newrecvs) > 0 {
  1286  		newrecv = newrecvs[0]
  1287  	}
  1288  	newt := types.NewSignature(oldt.Pkg(), newrecv,
  1289  		nil, subst.fields(oldt.Params()), subst.fields(oldt.Results()))
  1290  
  1291  	newfn.Nname.SetType(newt)
  1292  	newfn.Body = subst.list(oldfn.Body)
  1293  
  1294  	// Remove the nodes for the current closure from subst.inlvars
  1295  	for _, oldv := range oldfn.Dcl {
  1296  		delete(subst.inlvars, oldv)
  1297  	}
  1298  	for _, oldv := range oldfn.ClosureVars {
  1299  		delete(subst.inlvars, oldv)
  1300  	}
  1301  	// Go back to previous closure func
  1302  	subst.newclofn = prevxfunc
  1303  
  1304  	// Actually create the named function for the closure, now that
  1305  	// the closure is inlined in a specific function.
  1306  	m.SetTypecheck(0)
  1307  	if oldfn.ClosureCalled() {
  1308  		typecheck.Callee(m)
  1309  	} else {
  1310  		typecheck.Expr(m)
  1311  	}
  1312  	return m
  1313  }
  1314  
  1315  // node recursively copies a node from the saved pristine body of the
  1316  // inlined function, substituting references to input/output
  1317  // parameters with ones to the tmpnames, and substituting returns with
  1318  // assignments to the output.
  1319  func (subst *inlsubst) node(n ir.Node) ir.Node {
  1320  	if n == nil {
  1321  		return nil
  1322  	}
  1323  
  1324  	switch n.Op() {
  1325  	case ir.ONAME:
  1326  		n := n.(*ir.Name)
  1327  
  1328  		// Handle captured variables when inlining closures.
  1329  		if n.IsClosureVar() && subst.newclofn == nil {
  1330  			o := n.Outer
  1331  
  1332  			// Deal with case where sequence of closures are inlined.
  1333  			// TODO(danscales) - write test case to see if we need to
  1334  			// go up multiple levels.
  1335  			if o.Curfn != ir.CurFunc {
  1336  				o = o.Outer
  1337  			}
  1338  
  1339  			// make sure the outer param matches the inlining location
  1340  			if o == nil || o.Curfn != ir.CurFunc {
  1341  				base.Fatalf("%v: unresolvable capture %v\n", ir.Line(n), n)
  1342  			}
  1343  
  1344  			if base.Flag.LowerM > 2 {
  1345  				fmt.Printf("substituting captured name %+v  ->  %+v\n", n, o)
  1346  			}
  1347  			return o
  1348  		}
  1349  
  1350  		if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
  1351  			if base.Flag.LowerM > 2 {
  1352  				fmt.Printf("substituting name %+v  ->  %+v\n", n, inlvar)
  1353  			}
  1354  			return inlvar
  1355  		}
  1356  
  1357  		if base.Flag.LowerM > 2 {
  1358  			fmt.Printf("not substituting name %+v\n", n)
  1359  		}
  1360  		return n
  1361  
  1362  	case ir.OMETHEXPR:
  1363  		n := n.(*ir.SelectorExpr)
  1364  		return n
  1365  
  1366  	case ir.OLITERAL, ir.ONIL, ir.OTYPE:
  1367  		// If n is a named constant or type, we can continue
  1368  		// using it in the inline copy. Otherwise, make a copy
  1369  		// so we can update the line number.
  1370  		if n.Sym() != nil {
  1371  			return n
  1372  		}
  1373  
  1374  	case ir.ORETURN:
  1375  		if subst.newclofn != nil {
  1376  			// Don't do special substitutions if inside a closure
  1377  			break
  1378  		}
  1379  		// Since we don't handle bodies with closures,
  1380  		// this return is guaranteed to belong to the current inlined function.
  1381  		n := n.(*ir.ReturnStmt)
  1382  		init := subst.list(n.Init())
  1383  		if len(subst.retvars) != 0 && len(n.Results) != 0 {
  1384  			as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
  1385  
  1386  			// Make a shallow copy of retvars.
  1387  			// Otherwise OINLCALL.Rlist will be the same list,
  1388  			// and later walk and typecheck may clobber it.
  1389  			for _, n := range subst.retvars {
  1390  				as.Lhs.Append(n)
  1391  			}
  1392  			as.Rhs = subst.list(n.Results)
  1393  
  1394  			if subst.delayretvars {
  1395  				for _, n := range as.Lhs {
  1396  					as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
  1397  					n.Name().Defn = as
  1398  				}
  1399  			}
  1400  
  1401  			init = append(init, typecheck.Stmt(as))
  1402  		}
  1403  		init = append(init, ir.NewBranchStmt(base.Pos, ir.OGOTO, subst.retlabel))
  1404  		typecheck.Stmts(init)
  1405  		return ir.NewBlockStmt(base.Pos, init)
  1406  
  1407  	case ir.OGOTO:
  1408  		if subst.newclofn != nil {
  1409  			// Don't do special substitutions if inside a closure
  1410  			break
  1411  		}
  1412  		n := n.(*ir.BranchStmt)
  1413  		m := ir.Copy(n).(*ir.BranchStmt)
  1414  		m.SetPos(subst.updatedPos(m.Pos()))
  1415  		*m.PtrInit() = nil
  1416  		p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
  1417  		m.Label = typecheck.Lookup(p)
  1418  		return m
  1419  
  1420  	case ir.OLABEL:
  1421  		if subst.newclofn != nil {
  1422  			// Don't do special substitutions if inside a closure
  1423  			break
  1424  		}
  1425  		n := n.(*ir.LabelStmt)
  1426  		m := ir.Copy(n).(*ir.LabelStmt)
  1427  		m.SetPos(subst.updatedPos(m.Pos()))
  1428  		*m.PtrInit() = nil
  1429  		p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
  1430  		m.Label = typecheck.Lookup(p)
  1431  		return m
  1432  
  1433  	case ir.OCLOSURE:
  1434  		return subst.closure(n.(*ir.ClosureExpr))
  1435  
  1436  	}
  1437  
  1438  	m := ir.Copy(n)
  1439  	m.SetPos(subst.updatedPos(m.Pos()))
  1440  	ir.EditChildren(m, subst.edit)
  1441  
  1442  	switch m := m.(type) {
  1443  	case *ir.AssignStmt:
  1444  		if lhs, ok := m.X.(*ir.Name); ok && lhs.Defn == &subst.defnMarker {
  1445  			lhs.Defn = m
  1446  		}
  1447  	case *ir.AssignListStmt:
  1448  		for _, lhs := range m.Lhs {
  1449  			if lhs, ok := lhs.(*ir.Name); ok && lhs.Defn == &subst.defnMarker {
  1450  				lhs.Defn = m
  1451  			}
  1452  		}
  1453  	}
  1454  
  1455  	return m
  1456  }
  1457  
  1458  func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
  1459  	if subst.noPosUpdate {
  1460  		return xpos
  1461  	}
  1462  	pos := base.Ctxt.PosTable.Pos(xpos)
  1463  	oldbase := pos.Base() // can be nil
  1464  	newbase := subst.bases[oldbase]
  1465  	if newbase == nil {
  1466  		newbase = src.NewInliningBase(oldbase, subst.newInlIndex)
  1467  		subst.bases[oldbase] = newbase
  1468  	}
  1469  	pos.SetBase(newbase)
  1470  	return base.Ctxt.PosTable.XPos(pos)
  1471  }
  1472  
  1473  func pruneUnusedAutos(ll []*ir.Name, vis *hairyVisitor) []*ir.Name {
  1474  	s := make([]*ir.Name, 0, len(ll))
  1475  	for _, n := range ll {
  1476  		if n.Class == ir.PAUTO {
  1477  			if !vis.usedLocals.Has(n) {
  1478  				continue
  1479  			}
  1480  		}
  1481  		s = append(s, n)
  1482  	}
  1483  	return s
  1484  }
  1485  
  1486  // numNonClosures returns the number of functions in list which are not closures.
  1487  func numNonClosures(list []*ir.Func) int {
  1488  	count := 0
  1489  	for _, fn := range list {
  1490  		if fn.OClosure == nil {
  1491  			count++
  1492  		}
  1493  	}
  1494  	return count
  1495  }
  1496  
  1497  func doList(list []ir.Node, do func(ir.Node) bool) bool {
  1498  	for _, x := range list {
  1499  		if x != nil {
  1500  			if do(x) {
  1501  				return true
  1502  			}
  1503  		}
  1504  	}
  1505  	return false
  1506  }
  1507  

View as plain text