blob: 62e060e7d4962561217e57e10a31eb369700d694 [file] [log] [blame]
Russ Cox8c195bd2015-02-13 14:40:36 -05001// 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
5package gc
6
7import (
8 "cmd/internal/obj"
9 "fmt"
10)
11
12/*
13 * function literals aka closures
14 */
15func closurehdr(ntype *Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -050016 var name *Node
17 var a *Node
Russ Cox8c195bd2015-02-13 14:40:36 -050018
Russ Cox382b44e2015-02-23 16:07:24 -050019 n := Nod(OCLOSURE, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -050020 n.Ntype = ntype
21 n.Funcdepth = Funcdepth
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070022 n.Func.Outerfunc = Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -050023
24 funchdr(n)
25
26 // steal ntype's argument names and
27 // leave a fresh copy in their place.
28 // references to these variables need to
29 // refer to the variables in the external
30 // function declared below; see walkclosure.
31 n.List = ntype.List
32
33 n.Rlist = ntype.Rlist
34 ntype.List = nil
35 ntype.Rlist = nil
Russ Cox382b44e2015-02-23 16:07:24 -050036 for l := n.List; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050037 name = l.N.Left
38 if name != nil {
39 name = newname(name.Sym)
40 }
41 a = Nod(ODCLFIELD, name, l.N.Right)
42 a.Isddd = l.N.Isddd
43 if name != nil {
44 name.Isddd = a.Isddd
45 }
46 ntype.List = list(ntype.List, a)
47 }
48
Russ Cox382b44e2015-02-23 16:07:24 -050049 for l := n.Rlist; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050050 name = l.N.Left
51 if name != nil {
52 name = newname(name.Sym)
53 }
54 ntype.Rlist = list(ntype.Rlist, Nod(ODCLFIELD, name, l.N.Right))
55 }
56}
57
58func closurebody(body *NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -050059 if body == nil {
60 body = list1(Nod(OEMPTY, nil, nil))
61 }
62
Russ Cox382b44e2015-02-23 16:07:24 -050063 func_ := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -050064 func_.Nbody = body
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070065 func_.Func.Endlineno = lineno
Russ Cox8c195bd2015-02-13 14:40:36 -050066 funcbody(func_)
67
68 // closure-specific variables are hanging off the
69 // ordinary ones in the symbol table; see oldname.
70 // unhook them.
71 // make the list of pointers for the closure call.
Russ Cox382b44e2015-02-23 16:07:24 -050072 var v *Node
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070073 for l := func_.Func.Cvars; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050074 v = l.N
75 v.Closure.Closure = v.Outer
76 v.Outerexpr = oldname(v.Sym)
77 }
78
79 return func_
80}
81
82func typecheckclosure(func_ *Node, top int) {
Russ Cox8c195bd2015-02-13 14:40:36 -050083 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -050084
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070085 for l := func_.Func.Cvars; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -050086 n = l.N.Closure
Dave Cheneyb006d382015-03-06 18:42:58 +110087 if !n.Captured {
88 n.Captured = true
Russ Cox8c195bd2015-02-13 14:40:36 -050089 if n.Decldepth == 0 {
90 Fatal("typecheckclosure: var %v does not have decldepth assigned", Nconv(n, obj.FmtShort))
91 }
92
93 // Ignore assignments to the variable in straightline code
94 // preceding the first capturing by a closure.
95 if n.Decldepth == decldepth {
Dave Cheneyb006d382015-03-06 18:42:58 +110096 n.Assigned = false
Russ Cox8c195bd2015-02-13 14:40:36 -050097 }
98 }
99 }
100
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700101 for l := func_.Func.Dcl; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500102 if l.N.Op == ONAME && (l.N.Class == PPARAM || l.N.Class == PPARAMOUT) {
103 l.N.Decldepth = 1
104 }
105 }
106
Russ Cox382b44e2015-02-23 16:07:24 -0500107 oldfn := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -0500108 typecheck(&func_.Ntype, Etype)
109 func_.Type = func_.Ntype.Type
110 func_.Top = top
111
112 // Type check the body now, but only if we're inside a function.
113 // At top level (in a variable initialization: curfn==nil) we're not
114 // ready to type check code yet; we'll check it later, because the
115 // underlying closure function we create is added to xtop.
116 if Curfn != nil && func_.Type != nil {
117 Curfn = func_
Russ Cox382b44e2015-02-23 16:07:24 -0500118 olddd := decldepth
Russ Cox8c195bd2015-02-13 14:40:36 -0500119 decldepth = 1
120 typechecklist(func_.Nbody, Etop)
121 decldepth = olddd
122 Curfn = oldfn
123 }
124
125 // Create top-level function
126 xtop = list(xtop, makeclosure(func_))
127}
128
Russ Coxf6791da2015-02-20 13:54:45 -0500129// closurename returns name for OCLOSURE n.
130// It is not as simple as it ought to be, because we typecheck nested closures
131// starting from the innermost one. So when we check the inner closure,
132// we don't yet have name for the outer closure. This function uses recursion
133// to generate names all the way up if necessary.
134
135var closurename_closgen int
136
137func closurename(n *Node) *Sym {
Russ Coxf6791da2015-02-20 13:54:45 -0500138 if n.Sym != nil {
139 return n.Sym
140 }
Russ Cox382b44e2015-02-23 16:07:24 -0500141 gen := 0
142 outer := ""
143 prefix := ""
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700144 if n.Func.Outerfunc == nil {
Russ Coxf6791da2015-02-20 13:54:45 -0500145 // Global closure.
146 outer = "glob"
147
148 prefix = "func"
149 closurename_closgen++
150 gen = closurename_closgen
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700151 } else if n.Func.Outerfunc.Op == ODCLFUNC {
Russ Coxf6791da2015-02-20 13:54:45 -0500152 // The outermost closure inside of a named function.
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700153 outer = n.Func.Outerfunc.Nname.Sym.Name
Russ Coxf6791da2015-02-20 13:54:45 -0500154
155 prefix = "func"
156
157 // Yes, functions can be named _.
158 // Can't use function closgen in such case,
159 // because it would lead to name clashes.
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700160 if !isblank(n.Func.Outerfunc.Nname) {
161 n.Func.Outerfunc.Func.Closgen++
162 gen = n.Func.Outerfunc.Func.Closgen
Russ Coxf6791da2015-02-20 13:54:45 -0500163 } else {
164 closurename_closgen++
165 gen = closurename_closgen
166 }
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700167 } else if n.Func.Outerfunc.Op == OCLOSURE {
Russ Coxf6791da2015-02-20 13:54:45 -0500168 // Nested closure, recurse.
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700169 outer = closurename(n.Func.Outerfunc).Name
Russ Coxf6791da2015-02-20 13:54:45 -0500170
171 prefix = ""
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700172 n.Func.Outerfunc.Func.Closgen++
173 gen = n.Func.Outerfunc.Func.Closgen
Russ Coxf6791da2015-02-20 13:54:45 -0500174 } else {
175 Fatal("closurename called for %v", Nconv(n, obj.FmtShort))
176 }
Matthew Dempsky8b3670f2015-03-06 12:02:24 -0800177 n.Sym = Lookupf("%s.%s%d", outer, prefix, gen)
Russ Coxf6791da2015-02-20 13:54:45 -0500178 return n.Sym
179}
Russ Cox8c195bd2015-02-13 14:40:36 -0500180
181func makeclosure(func_ *Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -0500182 /*
183 * wrap body in external function
184 * that begins by reading closure parameters.
185 */
Russ Cox382b44e2015-02-23 16:07:24 -0500186 xtype := Nod(OTFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500187
188 xtype.List = func_.List
189 xtype.Rlist = func_.Rlist
190
191 // create the function
Russ Cox382b44e2015-02-23 16:07:24 -0500192 xfunc := Nod(ODCLFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500193
Josh Bleecher Snyder57279ba2015-03-10 21:37:13 -0700194 xfunc.Nname = newfuncname(closurename(func_))
Russ Cox8c195bd2015-02-13 14:40:36 -0500195 xfunc.Nname.Sym.Flags |= SymExported // disable export
196 xfunc.Nname.Ntype = xtype
197 xfunc.Nname.Defn = xfunc
198 declare(xfunc.Nname, PFUNC)
199 xfunc.Nname.Funcdepth = func_.Funcdepth
200 xfunc.Funcdepth = func_.Funcdepth
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700201 xfunc.Func.Endlineno = func_.Func.Endlineno
Russ Cox8c195bd2015-02-13 14:40:36 -0500202
203 xfunc.Nbody = func_.Nbody
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700204 xfunc.Func.Dcl = concat(func_.Func.Dcl, xfunc.Func.Dcl)
Russ Cox8c195bd2015-02-13 14:40:36 -0500205 if xfunc.Nbody == nil {
206 Fatal("empty body - won't generate any code")
207 }
208 typecheck(&xfunc, Etop)
209
210 xfunc.Closure = func_
211 func_.Closure = xfunc
212
213 func_.Nbody = nil
214 func_.List = nil
215 func_.Rlist = nil
216
217 return xfunc
218}
219
220// capturevars is called in a separate phase after all typechecking is done.
221// It decides whether each variable captured by a closure should be captured
222// by value or by reference.
223// We use value capturing for values <= 128 bytes that are never reassigned
224// after capturing (effectively constant).
225func capturevars(xfunc *Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500226 var v *Node
227 var outer *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500228
Russ Cox382b44e2015-02-23 16:07:24 -0500229 lno := int(lineno)
Russ Cox8c195bd2015-02-13 14:40:36 -0500230 lineno = xfunc.Lineno
231
Russ Cox382b44e2015-02-23 16:07:24 -0500232 func_ := xfunc.Closure
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700233 func_.Func.Enter = nil
234 for l := func_.Func.Cvars; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500235 v = l.N
236 if v.Type == nil {
237 // if v->type is nil, it means v looked like it was
238 // going to be used in the closure but wasn't.
239 // this happens because when parsing a, b, c := f()
240 // the a, b, c gets parsed as references to older
241 // a, b, c before the parser figures out this is a
242 // declaration.
243 v.Op = OXXX
244
245 continue
246 }
247
248 // type check the & of closed variables outside the closure,
249 // so that the outer frame also grabs them and knows they escape.
250 dowidth(v.Type)
251
252 outer = v.Outerexpr
253 v.Outerexpr = nil
254
255 // out parameters will be assigned to implicitly upon return.
Dave Cheneyb006d382015-03-06 18:42:58 +1100256 if outer.Class != PPARAMOUT && !v.Closure.Addrtaken && !v.Closure.Assigned && v.Type.Width <= 128 {
257 v.Byval = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500258 } else {
Dave Cheney7885de52015-03-05 18:20:54 +1100259 v.Closure.Addrtaken = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500260 outer = Nod(OADDR, outer, nil)
261 }
262
263 if Debug['m'] > 1 {
Russ Cox175929b2015-03-02 14:22:05 -0500264 var name *Sym
Russ Cox8c195bd2015-02-13 14:40:36 -0500265 if v.Curfn != nil && v.Curfn.Nname != nil {
266 name = v.Curfn.Nname.Sym
267 }
Russ Cox382b44e2015-02-23 16:07:24 -0500268 how := "ref"
Dave Cheneyb006d382015-03-06 18:42:58 +1100269 if v.Byval {
Russ Cox8c195bd2015-02-13 14:40:36 -0500270 how = "value"
271 }
Dave Cheneyb006d382015-03-06 18:42:58 +1100272 Warnl(int(v.Lineno), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", Sconv(name, 0), how, Sconv(v.Sym, 0), v.Closure.Addrtaken, v.Closure.Assigned, int32(v.Type.Width))
Russ Cox8c195bd2015-02-13 14:40:36 -0500273 }
274
275 typecheck(&outer, Erv)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700276 func_.Func.Enter = list(func_.Func.Enter, outer)
Russ Cox8c195bd2015-02-13 14:40:36 -0500277 }
278
279 lineno = int32(lno)
280}
281
282// transformclosure is called in a separate phase after escape analysis.
283// It transform closure bodies to properly reference captured variables.
284func transformclosure(xfunc *Node) {
Russ Cox382b44e2015-02-23 16:07:24 -0500285 lno := int(lineno)
Russ Cox8c195bd2015-02-13 14:40:36 -0500286 lineno = xfunc.Lineno
Russ Cox382b44e2015-02-23 16:07:24 -0500287 func_ := xfunc.Closure
Russ Cox8c195bd2015-02-13 14:40:36 -0500288
289 if func_.Top&Ecall != 0 {
290 // If the closure is directly called, we transform it to a plain function call
291 // with variables passed as args. This avoids allocation of a closure object.
292 // Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
293 // will complete the transformation later.
294 // For illustration, the following closure:
295 // func(a int) {
296 // println(byval)
297 // byref++
298 // }(42)
299 // becomes:
300 // func(a int, byval int, &byref *int) {
301 // println(byval)
302 // (*&byref)++
303 // }(42, byval, &byref)
304
305 // f is ONAME of the actual function.
Russ Cox382b44e2015-02-23 16:07:24 -0500306 f := xfunc.Nname
Russ Cox8c195bd2015-02-13 14:40:36 -0500307
308 // Get pointer to input arguments and rewind to the end.
309 // We are going to append captured variables to input args.
Russ Cox382b44e2015-02-23 16:07:24 -0500310 param := &getinargx(f.Type).Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500311
312 for ; *param != nil; param = &(*param).Down {
313 }
Russ Cox382b44e2015-02-23 16:07:24 -0500314 var v *Node
315 var addr *Node
316 var fld *Type
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700317 for l := func_.Func.Cvars; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500318 v = l.N
319 if v.Op == OXXX {
320 continue
321 }
322 fld = typ(TFIELD)
323 fld.Funarg = 1
Dave Cheneyb006d382015-03-06 18:42:58 +1100324 if v.Byval {
Russ Cox8c195bd2015-02-13 14:40:36 -0500325 // If v is captured by value, we merely downgrade it to PPARAM.
326 v.Class = PPARAM
327
328 v.Ullman = 1
329 fld.Nname = v
330 } else {
331 // If v of type T is captured by reference,
332 // we introduce function param &v *T
333 // and v remains PPARAMREF with &v heapaddr
334 // (accesses will implicitly deref &v).
Matthew Dempsky8b3670f2015-03-06 12:02:24 -0800335 addr = newname(Lookupf("&%s", v.Sym.Name))
Russ Cox8c195bd2015-02-13 14:40:36 -0500336 addr.Type = Ptrto(v.Type)
337 addr.Class = PPARAM
338 v.Heapaddr = addr
339 fld.Nname = addr
340 }
341
342 fld.Type = fld.Nname.Type
343 fld.Sym = fld.Nname.Sym
344
345 // Declare the new param and append it to input arguments.
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700346 xfunc.Func.Dcl = list(xfunc.Func.Dcl, fld.Nname)
Russ Cox8c195bd2015-02-13 14:40:36 -0500347
348 *param = fld
349 param = &fld.Down
350 }
351
352 // Recalculate param offsets.
353 if f.Type.Width > 0 {
354 Fatal("transformclosure: width is already calculated")
355 }
356 dowidth(f.Type)
357 xfunc.Type = f.Type // update type of ODCLFUNC
358 } else {
359 // The closure is not called, so it is going to stay as closure.
Russ Cox382b44e2015-02-23 16:07:24 -0500360 nvar := 0
Russ Cox8c195bd2015-02-13 14:40:36 -0500361
Russ Cox175929b2015-03-02 14:22:05 -0500362 var body *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -0500363 offset := int64(Widthptr)
364 var addr *Node
365 var v *Node
366 var cv *Node
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700367 for l := func_.Func.Cvars; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500368 v = l.N
369 if v.Op == OXXX {
370 continue
371 }
372 nvar++
373
374 // cv refers to the field inside of closure OSTRUCTLIT.
375 cv = Nod(OCLOSUREVAR, nil, nil)
376
377 cv.Type = v.Type
Dave Cheneyb006d382015-03-06 18:42:58 +1100378 if !v.Byval {
Russ Cox8c195bd2015-02-13 14:40:36 -0500379 cv.Type = Ptrto(v.Type)
380 }
381 offset = Rnd(offset, int64(cv.Type.Align))
382 cv.Xoffset = offset
383 offset += cv.Type.Width
384
Dave Cheneyb006d382015-03-06 18:42:58 +1100385 if v.Byval && v.Type.Width <= int64(2*Widthptr) && Thearch.Thechar == '6' {
Russ Cox8c195bd2015-02-13 14:40:36 -0500386 // If it is a small variable captured by value, downgrade it to PAUTO.
387 // This optimization is currently enabled only for amd64, see:
388 // https://github.com/golang/go/issues/9865
389 v.Class = PAUTO
390
391 v.Ullman = 1
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700392 xfunc.Func.Dcl = list(xfunc.Func.Dcl, v)
Russ Cox8c195bd2015-02-13 14:40:36 -0500393 body = list(body, Nod(OAS, v, cv))
394 } else {
395 // Declare variable holding addresses taken from closure
396 // and initialize in entry prologue.
Matthew Dempsky8b3670f2015-03-06 12:02:24 -0800397 addr = newname(Lookupf("&%s", v.Sym.Name))
Russ Cox8c195bd2015-02-13 14:40:36 -0500398 addr.Ntype = Nod(OIND, typenod(v.Type), nil)
399 addr.Class = PAUTO
Dave Cheney44e90312015-03-06 21:18:41 +1100400 addr.Used = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500401 addr.Curfn = xfunc
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700402 xfunc.Func.Dcl = list(xfunc.Func.Dcl, addr)
Russ Cox8c195bd2015-02-13 14:40:36 -0500403 v.Heapaddr = addr
Dave Cheneyb006d382015-03-06 18:42:58 +1100404 if v.Byval {
Russ Cox8c195bd2015-02-13 14:40:36 -0500405 cv = Nod(OADDR, cv, nil)
406 }
407 body = list(body, Nod(OAS, addr, cv))
408 }
409 }
410
411 typechecklist(body, Etop)
412 walkstmtlist(body)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700413 xfunc.Func.Enter = body
414 xfunc.Func.Needctxt = nvar > 0
Russ Cox8c195bd2015-02-13 14:40:36 -0500415 }
416
417 lineno = int32(lno)
418}
419
420func walkclosure(func_ *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -0500421 // If no closure vars, don't bother wrapping.
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700422 if func_.Func.Cvars == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -0500423 return func_.Closure.Nname
424 }
425
426 // Create closure in the form of a composite literal.
427 // supposing the closure captures an int i and a string s
428 // and has one float64 argument and no results,
429 // the generated code looks like:
430 //
Russ Coxf6791da2015-02-20 13:54:45 -0500431 // clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s}
Russ Cox8c195bd2015-02-13 14:40:36 -0500432 //
433 // The use of the struct provides type information to the garbage
434 // collector so that it can walk the closure. We could use (in this case)
435 // [3]unsafe.Pointer instead, but that would leave the gc in the dark.
436 // The information appears in the binary in the form of type descriptors;
437 // the struct is unnamed so that closures in multiple packages with the
438 // same struct type can share the descriptor.
439
Russ Cox382b44e2015-02-23 16:07:24 -0500440 typ := Nod(OTSTRUCT, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500441
Russ Coxf6791da2015-02-20 13:54:45 -0500442 typ.List = list1(Nod(ODCLFIELD, newname(Lookup(".F")), typenod(Types[TUINTPTR])))
Russ Cox382b44e2015-02-23 16:07:24 -0500443 var typ1 *Node
444 var v *Node
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700445 for l := func_.Func.Cvars; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500446 v = l.N
447 if v.Op == OXXX {
448 continue
449 }
450 typ1 = typenod(v.Type)
Dave Cheneyb006d382015-03-06 18:42:58 +1100451 if !v.Byval {
Russ Cox8c195bd2015-02-13 14:40:36 -0500452 typ1 = Nod(OIND, typ1, nil)
453 }
454 typ.List = list(typ.List, Nod(ODCLFIELD, newname(v.Sym), typ1))
455 }
456
Russ Cox382b44e2015-02-23 16:07:24 -0500457 clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -0500458 clos.Esc = func_.Esc
Dave Cheney44e90312015-03-06 21:18:41 +1100459 clos.Right.Implicit = true
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700460 clos.List = concat(list1(Nod(OCFUNC, func_.Closure.Nname, nil)), func_.Func.Enter)
Russ Cox8c195bd2015-02-13 14:40:36 -0500461
462 // Force type conversion from *struct to the func type.
463 clos = Nod(OCONVNOP, clos, nil)
464
465 clos.Type = func_.Type
466
467 typecheck(&clos, Erv)
468
469 // typecheck will insert a PTRLIT node under CONVNOP,
470 // tag it with escape analysis result.
471 clos.Left.Esc = func_.Esc
472
473 // non-escaping temp to use, if any.
474 // orderexpr did not compute the type; fill it in now.
475 if func_.Alloc != nil {
476 func_.Alloc.Type = clos.Left.Left.Type
477 func_.Alloc.Orig.Type = func_.Alloc.Type
478 clos.Left.Right = func_.Alloc
479 func_.Alloc = nil
480 }
481
482 walkexpr(&clos, init)
483
484 return clos
485}
486
487func typecheckpartialcall(fn *Node, sym *Node) {
488 switch fn.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700489 case ODOTINTER, ODOTMETH:
Russ Cox8c195bd2015-02-13 14:40:36 -0500490 break
491
492 default:
493 Fatal("invalid typecheckpartialcall")
494 }
495
496 // Create top-level function.
497 fn.Nname = makepartialcall(fn, fn.Type, sym)
498
499 fn.Right = sym
500 fn.Op = OCALLPART
501 fn.Type = fn.Nname.Type
502}
503
504var makepartialcall_gopkg *Pkg
505
506func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -0500507 var p string
Russ Cox8c195bd2015-02-13 14:40:36 -0500508
Russ Cox382b44e2015-02-23 16:07:24 -0500509 rcvrtype := fn.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500510 if exportname(meth.Sym.Name) {
Russ Coxf6791da2015-02-20 13:54:45 -0500511 p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, obj.FmtLeft|obj.FmtShort), meth.Sym.Name)
Russ Cox8c195bd2015-02-13 14:40:36 -0500512 } else {
Russ Coxf6791da2015-02-20 13:54:45 -0500513 p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, obj.FmtLeft|obj.FmtShort), Sconv(meth.Sym, obj.FmtLeft))
Russ Cox8c195bd2015-02-13 14:40:36 -0500514 }
Russ Cox382b44e2015-02-23 16:07:24 -0500515 basetype := rcvrtype
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000516 if Isptr[rcvrtype.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -0500517 basetype = basetype.Type
518 }
519 if basetype.Etype != TINTER && basetype.Sym == nil {
520 Fatal("missing base type for %v", Tconv(rcvrtype, 0))
521 }
522
Russ Cox175929b2015-03-02 14:22:05 -0500523 var spkg *Pkg
Russ Cox8c195bd2015-02-13 14:40:36 -0500524 if basetype.Sym != nil {
525 spkg = basetype.Sym.Pkg
526 }
527 if spkg == nil {
528 if makepartialcall_gopkg == nil {
Russ Coxbed1f902015-03-02 16:03:26 -0500529 makepartialcall_gopkg = mkpkg("go")
Russ Cox8c195bd2015-02-13 14:40:36 -0500530 }
531 spkg = makepartialcall_gopkg
532 }
533
Russ Cox382b44e2015-02-23 16:07:24 -0500534 sym := Pkglookup(p, spkg)
Russ Cox8c195bd2015-02-13 14:40:36 -0500535
536 if sym.Flags&SymUniq != 0 {
537 return sym.Def
538 }
539 sym.Flags |= SymUniq
540
Russ Cox382b44e2015-02-23 16:07:24 -0500541 savecurfn := Curfn
Russ Cox8c195bd2015-02-13 14:40:36 -0500542 Curfn = nil
543
Russ Cox382b44e2015-02-23 16:07:24 -0500544 xtype := Nod(OTFUNC, nil, nil)
545 i := 0
Russ Cox175929b2015-03-02 14:22:05 -0500546 var l *NodeList
547 var callargs *NodeList
Dave Cheneyd3287562015-03-09 16:24:07 +1100548 ddd := false
Russ Cox382b44e2015-02-23 16:07:24 -0500549 xfunc := Nod(ODCLFUNC, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500550 Curfn = xfunc
Russ Cox382b44e2015-02-23 16:07:24 -0500551 var fld *Node
552 var n *Node
553 for t := getinargx(t0).Type; t != nil; t = t.Down {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -0800554 n = newname(Lookupf("a%d", i))
Russ Cox8c195bd2015-02-13 14:40:36 -0500555 i++
Russ Cox8c195bd2015-02-13 14:40:36 -0500556 n.Class = PPARAM
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700557 xfunc.Func.Dcl = list(xfunc.Func.Dcl, n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500558 callargs = list(callargs, n)
559 fld = Nod(ODCLFIELD, n, typenod(t.Type))
Dave Cheneyd3287562015-03-09 16:24:07 +1100560 if t.Isddd {
561 fld.Isddd = true
562 ddd = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500563 }
564
565 l = list(l, fld)
566 }
567
568 xtype.List = l
569 i = 0
570 l = nil
Russ Cox175929b2015-03-02 14:22:05 -0500571 var retargs *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -0500572 for t := getoutargx(t0).Type; t != nil; t = t.Down {
Matthew Dempsky8b3670f2015-03-06 12:02:24 -0800573 n = newname(Lookupf("r%d", i))
Russ Cox8c195bd2015-02-13 14:40:36 -0500574 i++
Russ Cox8c195bd2015-02-13 14:40:36 -0500575 n.Class = PPARAMOUT
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700576 xfunc.Func.Dcl = list(xfunc.Func.Dcl, n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500577 retargs = list(retargs, n)
578 l = list(l, Nod(ODCLFIELD, n, typenod(t.Type)))
579 }
580
581 xtype.Rlist = l
582
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700583 xfunc.Func.Dupok = true
Josh Bleecher Snyder57279ba2015-03-10 21:37:13 -0700584 xfunc.Nname = newfuncname(sym)
Russ Cox8c195bd2015-02-13 14:40:36 -0500585 xfunc.Nname.Sym.Flags |= SymExported // disable export
586 xfunc.Nname.Ntype = xtype
587 xfunc.Nname.Defn = xfunc
588 declare(xfunc.Nname, PFUNC)
589
590 // Declare and initialize variable holding receiver.
Russ Cox8c195bd2015-02-13 14:40:36 -0500591
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700592 xfunc.Func.Needctxt = true
Russ Cox382b44e2015-02-23 16:07:24 -0500593 cv := Nod(OCLOSUREVAR, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500594 cv.Xoffset = int64(Widthptr)
595 cv.Type = rcvrtype
596 if int(cv.Type.Align) > Widthptr {
597 cv.Xoffset = int64(cv.Type.Align)
598 }
Russ Cox382b44e2015-02-23 16:07:24 -0500599 ptr := Nod(ONAME, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500600 ptr.Sym = Lookup("rcvr")
601 ptr.Class = PAUTO
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700602 ptr.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500603 ptr.Ullman = 1
Dave Cheney44e90312015-03-06 21:18:41 +1100604 ptr.Used = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500605 ptr.Curfn = xfunc
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -0700606 xfunc.Func.Dcl = list(xfunc.Func.Dcl, ptr)
Russ Cox44928112015-03-02 20:34:22 -0500607 var body *NodeList
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000608 if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500609 ptr.Ntype = typenod(rcvrtype)
610 body = list(body, Nod(OAS, ptr, cv))
611 } else {
612 ptr.Ntype = typenod(Ptrto(rcvrtype))
613 body = list(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
614 }
615
Russ Cox382b44e2015-02-23 16:07:24 -0500616 call := Nod(OCALL, Nod(OXDOT, ptr, meth), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500617 call.List = callargs
Dave Cheneyd3287562015-03-09 16:24:07 +1100618 call.Isddd = ddd
Russ Cox8c195bd2015-02-13 14:40:36 -0500619 if t0.Outtuple == 0 {
620 body = list(body, call)
621 } else {
Russ Cox382b44e2015-02-23 16:07:24 -0500622 n := Nod(OAS2, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500623 n.List = retargs
624 n.Rlist = list1(call)
625 body = list(body, n)
626 n = Nod(ORETURN, nil, nil)
627 body = list(body, n)
628 }
629
630 xfunc.Nbody = body
631
632 typecheck(&xfunc, Etop)
633 sym.Def = xfunc
634 xtop = list(xtop, xfunc)
635 Curfn = savecurfn
636
637 return xfunc
638}
639
640func walkpartialcall(n *Node, init **NodeList) *Node {
Russ Cox8c195bd2015-02-13 14:40:36 -0500641 // Create closure in the form of a composite literal.
642 // For x.M with receiver (x) type T, the generated code looks like:
643 //
644 // clos = &struct{F uintptr; R T}{M.T·f, x}
645 //
646 // Like walkclosure above.
647
Russ Coxdc7b54b2015-02-17 22:13:49 -0500648 if Isinter(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500649 // Trigger panic for method on nil interface now.
650 // Otherwise it happens in the wrapper and is confusing.
651 n.Left = cheapexpr(n.Left, init)
652
653 checknil(n.Left, init)
654 }
655
Russ Cox382b44e2015-02-23 16:07:24 -0500656 typ := Nod(OTSTRUCT, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500657 typ.List = list1(Nod(ODCLFIELD, newname(Lookup("F")), typenod(Types[TUINTPTR])))
658 typ.List = list(typ.List, Nod(ODCLFIELD, newname(Lookup("R")), typenod(n.Left.Type)))
659
Russ Cox382b44e2015-02-23 16:07:24 -0500660 clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -0500661 clos.Esc = n.Esc
Dave Cheney44e90312015-03-06 21:18:41 +1100662 clos.Right.Implicit = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500663 clos.List = list1(Nod(OCFUNC, n.Nname.Nname, nil))
664 clos.List = list(clos.List, n.Left)
665
666 // Force type conversion from *struct to the func type.
667 clos = Nod(OCONVNOP, clos, nil)
668
669 clos.Type = n.Type
670
671 typecheck(&clos, Erv)
672
673 // typecheck will insert a PTRLIT node under CONVNOP,
674 // tag it with escape analysis result.
675 clos.Left.Esc = n.Esc
676
677 // non-escaping temp to use, if any.
678 // orderexpr did not compute the type; fill it in now.
679 if n.Alloc != nil {
680 n.Alloc.Type = clos.Left.Left.Type
681 n.Alloc.Orig.Type = n.Alloc.Type
682 clos.Left.Right = n.Alloc
683 n.Alloc = nil
684 }
685
686 walkexpr(&clos, init)
687
688 return clos
689}