github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/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.  -ll and more is useful to flush out bugs.
    12  // These additional levels (beyond -l) may be buggy and are not supported.
    13  //      0: disabled
    14  //      1: 80-nodes leaf functions, oneliners, lazy typechecking (default)
    15  //      2: early typechecking of all imported bodies
    16  //      3: allow variadic functions
    17  //      4: allow non-leaf functions , (breaks runtime.Caller)
    18  //
    19  //  At some point this may get another default and become switch-offable with -N.
    20  //
    21  //  The debug['m'] flag enables diagnostic output.  a single -m is useful for verifying
    22  //  which calls get inlined or not, more is for debugging, and may go away at any point.
    23  //
    24  // TODO:
    25  //   - inline functions with ... args
    26  //   - handle T.meth(f()) with func f() (t T, arg, arg, )
    27  
    28  package gc
    29  
    30  import (
    31  	"cmd/compile/internal/types"
    32  	"cmd/internal/src"
    33  	"fmt"
    34  )
    35  
    36  // Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
    37  // the ->sym can be re-used in the local package, so peel it off the receiver's type.
    38  func fnpkg(fn *Node) *types.Pkg {
    39  	if fn.IsMethod() {
    40  		// method
    41  		rcvr := fn.Type.Recv().Type
    42  
    43  		if rcvr.IsPtr() {
    44  			rcvr = rcvr.Elem()
    45  		}
    46  		if rcvr.Sym == nil {
    47  			Fatalf("receiver with no sym: [%v] %L  (%v)", fn.Sym, fn, rcvr)
    48  		}
    49  		return rcvr.Sym.Pkg
    50  	}
    51  
    52  	// non-method
    53  	return fn.Sym.Pkg
    54  }
    55  
    56  // Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
    57  // because they're a copy of an already checked body.
    58  func typecheckinl(fn *Node) {
    59  	lno := setlineno(fn)
    60  
    61  	// typecheckinl is only for imported functions;
    62  	// their bodies may refer to unsafe as long as the package
    63  	// was marked safe during import (which was checked then).
    64  	// the ->inl of a local function has been typechecked before caninl copied it.
    65  	pkg := fnpkg(fn)
    66  
    67  	if pkg == localpkg || pkg == nil {
    68  		return // typecheckinl on local function
    69  	}
    70  
    71  	if Debug['m'] > 2 || Debug_export != 0 {
    72  		fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, fn.Func.Inl)
    73  	}
    74  
    75  	save_safemode := safemode
    76  	safemode = false
    77  
    78  	savefn := Curfn
    79  	Curfn = fn
    80  	typecheckslice(fn.Func.Inl.Slice(), Etop)
    81  	Curfn = savefn
    82  
    83  	safemode = save_safemode
    84  
    85  	lineno = lno
    86  }
    87  
    88  // Caninl determines whether fn is inlineable.
    89  // If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy.
    90  // fn and ->nbody will already have been typechecked.
    91  func caninl(fn *Node) {
    92  	if fn.Op != ODCLFUNC {
    93  		Fatalf("caninl %v", fn)
    94  	}
    95  	if fn.Func.Nname == nil {
    96  		Fatalf("caninl no nname %+v", fn)
    97  	}
    98  
    99  	var reason string // reason, if any, that the function was not inlined
   100  	if Debug['m'] > 1 {
   101  		defer func() {
   102  			if reason != "" {
   103  				fmt.Printf("%v: cannot inline %v: %s\n", fn.Line(), fn.Func.Nname, reason)
   104  			}
   105  		}()
   106  	}
   107  
   108  	// If marked "go:noinline", don't inline
   109  	if fn.Func.Pragma&Noinline != 0 {
   110  		reason = "marked go:noinline"
   111  		return
   112  	}
   113  
   114  	// If marked "go:cgo_unsafe_args", don't inline, since the
   115  	// function makes assumptions about its argument frame layout.
   116  	if fn.Func.Pragma&CgoUnsafeArgs != 0 {
   117  		reason = "marked go:cgo_unsafe_args"
   118  		return
   119  	}
   120  
   121  	// If fn has no body (is defined outside of Go), cannot inline it.
   122  	if fn.Nbody.Len() == 0 {
   123  		reason = "no function body"
   124  		return
   125  	}
   126  
   127  	if fn.Typecheck() == 0 {
   128  		Fatalf("caninl on non-typechecked function %v", fn)
   129  	}
   130  
   131  	// can't handle ... args yet
   132  	if Debug['l'] < 3 {
   133  		f := fn.Type.Params().Fields()
   134  		if len := f.Len(); len > 0 {
   135  			if t := f.Index(len - 1); t.Isddd() {
   136  				reason = "has ... args"
   137  				return
   138  			}
   139  		}
   140  	}
   141  
   142  	// Runtime package must not be instrumented.
   143  	// Instrument skips runtime package. However, some runtime code can be
   144  	// inlined into other packages and instrumented there. To avoid this,
   145  	// we disable inlining of runtime functions when instrumenting.
   146  	// The example that we observed is inlining of LockOSThread,
   147  	// which lead to false race reports on m contents.
   148  	if instrumenting && myimportpath == "runtime" {
   149  		reason = "instrumenting and is runtime function"
   150  		return
   151  	}
   152  
   153  	const maxBudget = 80
   154  	visitor := hairyVisitor{budget: maxBudget}
   155  	if visitor.visitList(fn.Nbody) {
   156  		reason = visitor.reason
   157  		return
   158  	}
   159  	if visitor.budget < 0 {
   160  		reason = "function too complex"
   161  		return
   162  	}
   163  
   164  	savefn := Curfn
   165  	Curfn = fn
   166  
   167  	n := fn.Func.Nname
   168  
   169  	n.Func.Inl.Set(fn.Nbody.Slice())
   170  	fn.Nbody.Set(inlcopylist(n.Func.Inl.Slice()))
   171  	inldcl := inlcopylist(n.Name.Defn.Func.Dcl)
   172  	n.Func.Inldcl.Set(inldcl)
   173  	n.Func.InlCost = maxBudget - visitor.budget
   174  
   175  	// hack, TODO, check for better way to link method nodes back to the thing with the ->inl
   176  	// this is so export can find the body of a method
   177  	fn.Type.FuncType().Nname = asTypesNode(n)
   178  
   179  	if Debug['m'] > 1 {
   180  		fmt.Printf("%v: can inline %#v as: %#v { %#v }\n", fn.Line(), n, fn.Type, n.Func.Inl)
   181  	} else if Debug['m'] != 0 {
   182  		fmt.Printf("%v: can inline %v\n", fn.Line(), n)
   183  	}
   184  
   185  	Curfn = savefn
   186  }
   187  
   188  // hairyVisitor visits a function body to determine its inlining
   189  // hairiness and whether or not it can be inlined.
   190  type hairyVisitor struct {
   191  	budget int32
   192  	reason string
   193  }
   194  
   195  // Look for anything we want to punt on.
   196  func (v *hairyVisitor) visitList(ll Nodes) bool {
   197  	for _, n := range ll.Slice() {
   198  		if v.visit(n) {
   199  			return true
   200  		}
   201  	}
   202  	return false
   203  }
   204  
   205  func (v *hairyVisitor) visit(n *Node) bool {
   206  	if n == nil {
   207  		return false
   208  	}
   209  
   210  	switch n.Op {
   211  	// Call is okay if inlinable and we have the budget for the body.
   212  	case OCALLFUNC:
   213  		if isIntrinsicCall(n) {
   214  			v.budget--
   215  			break
   216  		}
   217  		// Functions that call runtime.getcaller{pc,sp} can not be inlined
   218  		// because getcaller{pc,sp} expect a pointer to the caller's first argument.
   219  		if n.Left.Op == ONAME && n.Left.Class() == PFUNC && isRuntimePkg(n.Left.Sym.Pkg) {
   220  			fn := n.Left.Sym.Name
   221  			if fn == "getcallerpc" || fn == "getcallersp" {
   222  				v.reason = "call to " + fn
   223  				return true
   224  			}
   225  		}
   226  
   227  		if fn := n.Left.Func; fn != nil && fn.Inl.Len() != 0 {
   228  			v.budget -= fn.InlCost
   229  			break
   230  		}
   231  
   232  		if n.isMethodCalledAsFunction() {
   233  			if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl.Len() != 0 {
   234  				v.budget -= d.Func.InlCost
   235  				break
   236  			}
   237  		}
   238  		if Debug['l'] < 4 {
   239  			v.reason = "non-leaf function"
   240  			return true
   241  		}
   242  
   243  	// Call is okay if inlinable and we have the budget for the body.
   244  	case OCALLMETH:
   245  		t := n.Left.Type
   246  		if t == nil {
   247  			Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
   248  		}
   249  		if t.Nname() == nil {
   250  			Fatalf("no function definition for [%p] %+v\n", t, t)
   251  		}
   252  		if inlfn := asNode(t.FuncType().Nname).Func; inlfn.Inl.Len() != 0 {
   253  			v.budget -= inlfn.InlCost
   254  			break
   255  		}
   256  		if Debug['l'] < 4 {
   257  			v.reason = "non-leaf method"
   258  			return true
   259  		}
   260  
   261  	// Things that are too hairy, irrespective of the budget
   262  	case OCALL, OCALLINTER, OPANIC, ORECOVER:
   263  		if Debug['l'] < 4 {
   264  			v.reason = "non-leaf op " + n.Op.String()
   265  			return true
   266  		}
   267  
   268  	case OCLOSURE,
   269  		OCALLPART,
   270  		ORANGE,
   271  		OFOR,
   272  		OFORUNTIL,
   273  		OSELECT,
   274  		OTYPESW,
   275  		OPROC,
   276  		ODEFER,
   277  		ODCLTYPE, // can't print yet
   278  		OBREAK,
   279  		ORETJMP:
   280  		v.reason = "unhandled op " + n.Op.String()
   281  		return true
   282  
   283  	case ODCLCONST, OEMPTY, OFALL, OLABEL:
   284  		// These nodes don't produce code; omit from inlining budget.
   285  		return false
   286  	}
   287  
   288  	v.budget--
   289  	// TODO(mdempsky/josharian): Hacks to appease toolstash; remove.
   290  	// See issue 17566 and CL 31674 for discussion.
   291  	switch n.Op {
   292  	case OSTRUCTKEY:
   293  		v.budget--
   294  	case OSLICE, OSLICEARR, OSLICESTR:
   295  		v.budget--
   296  	case OSLICE3, OSLICE3ARR:
   297  		v.budget -= 2
   298  	}
   299  
   300  	if v.budget < 0 {
   301  		v.reason = "function too complex"
   302  		return true
   303  	}
   304  
   305  	return v.visit(n.Left) || v.visit(n.Right) ||
   306  		v.visitList(n.List) || v.visitList(n.Rlist) ||
   307  		v.visitList(n.Ninit) || v.visitList(n.Nbody)
   308  }
   309  
   310  // Inlcopy and inlcopylist recursively copy the body of a function.
   311  // Any name-like node of non-local class is marked for re-export by adding it to
   312  // the exportlist.
   313  func inlcopylist(ll []*Node) []*Node {
   314  	s := make([]*Node, 0, len(ll))
   315  	for _, n := range ll {
   316  		s = append(s, inlcopy(n))
   317  	}
   318  	return s
   319  }
   320  
   321  func inlcopy(n *Node) *Node {
   322  	if n == nil {
   323  		return nil
   324  	}
   325  
   326  	switch n.Op {
   327  	case ONAME, OTYPE, OLITERAL:
   328  		return n
   329  	}
   330  
   331  	m := *n
   332  	if m.Func != nil {
   333  		m.Func.Inl.Set(nil)
   334  	}
   335  	m.Left = inlcopy(n.Left)
   336  	m.Right = inlcopy(n.Right)
   337  	m.List.Set(inlcopylist(n.List.Slice()))
   338  	m.Rlist.Set(inlcopylist(n.Rlist.Slice()))
   339  	m.Ninit.Set(inlcopylist(n.Ninit.Slice()))
   340  	m.Nbody.Set(inlcopylist(n.Nbody.Slice()))
   341  
   342  	return &m
   343  }
   344  
   345  // Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
   346  // calls made to inlineable functions. This is the external entry point.
   347  func inlcalls(fn *Node) {
   348  	savefn := Curfn
   349  	Curfn = fn
   350  	fn = inlnode(fn)
   351  	if fn != Curfn {
   352  		Fatalf("inlnode replaced curfn")
   353  	}
   354  	Curfn = savefn
   355  }
   356  
   357  // Turn an OINLCALL into a statement.
   358  func inlconv2stmt(n *Node) {
   359  	n.Op = OBLOCK
   360  
   361  	// n->ninit stays
   362  	n.List.Set(n.Nbody.Slice())
   363  
   364  	n.Nbody.Set(nil)
   365  	n.Rlist.Set(nil)
   366  }
   367  
   368  // Turn an OINLCALL into a single valued expression.
   369  // The result of inlconv2expr MUST be assigned back to n, e.g.
   370  // 	n.Left = inlconv2expr(n.Left)
   371  func inlconv2expr(n *Node) *Node {
   372  	r := n.Rlist.First()
   373  	return addinit(r, append(n.Ninit.Slice(), n.Nbody.Slice()...))
   374  }
   375  
   376  // Turn the rlist (with the return values) of the OINLCALL in
   377  // n into an expression list lumping the ninit and body
   378  // containing the inlined statements on the first list element so
   379  // order will be preserved Used in return, oas2func and call
   380  // statements.
   381  func inlconv2list(n *Node) []*Node {
   382  	if n.Op != OINLCALL || n.Rlist.Len() == 0 {
   383  		Fatalf("inlconv2list %+v\n", n)
   384  	}
   385  
   386  	s := n.Rlist.Slice()
   387  	s[0] = addinit(s[0], append(n.Ninit.Slice(), n.Nbody.Slice()...))
   388  	return s
   389  }
   390  
   391  func inlnodelist(l Nodes) {
   392  	s := l.Slice()
   393  	for i := range s {
   394  		s[i] = inlnode(s[i])
   395  	}
   396  }
   397  
   398  // inlnode recurses over the tree to find inlineable calls, which will
   399  // be turned into OINLCALLs by mkinlcall. When the recursion comes
   400  // back up will examine left, right, list, rlist, ninit, ntest, nincr,
   401  // nbody and nelse and use one of the 4 inlconv/glue functions above
   402  // to turn the OINLCALL into an expression, a statement, or patch it
   403  // in to this nodes list or rlist as appropriate.
   404  // NOTE it makes no sense to pass the glue functions down the
   405  // recursion to the level where the OINLCALL gets created because they
   406  // have to edit /this/ n, so you'd have to push that one down as well,
   407  // but then you may as well do it here.  so this is cleaner and
   408  // shorter and less complicated.
   409  // The result of inlnode MUST be assigned back to n, e.g.
   410  // 	n.Left = inlnode(n.Left)
   411  func inlnode(n *Node) *Node {
   412  	if n == nil {
   413  		return n
   414  	}
   415  
   416  	switch n.Op {
   417  	// inhibit inlining of their argument
   418  	case ODEFER, OPROC:
   419  		switch n.Left.Op {
   420  		case OCALLFUNC, OCALLMETH:
   421  			n.Left.SetNoInline(true)
   422  		}
   423  		return n
   424  
   425  	// TODO do them here (or earlier),
   426  	// so escape analysis can avoid more heapmoves.
   427  	case OCLOSURE:
   428  		return n
   429  	}
   430  
   431  	lno := setlineno(n)
   432  
   433  	inlnodelist(n.Ninit)
   434  	for _, n1 := range n.Ninit.Slice() {
   435  		if n1.Op == OINLCALL {
   436  			inlconv2stmt(n1)
   437  		}
   438  	}
   439  
   440  	n.Left = inlnode(n.Left)
   441  	if n.Left != nil && n.Left.Op == OINLCALL {
   442  		n.Left = inlconv2expr(n.Left)
   443  	}
   444  
   445  	n.Right = inlnode(n.Right)
   446  	if n.Right != nil && n.Right.Op == OINLCALL {
   447  		if n.Op == OFOR || n.Op == OFORUNTIL {
   448  			inlconv2stmt(n.Right)
   449  		} else {
   450  			n.Right = inlconv2expr(n.Right)
   451  		}
   452  	}
   453  
   454  	inlnodelist(n.List)
   455  	switch n.Op {
   456  	case OBLOCK:
   457  		for _, n2 := range n.List.Slice() {
   458  			if n2.Op == OINLCALL {
   459  				inlconv2stmt(n2)
   460  			}
   461  		}
   462  
   463  	case ORETURN, OCALLFUNC, OCALLMETH, OCALLINTER, OAPPEND, OCOMPLEX:
   464  		// if we just replaced arg in f(arg()) or return arg with an inlined call
   465  		// and arg returns multiple values, glue as list
   466  		if n.List.Len() == 1 && n.List.First().Op == OINLCALL && n.List.First().Rlist.Len() > 1 {
   467  			n.List.Set(inlconv2list(n.List.First()))
   468  			break
   469  		}
   470  		fallthrough
   471  
   472  	default:
   473  		s := n.List.Slice()
   474  		for i1, n1 := range s {
   475  			if n1 != nil && n1.Op == OINLCALL {
   476  				s[i1] = inlconv2expr(s[i1])
   477  			}
   478  		}
   479  	}
   480  
   481  	inlnodelist(n.Rlist)
   482  	if n.Op == OAS2FUNC && n.Rlist.First().Op == OINLCALL {
   483  		n.Rlist.Set(inlconv2list(n.Rlist.First()))
   484  		n.Op = OAS2
   485  		n.SetTypecheck(0)
   486  		n = typecheck(n, Etop)
   487  	} else {
   488  		s := n.Rlist.Slice()
   489  		for i1, n1 := range s {
   490  			if n1.Op == OINLCALL {
   491  				if n.Op == OIF {
   492  					inlconv2stmt(n1)
   493  				} else {
   494  					s[i1] = inlconv2expr(s[i1])
   495  				}
   496  			}
   497  		}
   498  	}
   499  
   500  	inlnodelist(n.Nbody)
   501  	for _, n := range n.Nbody.Slice() {
   502  		if n.Op == OINLCALL {
   503  			inlconv2stmt(n)
   504  		}
   505  	}
   506  
   507  	// with all the branches out of the way, it is now time to
   508  	// transmogrify this node itself unless inhibited by the
   509  	// switch at the top of this function.
   510  	switch n.Op {
   511  	case OCALLFUNC, OCALLMETH:
   512  		if n.NoInline() {
   513  			return n
   514  		}
   515  	}
   516  
   517  	switch n.Op {
   518  	case OCALLFUNC:
   519  		if Debug['m'] > 3 {
   520  			fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
   521  		}
   522  		if n.Left.Func != nil && n.Left.Func.Inl.Len() != 0 && !isIntrinsicCall(n) { // normal case
   523  			n = mkinlcall(n, n.Left, n.Isddd())
   524  		} else if n.isMethodCalledAsFunction() && asNode(n.Left.Sym.Def) != nil {
   525  			n = mkinlcall(n, asNode(n.Left.Sym.Def), n.Isddd())
   526  		}
   527  
   528  	case OCALLMETH:
   529  		if Debug['m'] > 3 {
   530  			fmt.Printf("%v:call to meth %L\n", n.Line(), n.Left.Right)
   531  		}
   532  
   533  		// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
   534  		if n.Left.Type == nil {
   535  			Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
   536  		}
   537  
   538  		if n.Left.Type.Nname() == nil {
   539  			Fatalf("no function definition for [%p] %+v\n", n.Left.Type, n.Left.Type)
   540  		}
   541  
   542  		n = mkinlcall(n, asNode(n.Left.Type.FuncType().Nname), n.Isddd())
   543  	}
   544  
   545  	lineno = lno
   546  	return n
   547  }
   548  
   549  // The result of mkinlcall MUST be assigned back to n, e.g.
   550  // 	n.Left = mkinlcall(n.Left, fn, isddd)
   551  func mkinlcall(n *Node, fn *Node, isddd bool) *Node {
   552  	save_safemode := safemode
   553  
   554  	// imported functions may refer to unsafe as long as the
   555  	// package was marked safe during import (already checked).
   556  	pkg := fnpkg(fn)
   557  
   558  	if pkg != localpkg && pkg != nil {
   559  		safemode = false
   560  	}
   561  	n = mkinlcall1(n, fn, isddd)
   562  	safemode = save_safemode
   563  	return n
   564  }
   565  
   566  func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node {
   567  	if asNode(t.Nname) != nil && !isblank(asNode(t.Nname)) {
   568  		inlvar := inlvars[asNode(t.Nname)]
   569  		if inlvar == nil {
   570  			Fatalf("missing inlvar for %v\n", asNode(t.Nname))
   571  		}
   572  		return inlvar
   573  	}
   574  
   575  	return typecheck(nblank, Erv|Easgn)
   576  }
   577  
   578  var inlgen int
   579  
   580  // If n is a call, and fn is a function with an inlinable body,
   581  // return an OINLCALL.
   582  // On return ninit has the parameter assignments, the nbody is the
   583  // inlined function body and list, rlist contain the input, output
   584  // parameters.
   585  // The result of mkinlcall1 MUST be assigned back to n, e.g.
   586  // 	n.Left = mkinlcall1(n.Left, fn, isddd)
   587  func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
   588  	if fn.Func.Inl.Len() == 0 {
   589  		// No inlinable body.
   590  		return n
   591  	}
   592  
   593  	if fn == Curfn || fn.Name.Defn == Curfn {
   594  		// Can't recursively inline a function into itself.
   595  		return n
   596  	}
   597  
   598  	if Debug['l'] < 2 {
   599  		typecheckinl(fn)
   600  	}
   601  
   602  	// We have a function node, and it has an inlineable body.
   603  	if Debug['m'] > 1 {
   604  		fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, fn.Func.Inl)
   605  	} else if Debug['m'] != 0 {
   606  		fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
   607  	}
   608  	if Debug['m'] > 2 {
   609  		fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n)
   610  	}
   611  
   612  	ninit := n.Ninit
   613  
   614  	// Find declarations corresponding to inlineable body.
   615  	var dcl []*Node
   616  	if fn.Name.Defn != nil {
   617  		dcl = fn.Func.Inldcl.Slice() // local function
   618  	} else {
   619  		dcl = fn.Func.Dcl // imported function
   620  	}
   621  
   622  	// Make temp names to use instead of the originals.
   623  	inlvars := make(map[*Node]*Node)
   624  	for _, ln := range dcl {
   625  		if ln.Op != ONAME {
   626  			continue
   627  		}
   628  		if ln.Class() == PPARAMOUT { // return values handled below.
   629  			continue
   630  		}
   631  		if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
   632  			continue
   633  		}
   634  		inlvars[ln] = typecheck(inlvar(ln), Erv)
   635  		if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM {
   636  			ninit.Append(nod(ODCL, inlvars[ln], nil))
   637  		}
   638  	}
   639  
   640  	// temporaries for return values.
   641  	var retvars []*Node
   642  	for i, t := range fn.Type.Results().Fields().Slice() {
   643  		var m *Node
   644  		if t != nil && asNode(t.Nname) != nil && !isblank(asNode(t.Nname)) {
   645  			m = inlvar(asNode(t.Nname))
   646  			m = typecheck(m, Erv)
   647  			inlvars[asNode(t.Nname)] = m
   648  		} else {
   649  			// anonymous return values, synthesize names for use in assignment that replaces return
   650  			m = retvar(t, i)
   651  		}
   652  
   653  		ninit.Append(nod(ODCL, m, nil))
   654  		retvars = append(retvars, m)
   655  	}
   656  
   657  	// Assign arguments to the parameters' temp names.
   658  	as := nod(OAS2, nil, nil)
   659  	as.Rlist.Set(n.List.Slice())
   660  
   661  	// For non-dotted calls to variadic functions, we assign the
   662  	// variadic parameter's temp name separately.
   663  	var vas *Node
   664  
   665  	if fn.IsMethod() {
   666  		rcv := fn.Type.Recv()
   667  
   668  		if n.Left.Op == ODOTMETH {
   669  			// For x.M(...), assign x directly to the
   670  			// receiver parameter.
   671  			if n.Left.Left == nil {
   672  				Fatalf("method call without receiver: %+v", n)
   673  			}
   674  			ras := nod(OAS, tinlvar(rcv, inlvars), n.Left.Left)
   675  			ras = typecheck(ras, Etop)
   676  			ninit.Append(ras)
   677  		} else {
   678  			// For T.M(...), add the receiver parameter to
   679  			// as.List, so it's assigned by the normal
   680  			// arguments.
   681  			if as.Rlist.Len() == 0 {
   682  				Fatalf("non-method call to method without first arg: %+v", n)
   683  			}
   684  			as.List.Append(tinlvar(rcv, inlvars))
   685  		}
   686  	}
   687  
   688  	for _, param := range fn.Type.Params().Fields().Slice() {
   689  		// For ordinary parameters or variadic parameters in
   690  		// dotted calls, just add the variable to the
   691  		// assignment list, and we're done.
   692  		if !param.Isddd() || isddd {
   693  			as.List.Append(tinlvar(param, inlvars))
   694  			continue
   695  		}
   696  
   697  		// Otherwise, we need to collect the remaining values
   698  		// to pass as a slice.
   699  
   700  		numvals := n.List.Len()
   701  		if numvals == 1 && n.List.First().Type.IsFuncArgStruct() {
   702  			numvals = n.List.First().Type.NumFields()
   703  		}
   704  
   705  		x := as.List.Len()
   706  		for as.List.Len() < numvals {
   707  			as.List.Append(argvar(param.Type, as.List.Len()))
   708  		}
   709  		varargs := as.List.Slice()[x:]
   710  
   711  		vas = nod(OAS, tinlvar(param, inlvars), nil)
   712  		if len(varargs) == 0 {
   713  			vas.Right = nodnil()
   714  			vas.Right.Type = param.Type
   715  		} else {
   716  			vas.Right = nod(OCOMPLIT, nil, typenod(param.Type))
   717  			vas.Right.List.Set(varargs)
   718  		}
   719  	}
   720  
   721  	if as.Rlist.Len() != 0 {
   722  		as = typecheck(as, Etop)
   723  		ninit.Append(as)
   724  	}
   725  
   726  	if vas != nil {
   727  		vas = typecheck(vas, Etop)
   728  		ninit.Append(vas)
   729  	}
   730  
   731  	// Zero the return parameters.
   732  	for _, n := range retvars {
   733  		ras := nod(OAS, n, nil)
   734  		ras = typecheck(ras, Etop)
   735  		ninit.Append(ras)
   736  	}
   737  
   738  	retlabel := autolabel(".i")
   739  	retlabel.Etype = 1 // flag 'safe' for escape analysis (no backjumps)
   740  
   741  	inlgen++
   742  
   743  	subst := inlsubst{
   744  		retlabel: retlabel,
   745  		retvars:  retvars,
   746  		inlvars:  inlvars,
   747  	}
   748  
   749  	body := subst.list(fn.Func.Inl)
   750  
   751  	lab := nod(OLABEL, retlabel, nil)
   752  	body = append(body, lab)
   753  
   754  	typecheckslice(body, Etop)
   755  
   756  	//dumplist("ninit post", ninit);
   757  
   758  	call := nod(OINLCALL, nil, nil)
   759  	call.Ninit.Set(ninit.Slice())
   760  	call.Nbody.Set(body)
   761  	call.Rlist.Set(retvars)
   762  	call.Type = n.Type
   763  	call.SetTypecheck(1)
   764  
   765  	// Hide the args from setPos -- the parameters to the inlined
   766  	// call already have good line numbers that should be preserved.
   767  	args := as.Rlist
   768  	as.Rlist.Set(nil)
   769  
   770  	// Rewrite the line information for the inlined AST.
   771  	parent := -1
   772  	callBase := Ctxt.PosTable.Pos(n.Pos).Base()
   773  	if callBase != nil {
   774  		parent = callBase.InliningIndex()
   775  	}
   776  	newIndex := Ctxt.InlTree.Add(parent, n.Pos, fn.Sym.Linksym())
   777  	setpos := &setPos{
   778  		bases:       make(map[*src.PosBase]*src.PosBase),
   779  		newInlIndex: newIndex,
   780  	}
   781  	setpos.node(call)
   782  
   783  	as.Rlist.Set(args.Slice())
   784  
   785  	//dumplist("call body", body);
   786  
   787  	n = call
   788  
   789  	// transitive inlining
   790  	// might be nice to do this before exporting the body,
   791  	// but can't emit the body with inlining expanded.
   792  	// instead we emit the things that the body needs
   793  	// and each use must redo the inlining.
   794  	// luckily these are small.
   795  	body = fn.Func.Inl.Slice()
   796  	fn.Func.Inl.Set(nil) // prevent infinite recursion (shouldn't happen anyway)
   797  	inlnodelist(call.Nbody)
   798  	for _, n := range call.Nbody.Slice() {
   799  		if n.Op == OINLCALL {
   800  			inlconv2stmt(n)
   801  		}
   802  	}
   803  	fn.Func.Inl.Set(body)
   804  
   805  	if Debug['m'] > 2 {
   806  		fmt.Printf("%v: After inlining %+v\n\n", n.Line(), n)
   807  	}
   808  
   809  	return n
   810  }
   811  
   812  // Every time we expand a function we generate a new set of tmpnames,
   813  // PAUTO's in the calling functions, and link them off of the
   814  // PPARAM's, PAUTOS and PPARAMOUTs of the called function.
   815  func inlvar(var_ *Node) *Node {
   816  	if Debug['m'] > 3 {
   817  		fmt.Printf("inlvar %+v\n", var_)
   818  	}
   819  
   820  	n := newname(var_.Sym)
   821  	n.Type = var_.Type
   822  	n.SetClass(PAUTO)
   823  	n.Name.SetUsed(true)
   824  	n.Name.Curfn = Curfn // the calling function, not the called one
   825  	n.SetAddrtaken(var_.Addrtaken())
   826  
   827  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
   828  	return n
   829  }
   830  
   831  // Synthesize a variable to store the inlined function's results in.
   832  func retvar(t *types.Field, i int) *Node {
   833  	n := newname(lookupN("~r", i))
   834  	n.Type = t.Type
   835  	n.SetClass(PAUTO)
   836  	n.Name.SetUsed(true)
   837  	n.Name.Curfn = Curfn // the calling function, not the called one
   838  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
   839  	return n
   840  }
   841  
   842  // Synthesize a variable to store the inlined function's arguments
   843  // when they come from a multiple return call.
   844  func argvar(t *types.Type, i int) *Node {
   845  	n := newname(lookupN("~arg", i))
   846  	n.Type = t.Elem()
   847  	n.SetClass(PAUTO)
   848  	n.Name.SetUsed(true)
   849  	n.Name.Curfn = Curfn // the calling function, not the called one
   850  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
   851  	return n
   852  }
   853  
   854  // The inlsubst type implements the actual inlining of a single
   855  // function call.
   856  type inlsubst struct {
   857  	// Target of the goto substituted in place of a return.
   858  	retlabel *Node
   859  
   860  	// Temporary result variables.
   861  	retvars []*Node
   862  
   863  	inlvars map[*Node]*Node
   864  }
   865  
   866  // list inlines a list of nodes.
   867  func (subst *inlsubst) list(ll Nodes) []*Node {
   868  	s := make([]*Node, 0, ll.Len())
   869  	for _, n := range ll.Slice() {
   870  		s = append(s, subst.node(n))
   871  	}
   872  	return s
   873  }
   874  
   875  // node recursively copies a node from the saved pristine body of the
   876  // inlined function, substituting references to input/output
   877  // parameters with ones to the tmpnames, and substituting returns with
   878  // assignments to the output.
   879  func (subst *inlsubst) node(n *Node) *Node {
   880  	if n == nil {
   881  		return nil
   882  	}
   883  
   884  	switch n.Op {
   885  	case ONAME:
   886  		if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
   887  			if Debug['m'] > 2 {
   888  				fmt.Printf("substituting name %+v  ->  %+v\n", n, inlvar)
   889  			}
   890  			return inlvar
   891  		}
   892  
   893  		if Debug['m'] > 2 {
   894  			fmt.Printf("not substituting name %+v\n", n)
   895  		}
   896  		return n
   897  
   898  	case OLITERAL, OTYPE:
   899  		// If n is a named constant or type, we can continue
   900  		// using it in the inline copy. Otherwise, make a copy
   901  		// so we can update the line number.
   902  		if n.Sym != nil {
   903  			return n
   904  		}
   905  
   906  		// Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
   907  
   908  	//		dump("Return before substitution", n);
   909  	case ORETURN:
   910  		m := nod(OGOTO, subst.retlabel, nil)
   911  
   912  		m.Ninit.Set(subst.list(n.Ninit))
   913  
   914  		if len(subst.retvars) != 0 && n.List.Len() != 0 {
   915  			as := nod(OAS2, nil, nil)
   916  
   917  			// Make a shallow copy of retvars.
   918  			// Otherwise OINLCALL.Rlist will be the same list,
   919  			// and later walk and typecheck may clobber it.
   920  			for _, n := range subst.retvars {
   921  				as.List.Append(n)
   922  			}
   923  			as.Rlist.Set(subst.list(n.List))
   924  			as = typecheck(as, Etop)
   925  			m.Ninit.Append(as)
   926  		}
   927  
   928  		typecheckslice(m.Ninit.Slice(), Etop)
   929  		m = typecheck(m, Etop)
   930  
   931  		//		dump("Return after substitution", m);
   932  		return m
   933  
   934  	case OGOTO, OLABEL:
   935  		m := nod(OXXX, nil, nil)
   936  		*m = *n
   937  		m.Ninit.Set(nil)
   938  		p := fmt.Sprintf("%s·%d", n.Left.Sym.Name, inlgen)
   939  		m.Left = newname(lookup(p))
   940  
   941  		return m
   942  	}
   943  
   944  	m := nod(OXXX, nil, nil)
   945  	*m = *n
   946  	m.Ninit.Set(nil)
   947  
   948  	if n.Op == OCLOSURE {
   949  		Fatalf("cannot inline function containing closure: %+v", n)
   950  	}
   951  
   952  	m.Left = subst.node(n.Left)
   953  	m.Right = subst.node(n.Right)
   954  	m.List.Set(subst.list(n.List))
   955  	m.Rlist.Set(subst.list(n.Rlist))
   956  	m.Ninit.Set(append(m.Ninit.Slice(), subst.list(n.Ninit)...))
   957  	m.Nbody.Set(subst.list(n.Nbody))
   958  
   959  	return m
   960  }
   961  
   962  // setPos is a visitor to update position info with a new inlining index.
   963  type setPos struct {
   964  	bases       map[*src.PosBase]*src.PosBase
   965  	newInlIndex int
   966  }
   967  
   968  func (s *setPos) nodelist(ll Nodes) {
   969  	for _, n := range ll.Slice() {
   970  		s.node(n)
   971  	}
   972  }
   973  
   974  func (s *setPos) node(n *Node) {
   975  	if n == nil {
   976  		return
   977  	}
   978  	if n.Op == OLITERAL || n.Op == OTYPE {
   979  		if n.Sym != nil {
   980  			// This node is not a copy, so don't clobber position.
   981  			return
   982  		}
   983  	}
   984  
   985  	// don't clobber names, unless they're freshly synthesized
   986  	if n.Op != ONAME || !n.Pos.IsKnown() {
   987  		n.Pos = s.updatedPos(n)
   988  	}
   989  
   990  	s.node(n.Left)
   991  	s.node(n.Right)
   992  	s.nodelist(n.List)
   993  	s.nodelist(n.Rlist)
   994  	s.nodelist(n.Ninit)
   995  	s.nodelist(n.Nbody)
   996  }
   997  
   998  func (s *setPos) updatedPos(n *Node) src.XPos {
   999  	pos := Ctxt.PosTable.Pos(n.Pos)
  1000  	oldbase := pos.Base() // can be nil
  1001  	newbase := s.bases[oldbase]
  1002  	if newbase == nil {
  1003  		newbase = src.NewInliningBase(oldbase, s.newInlIndex)
  1004  		pos.SetBase(newbase)
  1005  		s.bases[oldbase] = newbase
  1006  	}
  1007  	pos.SetBase(newbase)
  1008  	return Ctxt.PosTable.XPos(pos)
  1009  }
  1010  
  1011  func (n *Node) isMethodCalledAsFunction() bool {
  1012  	return n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME
  1013  }