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