github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/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  
   284  	v.budget--
   285  	// TODO(mdempsky/josharian): Hacks to appease toolstash; remove.
   286  	// See issue 17566 and CL 31674 for discussion.
   287  	switch n.Op {
   288  	case OSTRUCTKEY:
   289  		v.budget--
   290  	case OSLICE, OSLICEARR, OSLICESTR:
   291  		v.budget--
   292  	case OSLICE3, OSLICE3ARR:
   293  		v.budget -= 2
   294  	}
   295  
   296  	if v.budget < 0 {
   297  		v.reason = "function too complex"
   298  		return true
   299  	}
   300  
   301  	return v.visit(n.Left) || v.visit(n.Right) ||
   302  		v.visitList(n.List) || v.visitList(n.Rlist) ||
   303  		v.visitList(n.Ninit) || v.visitList(n.Nbody)
   304  }
   305  
   306  // Inlcopy and inlcopylist recursively copy the body of a function.
   307  // Any name-like node of non-local class is marked for re-export by adding it to
   308  // the exportlist.
   309  func inlcopylist(ll []*Node) []*Node {
   310  	s := make([]*Node, 0, len(ll))
   311  	for _, n := range ll {
   312  		s = append(s, inlcopy(n))
   313  	}
   314  	return s
   315  }
   316  
   317  func inlcopy(n *Node) *Node {
   318  	if n == nil {
   319  		return nil
   320  	}
   321  
   322  	switch n.Op {
   323  	case ONAME, OTYPE, OLITERAL:
   324  		return n
   325  	}
   326  
   327  	m := *n
   328  	if m.Func != nil {
   329  		m.Func.Inl.Set(nil)
   330  	}
   331  	m.Left = inlcopy(n.Left)
   332  	m.Right = inlcopy(n.Right)
   333  	m.List.Set(inlcopylist(n.List.Slice()))
   334  	m.Rlist.Set(inlcopylist(n.Rlist.Slice()))
   335  	m.Ninit.Set(inlcopylist(n.Ninit.Slice()))
   336  	m.Nbody.Set(inlcopylist(n.Nbody.Slice()))
   337  
   338  	return &m
   339  }
   340  
   341  // Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
   342  // calls made to inlineable functions. This is the external entry point.
   343  func inlcalls(fn *Node) {
   344  	savefn := Curfn
   345  	Curfn = fn
   346  	fn = inlnode(fn)
   347  	if fn != Curfn {
   348  		Fatalf("inlnode replaced curfn")
   349  	}
   350  	Curfn = savefn
   351  }
   352  
   353  // Turn an OINLCALL into a statement.
   354  func inlconv2stmt(n *Node) {
   355  	n.Op = OBLOCK
   356  
   357  	// n->ninit stays
   358  	n.List.Set(n.Nbody.Slice())
   359  
   360  	n.Nbody.Set(nil)
   361  	n.Rlist.Set(nil)
   362  }
   363  
   364  // Turn an OINLCALL into a single valued expression.
   365  // The result of inlconv2expr MUST be assigned back to n, e.g.
   366  // 	n.Left = inlconv2expr(n.Left)
   367  func inlconv2expr(n *Node) *Node {
   368  	r := n.Rlist.First()
   369  	return addinit(r, append(n.Ninit.Slice(), n.Nbody.Slice()...))
   370  }
   371  
   372  // Turn the rlist (with the return values) of the OINLCALL in
   373  // n into an expression list lumping the ninit and body
   374  // containing the inlined statements on the first list element so
   375  // order will be preserved Used in return, oas2func and call
   376  // statements.
   377  func inlconv2list(n *Node) []*Node {
   378  	if n.Op != OINLCALL || n.Rlist.Len() == 0 {
   379  		Fatalf("inlconv2list %+v\n", n)
   380  	}
   381  
   382  	s := n.Rlist.Slice()
   383  	s[0] = addinit(s[0], append(n.Ninit.Slice(), n.Nbody.Slice()...))
   384  	return s
   385  }
   386  
   387  func inlnodelist(l Nodes) {
   388  	s := l.Slice()
   389  	for i := range s {
   390  		s[i] = inlnode(s[i])
   391  	}
   392  }
   393  
   394  // inlnode recurses over the tree to find inlineable calls, which will
   395  // be turned into OINLCALLs by mkinlcall. When the recursion comes
   396  // back up will examine left, right, list, rlist, ninit, ntest, nincr,
   397  // nbody and nelse and use one of the 4 inlconv/glue functions above
   398  // to turn the OINLCALL into an expression, a statement, or patch it
   399  // in to this nodes list or rlist as appropriate.
   400  // NOTE it makes no sense to pass the glue functions down the
   401  // recursion to the level where the OINLCALL gets created because they
   402  // have to edit /this/ n, so you'd have to push that one down as well,
   403  // but then you may as well do it here.  so this is cleaner and
   404  // shorter and less complicated.
   405  // The result of inlnode MUST be assigned back to n, e.g.
   406  // 	n.Left = inlnode(n.Left)
   407  func inlnode(n *Node) *Node {
   408  	if n == nil {
   409  		return n
   410  	}
   411  
   412  	switch n.Op {
   413  	// inhibit inlining of their argument
   414  	case ODEFER, OPROC:
   415  		switch n.Left.Op {
   416  		case OCALLFUNC, OCALLMETH:
   417  			n.Left.SetNoInline(true)
   418  		}
   419  		return n
   420  
   421  	// TODO do them here (or earlier),
   422  	// so escape analysis can avoid more heapmoves.
   423  	case OCLOSURE:
   424  		return n
   425  	}
   426  
   427  	lno := setlineno(n)
   428  
   429  	inlnodelist(n.Ninit)
   430  	for _, n1 := range n.Ninit.Slice() {
   431  		if n1.Op == OINLCALL {
   432  			inlconv2stmt(n1)
   433  		}
   434  	}
   435  
   436  	n.Left = inlnode(n.Left)
   437  	if n.Left != nil && n.Left.Op == OINLCALL {
   438  		n.Left = inlconv2expr(n.Left)
   439  	}
   440  
   441  	n.Right = inlnode(n.Right)
   442  	if n.Right != nil && n.Right.Op == OINLCALL {
   443  		if n.Op == OFOR || n.Op == OFORUNTIL {
   444  			inlconv2stmt(n.Right)
   445  		} else {
   446  			n.Right = inlconv2expr(n.Right)
   447  		}
   448  	}
   449  
   450  	inlnodelist(n.List)
   451  	switch n.Op {
   452  	case OBLOCK:
   453  		for _, n2 := range n.List.Slice() {
   454  			if n2.Op == OINLCALL {
   455  				inlconv2stmt(n2)
   456  			}
   457  		}
   458  
   459  	case ORETURN, OCALLFUNC, OCALLMETH, OCALLINTER, OAPPEND, OCOMPLEX:
   460  		// if we just replaced arg in f(arg()) or return arg with an inlined call
   461  		// and arg returns multiple values, glue as list
   462  		if n.List.Len() == 1 && n.List.First().Op == OINLCALL && n.List.First().Rlist.Len() > 1 {
   463  			n.List.Set(inlconv2list(n.List.First()))
   464  			break
   465  		}
   466  		fallthrough
   467  
   468  	default:
   469  		s := n.List.Slice()
   470  		for i1, n1 := range s {
   471  			if n1 != nil && n1.Op == OINLCALL {
   472  				s[i1] = inlconv2expr(s[i1])
   473  			}
   474  		}
   475  	}
   476  
   477  	inlnodelist(n.Rlist)
   478  	if n.Op == OAS2FUNC && n.Rlist.First().Op == OINLCALL {
   479  		n.Rlist.Set(inlconv2list(n.Rlist.First()))
   480  		n.Op = OAS2
   481  		n.SetTypecheck(0)
   482  		n = typecheck(n, Etop)
   483  	} else {
   484  		s := n.Rlist.Slice()
   485  		for i1, n1 := range s {
   486  			if n1.Op == OINLCALL {
   487  				if n.Op == OIF {
   488  					inlconv2stmt(n1)
   489  				} else {
   490  					s[i1] = inlconv2expr(s[i1])
   491  				}
   492  			}
   493  		}
   494  	}
   495  
   496  	inlnodelist(n.Nbody)
   497  	for _, n := range n.Nbody.Slice() {
   498  		if n.Op == OINLCALL {
   499  			inlconv2stmt(n)
   500  		}
   501  	}
   502  
   503  	// with all the branches out of the way, it is now time to
   504  	// transmogrify this node itself unless inhibited by the
   505  	// switch at the top of this function.
   506  	switch n.Op {
   507  	case OCALLFUNC, OCALLMETH:
   508  		if n.NoInline() {
   509  			return n
   510  		}
   511  	}
   512  
   513  	switch n.Op {
   514  	case OCALLFUNC:
   515  		if Debug['m'] > 3 {
   516  			fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
   517  		}
   518  		if n.Left.Func != nil && n.Left.Func.Inl.Len() != 0 && !isIntrinsicCall(n) { // normal case
   519  			n = mkinlcall(n, n.Left, n.Isddd())
   520  		} else if n.isMethodCalledAsFunction() && asNode(n.Left.Sym.Def) != nil {
   521  			n = mkinlcall(n, asNode(n.Left.Sym.Def), n.Isddd())
   522  		}
   523  
   524  	case OCALLMETH:
   525  		if Debug['m'] > 3 {
   526  			fmt.Printf("%v:call to meth %L\n", n.Line(), n.Left.Right)
   527  		}
   528  
   529  		// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
   530  		if n.Left.Type == nil {
   531  			Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
   532  		}
   533  
   534  		if n.Left.Type.Nname() == nil {
   535  			Fatalf("no function definition for [%p] %+v\n", n.Left.Type, n.Left.Type)
   536  		}
   537  
   538  		n = mkinlcall(n, asNode(n.Left.Type.FuncType().Nname), n.Isddd())
   539  	}
   540  
   541  	lineno = lno
   542  	return n
   543  }
   544  
   545  // The result of mkinlcall MUST be assigned back to n, e.g.
   546  // 	n.Left = mkinlcall(n.Left, fn, isddd)
   547  func mkinlcall(n *Node, fn *Node, isddd bool) *Node {
   548  	save_safemode := safemode
   549  
   550  	// imported functions may refer to unsafe as long as the
   551  	// package was marked safe during import (already checked).
   552  	pkg := fnpkg(fn)
   553  
   554  	if pkg != localpkg && pkg != nil {
   555  		safemode = false
   556  	}
   557  	n = mkinlcall1(n, fn, isddd)
   558  	safemode = save_safemode
   559  	return n
   560  }
   561  
   562  func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node {
   563  	if asNode(t.Nname) != nil && !isblank(asNode(t.Nname)) {
   564  		inlvar := inlvars[asNode(t.Nname)]
   565  		if inlvar == nil {
   566  			Fatalf("missing inlvar for %v\n", asNode(t.Nname))
   567  		}
   568  		return inlvar
   569  	}
   570  
   571  	return typecheck(nblank, Erv|Easgn)
   572  }
   573  
   574  var inlgen int
   575  
   576  // If n is a call, and fn is a function with an inlinable body,
   577  // return an OINLCALL.
   578  // On return ninit has the parameter assignments, the nbody is the
   579  // inlined function body and list, rlist contain the input, output
   580  // parameters.
   581  // The result of mkinlcall1 MUST be assigned back to n, e.g.
   582  // 	n.Left = mkinlcall1(n.Left, fn, isddd)
   583  func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
   584  	if fn.Func.Inl.Len() == 0 {
   585  		// No inlinable body.
   586  		return n
   587  	}
   588  
   589  	if fn == Curfn || fn.Name.Defn == Curfn {
   590  		// Can't recursively inline a function into itself.
   591  		return n
   592  	}
   593  
   594  	if Debug['l'] < 2 {
   595  		typecheckinl(fn)
   596  	}
   597  
   598  	// We have a function node, and it has an inlineable body.
   599  	if Debug['m'] > 1 {
   600  		fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, fn.Func.Inl)
   601  	} else if Debug['m'] != 0 {
   602  		fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
   603  	}
   604  	if Debug['m'] > 2 {
   605  		fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n)
   606  	}
   607  
   608  	ninit := n.Ninit
   609  
   610  	// Find declarations corresponding to inlineable body.
   611  	var dcl []*Node
   612  	if fn.Name.Defn != nil {
   613  		dcl = fn.Func.Inldcl.Slice() // local function
   614  	} else {
   615  		dcl = fn.Func.Dcl // imported function
   616  	}
   617  
   618  	// Make temp names to use instead of the originals.
   619  	inlvars := make(map[*Node]*Node)
   620  	for _, ln := range dcl {
   621  		if ln.Op != ONAME {
   622  			continue
   623  		}
   624  		if ln.Class() == PPARAMOUT { // return values handled below.
   625  			continue
   626  		}
   627  		if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
   628  			continue
   629  		}
   630  		inlvars[ln] = typecheck(inlvar(ln), Erv)
   631  		if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM {
   632  			ninit.Append(nod(ODCL, inlvars[ln], nil))
   633  		}
   634  	}
   635  
   636  	// temporaries for return values.
   637  	var retvars []*Node
   638  	for i, t := range fn.Type.Results().Fields().Slice() {
   639  		var m *Node
   640  		if t != nil && asNode(t.Nname) != nil && !isblank(asNode(t.Nname)) {
   641  			m = inlvar(asNode(t.Nname))
   642  			m = typecheck(m, Erv)
   643  			inlvars[asNode(t.Nname)] = m
   644  		} else {
   645  			// anonymous return values, synthesize names for use in assignment that replaces return
   646  			m = retvar(t, i)
   647  		}
   648  
   649  		ninit.Append(nod(ODCL, m, nil))
   650  		retvars = append(retvars, m)
   651  	}
   652  
   653  	// Assign arguments to the parameters' temp names.
   654  	as := nod(OAS2, nil, nil)
   655  	as.Rlist.Set(n.List.Slice())
   656  
   657  	// For non-dotted calls to variadic functions, we assign the
   658  	// variadic parameter's temp name separately.
   659  	var vas *Node
   660  
   661  	if fn.IsMethod() {
   662  		rcv := fn.Type.Recv()
   663  
   664  		if n.Left.Op == ODOTMETH {
   665  			// For x.M(...), assign x directly to the
   666  			// receiver parameter.
   667  			if n.Left.Left == nil {
   668  				Fatalf("method call without receiver: %+v", n)
   669  			}
   670  			ras := nod(OAS, tinlvar(rcv, inlvars), n.Left.Left)
   671  			ras = typecheck(ras, Etop)
   672  			ninit.Append(ras)
   673  		} else {
   674  			// For T.M(...), add the receiver parameter to
   675  			// as.List, so it's assigned by the normal
   676  			// arguments.
   677  			if as.Rlist.Len() == 0 {
   678  				Fatalf("non-method call to method without first arg: %+v", n)
   679  			}
   680  			as.List.Append(tinlvar(rcv, inlvars))
   681  		}
   682  	}
   683  
   684  	for _, param := range fn.Type.Params().Fields().Slice() {
   685  		// For ordinary parameters or variadic parameters in
   686  		// dotted calls, just add the variable to the
   687  		// assignment list, and we're done.
   688  		if !param.Isddd() || isddd {
   689  			as.List.Append(tinlvar(param, inlvars))
   690  			continue
   691  		}
   692  
   693  		// Otherwise, we need to collect the remaining values
   694  		// to pass as a slice.
   695  
   696  		numvals := n.List.Len()
   697  		if numvals == 1 && n.List.First().Type.IsFuncArgStruct() {
   698  			numvals = n.List.First().Type.NumFields()
   699  		}
   700  
   701  		x := as.List.Len()
   702  		for as.List.Len() < numvals {
   703  			as.List.Append(argvar(param.Type, as.List.Len()))
   704  		}
   705  		varargs := as.List.Slice()[x:]
   706  
   707  		vas = nod(OAS, tinlvar(param, inlvars), nil)
   708  		if len(varargs) == 0 {
   709  			vas.Right = nodnil()
   710  			vas.Right.Type = param.Type
   711  		} else {
   712  			vas.Right = nod(OCOMPLIT, nil, typenod(param.Type))
   713  			vas.Right.List.Set(varargs)
   714  		}
   715  	}
   716  
   717  	if as.Rlist.Len() != 0 {
   718  		as = typecheck(as, Etop)
   719  		ninit.Append(as)
   720  	}
   721  
   722  	if vas != nil {
   723  		vas = typecheck(vas, Etop)
   724  		ninit.Append(vas)
   725  	}
   726  
   727  	// Zero the return parameters.
   728  	for _, n := range retvars {
   729  		as = nod(OAS, n, nil)
   730  		as = typecheck(as, Etop)
   731  		ninit.Append(as)
   732  	}
   733  
   734  	retlabel := autolabel(".i")
   735  	retlabel.Etype = 1 // flag 'safe' for escape analysis (no backjumps)
   736  
   737  	inlgen++
   738  
   739  	subst := inlsubst{
   740  		retlabel: retlabel,
   741  		retvars:  retvars,
   742  		inlvars:  inlvars,
   743  	}
   744  
   745  	body := subst.list(fn.Func.Inl)
   746  
   747  	lab := nod(OLABEL, retlabel, nil)
   748  	body = append(body, lab)
   749  
   750  	typecheckslice(body, Etop)
   751  
   752  	//dumplist("ninit post", ninit);
   753  
   754  	call := nod(OINLCALL, nil, nil)
   755  	call.Ninit.Set(ninit.Slice())
   756  	call.Nbody.Set(body)
   757  	call.Rlist.Set(retvars)
   758  	call.Type = n.Type
   759  	call.SetTypecheck(1)
   760  
   761  	// Hide the args from setPos -- the parameters to the inlined
   762  	// call already have good line numbers that should be preserved.
   763  	args := as.Rlist
   764  	as.Rlist.Set(nil)
   765  
   766  	// Rewrite the line information for the inlined AST.
   767  	parent := -1
   768  	callBase := Ctxt.PosTable.Pos(n.Pos).Base()
   769  	if callBase != nil {
   770  		parent = callBase.InliningIndex()
   771  	}
   772  	newIndex := Ctxt.InlTree.Add(parent, n.Pos, fn.Sym.Linksym())
   773  	setpos := &setPos{
   774  		bases:       make(map[*src.PosBase]*src.PosBase),
   775  		newInlIndex: newIndex,
   776  	}
   777  	setpos.node(call)
   778  
   779  	as.Rlist.Set(args.Slice())
   780  
   781  	//dumplist("call body", body);
   782  
   783  	n = call
   784  
   785  	// transitive inlining
   786  	// might be nice to do this before exporting the body,
   787  	// but can't emit the body with inlining expanded.
   788  	// instead we emit the things that the body needs
   789  	// and each use must redo the inlining.
   790  	// luckily these are small.
   791  	body = fn.Func.Inl.Slice()
   792  	fn.Func.Inl.Set(nil) // prevent infinite recursion (shouldn't happen anyway)
   793  	inlnodelist(call.Nbody)
   794  	for _, n := range call.Nbody.Slice() {
   795  		if n.Op == OINLCALL {
   796  			inlconv2stmt(n)
   797  		}
   798  	}
   799  	fn.Func.Inl.Set(body)
   800  
   801  	if Debug['m'] > 2 {
   802  		fmt.Printf("%v: After inlining %+v\n\n", n.Line(), n)
   803  	}
   804  
   805  	return n
   806  }
   807  
   808  // Every time we expand a function we generate a new set of tmpnames,
   809  // PAUTO's in the calling functions, and link them off of the
   810  // PPARAM's, PAUTOS and PPARAMOUTs of the called function.
   811  func inlvar(var_ *Node) *Node {
   812  	if Debug['m'] > 3 {
   813  		fmt.Printf("inlvar %+v\n", var_)
   814  	}
   815  
   816  	n := newname(var_.Sym)
   817  	n.Type = var_.Type
   818  	n.SetClass(PAUTO)
   819  	n.Name.SetUsed(true)
   820  	n.Name.Curfn = Curfn // the calling function, not the called one
   821  	n.SetAddrtaken(var_.Addrtaken())
   822  
   823  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
   824  	return n
   825  }
   826  
   827  // Synthesize a variable to store the inlined function's results in.
   828  func retvar(t *types.Field, i int) *Node {
   829  	n := newname(lookupN("~r", i))
   830  	n.Type = t.Type
   831  	n.SetClass(PAUTO)
   832  	n.Name.SetUsed(true)
   833  	n.Name.Curfn = Curfn // the calling function, not the called one
   834  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
   835  	return n
   836  }
   837  
   838  // Synthesize a variable to store the inlined function's arguments
   839  // when they come from a multiple return call.
   840  func argvar(t *types.Type, i int) *Node {
   841  	n := newname(lookupN("~arg", i))
   842  	n.Type = t.Elem()
   843  	n.SetClass(PAUTO)
   844  	n.Name.SetUsed(true)
   845  	n.Name.Curfn = Curfn // the calling function, not the called one
   846  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
   847  	return n
   848  }
   849  
   850  // The inlsubst type implements the actual inlining of a single
   851  // function call.
   852  type inlsubst struct {
   853  	// Target of the goto substituted in place of a return.
   854  	retlabel *Node
   855  
   856  	// Temporary result variables.
   857  	retvars []*Node
   858  
   859  	inlvars map[*Node]*Node
   860  }
   861  
   862  // list inlines a list of nodes.
   863  func (subst *inlsubst) list(ll Nodes) []*Node {
   864  	s := make([]*Node, 0, ll.Len())
   865  	for _, n := range ll.Slice() {
   866  		s = append(s, subst.node(n))
   867  	}
   868  	return s
   869  }
   870  
   871  // node recursively copies a node from the saved pristine body of the
   872  // inlined function, substituting references to input/output
   873  // parameters with ones to the tmpnames, and substituting returns with
   874  // assignments to the output.
   875  func (subst *inlsubst) node(n *Node) *Node {
   876  	if n == nil {
   877  		return nil
   878  	}
   879  
   880  	switch n.Op {
   881  	case ONAME:
   882  		if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
   883  			if Debug['m'] > 2 {
   884  				fmt.Printf("substituting name %+v  ->  %+v\n", n, inlvar)
   885  			}
   886  			return inlvar
   887  		}
   888  
   889  		if Debug['m'] > 2 {
   890  			fmt.Printf("not substituting name %+v\n", n)
   891  		}
   892  		return n
   893  
   894  	case OLITERAL, OTYPE:
   895  		// If n is a named constant or type, we can continue
   896  		// using it in the inline copy. Otherwise, make a copy
   897  		// so we can update the line number.
   898  		if n.Sym != nil {
   899  			return n
   900  		}
   901  
   902  		// Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
   903  
   904  	//		dump("Return before substitution", n);
   905  	case ORETURN:
   906  		m := nod(OGOTO, subst.retlabel, nil)
   907  
   908  		m.Ninit.Set(subst.list(n.Ninit))
   909  
   910  		if len(subst.retvars) != 0 && n.List.Len() != 0 {
   911  			as := nod(OAS2, nil, nil)
   912  
   913  			// Make a shallow copy of retvars.
   914  			// Otherwise OINLCALL.Rlist will be the same list,
   915  			// and later walk and typecheck may clobber it.
   916  			for _, n := range subst.retvars {
   917  				as.List.Append(n)
   918  			}
   919  			as.Rlist.Set(subst.list(n.List))
   920  			as = typecheck(as, Etop)
   921  			m.Ninit.Append(as)
   922  		}
   923  
   924  		typecheckslice(m.Ninit.Slice(), Etop)
   925  		m = typecheck(m, Etop)
   926  
   927  		//		dump("Return after substitution", m);
   928  		return m
   929  
   930  	case OGOTO, OLABEL:
   931  		m := nod(OXXX, nil, nil)
   932  		*m = *n
   933  		m.Ninit.Set(nil)
   934  		p := fmt.Sprintf("%s·%d", n.Left.Sym.Name, inlgen)
   935  		m.Left = newname(lookup(p))
   936  
   937  		return m
   938  	}
   939  
   940  	m := nod(OXXX, nil, nil)
   941  	*m = *n
   942  	m.Ninit.Set(nil)
   943  
   944  	if n.Op == OCLOSURE {
   945  		Fatalf("cannot inline function containing closure: %+v", n)
   946  	}
   947  
   948  	m.Left = subst.node(n.Left)
   949  	m.Right = subst.node(n.Right)
   950  	m.List.Set(subst.list(n.List))
   951  	m.Rlist.Set(subst.list(n.Rlist))
   952  	m.Ninit.Set(append(m.Ninit.Slice(), subst.list(n.Ninit)...))
   953  	m.Nbody.Set(subst.list(n.Nbody))
   954  
   955  	return m
   956  }
   957  
   958  // setPos is a visitor to update position info with a new inlining index.
   959  type setPos struct {
   960  	bases       map[*src.PosBase]*src.PosBase
   961  	newInlIndex int
   962  }
   963  
   964  func (s *setPos) nodelist(ll Nodes) {
   965  	for _, n := range ll.Slice() {
   966  		s.node(n)
   967  	}
   968  }
   969  
   970  func (s *setPos) node(n *Node) {
   971  	if n == nil {
   972  		return
   973  	}
   974  	if n.Op == OLITERAL || n.Op == OTYPE {
   975  		if n.Sym != nil {
   976  			// This node is not a copy, so don't clobber position.
   977  			return
   978  		}
   979  	}
   980  
   981  	// don't clobber names, unless they're freshly synthesized
   982  	if n.Op != ONAME || !n.Pos.IsKnown() {
   983  		n.Pos = s.updatedPos(n)
   984  	}
   985  
   986  	s.node(n.Left)
   987  	s.node(n.Right)
   988  	s.nodelist(n.List)
   989  	s.nodelist(n.Rlist)
   990  	s.nodelist(n.Ninit)
   991  	s.nodelist(n.Nbody)
   992  }
   993  
   994  func (s *setPos) updatedPos(n *Node) src.XPos {
   995  	pos := Ctxt.PosTable.Pos(n.Pos)
   996  	oldbase := pos.Base() // can be nil
   997  	newbase := s.bases[oldbase]
   998  	if newbase == nil {
   999  		newbase = src.NewInliningBase(oldbase, s.newInlIndex)
  1000  		pos.SetBase(newbase)
  1001  		s.bases[oldbase] = newbase
  1002  	}
  1003  	pos.SetBase(newbase)
  1004  	return Ctxt.PosTable.XPos(pos)
  1005  }
  1006  
  1007  func (n *Node) isMethodCalledAsFunction() bool {
  1008  	return n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME
  1009  }