github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/gc/closure.go (about)

     1  // Copyright 2009 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  package gc
     6  
     7  import (
     8  	"fmt"
     9  )
    10  
    11  // function literals aka closures
    12  func closurehdr(ntype *Node) {
    13  	var name *Node
    14  	var a *Node
    15  
    16  	n := Nod(OCLOSURE, nil, nil)
    17  	n.Func.Ntype = ntype
    18  	n.Func.Depth = Funcdepth
    19  	n.Func.Outerfunc = Curfn
    20  
    21  	funchdr(n)
    22  
    23  	// steal ntype's argument names and
    24  	// leave a fresh copy in their place.
    25  	// references to these variables need to
    26  	// refer to the variables in the external
    27  	// function declared below; see walkclosure.
    28  	n.List.Set(ntype.List.Slice())
    29  
    30  	n.Rlist.Set(ntype.Rlist.Slice())
    31  	ntype.List.Set(nil)
    32  	ntype.Rlist.Set(nil)
    33  	for _, n1 := range n.List.Slice() {
    34  		name = n1.Left
    35  		if name != nil {
    36  			name = newname(name.Sym)
    37  		}
    38  		a = Nod(ODCLFIELD, name, n1.Right)
    39  		a.Isddd = n1.Isddd
    40  		if name != nil {
    41  			name.Isddd = a.Isddd
    42  		}
    43  		ntype.List.Append(a)
    44  	}
    45  	for _, n2 := range n.Rlist.Slice() {
    46  		name = n2.Left
    47  		if name != nil {
    48  			name = newname(name.Sym)
    49  		}
    50  		ntype.Rlist.Append(Nod(ODCLFIELD, name, n2.Right))
    51  	}
    52  }
    53  
    54  func closurebody(body []*Node) *Node {
    55  	if len(body) == 0 {
    56  		body = []*Node{Nod(OEMPTY, nil, nil)}
    57  	}
    58  
    59  	func_ := Curfn
    60  	func_.Nbody.Set(body)
    61  	func_.Func.Endlineno = lineno
    62  	funcbody(func_)
    63  
    64  	// closure-specific variables are hanging off the
    65  	// ordinary ones in the symbol table; see oldname.
    66  	// unhook them.
    67  	// make the list of pointers for the closure call.
    68  	for _, v := range func_.Func.Cvars.Slice() {
    69  		// Unlink from v1; see comment in syntax.go type Param for these fields.
    70  		v1 := v.Name.Defn
    71  		v1.Name.Param.Innermost = v.Name.Param.Outer
    72  
    73  		// If the closure usage of v is not dense,
    74  		// we need to make it dense; now that we're out
    75  		// of the function in which v appeared,
    76  		// look up v.Sym in the enclosing function
    77  		// and keep it around for use in the compiled code.
    78  		//
    79  		// That is, suppose we just finished parsing the innermost
    80  		// closure f4 in this code:
    81  		//
    82  		//	func f() {
    83  		//		v := 1
    84  		//		func() { // f2
    85  		//			use(v)
    86  		//			func() { // f3
    87  		//				func() { // f4
    88  		//					use(v)
    89  		//				}()
    90  		//			}()
    91  		//		}()
    92  		//	}
    93  		//
    94  		// At this point v.Outer is f2's v; there is no f3's v.
    95  		// To construct the closure f4 from within f3,
    96  		// we need to use f3's v and in this case we need to create f3's v.
    97  		// We are now in the context of f3, so calling oldname(v.Sym)
    98  		// obtains f3's v, creating it if necessary (as it is in the example).
    99  		//
   100  		// capturevars will decide whether to use v directly or &v.
   101  		v.Name.Param.Outer = oldname(v.Sym)
   102  	}
   103  
   104  	return func_
   105  }
   106  
   107  func typecheckclosure(func_ *Node, top int) {
   108  	for _, ln := range func_.Func.Cvars.Slice() {
   109  		n := ln.Name.Defn
   110  		if !n.Name.Captured {
   111  			n.Name.Captured = true
   112  			if n.Name.Decldepth == 0 {
   113  				Fatalf("typecheckclosure: var %v does not have decldepth assigned", Nconv(n, FmtShort))
   114  			}
   115  
   116  			// Ignore assignments to the variable in straightline code
   117  			// preceding the first capturing by a closure.
   118  			if n.Name.Decldepth == decldepth {
   119  				n.Assigned = false
   120  			}
   121  		}
   122  	}
   123  
   124  	for _, ln := range func_.Func.Dcl {
   125  		if ln.Op == ONAME && (ln.Class == PPARAM || ln.Class == PPARAMOUT) {
   126  			ln.Name.Decldepth = 1
   127  		}
   128  	}
   129  
   130  	oldfn := Curfn
   131  	func_.Func.Ntype = typecheck(func_.Func.Ntype, Etype)
   132  	func_.Type = func_.Func.Ntype.Type
   133  	func_.Func.Top = top
   134  
   135  	// Type check the body now, but only if we're inside a function.
   136  	// At top level (in a variable initialization: curfn==nil) we're not
   137  	// ready to type check code yet; we'll check it later, because the
   138  	// underlying closure function we create is added to xtop.
   139  	if Curfn != nil && func_.Type != nil {
   140  		Curfn = func_
   141  		olddd := decldepth
   142  		decldepth = 1
   143  		typecheckslice(func_.Nbody.Slice(), Etop)
   144  		decldepth = olddd
   145  		Curfn = oldfn
   146  	}
   147  
   148  	// Create top-level function
   149  	xtop = append(xtop, makeclosure(func_))
   150  }
   151  
   152  // closurename returns name for OCLOSURE n.
   153  // It is not as simple as it ought to be, because we typecheck nested closures
   154  // starting from the innermost one. So when we check the inner closure,
   155  // we don't yet have name for the outer closure. This function uses recursion
   156  // to generate names all the way up if necessary.
   157  
   158  var closurename_closgen int
   159  
   160  func closurename(n *Node) *Sym {
   161  	if n.Sym != nil {
   162  		return n.Sym
   163  	}
   164  	gen := 0
   165  	outer := ""
   166  	prefix := ""
   167  	if n.Func.Outerfunc == nil {
   168  		// Global closure.
   169  		outer = "glob."
   170  
   171  		prefix = "func"
   172  		closurename_closgen++
   173  		gen = closurename_closgen
   174  	} else if n.Func.Outerfunc.Op == ODCLFUNC {
   175  		// The outermost closure inside of a named function.
   176  		outer = n.Func.Outerfunc.Func.Nname.Sym.Name
   177  
   178  		prefix = "func"
   179  
   180  		// Yes, functions can be named _.
   181  		// Can't use function closgen in such case,
   182  		// because it would lead to name clashes.
   183  		if !isblank(n.Func.Outerfunc.Func.Nname) {
   184  			n.Func.Outerfunc.Func.Closgen++
   185  			gen = n.Func.Outerfunc.Func.Closgen
   186  		} else {
   187  			closurename_closgen++
   188  			gen = closurename_closgen
   189  		}
   190  	} else if n.Func.Outerfunc.Op == OCLOSURE {
   191  		// Nested closure, recurse.
   192  		outer = closurename(n.Func.Outerfunc).Name
   193  
   194  		prefix = ""
   195  		n.Func.Outerfunc.Func.Closgen++
   196  		gen = n.Func.Outerfunc.Func.Closgen
   197  	} else {
   198  		Fatalf("closurename called for %v", Nconv(n, FmtShort))
   199  	}
   200  	n.Sym = Lookupf("%s.%s%d", outer, prefix, gen)
   201  	return n.Sym
   202  }
   203  
   204  func makeclosure(func_ *Node) *Node {
   205  	// wrap body in external function
   206  	// that begins by reading closure parameters.
   207  	xtype := Nod(OTFUNC, nil, nil)
   208  
   209  	xtype.List.Set(func_.List.Slice())
   210  	xtype.Rlist.Set(func_.Rlist.Slice())
   211  
   212  	// create the function
   213  	xfunc := Nod(ODCLFUNC, nil, nil)
   214  
   215  	xfunc.Func.Nname = newfuncname(closurename(func_))
   216  	xfunc.Func.Nname.Sym.Flags |= SymExported // disable export
   217  	xfunc.Func.Nname.Name.Param.Ntype = xtype
   218  	xfunc.Func.Nname.Name.Defn = xfunc
   219  	declare(xfunc.Func.Nname, PFUNC)
   220  	xfunc.Func.Nname.Name.Funcdepth = func_.Func.Depth
   221  	xfunc.Func.Depth = func_.Func.Depth
   222  	xfunc.Func.Endlineno = func_.Func.Endlineno
   223  	makefuncsym(xfunc.Func.Nname.Sym)
   224  
   225  	xfunc.Nbody.Set(func_.Nbody.Slice())
   226  	xfunc.Func.Dcl = append(func_.Func.Dcl, xfunc.Func.Dcl...)
   227  	func_.Func.Dcl = nil
   228  	if xfunc.Nbody.Len() == 0 {
   229  		Fatalf("empty body - won't generate any code")
   230  	}
   231  	xfunc = typecheck(xfunc, Etop)
   232  
   233  	xfunc.Func.Closure = func_
   234  	func_.Func.Closure = xfunc
   235  
   236  	func_.Nbody.Set(nil)
   237  	func_.List.Set(nil)
   238  	func_.Rlist.Set(nil)
   239  
   240  	return xfunc
   241  }
   242  
   243  // capturevars is called in a separate phase after all typechecking is done.
   244  // It decides whether each variable captured by a closure should be captured
   245  // by value or by reference.
   246  // We use value capturing for values <= 128 bytes that are never reassigned
   247  // after capturing (effectively constant).
   248  func capturevars(xfunc *Node) {
   249  	lno := lineno
   250  	lineno = xfunc.Lineno
   251  
   252  	func_ := xfunc.Func.Closure
   253  	func_.Func.Enter.Set(nil)
   254  	for _, v := range func_.Func.Cvars.Slice() {
   255  		if v.Type == nil {
   256  			// if v->type is nil, it means v looked like it was
   257  			// going to be used in the closure but wasn't.
   258  			// this happens because when parsing a, b, c := f()
   259  			// the a, b, c gets parsed as references to older
   260  			// a, b, c before the parser figures out this is a
   261  			// declaration.
   262  			v.Op = OXXX
   263  
   264  			continue
   265  		}
   266  
   267  		// type check the & of closed variables outside the closure,
   268  		// so that the outer frame also grabs them and knows they escape.
   269  		dowidth(v.Type)
   270  
   271  		outer := v.Name.Param.Outer
   272  		outermost := v.Name.Defn
   273  
   274  		// out parameters will be assigned to implicitly upon return.
   275  		if outer.Class != PPARAMOUT && !outermost.Addrtaken && !outermost.Assigned && v.Type.Width <= 128 {
   276  			v.Name.Byval = true
   277  		} else {
   278  			outermost.Addrtaken = true
   279  			outer = Nod(OADDR, outer, nil)
   280  		}
   281  
   282  		if Debug['m'] > 1 {
   283  			var name *Sym
   284  			if v.Name.Curfn != nil && v.Name.Curfn.Func.Nname != nil {
   285  				name = v.Name.Curfn.Func.Nname.Sym
   286  			}
   287  			how := "ref"
   288  			if v.Name.Byval {
   289  				how = "value"
   290  			}
   291  			Warnl(v.Lineno, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, outermost.Addrtaken, outermost.Assigned, int32(v.Type.Width))
   292  		}
   293  
   294  		outer = typecheck(outer, Erv)
   295  		func_.Func.Enter.Append(outer)
   296  	}
   297  
   298  	lineno = lno
   299  }
   300  
   301  // transformclosure is called in a separate phase after escape analysis.
   302  // It transform closure bodies to properly reference captured variables.
   303  func transformclosure(xfunc *Node) {
   304  	lno := lineno
   305  	lineno = xfunc.Lineno
   306  	func_ := xfunc.Func.Closure
   307  
   308  	if func_.Func.Top&Ecall != 0 {
   309  		// If the closure is directly called, we transform it to a plain function call
   310  		// with variables passed as args. This avoids allocation of a closure object.
   311  		// Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
   312  		// will complete the transformation later.
   313  		// For illustration, the following closure:
   314  		//	func(a int) {
   315  		//		println(byval)
   316  		//		byref++
   317  		//	}(42)
   318  		// becomes:
   319  		//	func(a int, byval int, &byref *int) {
   320  		//		println(byval)
   321  		//		(*&byref)++
   322  		//	}(byval, &byref, 42)
   323  
   324  		// f is ONAME of the actual function.
   325  		f := xfunc.Func.Nname
   326  
   327  		// We are going to insert captured variables before input args.
   328  		var params []*Field
   329  		var decls []*Node
   330  		for _, v := range func_.Func.Cvars.Slice() {
   331  			if v.Op == OXXX {
   332  				continue
   333  			}
   334  			fld := newField()
   335  			fld.Funarg = FunargParams
   336  			if v.Name.Byval {
   337  				// If v is captured by value, we merely downgrade it to PPARAM.
   338  				v.Class = PPARAM
   339  
   340  				v.Ullman = 1
   341  				fld.Nname = v
   342  			} else {
   343  				// If v of type T is captured by reference,
   344  				// we introduce function param &v *T
   345  				// and v remains PAUTOHEAP with &v heapaddr
   346  				// (accesses will implicitly deref &v).
   347  				addr := newname(Lookupf("&%s", v.Sym.Name))
   348  				addr.Type = Ptrto(v.Type)
   349  				addr.Class = PPARAM
   350  				v.Name.Heapaddr = addr
   351  				fld.Nname = addr
   352  			}
   353  
   354  			fld.Type = fld.Nname.Type
   355  			fld.Sym = fld.Nname.Sym
   356  
   357  			params = append(params, fld)
   358  			decls = append(decls, fld.Nname)
   359  		}
   360  
   361  		if len(params) > 0 {
   362  			// Prepend params and decls.
   363  			f.Type.Params().SetFields(append(params, f.Type.Params().FieldSlice()...))
   364  			xfunc.Func.Dcl = append(decls, xfunc.Func.Dcl...)
   365  		}
   366  
   367  		// Recalculate param offsets.
   368  		if f.Type.Width > 0 {
   369  			Fatalf("transformclosure: width is already calculated")
   370  		}
   371  		dowidth(f.Type)
   372  		xfunc.Type = f.Type // update type of ODCLFUNC
   373  	} else {
   374  		// The closure is not called, so it is going to stay as closure.
   375  		var body []*Node
   376  		offset := int64(Widthptr)
   377  		var addr *Node
   378  		var cv *Node
   379  		for _, v := range func_.Func.Cvars.Slice() {
   380  			if v.Op == OXXX {
   381  				continue
   382  			}
   383  
   384  			// cv refers to the field inside of closure OSTRUCTLIT.
   385  			cv = Nod(OCLOSUREVAR, nil, nil)
   386  
   387  			cv.Type = v.Type
   388  			if !v.Name.Byval {
   389  				cv.Type = Ptrto(v.Type)
   390  			}
   391  			offset = Rnd(offset, int64(cv.Type.Align))
   392  			cv.Xoffset = offset
   393  			offset += cv.Type.Width
   394  
   395  			if v.Name.Byval && v.Type.Width <= int64(2*Widthptr) {
   396  				// If it is a small variable captured by value, downgrade it to PAUTO.
   397  				v.Class = PAUTO
   398  				v.Ullman = 1
   399  				xfunc.Func.Dcl = append(xfunc.Func.Dcl, v)
   400  				body = append(body, Nod(OAS, v, cv))
   401  			} else {
   402  				// Declare variable holding addresses taken from closure
   403  				// and initialize in entry prologue.
   404  				addr = newname(Lookupf("&%s", v.Sym.Name))
   405  				addr.Name.Param.Ntype = Nod(OIND, typenod(v.Type), nil)
   406  				addr.Class = PAUTO
   407  				addr.Used = true
   408  				addr.Name.Curfn = xfunc
   409  				xfunc.Func.Dcl = append(xfunc.Func.Dcl, addr)
   410  				v.Name.Heapaddr = addr
   411  				if v.Name.Byval {
   412  					cv = Nod(OADDR, cv, nil)
   413  				}
   414  				body = append(body, Nod(OAS, addr, cv))
   415  			}
   416  		}
   417  
   418  		if len(body) > 0 {
   419  			typecheckslice(body, Etop)
   420  			walkstmtlist(body)
   421  			xfunc.Func.Enter.Set(body)
   422  			xfunc.Func.Needctxt = true
   423  		}
   424  	}
   425  
   426  	lineno = lno
   427  }
   428  
   429  // hasemptycvars returns true iff closure func_ has an
   430  // empty list of captured vars. OXXX nodes don't count.
   431  func hasemptycvars(func_ *Node) bool {
   432  	for _, v := range func_.Func.Cvars.Slice() {
   433  		if v.Op == OXXX {
   434  			continue
   435  		}
   436  		return false
   437  	}
   438  	return true
   439  }
   440  
   441  // closuredebugruntimecheck applies boilerplate checks for debug flags
   442  // and compiling runtime
   443  func closuredebugruntimecheck(r *Node) {
   444  	if Debug_closure > 0 {
   445  		if r.Esc == EscHeap {
   446  			Warnl(r.Lineno, "heap closure, captured vars = %v", r.Func.Cvars)
   447  		} else {
   448  			Warnl(r.Lineno, "stack closure, captured vars = %v", r.Func.Cvars)
   449  		}
   450  	}
   451  	if compiling_runtime && r.Esc == EscHeap {
   452  		yyerrorl(r.Lineno, "heap-allocated closure, not allowed in runtime.")
   453  	}
   454  }
   455  
   456  func walkclosure(func_ *Node, init *Nodes) *Node {
   457  	// If no closure vars, don't bother wrapping.
   458  	if hasemptycvars(func_) {
   459  		if Debug_closure > 0 {
   460  			Warnl(func_.Lineno, "closure converted to global")
   461  		}
   462  		return func_.Func.Closure.Func.Nname
   463  	} else {
   464  		closuredebugruntimecheck(func_)
   465  	}
   466  
   467  	// Create closure in the form of a composite literal.
   468  	// supposing the closure captures an int i and a string s
   469  	// and has one float64 argument and no results,
   470  	// the generated code looks like:
   471  	//
   472  	//	clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s}
   473  	//
   474  	// The use of the struct provides type information to the garbage
   475  	// collector so that it can walk the closure. We could use (in this case)
   476  	// [3]unsafe.Pointer instead, but that would leave the gc in the dark.
   477  	// The information appears in the binary in the form of type descriptors;
   478  	// the struct is unnamed so that closures in multiple packages with the
   479  	// same struct type can share the descriptor.
   480  
   481  	typ := Nod(OTSTRUCT, nil, nil)
   482  
   483  	typ.List.Set1(Nod(ODCLFIELD, newname(Lookup(".F")), typenod(Types[TUINTPTR])))
   484  	var typ1 *Node
   485  	for _, v := range func_.Func.Cvars.Slice() {
   486  		if v.Op == OXXX {
   487  			continue
   488  		}
   489  		typ1 = typenod(v.Type)
   490  		if !v.Name.Byval {
   491  			typ1 = Nod(OIND, typ1, nil)
   492  		}
   493  		typ.List.Append(Nod(ODCLFIELD, newname(v.Sym), typ1))
   494  	}
   495  
   496  	clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
   497  	clos.Esc = func_.Esc
   498  	clos.Right.Implicit = true
   499  	clos.List.Set(append([]*Node{Nod(OCFUNC, func_.Func.Closure.Func.Nname, nil)}, func_.Func.Enter.Slice()...))
   500  
   501  	// Force type conversion from *struct to the func type.
   502  	clos = Nod(OCONVNOP, clos, nil)
   503  
   504  	clos.Type = func_.Type
   505  
   506  	clos = typecheck(clos, Erv)
   507  
   508  	// typecheck will insert a PTRLIT node under CONVNOP,
   509  	// tag it with escape analysis result.
   510  	clos.Left.Esc = func_.Esc
   511  
   512  	// non-escaping temp to use, if any.
   513  	// orderexpr did not compute the type; fill it in now.
   514  	if x := prealloc[func_]; x != nil {
   515  		x.Type = clos.Left.Left.Type
   516  		x.Orig.Type = x.Type
   517  		clos.Left.Right = x
   518  		delete(prealloc, func_)
   519  	}
   520  
   521  	return walkexpr(clos, init)
   522  }
   523  
   524  func typecheckpartialcall(fn *Node, sym *Sym) {
   525  	switch fn.Op {
   526  	case ODOTINTER, ODOTMETH:
   527  		break
   528  
   529  	default:
   530  		Fatalf("invalid typecheckpartialcall")
   531  	}
   532  
   533  	// Create top-level function.
   534  	xfunc := makepartialcall(fn, fn.Type, sym)
   535  	fn.Func = xfunc.Func
   536  	fn.Right = newname(sym)
   537  	fn.Op = OCALLPART
   538  	fn.Type = xfunc.Type
   539  }
   540  
   541  var makepartialcall_gopkg *Pkg
   542  
   543  func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
   544  	var p string
   545  
   546  	rcvrtype := fn.Left.Type
   547  	if exportname(meth.Name) {
   548  		p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, FmtLeft|FmtShort), meth.Name)
   549  	} else {
   550  		p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, FmtLeft|FmtShort), sconv(meth, FmtLeft))
   551  	}
   552  	basetype := rcvrtype
   553  	if rcvrtype.IsPtr() {
   554  		basetype = basetype.Elem()
   555  	}
   556  	if !basetype.IsInterface() && basetype.Sym == nil {
   557  		Fatalf("missing base type for %v", rcvrtype)
   558  	}
   559  
   560  	var spkg *Pkg
   561  	if basetype.Sym != nil {
   562  		spkg = basetype.Sym.Pkg
   563  	}
   564  	if spkg == nil {
   565  		if makepartialcall_gopkg == nil {
   566  			makepartialcall_gopkg = mkpkg("go")
   567  		}
   568  		spkg = makepartialcall_gopkg
   569  	}
   570  
   571  	sym := Pkglookup(p, spkg)
   572  
   573  	if sym.Flags&SymUniq != 0 {
   574  		return sym.Def
   575  	}
   576  	sym.Flags |= SymUniq
   577  
   578  	savecurfn := Curfn
   579  	Curfn = nil
   580  
   581  	xtype := Nod(OTFUNC, nil, nil)
   582  	i := 0
   583  	var l []*Node
   584  	var callargs []*Node
   585  	ddd := false
   586  	xfunc := Nod(ODCLFUNC, nil, nil)
   587  	Curfn = xfunc
   588  	var fld *Node
   589  	var n *Node
   590  	for _, t := range t0.Params().Fields().Slice() {
   591  		n = newname(LookupN("a", i))
   592  		i++
   593  		n.Class = PPARAM
   594  		xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
   595  		callargs = append(callargs, n)
   596  		fld = Nod(ODCLFIELD, n, typenod(t.Type))
   597  		if t.Isddd {
   598  			fld.Isddd = true
   599  			ddd = true
   600  		}
   601  
   602  		l = append(l, fld)
   603  	}
   604  
   605  	xtype.List.Set(l)
   606  	i = 0
   607  	l = nil
   608  	var retargs []*Node
   609  	for _, t := range t0.Results().Fields().Slice() {
   610  		n = newname(LookupN("r", i))
   611  		i++
   612  		n.Class = PPARAMOUT
   613  		xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
   614  		retargs = append(retargs, n)
   615  		l = append(l, Nod(ODCLFIELD, n, typenod(t.Type)))
   616  	}
   617  
   618  	xtype.Rlist.Set(l)
   619  
   620  	xfunc.Func.Dupok = true
   621  	xfunc.Func.Nname = newfuncname(sym)
   622  	xfunc.Func.Nname.Sym.Flags |= SymExported // disable export
   623  	xfunc.Func.Nname.Name.Param.Ntype = xtype
   624  	xfunc.Func.Nname.Name.Defn = xfunc
   625  	declare(xfunc.Func.Nname, PFUNC)
   626  
   627  	// Declare and initialize variable holding receiver.
   628  
   629  	xfunc.Func.Needctxt = true
   630  	cv := Nod(OCLOSUREVAR, nil, nil)
   631  	cv.Xoffset = int64(Widthptr)
   632  	cv.Type = rcvrtype
   633  	if int(cv.Type.Align) > Widthptr {
   634  		cv.Xoffset = int64(cv.Type.Align)
   635  	}
   636  	ptr := Nod(ONAME, nil, nil)
   637  	ptr.Sym = Lookup("rcvr")
   638  	ptr.Class = PAUTO
   639  	ptr.Addable = true
   640  	ptr.Ullman = 1
   641  	ptr.Used = true
   642  	ptr.Name.Curfn = xfunc
   643  	ptr.Xoffset = 0
   644  	xfunc.Func.Dcl = append(xfunc.Func.Dcl, ptr)
   645  	var body []*Node
   646  	if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
   647  		ptr.Name.Param.Ntype = typenod(rcvrtype)
   648  		body = append(body, Nod(OAS, ptr, cv))
   649  	} else {
   650  		ptr.Name.Param.Ntype = typenod(Ptrto(rcvrtype))
   651  		body = append(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
   652  	}
   653  
   654  	call := Nod(OCALL, NodSym(OXDOT, ptr, meth), nil)
   655  	call.List.Set(callargs)
   656  	call.Isddd = ddd
   657  	if t0.Results().NumFields() == 0 {
   658  		body = append(body, call)
   659  	} else {
   660  		n := Nod(OAS2, nil, nil)
   661  		n.List.Set(retargs)
   662  		n.Rlist.Set1(call)
   663  		body = append(body, n)
   664  		n = Nod(ORETURN, nil, nil)
   665  		body = append(body, n)
   666  	}
   667  
   668  	xfunc.Nbody.Set(body)
   669  
   670  	xfunc = typecheck(xfunc, Etop)
   671  	sym.Def = xfunc
   672  	xtop = append(xtop, xfunc)
   673  	Curfn = savecurfn
   674  
   675  	return xfunc
   676  }
   677  
   678  func walkpartialcall(n *Node, init *Nodes) *Node {
   679  	// Create closure in the form of a composite literal.
   680  	// For x.M with receiver (x) type T, the generated code looks like:
   681  	//
   682  	//	clos = &struct{F uintptr; R T}{M.T·f, x}
   683  	//
   684  	// Like walkclosure above.
   685  
   686  	if n.Left.Type.IsInterface() {
   687  		// Trigger panic for method on nil interface now.
   688  		// Otherwise it happens in the wrapper and is confusing.
   689  		n.Left = cheapexpr(n.Left, init)
   690  
   691  		checknil(n.Left, init)
   692  	}
   693  
   694  	typ := Nod(OTSTRUCT, nil, nil)
   695  	typ.List.Set1(Nod(ODCLFIELD, newname(Lookup("F")), typenod(Types[TUINTPTR])))
   696  	typ.List.Append(Nod(ODCLFIELD, newname(Lookup("R")), typenod(n.Left.Type)))
   697  
   698  	clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
   699  	clos.Esc = n.Esc
   700  	clos.Right.Implicit = true
   701  	clos.List.Set1(Nod(OCFUNC, n.Func.Nname, nil))
   702  	clos.List.Append(n.Left)
   703  
   704  	// Force type conversion from *struct to the func type.
   705  	clos = Nod(OCONVNOP, clos, nil)
   706  
   707  	clos.Type = n.Type
   708  
   709  	clos = typecheck(clos, Erv)
   710  
   711  	// typecheck will insert a PTRLIT node under CONVNOP,
   712  	// tag it with escape analysis result.
   713  	clos.Left.Esc = n.Esc
   714  
   715  	// non-escaping temp to use, if any.
   716  	// orderexpr did not compute the type; fill it in now.
   717  	if x := prealloc[n]; x != nil {
   718  		x.Type = clos.Left.Left.Type
   719  		x.Orig.Type = x.Type
   720  		clos.Left.Right = x
   721  		delete(prealloc, n)
   722  	}
   723  
   724  	return walkexpr(clos, init)
   725  }