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.
12 // function literals aka closures
13 func closurehdr(ntype *Node) {
17 n := Nod(OCLOSURE, nil, nil)
19 n.Func.Depth = Funcdepth
20 n.Func.Outerfunc = Curfn
24 // steal ntype's argument names and
25 // leave a fresh copy in their place.
26 // references to these variables need to
27 // refer to the variables in the external
28 // function declared below; see walkclosure.
34 for l := n.List; l != nil; l = l.Next {
37 name = newname(name.Sym)
39 a = Nod(ODCLFIELD, name, l.N.Right)
44 ntype.List = list(ntype.List, a)
47 for l := n.Rlist; l != nil; l = l.Next {
50 name = newname(name.Sym)
52 ntype.Rlist = list(ntype.Rlist, Nod(ODCLFIELD, name, l.N.Right))
56 func closurebody(body *NodeList) *Node {
58 body = list1(Nod(OEMPTY, nil, nil))
63 func_.Func.Endlineno = lineno
66 // closure-specific variables are hanging off the
67 // ordinary ones in the symbol table; see oldname.
69 // make the list of pointers for the closure call.
70 for _, v := range func_.Func.Cvars.Slice() {
71 v.Name.Param.Closure.Name.Param.Closure = v.Name.Param.Outer
72 v.Name.Param.Outerexpr = oldname(v.Sym)
78 func typecheckclosure(func_ *Node, top int) {
79 for _, ln := range func_.Func.Cvars.Slice() {
80 n := ln.Name.Param.Closure
82 n.Name.Captured = true
83 if n.Name.Decldepth == 0 {
84 Fatalf("typecheckclosure: var %v does not have decldepth assigned", Nconv(n, obj.FmtShort))
87 // Ignore assignments to the variable in straightline code
88 // preceding the first capturing by a closure.
89 if n.Name.Decldepth == decldepth {
95 for _, ln := range func_.Func.Dcl {
96 if ln.Op == ONAME && (ln.Class == PPARAM || ln.Class == PPARAMOUT) {
102 typecheck(&func_.Func.Ntype, Etype)
103 func_.Type = func_.Func.Ntype.Type
106 // Type check the body now, but only if we're inside a function.
107 // At top level (in a variable initialization: curfn==nil) we're not
108 // ready to type check code yet; we'll check it later, because the
109 // underlying closure function we create is added to xtop.
110 if Curfn != nil && func_.Type != nil {
114 typechecklist(func_.Nbody, Etop)
119 // Create top-level function
120 xtop = list(xtop, makeclosure(func_))
123 // closurename returns name for OCLOSURE n.
124 // It is not as simple as it ought to be, because we typecheck nested closures
125 // starting from the innermost one. So when we check the inner closure,
126 // we don't yet have name for the outer closure. This function uses recursion
127 // to generate names all the way up if necessary.
129 var closurename_closgen int
131 func closurename(n *Node) *Sym {
138 if n.Func.Outerfunc == nil {
143 closurename_closgen++
144 gen = closurename_closgen
145 } else if n.Func.Outerfunc.Op == ODCLFUNC {
146 // The outermost closure inside of a named function.
147 outer = n.Func.Outerfunc.Func.Nname.Sym.Name
151 // Yes, functions can be named _.
152 // Can't use function closgen in such case,
153 // because it would lead to name clashes.
154 if !isblank(n.Func.Outerfunc.Func.Nname) {
155 n.Func.Outerfunc.Func.Closgen++
156 gen = n.Func.Outerfunc.Func.Closgen
158 closurename_closgen++
159 gen = closurename_closgen
161 } else if n.Func.Outerfunc.Op == OCLOSURE {
162 // Nested closure, recurse.
163 outer = closurename(n.Func.Outerfunc).Name
166 n.Func.Outerfunc.Func.Closgen++
167 gen = n.Func.Outerfunc.Func.Closgen
169 Fatalf("closurename called for %v", Nconv(n, obj.FmtShort))
171 n.Sym = Lookupf("%s.%s%d", outer, prefix, gen)
175 func makeclosure(func_ *Node) *Node {
176 // wrap body in external function
177 // that begins by reading closure parameters.
178 xtype := Nod(OTFUNC, nil, nil)
180 xtype.List = func_.List
181 xtype.Rlist = func_.Rlist
183 // create the function
184 xfunc := Nod(ODCLFUNC, nil, nil)
186 xfunc.Func.Nname = newfuncname(closurename(func_))
187 xfunc.Func.Nname.Sym.Flags |= SymExported // disable export
188 xfunc.Func.Nname.Name.Param.Ntype = xtype
189 xfunc.Func.Nname.Name.Defn = xfunc
190 declare(xfunc.Func.Nname, PFUNC)
191 xfunc.Func.Nname.Name.Funcdepth = func_.Func.Depth
192 xfunc.Func.Depth = func_.Func.Depth
193 xfunc.Func.Endlineno = func_.Func.Endlineno
194 makefuncsym(xfunc.Func.Nname.Sym)
196 xfunc.Nbody = func_.Nbody
197 xfunc.Func.Dcl = append(func_.Func.Dcl, xfunc.Func.Dcl...)
199 if xfunc.Nbody == nil {
200 Fatalf("empty body - won't generate any code")
202 typecheck(&xfunc, Etop)
204 xfunc.Func.Closure = func_
205 func_.Func.Closure = xfunc
214 // capturevars is called in a separate phase after all typechecking is done.
215 // It decides whether each variable captured by a closure should be captured
216 // by value or by reference.
217 // We use value capturing for values <= 128 bytes that are never reassigned
218 // after capturing (effectively constant).
219 func capturevars(xfunc *Node) {
223 lineno = xfunc.Lineno
225 func_ := xfunc.Func.Closure
226 func_.Func.Enter.Set(nil)
227 for _, v := range func_.Func.Cvars.Slice() {
229 // if v->type is nil, it means v looked like it was
230 // going to be used in the closure but wasn't.
231 // this happens because when parsing a, b, c := f()
232 // the a, b, c gets parsed as references to older
233 // a, b, c before the parser figures out this is a
240 // type check the & of closed variables outside the closure,
241 // so that the outer frame also grabs them and knows they escape.
244 outer = v.Name.Param.Outerexpr
245 v.Name.Param.Outerexpr = nil
247 // out parameters will be assigned to implicitly upon return.
248 if outer.Class != PPARAMOUT && !v.Name.Param.Closure.Addrtaken && !v.Name.Param.Closure.Assigned && v.Type.Width <= 128 {
251 v.Name.Param.Closure.Addrtaken = true
252 outer = Nod(OADDR, outer, nil)
257 if v.Name.Curfn != nil && v.Name.Curfn.Func.Nname != nil {
258 name = v.Name.Curfn.Func.Nname.Sym
264 Warnl(int(v.Lineno), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, v.Name.Param.Closure.Addrtaken, v.Name.Param.Closure.Assigned, int32(v.Type.Width))
267 typecheck(&outer, Erv)
268 func_.Func.Enter.Append(outer)
274 // transformclosure is called in a separate phase after escape analysis.
275 // It transform closure bodies to properly reference captured variables.
276 func transformclosure(xfunc *Node) {
278 lineno = xfunc.Lineno
279 func_ := xfunc.Func.Closure
281 if func_.Func.Top&Ecall != 0 {
282 // If the closure is directly called, we transform it to a plain function call
283 // with variables passed as args. This avoids allocation of a closure object.
284 // Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
285 // will complete the transformation later.
286 // For illustration, the following closure:
292 // func(a int, byval int, &byref *int) {
295 // }(byval, &byref, 42)
297 // f is ONAME of the actual function.
298 f := xfunc.Func.Nname
300 // Get pointer to input arguments.
301 // We are going to insert captured variables before input args.
302 param := &getinargx(f.Type).Type
303 original_args := *param // old input args
304 original_dcl := xfunc.Func.Dcl
309 for _, v := range func_.Func.Cvars.Slice() {
316 // If v is captured by value, we merely downgrade it to PPARAM.
322 // If v of type T is captured by reference,
323 // we introduce function param &v *T
324 // and v remains PPARAMREF with &v heapaddr
325 // (accesses will implicitly deref &v).
326 addr = newname(Lookupf("&%s", v.Sym.Name))
327 addr.Type = Ptrto(v.Type)
329 v.Name.Heapaddr = addr
333 fld.Type = fld.Nname.Type
334 fld.Sym = fld.Nname.Sym
336 // Declare the new param and add it the first part of the input arguments.
337 xfunc.Func.Dcl = append(xfunc.Func.Dcl, fld.Nname)
342 *param = original_args
343 xfunc.Func.Dcl = append(xfunc.Func.Dcl, original_dcl...)
345 // Recalculate param offsets.
346 if f.Type.Width > 0 {
347 Fatalf("transformclosure: width is already calculated")
350 xfunc.Type = f.Type // update type of ODCLFUNC
352 // The closure is not called, so it is going to stay as closure.
354 offset := int64(Widthptr)
357 for _, v := range func_.Func.Cvars.Slice() {
362 // cv refers to the field inside of closure OSTRUCTLIT.
363 cv = Nod(OCLOSUREVAR, nil, nil)
367 cv.Type = Ptrto(v.Type)
369 offset = Rnd(offset, int64(cv.Type.Align))
371 offset += cv.Type.Width
373 if v.Name.Byval && v.Type.Width <= int64(2*Widthptr) {
374 // If it is a small variable captured by value, downgrade it to PAUTO.
377 xfunc.Func.Dcl = append(xfunc.Func.Dcl, v)
378 body = append(body, Nod(OAS, v, cv))
380 // Declare variable holding addresses taken from closure
381 // and initialize in entry prologue.
382 addr = newname(Lookupf("&%s", v.Sym.Name))
383 addr.Name.Param.Ntype = Nod(OIND, typenod(v.Type), nil)
386 addr.Name.Curfn = xfunc
387 xfunc.Func.Dcl = append(xfunc.Func.Dcl, addr)
388 v.Name.Heapaddr = addr
390 cv = Nod(OADDR, cv, nil)
392 body = append(body, Nod(OAS, addr, cv))
397 typecheckslice(body, Etop)
399 xfunc.Func.Enter.Set(body)
400 xfunc.Func.Needctxt = true
407 func walkclosure(func_ *Node, init **NodeList) *Node {
408 // If no closure vars, don't bother wrapping.
409 if len(func_.Func.Cvars.Slice()) == 0 {
410 return func_.Func.Closure.Func.Nname
413 // Create closure in the form of a composite literal.
414 // supposing the closure captures an int i and a string s
415 // and has one float64 argument and no results,
416 // the generated code looks like:
418 // clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s}
420 // The use of the struct provides type information to the garbage
421 // collector so that it can walk the closure. We could use (in this case)
422 // [3]unsafe.Pointer instead, but that would leave the gc in the dark.
423 // The information appears in the binary in the form of type descriptors;
424 // the struct is unnamed so that closures in multiple packages with the
425 // same struct type can share the descriptor.
427 typ := Nod(OTSTRUCT, nil, nil)
429 typ.List = list1(Nod(ODCLFIELD, newname(Lookup(".F")), typenod(Types[TUINTPTR])))
431 for _, v := range func_.Func.Cvars.Slice() {
435 typ1 = typenod(v.Type)
437 typ1 = Nod(OIND, typ1, nil)
439 typ.List = list(typ.List, Nod(ODCLFIELD, newname(v.Sym), typ1))
442 clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
444 clos.Right.Implicit = true
445 clos.List = concat(list1(Nod(OCFUNC, func_.Func.Closure.Func.Nname, nil)), func_.Func.Enter.NodeList())
447 // Force type conversion from *struct to the func type.
448 clos = Nod(OCONVNOP, clos, nil)
450 clos.Type = func_.Type
452 typecheck(&clos, Erv)
454 // typecheck will insert a PTRLIT node under CONVNOP,
455 // tag it with escape analysis result.
456 clos.Left.Esc = func_.Esc
458 // non-escaping temp to use, if any.
459 // orderexpr did not compute the type; fill it in now.
460 if x := prealloc[func_]; x != nil {
461 x.Type = clos.Left.Left.Type
464 delete(prealloc, func_)
467 walkexpr(&clos, init)
472 func typecheckpartialcall(fn *Node, sym *Node) {
474 case ODOTINTER, ODOTMETH:
478 Fatalf("invalid typecheckpartialcall")
481 // Create top-level function.
482 xfunc := makepartialcall(fn, fn.Type, sym)
489 var makepartialcall_gopkg *Pkg
491 func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
494 rcvrtype := fn.Left.Type
495 if exportname(meth.Sym.Name) {
496 p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, obj.FmtLeft|obj.FmtShort), meth.Sym.Name)
498 p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, obj.FmtLeft|obj.FmtShort), Sconv(meth.Sym, obj.FmtLeft))
501 if Isptr[rcvrtype.Etype] {
502 basetype = basetype.Type
504 if basetype.Etype != TINTER && basetype.Sym == nil {
505 Fatalf("missing base type for %v", rcvrtype)
509 if basetype.Sym != nil {
510 spkg = basetype.Sym.Pkg
513 if makepartialcall_gopkg == nil {
514 makepartialcall_gopkg = mkpkg("go")
516 spkg = makepartialcall_gopkg
519 sym := Pkglookup(p, spkg)
521 if sym.Flags&SymUniq != 0 {
529 xtype := Nod(OTFUNC, nil, nil)
532 var callargs *NodeList
534 xfunc := Nod(ODCLFUNC, nil, nil)
538 for t := getinargx(t0).Type; t != nil; t = t.Down {
539 n = newname(Lookupf("a%d", i))
542 xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
543 callargs = list(callargs, n)
544 fld = Nod(ODCLFIELD, n, typenod(t.Type))
556 var retargs *NodeList
557 for t := getoutargx(t0).Type; t != nil; t = t.Down {
558 n = newname(Lookupf("r%d", i))
561 xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
562 retargs = list(retargs, n)
563 l = list(l, Nod(ODCLFIELD, n, typenod(t.Type)))
568 xfunc.Func.Dupok = true
569 xfunc.Func.Nname = newfuncname(sym)
570 xfunc.Func.Nname.Sym.Flags |= SymExported // disable export
571 xfunc.Func.Nname.Name.Param.Ntype = xtype
572 xfunc.Func.Nname.Name.Defn = xfunc
573 declare(xfunc.Func.Nname, PFUNC)
575 // Declare and initialize variable holding receiver.
577 xfunc.Func.Needctxt = true
578 cv := Nod(OCLOSUREVAR, nil, nil)
579 cv.Xoffset = int64(Widthptr)
581 if int(cv.Type.Align) > Widthptr {
582 cv.Xoffset = int64(cv.Type.Align)
584 ptr := Nod(ONAME, nil, nil)
585 ptr.Sym = Lookup("rcvr")
590 ptr.Name.Curfn = xfunc
592 xfunc.Func.Dcl = append(xfunc.Func.Dcl, ptr)
594 if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) {
595 ptr.Name.Param.Ntype = typenod(rcvrtype)
596 body = list(body, Nod(OAS, ptr, cv))
598 ptr.Name.Param.Ntype = typenod(Ptrto(rcvrtype))
599 body = list(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
602 call := Nod(OCALL, Nod(OXDOT, ptr, meth), nil)
605 if t0.Outtuple == 0 {
606 body = list(body, call)
608 n := Nod(OAS2, nil, nil)
610 n.Rlist = list1(call)
612 n = Nod(ORETURN, nil, nil)
618 typecheck(&xfunc, Etop)
620 xtop = list(xtop, xfunc)
626 func walkpartialcall(n *Node, init **NodeList) *Node {
627 // Create closure in the form of a composite literal.
628 // For x.M with receiver (x) type T, the generated code looks like:
630 // clos = &struct{F uintptr; R T}{M.T·f, x}
632 // Like walkclosure above.
634 if Isinter(n.Left.Type) {
635 // Trigger panic for method on nil interface now.
636 // Otherwise it happens in the wrapper and is confusing.
637 n.Left = cheapexpr(n.Left, init)
639 checknil(n.Left, init)
642 typ := Nod(OTSTRUCT, nil, nil)
643 typ.List = list1(Nod(ODCLFIELD, newname(Lookup("F")), typenod(Types[TUINTPTR])))
644 typ.List = list(typ.List, Nod(ODCLFIELD, newname(Lookup("R")), typenod(n.Left.Type)))
646 clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
648 clos.Right.Implicit = true
649 clos.List = list1(Nod(OCFUNC, n.Func.Nname, nil))
650 clos.List = list(clos.List, n.Left)
652 // Force type conversion from *struct to the func type.
653 clos = Nod(OCONVNOP, clos, nil)
657 typecheck(&clos, Erv)
659 // typecheck will insert a PTRLIT node under CONVNOP,
660 // tag it with escape analysis result.
661 clos.Left.Esc = n.Esc
663 // non-escaping temp to use, if any.
664 // orderexpr did not compute the type; fill it in now.
665 if x := prealloc[n]; x != nil {
666 x.Type = clos.Left.Left.Type
672 walkexpr(&clos, init)