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