github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/compile/internal/gc/inl.go (about)

     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 inlcalls 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, lazy typechecking (default)
    15  //      2: (unassigned)
    16  //      3: allow variadic functions
    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  // TODO:
    28  //   - inline functions with ... args
    29  
    30  package gc
    31  
    32  import (
    33  	"cmd/compile/internal/types"
    34  	"cmd/internal/obj"
    35  	"cmd/internal/src"
    36  	"fmt"
    37  	"strings"
    38  )
    39  
    40  // Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
    41  // the ->sym can be re-used in the local package, so peel it off the receiver's type.
    42  func fnpkg(fn *Node) *types.Pkg {
    43  	if fn.IsMethod() {
    44  		// method
    45  		rcvr := fn.Type.Recv().Type
    46  
    47  		if rcvr.IsPtr() {
    48  			rcvr = rcvr.Elem()
    49  		}
    50  		if rcvr.Sym == nil {
    51  			Fatalf("receiver with no sym: [%v] %L  (%v)", fn.Sym, fn, rcvr)
    52  		}
    53  		return rcvr.Sym.Pkg
    54  	}
    55  
    56  	// non-method
    57  	return fn.Sym.Pkg
    58  }
    59  
    60  // Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
    61  // because they're a copy of an already checked body.
    62  func typecheckinl(fn *Node) {
    63  	lno := setlineno(fn)
    64  
    65  	// typecheckinl is only for imported functions;
    66  	// their bodies may refer to unsafe as long as the package
    67  	// was marked safe during import (which was checked then).
    68  	// the ->inl of a local function has been typechecked before caninl copied it.
    69  	pkg := fnpkg(fn)
    70  
    71  	if pkg == localpkg || pkg == nil {
    72  		return // typecheckinl on local function
    73  	}
    74  
    75  	if Debug['m'] > 2 || Debug_export != 0 {
    76  		fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, fn.Func.Inl)
    77  	}
    78  
    79  	save_safemode := safemode
    80  	safemode = false
    81  
    82  	savefn := Curfn
    83  	Curfn = fn
    84  	typecheckslice(fn.Func.Inl.Slice(), Etop)
    85  	Curfn = savefn
    86  
    87  	safemode = save_safemode
    88  
    89  	lineno = lno
    90  }
    91  
    92  // Caninl determines whether fn is inlineable.
    93  // If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy.
    94  // fn and ->nbody will already have been typechecked.
    95  func caninl(fn *Node) {
    96  	if fn.Op != ODCLFUNC {
    97  		Fatalf("caninl %v", fn)
    98  	}
    99  	if fn.Func.Nname == nil {
   100  		Fatalf("caninl no nname %+v", fn)
   101  	}
   102  
   103  	var reason string // reason, if any, that the function was not inlined
   104  	if Debug['m'] > 1 {
   105  		defer func() {
   106  			if reason != "" {
   107  				fmt.Printf("%v: cannot inline %v: %s\n", fn.Line(), fn.Func.Nname, reason)
   108  			}
   109  		}()
   110  	}
   111  
   112  	// If marked "go:noinline", don't inline
   113  	if fn.Func.Pragma&Noinline != 0 {
   114  		reason = "marked go:noinline"
   115  		return
   116  	}
   117  
   118  	// If marked "go:cgo_unsafe_args", don't inline, since the
   119  	// function makes assumptions about its argument frame layout.
   120  	if fn.Func.Pragma&CgoUnsafeArgs != 0 {
   121  		reason = "marked go:cgo_unsafe_args"
   122  		return
   123  	}
   124  
   125  	// The nowritebarrierrec checker currently works at function
   126  	// granularity, so inlining yeswritebarrierrec functions can
   127  	// confuse it (#22342). As a workaround, disallow inlining
   128  	// them for now.
   129  	if fn.Func.Pragma&Yeswritebarrierrec != 0 {
   130  		reason = "marked go:yeswritebarrierrec"
   131  		return
   132  	}
   133  
   134  	// If fn has no body (is defined outside of Go), cannot inline it.
   135  	if fn.Nbody.Len() == 0 {
   136  		reason = "no function body"
   137  		return
   138  	}
   139  
   140  	if fn.Typecheck() == 0 {
   141  		Fatalf("caninl on non-typechecked function %v", fn)
   142  	}
   143  
   144  	// can't handle ... args yet
   145  	if Debug['l'] < 3 {
   146  		f := fn.Type.Params().Fields()
   147  		if len := f.Len(); len > 0 {
   148  			if t := f.Index(len - 1); t.Isddd() {
   149  				reason = "has ... args"
   150  				return
   151  			}
   152  		}
   153  	}
   154  
   155  	// Runtime package must not be instrumented.
   156  	// Instrument skips runtime package. However, some runtime code can be
   157  	// inlined into other packages and instrumented there. To avoid this,
   158  	// we disable inlining of runtime functions when instrumenting.
   159  	// The example that we observed is inlining of LockOSThread,
   160  	// which lead to false race reports on m contents.
   161  	if instrumenting && myimportpath == "runtime" {
   162  		reason = "instrumenting and is runtime function"
   163  		return
   164  	}
   165  
   166  	n := fn.Func.Nname
   167  	if n.Func.InlinabilityChecked() {
   168  		return
   169  	}
   170  	defer n.Func.SetInlinabilityChecked(true)
   171  
   172  	const maxBudget = 80
   173  	visitor := hairyVisitor{budget: maxBudget}
   174  	if visitor.visitList(fn.Nbody) {
   175  		reason = visitor.reason
   176  		return
   177  	}
   178  	if visitor.budget < 0 {
   179  		reason = fmt.Sprintf("function too complex: cost %d exceeds budget %d", maxBudget-visitor.budget, maxBudget)
   180  		return
   181  	}
   182  
   183  	savefn := Curfn
   184  	Curfn = fn
   185  
   186  	n.Func.Inl.Set(fn.Nbody.Slice())
   187  	fn.Nbody.Set(inlcopylist(n.Func.Inl.Slice()))
   188  	inldcl := inlcopylist(n.Name.Defn.Func.Dcl)
   189  	n.Func.Inldcl.Set(inldcl)
   190  	n.Func.InlCost = maxBudget - visitor.budget
   191  
   192  	// hack, TODO, check for better way to link method nodes back to the thing with the ->inl
   193  	// this is so export can find the body of a method
   194  	fn.Type.FuncType().Nname = asTypesNode(n)
   195  
   196  	if Debug['m'] > 1 {
   197  		fmt.Printf("%v: can inline %#v as: %#v { %#v }\n", fn.Line(), n, fn.Type, n.Func.Inl)
   198  	} else if Debug['m'] != 0 {
   199  		fmt.Printf("%v: can inline %v\n", fn.Line(), n)
   200  	}
   201  
   202  	Curfn = savefn
   203  }
   204  
   205  // inlFlood marks n's inline body for export and recursively ensures
   206  // all called functions are marked too.
   207  func inlFlood(n *Node) {
   208  	if n == nil {
   209  		return
   210  	}
   211  	if n.Op != ONAME || n.Class() != PFUNC {
   212  		Fatalf("inlFlood: unexpected %v, %v, %v", n, n.Op, n.Class())
   213  	}
   214  	if n.Func == nil {
   215  		// TODO(mdempsky): Should init have a Func too?
   216  		if n.Sym.Name == "init" {
   217  			return
   218  		}
   219  		Fatalf("inlFlood: missing Func on %v", n)
   220  	}
   221  	if n.Func.Inl.Len() == 0 {
   222  		return
   223  	}
   224  
   225  	if n.Func.ExportInline() {
   226  		return
   227  	}
   228  	n.Func.SetExportInline(true)
   229  
   230  	typecheckinl(n)
   231  
   232  	// Recursively flood any functions called by this one.
   233  	inspectList(n.Func.Inl, func(n *Node) bool {
   234  		switch n.Op {
   235  		case OCALLFUNC, OCALLMETH:
   236  			inlFlood(asNode(n.Left.Type.Nname()))
   237  		}
   238  		return true
   239  	})
   240  }
   241  
   242  // hairyVisitor visits a function body to determine its inlining
   243  // hairiness and whether or not it can be inlined.
   244  type hairyVisitor struct {
   245  	budget int32
   246  	reason string
   247  }
   248  
   249  // Look for anything we want to punt on.
   250  func (v *hairyVisitor) visitList(ll Nodes) bool {
   251  	for _, n := range ll.Slice() {
   252  		if v.visit(n) {
   253  			return true
   254  		}
   255  	}
   256  	return false
   257  }
   258  
   259  func (v *hairyVisitor) visit(n *Node) bool {
   260  	if n == nil {
   261  		return false
   262  	}
   263  
   264  	switch n.Op {
   265  	// Call is okay if inlinable and we have the budget for the body.
   266  	case OCALLFUNC:
   267  		if isIntrinsicCall(n) {
   268  			v.budget--
   269  			break
   270  		}
   271  		// Functions that call runtime.getcaller{pc,sp} can not be inlined
   272  		// because getcaller{pc,sp} expect a pointer to the caller's first argument.
   273  		if n.Left.Op == ONAME && n.Left.Class() == PFUNC && isRuntimePkg(n.Left.Sym.Pkg) {
   274  			fn := n.Left.Sym.Name
   275  			if fn == "getcallerpc" || fn == "getcallersp" {
   276  				v.reason = "call to " + fn
   277  				return true
   278  			}
   279  		}
   280  
   281  		if fn := n.Left.Func; fn != nil && fn.Inl.Len() != 0 {
   282  			v.budget -= fn.InlCost
   283  			break
   284  		}
   285  		if n.Left.isMethodExpression() {
   286  			if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl.Len() != 0 {
   287  				v.budget -= d.Func.InlCost
   288  				break
   289  			}
   290  		}
   291  		// TODO(mdempsky): Budget for OCLOSURE calls if we
   292  		// ever allow that. See #15561 and #23093.
   293  		if Debug['l'] < 4 {
   294  			v.reason = "non-leaf function"
   295  			return true
   296  		}
   297  
   298  	// Call is okay if inlinable and we have the budget for the body.
   299  	case OCALLMETH:
   300  		t := n.Left.Type
   301  		if t == nil {
   302  			Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
   303  		}
   304  		if t.Nname() == nil {
   305  			Fatalf("no function definition for [%p] %+v\n", t, t)
   306  		}
   307  		if isRuntimePkg(n.Left.Sym.Pkg) {
   308  			fn := n.Left.Sym.Name
   309  			if fn == "heapBits.nextArena" {
   310  				// Special case: explicitly allow
   311  				// mid-stack inlining of
   312  				// runtime.heapBits.next even though
   313  				// it calls slow-path
   314  				// runtime.heapBits.nextArena.
   315  				//
   316  				// TODO(austin): Once mid-stack
   317  				// inlining is the default, remove
   318  				// this special case.
   319  				break
   320  			}
   321  		}
   322  		if inlfn := asNode(t.FuncType().Nname).Func; inlfn.Inl.Len() != 0 {
   323  			v.budget -= inlfn.InlCost
   324  			break
   325  		}
   326  		if Debug['l'] < 4 {
   327  			v.reason = "non-leaf method"
   328  			return true
   329  		}
   330  
   331  	// Things that are too hairy, irrespective of the budget
   332  	case OCALL, OCALLINTER, OPANIC:
   333  		if Debug['l'] < 4 {
   334  			v.reason = "non-leaf op " + n.Op.String()
   335  			return true
   336  		}
   337  
   338  	case ORECOVER:
   339  		// recover matches the argument frame pointer to find
   340  		// the right panic value, so it needs an argument frame.
   341  		v.reason = "call to recover"
   342  		return true
   343  
   344  	case OCLOSURE,
   345  		OCALLPART,
   346  		ORANGE,
   347  		OFOR,
   348  		OFORUNTIL,
   349  		OSELECT,
   350  		OTYPESW,
   351  		OPROC,
   352  		ODEFER,
   353  		ODCLTYPE, // can't print yet
   354  		OBREAK,
   355  		ORETJMP:
   356  		v.reason = "unhandled op " + n.Op.String()
   357  		return true
   358  
   359  	case ODCLCONST, OEMPTY, OFALL, OLABEL:
   360  		// These nodes don't produce code; omit from inlining budget.
   361  		return false
   362  
   363  	case OIF:
   364  		if Isconst(n.Left, CTBOOL) {
   365  			// This if and the condition cost nothing.
   366  			return v.visitList(n.Nbody) || v.visitList(n.Rlist)
   367  		}
   368  	}
   369  
   370  	v.budget--
   371  	// TODO(mdempsky/josharian): Hacks to appease toolstash; remove.
   372  	// See issue 17566 and CL 31674 for discussion.
   373  	switch n.Op {
   374  	case OSTRUCTKEY:
   375  		v.budget--
   376  	case OSLICE, OSLICEARR, OSLICESTR:
   377  		v.budget--
   378  	case OSLICE3, OSLICE3ARR:
   379  		v.budget -= 2
   380  	}
   381  
   382  	// When debugging, don't stop early, to get full cost of inlining this function
   383  	if v.budget < 0 && Debug['m'] < 2 {
   384  		return true
   385  	}
   386  
   387  	return v.visit(n.Left) || v.visit(n.Right) ||
   388  		v.visitList(n.List) || v.visitList(n.Rlist) ||
   389  		v.visitList(n.Ninit) || v.visitList(n.Nbody)
   390  }
   391  
   392  // Inlcopy and inlcopylist recursively copy the body of a function.
   393  // Any name-like node of non-local class is marked for re-export by adding it to
   394  // the exportlist.
   395  func inlcopylist(ll []*Node) []*Node {
   396  	s := make([]*Node, 0, len(ll))
   397  	for _, n := range ll {
   398  		s = append(s, inlcopy(n))
   399  	}
   400  	return s
   401  }
   402  
   403  func inlcopy(n *Node) *Node {
   404  	if n == nil {
   405  		return nil
   406  	}
   407  
   408  	switch n.Op {
   409  	case ONAME, OTYPE, OLITERAL:
   410  		return n
   411  	}
   412  
   413  	m := *n
   414  	if m.Func != nil {
   415  		m.Func.Inl.Set(nil)
   416  	}
   417  	m.Left = inlcopy(n.Left)
   418  	m.Right = inlcopy(n.Right)
   419  	m.List.Set(inlcopylist(n.List.Slice()))
   420  	m.Rlist.Set(inlcopylist(n.Rlist.Slice()))
   421  	m.Ninit.Set(inlcopylist(n.Ninit.Slice()))
   422  	m.Nbody.Set(inlcopylist(n.Nbody.Slice()))
   423  
   424  	return &m
   425  }
   426  
   427  // Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
   428  // calls made to inlineable functions. This is the external entry point.
   429  func inlcalls(fn *Node) {
   430  	savefn := Curfn
   431  	Curfn = fn
   432  	fn = inlnode(fn)
   433  	if fn != Curfn {
   434  		Fatalf("inlnode replaced curfn")
   435  	}
   436  	Curfn = savefn
   437  }
   438  
   439  // Turn an OINLCALL into a statement.
   440  func inlconv2stmt(n *Node) {
   441  	n.Op = OBLOCK
   442  
   443  	// n->ninit stays
   444  	n.List.Set(n.Nbody.Slice())
   445  
   446  	n.Nbody.Set(nil)
   447  	n.Rlist.Set(nil)
   448  }
   449  
   450  // Turn an OINLCALL into a single valued expression.
   451  // The result of inlconv2expr MUST be assigned back to n, e.g.
   452  // 	n.Left = inlconv2expr(n.Left)
   453  func inlconv2expr(n *Node) *Node {
   454  	r := n.Rlist.First()
   455  	return addinit(r, append(n.Ninit.Slice(), n.Nbody.Slice()...))
   456  }
   457  
   458  // Turn the rlist (with the return values) of the OINLCALL in
   459  // n into an expression list lumping the ninit and body
   460  // containing the inlined statements on the first list element so
   461  // order will be preserved Used in return, oas2func and call
   462  // statements.
   463  func inlconv2list(n *Node) []*Node {
   464  	if n.Op != OINLCALL || n.Rlist.Len() == 0 {
   465  		Fatalf("inlconv2list %+v\n", n)
   466  	}
   467  
   468  	s := n.Rlist.Slice()
   469  	s[0] = addinit(s[0], append(n.Ninit.Slice(), n.Nbody.Slice()...))
   470  	return s
   471  }
   472  
   473  func inlnodelist(l Nodes) {
   474  	s := l.Slice()
   475  	for i := range s {
   476  		s[i] = inlnode(s[i])
   477  	}
   478  }
   479  
   480  // inlnode recurses over the tree to find inlineable calls, which will
   481  // be turned into OINLCALLs by mkinlcall. When the recursion comes
   482  // back up will examine left, right, list, rlist, ninit, ntest, nincr,
   483  // nbody and nelse and use one of the 4 inlconv/glue functions above
   484  // to turn the OINLCALL into an expression, a statement, or patch it
   485  // in to this nodes list or rlist as appropriate.
   486  // NOTE it makes no sense to pass the glue functions down the
   487  // recursion to the level where the OINLCALL gets created because they
   488  // have to edit /this/ n, so you'd have to push that one down as well,
   489  // but then you may as well do it here.  so this is cleaner and
   490  // shorter and less complicated.
   491  // The result of inlnode MUST be assigned back to n, e.g.
   492  // 	n.Left = inlnode(n.Left)
   493  func inlnode(n *Node) *Node {
   494  	if n == nil {
   495  		return n
   496  	}
   497  
   498  	switch n.Op {
   499  	// inhibit inlining of their argument
   500  	case ODEFER, OPROC:
   501  		switch n.Left.Op {
   502  		case OCALLFUNC, OCALLMETH:
   503  			n.Left.SetNoInline(true)
   504  		}
   505  		return n
   506  
   507  	// TODO do them here (or earlier),
   508  	// so escape analysis can avoid more heapmoves.
   509  	case OCLOSURE:
   510  		return n
   511  	}
   512  
   513  	lno := setlineno(n)
   514  
   515  	inlnodelist(n.Ninit)
   516  	for _, n1 := range n.Ninit.Slice() {
   517  		if n1.Op == OINLCALL {
   518  			inlconv2stmt(n1)
   519  		}
   520  	}
   521  
   522  	n.Left = inlnode(n.Left)
   523  	if n.Left != nil && n.Left.Op == OINLCALL {
   524  		n.Left = inlconv2expr(n.Left)
   525  	}
   526  
   527  	n.Right = inlnode(n.Right)
   528  	if n.Right != nil && n.Right.Op == OINLCALL {
   529  		if n.Op == OFOR || n.Op == OFORUNTIL {
   530  			inlconv2stmt(n.Right)
   531  		} else {
   532  			n.Right = inlconv2expr(n.Right)
   533  		}
   534  	}
   535  
   536  	inlnodelist(n.List)
   537  	switch n.Op {
   538  	case OBLOCK:
   539  		for _, n2 := range n.List.Slice() {
   540  			if n2.Op == OINLCALL {
   541  				inlconv2stmt(n2)
   542  			}
   543  		}
   544  
   545  	case ORETURN, OCALLFUNC, OCALLMETH, OCALLINTER, OAPPEND, OCOMPLEX:
   546  		// if we just replaced arg in f(arg()) or return arg with an inlined call
   547  		// and arg returns multiple values, glue as list
   548  		if n.List.Len() == 1 && n.List.First().Op == OINLCALL && n.List.First().Rlist.Len() > 1 {
   549  			n.List.Set(inlconv2list(n.List.First()))
   550  			break
   551  		}
   552  		fallthrough
   553  
   554  	default:
   555  		s := n.List.Slice()
   556  		for i1, n1 := range s {
   557  			if n1 != nil && n1.Op == OINLCALL {
   558  				s[i1] = inlconv2expr(s[i1])
   559  			}
   560  		}
   561  	}
   562  
   563  	inlnodelist(n.Rlist)
   564  	if n.Op == OAS2FUNC && n.Rlist.First().Op == OINLCALL {
   565  		n.Rlist.Set(inlconv2list(n.Rlist.First()))
   566  		n.Op = OAS2
   567  		n.SetTypecheck(0)
   568  		n = typecheck(n, Etop)
   569  	} else {
   570  		s := n.Rlist.Slice()
   571  		for i1, n1 := range s {
   572  			if n1.Op == OINLCALL {
   573  				if n.Op == OIF {
   574  					inlconv2stmt(n1)
   575  				} else {
   576  					s[i1] = inlconv2expr(s[i1])
   577  				}
   578  			}
   579  		}
   580  	}
   581  
   582  	inlnodelist(n.Nbody)
   583  	for _, n := range n.Nbody.Slice() {
   584  		if n.Op == OINLCALL {
   585  			inlconv2stmt(n)
   586  		}
   587  	}
   588  
   589  	// with all the branches out of the way, it is now time to
   590  	// transmogrify this node itself unless inhibited by the
   591  	// switch at the top of this function.
   592  	switch n.Op {
   593  	case OCALLFUNC, OCALLMETH:
   594  		if n.NoInline() {
   595  			return n
   596  		}
   597  	}
   598  
   599  	switch n.Op {
   600  	case OCALLFUNC:
   601  		if Debug['m'] > 3 {
   602  			fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
   603  		}
   604  		if n.Left.Func != nil && n.Left.Func.Inl.Len() != 0 && !isIntrinsicCall(n) { // normal case
   605  			n = mkinlcall(n, n.Left, n.Isddd())
   606  		} else if n.Left.isMethodExpression() && asNode(n.Left.Sym.Def) != nil {
   607  			n = mkinlcall(n, asNode(n.Left.Sym.Def), n.Isddd())
   608  		} else if n.Left.Op == OCLOSURE {
   609  			if f := inlinableClosure(n.Left); f != nil {
   610  				n = mkinlcall(n, f, n.Isddd())
   611  			}
   612  		} else if n.Left.Op == ONAME && n.Left.Name != nil && n.Left.Name.Defn != nil {
   613  			if d := n.Left.Name.Defn; d.Op == OAS && d.Right.Op == OCLOSURE {
   614  				if f := inlinableClosure(d.Right); f != nil {
   615  					// NB: this check is necessary to prevent indirect re-assignment of the variable
   616  					// having the address taken after the invocation or only used for reads is actually fine
   617  					// but we have no easy way to distinguish the safe cases
   618  					if d.Left.Addrtaken() {
   619  						if Debug['m'] > 1 {
   620  							fmt.Printf("%v: cannot inline escaping closure variable %v\n", n.Line(), n.Left)
   621  						}
   622  						break
   623  					}
   624  
   625  					// ensure the variable is never re-assigned
   626  					if unsafe, a := reassigned(n.Left); unsafe {
   627  						if Debug['m'] > 1 {
   628  							if a != nil {
   629  								fmt.Printf("%v: cannot inline re-assigned closure variable at %v: %v\n", n.Line(), a.Line(), a)
   630  							} else {
   631  								fmt.Printf("%v: cannot inline global closure variable %v\n", n.Line(), n.Left)
   632  							}
   633  						}
   634  						break
   635  					}
   636  					n = mkinlcall(n, f, n.Isddd())
   637  				}
   638  			}
   639  		}
   640  
   641  	case OCALLMETH:
   642  		if Debug['m'] > 3 {
   643  			fmt.Printf("%v:call to meth %L\n", n.Line(), n.Left.Right)
   644  		}
   645  
   646  		// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
   647  		if n.Left.Type == nil {
   648  			Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
   649  		}
   650  
   651  		if n.Left.Type.Nname() == nil {
   652  			Fatalf("no function definition for [%p] %+v\n", n.Left.Type, n.Left.Type)
   653  		}
   654  
   655  		n = mkinlcall(n, asNode(n.Left.Type.FuncType().Nname), n.Isddd())
   656  	}
   657  
   658  	lineno = lno
   659  	return n
   660  }
   661  
   662  // inlinableClosure takes an OCLOSURE node and follows linkage to the matching ONAME with
   663  // the inlinable body. Returns nil if the function is not inlinable.
   664  func inlinableClosure(n *Node) *Node {
   665  	c := n.Func.Closure
   666  	caninl(c)
   667  	f := c.Func.Nname
   668  	if f == nil || f.Func.Inl.Len() == 0 {
   669  		return nil
   670  	}
   671  	return f
   672  }
   673  
   674  // reassigned takes an ONAME node, walks the function in which it is defined, and returns a boolean
   675  // indicating whether the name has any assignments other than its declaration.
   676  // The second return value is the first such assignment encountered in the walk, if any. It is mostly
   677  // useful for -m output documenting the reason for inhibited optimizations.
   678  // NB: global variables are always considered to be re-assigned.
   679  // TODO: handle initial declaration not including an assignment and followed by a single assignment?
   680  func reassigned(n *Node) (bool, *Node) {
   681  	if n.Op != ONAME {
   682  		Fatalf("reassigned %v", n)
   683  	}
   684  	// no way to reliably check for no-reassignment of globals, assume it can be
   685  	if n.Name.Curfn == nil {
   686  		return true, nil
   687  	}
   688  	f := n.Name.Curfn
   689  	// There just might be a good reason for this although this can be pretty surprising:
   690  	// local variables inside a closure have Curfn pointing to the OCLOSURE node instead
   691  	// of the corresponding ODCLFUNC.
   692  	// We need to walk the function body to check for reassignments so we follow the
   693  	// linkage to the ODCLFUNC node as that is where body is held.
   694  	if f.Op == OCLOSURE {
   695  		f = f.Func.Closure
   696  	}
   697  	v := reassignVisitor{name: n}
   698  	a := v.visitList(f.Nbody)
   699  	return a != nil, a
   700  }
   701  
   702  type reassignVisitor struct {
   703  	name *Node
   704  }
   705  
   706  func (v *reassignVisitor) visit(n *Node) *Node {
   707  	if n == nil {
   708  		return nil
   709  	}
   710  	switch n.Op {
   711  	case OAS:
   712  		if n.Left == v.name && n != v.name.Name.Defn {
   713  			return n
   714  		}
   715  		return nil
   716  	case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE:
   717  		for _, p := range n.List.Slice() {
   718  			if p == v.name && n != v.name.Name.Defn {
   719  				return n
   720  			}
   721  		}
   722  		return nil
   723  	}
   724  	if a := v.visit(n.Left); a != nil {
   725  		return a
   726  	}
   727  	if a := v.visit(n.Right); a != nil {
   728  		return a
   729  	}
   730  	if a := v.visitList(n.List); a != nil {
   731  		return a
   732  	}
   733  	if a := v.visitList(n.Rlist); a != nil {
   734  		return a
   735  	}
   736  	if a := v.visitList(n.Ninit); a != nil {
   737  		return a
   738  	}
   739  	if a := v.visitList(n.Nbody); a != nil {
   740  		return a
   741  	}
   742  	return nil
   743  }
   744  
   745  func (v *reassignVisitor) visitList(l Nodes) *Node {
   746  	for _, n := range l.Slice() {
   747  		if a := v.visit(n); a != nil {
   748  			return a
   749  		}
   750  	}
   751  	return nil
   752  }
   753  
   754  // The result of mkinlcall MUST be assigned back to n, e.g.
   755  // 	n.Left = mkinlcall(n.Left, fn, isddd)
   756  func mkinlcall(n *Node, fn *Node, isddd bool) *Node {
   757  	save_safemode := safemode
   758  
   759  	// imported functions may refer to unsafe as long as the
   760  	// package was marked safe during import (already checked).
   761  	pkg := fnpkg(fn)
   762  
   763  	if pkg != localpkg && pkg != nil {
   764  		safemode = false
   765  	}
   766  	n = mkinlcall1(n, fn, isddd)
   767  	safemode = save_safemode
   768  	return n
   769  }
   770  
   771  func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node {
   772  	if asNode(t.Nname) != nil && !isblank(asNode(t.Nname)) {
   773  		inlvar := inlvars[asNode(t.Nname)]
   774  		if inlvar == nil {
   775  			Fatalf("missing inlvar for %v\n", asNode(t.Nname))
   776  		}
   777  		return inlvar
   778  	}
   779  
   780  	return typecheck(nblank, Erv|Easgn)
   781  }
   782  
   783  var inlgen int
   784  
   785  // If n is a call, and fn is a function with an inlinable body,
   786  // return an OINLCALL.
   787  // On return ninit has the parameter assignments, the nbody is the
   788  // inlined function body and list, rlist contain the input, output
   789  // parameters.
   790  // The result of mkinlcall1 MUST be assigned back to n, e.g.
   791  // 	n.Left = mkinlcall1(n.Left, fn, isddd)
   792  func mkinlcall1(n, fn *Node, isddd bool) *Node {
   793  	if fn.Func.Inl.Len() == 0 {
   794  		// No inlinable body.
   795  		return n
   796  	}
   797  
   798  	if fn == Curfn || fn.Name.Defn == Curfn {
   799  		// Can't recursively inline a function into itself.
   800  		return n
   801  	}
   802  
   803  	if Debug_typecheckinl == 0 {
   804  		typecheckinl(fn)
   805  	}
   806  
   807  	// We have a function node, and it has an inlineable body.
   808  	if Debug['m'] > 1 {
   809  		fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, fn.Func.Inl)
   810  	} else if Debug['m'] != 0 {
   811  		fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
   812  	}
   813  	if Debug['m'] > 2 {
   814  		fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n)
   815  	}
   816  
   817  	ninit := n.Ninit
   818  
   819  	// Make temp names to use instead of the originals.
   820  	inlvars := make(map[*Node]*Node)
   821  
   822  	// record formals/locals for later post-processing
   823  	var inlfvars []*Node
   824  
   825  	// Find declarations corresponding to inlineable body.
   826  	var dcl []*Node
   827  	if fn.Name.Defn != nil {
   828  		dcl = fn.Func.Inldcl.Slice() // local function
   829  
   830  		// handle captured variables when inlining closures
   831  		if c := fn.Name.Defn.Func.Closure; c != nil {
   832  			for _, v := range c.Func.Cvars.Slice() {
   833  				if v.Op == OXXX {
   834  					continue
   835  				}
   836  
   837  				o := v.Name.Param.Outer
   838  				// make sure the outer param matches the inlining location
   839  				// NB: if we enabled inlining of functions containing OCLOSURE or refined
   840  				// the reassigned check via some sort of copy propagation this would most
   841  				// likely need to be changed to a loop to walk up to the correct Param
   842  				if o == nil || (o.Name.Curfn != Curfn && o.Name.Curfn.Func.Closure != Curfn) {
   843  					Fatalf("%v: unresolvable capture %v %v\n", n.Line(), fn, v)
   844  				}
   845  
   846  				if v.Name.Byval() {
   847  					iv := typecheck(inlvar(v), Erv)
   848  					ninit.Append(nod(ODCL, iv, nil))
   849  					ninit.Append(typecheck(nod(OAS, iv, o), Etop))
   850  					inlvars[v] = iv
   851  				} else {
   852  					addr := newname(lookup("&" + v.Sym.Name))
   853  					addr.Type = types.NewPtr(v.Type)
   854  					ia := typecheck(inlvar(addr), Erv)
   855  					ninit.Append(nod(ODCL, ia, nil))
   856  					ninit.Append(typecheck(nod(OAS, ia, nod(OADDR, o, nil)), Etop))
   857  					inlvars[addr] = ia
   858  
   859  					// When capturing by reference, all occurrence of the captured var
   860  					// must be substituted with dereference of the temporary address
   861  					inlvars[v] = typecheck(nod(OIND, ia, nil), Erv)
   862  				}
   863  			}
   864  		}
   865  	} else {
   866  		dcl = fn.Func.Dcl // imported function
   867  	}
   868  
   869  	for _, ln := range dcl {
   870  		if ln.Op != ONAME {
   871  			continue
   872  		}
   873  		if ln.Class() == PPARAMOUT { // return values handled below.
   874  			continue
   875  		}
   876  		if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
   877  			continue
   878  		}
   879  		inlvars[ln] = typecheck(inlvar(ln), Erv)
   880  		if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM {
   881  			ninit.Append(nod(ODCL, inlvars[ln], nil))
   882  		}
   883  		if genDwarfInline > 0 {
   884  			inlf := inlvars[ln]
   885  			if ln.Class() == PPARAM {
   886  				inlf.SetInlFormal(true)
   887  			} else {
   888  				inlf.SetInlLocal(true)
   889  			}
   890  			inlf.Pos = ln.Pos
   891  			inlfvars = append(inlfvars, inlf)
   892  		}
   893  	}
   894  
   895  	// temporaries for return values.
   896  	var retvars []*Node
   897  	for i, t := range fn.Type.Results().Fields().Slice() {
   898  		var m *Node
   899  		var mpos src.XPos
   900  		if t != nil && asNode(t.Nname) != nil && !isblank(asNode(t.Nname)) {
   901  			mpos = asNode(t.Nname).Pos
   902  			m = inlvar(asNode(t.Nname))
   903  			m = typecheck(m, Erv)
   904  			inlvars[asNode(t.Nname)] = m
   905  		} else {
   906  			// anonymous return values, synthesize names for use in assignment that replaces return
   907  			m = retvar(t, i)
   908  		}
   909  
   910  		if genDwarfInline > 0 {
   911  			// Don't update the src.Pos on a return variable if it
   912  			// was manufactured by the inliner (e.g. "~R2"); such vars
   913  			// were not part of the original callee.
   914  			if !strings.HasPrefix(m.Sym.Name, "~R") {
   915  				m.SetInlFormal(true)
   916  				m.Pos = mpos
   917  				inlfvars = append(inlfvars, m)
   918  			}
   919  		}
   920  
   921  		ninit.Append(nod(ODCL, m, nil))
   922  		retvars = append(retvars, m)
   923  	}
   924  
   925  	// Assign arguments to the parameters' temp names.
   926  	as := nod(OAS2, nil, nil)
   927  	as.Rlist.Set(n.List.Slice())
   928  
   929  	// For non-dotted calls to variadic functions, we assign the
   930  	// variadic parameter's temp name separately.
   931  	var vas *Node
   932  
   933  	if fn.IsMethod() {
   934  		rcv := fn.Type.Recv()
   935  
   936  		if n.Left.Op == ODOTMETH {
   937  			// For x.M(...), assign x directly to the
   938  			// receiver parameter.
   939  			if n.Left.Left == nil {
   940  				Fatalf("method call without receiver: %+v", n)
   941  			}
   942  			ras := nod(OAS, tinlvar(rcv, inlvars), n.Left.Left)
   943  			ras = typecheck(ras, Etop)
   944  			ninit.Append(ras)
   945  		} else {
   946  			// For T.M(...), add the receiver parameter to
   947  			// as.List, so it's assigned by the normal
   948  			// arguments.
   949  			if as.Rlist.Len() == 0 {
   950  				Fatalf("non-method call to method without first arg: %+v", n)
   951  			}
   952  			as.List.Append(tinlvar(rcv, inlvars))
   953  		}
   954  	}
   955  
   956  	for _, param := range fn.Type.Params().Fields().Slice() {
   957  		// For ordinary parameters or variadic parameters in
   958  		// dotted calls, just add the variable to the
   959  		// assignment list, and we're done.
   960  		if !param.Isddd() || isddd {
   961  			as.List.Append(tinlvar(param, inlvars))
   962  			continue
   963  		}
   964  
   965  		// Otherwise, we need to collect the remaining values
   966  		// to pass as a slice.
   967  
   968  		numvals := n.List.Len()
   969  		if numvals == 1 && n.List.First().Type.IsFuncArgStruct() {
   970  			numvals = n.List.First().Type.NumFields()
   971  		}
   972  
   973  		x := as.List.Len()
   974  		for as.List.Len() < numvals {
   975  			as.List.Append(argvar(param.Type, as.List.Len()))
   976  		}
   977  		varargs := as.List.Slice()[x:]
   978  
   979  		vas = nod(OAS, tinlvar(param, inlvars), nil)
   980  		if len(varargs) == 0 {
   981  			vas.Right = nodnil()
   982  			vas.Right.Type = param.Type
   983  		} else {
   984  			vas.Right = nod(OCOMPLIT, nil, typenod(param.Type))
   985  			vas.Right.List.Set(varargs)
   986  		}
   987  	}
   988  
   989  	if as.Rlist.Len() != 0 {
   990  		as = typecheck(as, Etop)
   991  		ninit.Append(as)
   992  	}
   993  
   994  	if vas != nil {
   995  		vas = typecheck(vas, Etop)
   996  		ninit.Append(vas)
   997  	}
   998  
   999  	// Zero the return parameters.
  1000  	for _, n := range retvars {
  1001  		ras := nod(OAS, n, nil)
  1002  		ras = typecheck(ras, Etop)
  1003  		ninit.Append(ras)
  1004  	}
  1005  
  1006  	retlabel := autolabel(".i")
  1007  	retlabel.Etype = 1 // flag 'safe' for escape analysis (no backjumps)
  1008  
  1009  	inlgen++
  1010  
  1011  	parent := -1
  1012  	if b := Ctxt.PosTable.Pos(n.Pos).Base(); b != nil {
  1013  		parent = b.InliningIndex()
  1014  	}
  1015  	newIndex := Ctxt.InlTree.Add(parent, n.Pos, fn.Sym.Linksym())
  1016  
  1017  	if genDwarfInline > 0 {
  1018  		if !fn.Sym.Linksym().WasInlined() {
  1019  			Ctxt.DwFixups.SetPrecursorFunc(fn.Sym.Linksym(), fn)
  1020  			fn.Sym.Linksym().Set(obj.AttrWasInlined, true)
  1021  		}
  1022  	}
  1023  
  1024  	subst := inlsubst{
  1025  		retlabel:    retlabel,
  1026  		retvars:     retvars,
  1027  		inlvars:     inlvars,
  1028  		bases:       make(map[*src.PosBase]*src.PosBase),
  1029  		newInlIndex: newIndex,
  1030  	}
  1031  
  1032  	body := subst.list(fn.Func.Inl)
  1033  
  1034  	lab := nod(OLABEL, retlabel, nil)
  1035  	body = append(body, lab)
  1036  
  1037  	typecheckslice(body, Etop)
  1038  
  1039  	if genDwarfInline > 0 {
  1040  		for _, v := range inlfvars {
  1041  			v.Pos = subst.updatedPos(v.Pos)
  1042  		}
  1043  	}
  1044  
  1045  	//dumplist("ninit post", ninit);
  1046  
  1047  	call := nod(OINLCALL, nil, nil)
  1048  	call.Ninit.Set(ninit.Slice())
  1049  	call.Nbody.Set(body)
  1050  	call.Rlist.Set(retvars)
  1051  	call.Type = n.Type
  1052  	call.SetTypecheck(1)
  1053  
  1054  	// transitive inlining
  1055  	// might be nice to do this before exporting the body,
  1056  	// but can't emit the body with inlining expanded.
  1057  	// instead we emit the things that the body needs
  1058  	// and each use must redo the inlining.
  1059  	// luckily these are small.
  1060  	inlnodelist(call.Nbody)
  1061  	for _, n := range call.Nbody.Slice() {
  1062  		if n.Op == OINLCALL {
  1063  			inlconv2stmt(n)
  1064  		}
  1065  	}
  1066  
  1067  	if Debug['m'] > 2 {
  1068  		fmt.Printf("%v: After inlining %+v\n\n", call.Line(), call)
  1069  	}
  1070  
  1071  	return call
  1072  }
  1073  
  1074  // Every time we expand a function we generate a new set of tmpnames,
  1075  // PAUTO's in the calling functions, and link them off of the
  1076  // PPARAM's, PAUTOS and PPARAMOUTs of the called function.
  1077  func inlvar(var_ *Node) *Node {
  1078  	if Debug['m'] > 3 {
  1079  		fmt.Printf("inlvar %+v\n", var_)
  1080  	}
  1081  
  1082  	n := newname(var_.Sym)
  1083  	n.Type = var_.Type
  1084  	n.SetClass(PAUTO)
  1085  	n.Name.SetUsed(true)
  1086  	n.Name.Curfn = Curfn // the calling function, not the called one
  1087  	n.SetAddrtaken(var_.Addrtaken())
  1088  
  1089  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
  1090  	return n
  1091  }
  1092  
  1093  // Synthesize a variable to store the inlined function's results in.
  1094  func retvar(t *types.Field, i int) *Node {
  1095  	n := newname(lookupN("~R", i))
  1096  	n.Type = t.Type
  1097  	n.SetClass(PAUTO)
  1098  	n.Name.SetUsed(true)
  1099  	n.Name.Curfn = Curfn // the calling function, not the called one
  1100  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
  1101  	return n
  1102  }
  1103  
  1104  // Synthesize a variable to store the inlined function's arguments
  1105  // when they come from a multiple return call.
  1106  func argvar(t *types.Type, i int) *Node {
  1107  	n := newname(lookupN("~arg", i))
  1108  	n.Type = t.Elem()
  1109  	n.SetClass(PAUTO)
  1110  	n.Name.SetUsed(true)
  1111  	n.Name.Curfn = Curfn // the calling function, not the called one
  1112  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
  1113  	return n
  1114  }
  1115  
  1116  // The inlsubst type implements the actual inlining of a single
  1117  // function call.
  1118  type inlsubst struct {
  1119  	// Target of the goto substituted in place of a return.
  1120  	retlabel *Node
  1121  
  1122  	// Temporary result variables.
  1123  	retvars []*Node
  1124  
  1125  	inlvars map[*Node]*Node
  1126  
  1127  	// bases maps from original PosBase to PosBase with an extra
  1128  	// inlined call frame.
  1129  	bases map[*src.PosBase]*src.PosBase
  1130  
  1131  	// newInlIndex is the index of the inlined call frame to
  1132  	// insert for inlined nodes.
  1133  	newInlIndex int
  1134  }
  1135  
  1136  // list inlines a list of nodes.
  1137  func (subst *inlsubst) list(ll Nodes) []*Node {
  1138  	s := make([]*Node, 0, ll.Len())
  1139  	for _, n := range ll.Slice() {
  1140  		s = append(s, subst.node(n))
  1141  	}
  1142  	return s
  1143  }
  1144  
  1145  // node recursively copies a node from the saved pristine body of the
  1146  // inlined function, substituting references to input/output
  1147  // parameters with ones to the tmpnames, and substituting returns with
  1148  // assignments to the output.
  1149  func (subst *inlsubst) node(n *Node) *Node {
  1150  	if n == nil {
  1151  		return nil
  1152  	}
  1153  
  1154  	switch n.Op {
  1155  	case ONAME:
  1156  		if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
  1157  			if Debug['m'] > 2 {
  1158  				fmt.Printf("substituting name %+v  ->  %+v\n", n, inlvar)
  1159  			}
  1160  			return inlvar
  1161  		}
  1162  
  1163  		if Debug['m'] > 2 {
  1164  			fmt.Printf("not substituting name %+v\n", n)
  1165  		}
  1166  		return n
  1167  
  1168  	case OLITERAL, OTYPE:
  1169  		// If n is a named constant or type, we can continue
  1170  		// using it in the inline copy. Otherwise, make a copy
  1171  		// so we can update the line number.
  1172  		if n.Sym != nil {
  1173  			return n
  1174  		}
  1175  
  1176  		// Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
  1177  
  1178  	//		dump("Return before substitution", n);
  1179  	case ORETURN:
  1180  		m := nod(OGOTO, subst.retlabel, nil)
  1181  		m.Ninit.Set(subst.list(n.Ninit))
  1182  
  1183  		if len(subst.retvars) != 0 && n.List.Len() != 0 {
  1184  			as := nod(OAS2, nil, nil)
  1185  
  1186  			// Make a shallow copy of retvars.
  1187  			// Otherwise OINLCALL.Rlist will be the same list,
  1188  			// and later walk and typecheck may clobber it.
  1189  			for _, n := range subst.retvars {
  1190  				as.List.Append(n)
  1191  			}
  1192  			as.Rlist.Set(subst.list(n.List))
  1193  			as = typecheck(as, Etop)
  1194  			m.Ninit.Append(as)
  1195  		}
  1196  
  1197  		typecheckslice(m.Ninit.Slice(), Etop)
  1198  		m = typecheck(m, Etop)
  1199  
  1200  		//		dump("Return after substitution", m);
  1201  		return m
  1202  
  1203  	case OGOTO, OLABEL:
  1204  		m := nod(OXXX, nil, nil)
  1205  		*m = *n
  1206  		m.Pos = subst.updatedPos(m.Pos)
  1207  		m.Ninit.Set(nil)
  1208  		p := fmt.Sprintf("%s·%d", n.Left.Sym.Name, inlgen)
  1209  		m.Left = newname(lookup(p))
  1210  
  1211  		return m
  1212  	}
  1213  
  1214  	m := nod(OXXX, nil, nil)
  1215  	*m = *n
  1216  	m.Pos = subst.updatedPos(m.Pos)
  1217  	m.Ninit.Set(nil)
  1218  
  1219  	if n.Op == OCLOSURE {
  1220  		Fatalf("cannot inline function containing closure: %+v", n)
  1221  	}
  1222  
  1223  	m.Left = subst.node(n.Left)
  1224  	m.Right = subst.node(n.Right)
  1225  	m.List.Set(subst.list(n.List))
  1226  	m.Rlist.Set(subst.list(n.Rlist))
  1227  	m.Ninit.Set(append(m.Ninit.Slice(), subst.list(n.Ninit)...))
  1228  	m.Nbody.Set(subst.list(n.Nbody))
  1229  
  1230  	return m
  1231  }
  1232  
  1233  func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
  1234  	pos := Ctxt.PosTable.Pos(xpos)
  1235  	oldbase := pos.Base() // can be nil
  1236  	newbase := subst.bases[oldbase]
  1237  	if newbase == nil {
  1238  		newbase = src.NewInliningBase(oldbase, subst.newInlIndex)
  1239  		subst.bases[oldbase] = newbase
  1240  	}
  1241  	pos.SetBase(newbase)
  1242  	return Ctxt.PosTable.XPos(pos)
  1243  }