Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 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 | "cmd/internal/obj" |
| 9 | "fmt" |
| 10 | ) |
| 11 | |
| 12 | /* |
| 13 | * function literals aka closures |
| 14 | */ |
| 15 | func closurehdr(ntype *Node) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 16 | var name *Node |
| 17 | var a *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 18 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 19 | n := Nod(OCLOSURE, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 20 | n.Ntype = ntype |
| 21 | n.Funcdepth = Funcdepth |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 22 | n.Func.Outerfunc = Curfn |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 23 | |
| 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 36 | for l := n.List; l != nil; l = l.Next { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 37 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 49 | for l := n.Rlist; l != nil; l = l.Next { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 50 | 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 | |
| 58 | func closurebody(body *NodeList) *Node { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 59 | if body == nil { |
| 60 | body = list1(Nod(OEMPTY, nil, nil)) |
| 61 | } |
| 62 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 63 | func_ := Curfn |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 64 | func_.Nbody = body |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 65 | func_.Func.Endlineno = lineno |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 66 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 72 | var v *Node |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 73 | for l := func_.Func.Cvars; l != nil; l = l.Next { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 74 | v = l.N |
| 75 | v.Closure.Closure = v.Outer |
| 76 | v.Outerexpr = oldname(v.Sym) |
| 77 | } |
| 78 | |
| 79 | return func_ |
| 80 | } |
| 81 | |
| 82 | func typecheckclosure(func_ *Node, top int) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 83 | var n *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 84 | |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 85 | for l := func_.Func.Cvars; l != nil; l = l.Next { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 86 | n = l.N.Closure |
Dave Cheney | b006d38 | 2015-03-06 18:42:58 +1100 | [diff] [blame] | 87 | if !n.Captured { |
| 88 | n.Captured = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 89 | 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 Cheney | b006d38 | 2015-03-06 18:42:58 +1100 | [diff] [blame] | 96 | n.Assigned = false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 97 | } |
| 98 | } |
| 99 | } |
| 100 | |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 101 | for l := func_.Func.Dcl; l != nil; l = l.Next { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 102 | if l.N.Op == ONAME && (l.N.Class == PPARAM || l.N.Class == PPARAMOUT) { |
| 103 | l.N.Decldepth = 1 |
| 104 | } |
| 105 | } |
| 106 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 107 | oldfn := Curfn |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 108 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 118 | olddd := decldepth |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 119 | 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 Cox | f6791da | 2015-02-20 13:54:45 -0500 | [diff] [blame] | 129 | // 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 | |
| 135 | var closurename_closgen int |
| 136 | |
| 137 | func closurename(n *Node) *Sym { |
Russ Cox | f6791da | 2015-02-20 13:54:45 -0500 | [diff] [blame] | 138 | if n.Sym != nil { |
| 139 | return n.Sym |
| 140 | } |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 141 | gen := 0 |
| 142 | outer := "" |
| 143 | prefix := "" |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 144 | if n.Func.Outerfunc == nil { |
Russ Cox | f6791da | 2015-02-20 13:54:45 -0500 | [diff] [blame] | 145 | // Global closure. |
| 146 | outer = "glob" |
| 147 | |
| 148 | prefix = "func" |
| 149 | closurename_closgen++ |
| 150 | gen = closurename_closgen |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 151 | } else if n.Func.Outerfunc.Op == ODCLFUNC { |
Russ Cox | f6791da | 2015-02-20 13:54:45 -0500 | [diff] [blame] | 152 | // The outermost closure inside of a named function. |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 153 | outer = n.Func.Outerfunc.Nname.Sym.Name |
Russ Cox | f6791da | 2015-02-20 13:54:45 -0500 | [diff] [blame] | 154 | |
| 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 Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 160 | if !isblank(n.Func.Outerfunc.Nname) { |
| 161 | n.Func.Outerfunc.Func.Closgen++ |
| 162 | gen = n.Func.Outerfunc.Func.Closgen |
Russ Cox | f6791da | 2015-02-20 13:54:45 -0500 | [diff] [blame] | 163 | } else { |
| 164 | closurename_closgen++ |
| 165 | gen = closurename_closgen |
| 166 | } |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 167 | } else if n.Func.Outerfunc.Op == OCLOSURE { |
Russ Cox | f6791da | 2015-02-20 13:54:45 -0500 | [diff] [blame] | 168 | // Nested closure, recurse. |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 169 | outer = closurename(n.Func.Outerfunc).Name |
Russ Cox | f6791da | 2015-02-20 13:54:45 -0500 | [diff] [blame] | 170 | |
| 171 | prefix = "" |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 172 | n.Func.Outerfunc.Func.Closgen++ |
| 173 | gen = n.Func.Outerfunc.Func.Closgen |
Russ Cox | f6791da | 2015-02-20 13:54:45 -0500 | [diff] [blame] | 174 | } else { |
| 175 | Fatal("closurename called for %v", Nconv(n, obj.FmtShort)) |
| 176 | } |
Matthew Dempsky | 8b3670f | 2015-03-06 12:02:24 -0800 | [diff] [blame] | 177 | n.Sym = Lookupf("%s.%s%d", outer, prefix, gen) |
Russ Cox | f6791da | 2015-02-20 13:54:45 -0500 | [diff] [blame] | 178 | return n.Sym |
| 179 | } |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 180 | |
| 181 | func makeclosure(func_ *Node) *Node { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 182 | /* |
| 183 | * wrap body in external function |
| 184 | * that begins by reading closure parameters. |
| 185 | */ |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 186 | xtype := Nod(OTFUNC, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 187 | |
| 188 | xtype.List = func_.List |
| 189 | xtype.Rlist = func_.Rlist |
| 190 | |
| 191 | // create the function |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 192 | xfunc := Nod(ODCLFUNC, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 193 | |
Josh Bleecher Snyder | 57279ba | 2015-03-10 21:37:13 -0700 | [diff] [blame] | 194 | xfunc.Nname = newfuncname(closurename(func_)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 195 | 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 Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 201 | xfunc.Func.Endlineno = func_.Func.Endlineno |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 202 | |
| 203 | xfunc.Nbody = func_.Nbody |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 204 | xfunc.Func.Dcl = concat(func_.Func.Dcl, xfunc.Func.Dcl) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 205 | 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). |
| 225 | func capturevars(xfunc *Node) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 226 | var v *Node |
| 227 | var outer *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 228 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 229 | lno := int(lineno) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 230 | lineno = xfunc.Lineno |
| 231 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 232 | func_ := xfunc.Closure |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 233 | func_.Func.Enter = nil |
| 234 | for l := func_.Func.Cvars; l != nil; l = l.Next { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 235 | 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 Cheney | b006d38 | 2015-03-06 18:42:58 +1100 | [diff] [blame] | 256 | if outer.Class != PPARAMOUT && !v.Closure.Addrtaken && !v.Closure.Assigned && v.Type.Width <= 128 { |
| 257 | v.Byval = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 258 | } else { |
Dave Cheney | 7885de5 | 2015-03-05 18:20:54 +1100 | [diff] [blame] | 259 | v.Closure.Addrtaken = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 260 | outer = Nod(OADDR, outer, nil) |
| 261 | } |
| 262 | |
| 263 | if Debug['m'] > 1 { |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 264 | var name *Sym |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 265 | if v.Curfn != nil && v.Curfn.Nname != nil { |
| 266 | name = v.Curfn.Nname.Sym |
| 267 | } |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 268 | how := "ref" |
Dave Cheney | b006d38 | 2015-03-06 18:42:58 +1100 | [diff] [blame] | 269 | if v.Byval { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 270 | how = "value" |
| 271 | } |
Dave Cheney | b006d38 | 2015-03-06 18:42:58 +1100 | [diff] [blame] | 272 | 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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 273 | } |
| 274 | |
| 275 | typecheck(&outer, Erv) |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 276 | func_.Func.Enter = list(func_.Func.Enter, outer) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 277 | } |
| 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. |
| 284 | func transformclosure(xfunc *Node) { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 285 | lno := int(lineno) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 286 | lineno = xfunc.Lineno |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 287 | func_ := xfunc.Closure |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 288 | |
| 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 306 | f := xfunc.Nname |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 307 | |
| 308 | // Get pointer to input arguments and rewind to the end. |
| 309 | // We are going to append captured variables to input args. |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 310 | param := &getinargx(f.Type).Type |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 311 | |
| 312 | for ; *param != nil; param = &(*param).Down { |
| 313 | } |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 314 | var v *Node |
| 315 | var addr *Node |
| 316 | var fld *Type |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 317 | for l := func_.Func.Cvars; l != nil; l = l.Next { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 318 | v = l.N |
| 319 | if v.Op == OXXX { |
| 320 | continue |
| 321 | } |
| 322 | fld = typ(TFIELD) |
| 323 | fld.Funarg = 1 |
Dave Cheney | b006d38 | 2015-03-06 18:42:58 +1100 | [diff] [blame] | 324 | if v.Byval { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 325 | // 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 Dempsky | 8b3670f | 2015-03-06 12:02:24 -0800 | [diff] [blame] | 335 | addr = newname(Lookupf("&%s", v.Sym.Name)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 336 | 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 Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 346 | xfunc.Func.Dcl = list(xfunc.Func.Dcl, fld.Nname) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 347 | |
| 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 360 | nvar := 0 |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 361 | |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 362 | var body *NodeList |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 363 | offset := int64(Widthptr) |
| 364 | var addr *Node |
| 365 | var v *Node |
| 366 | var cv *Node |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 367 | for l := func_.Func.Cvars; l != nil; l = l.Next { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 368 | 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 Cheney | b006d38 | 2015-03-06 18:42:58 +1100 | [diff] [blame] | 378 | if !v.Byval { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 379 | 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 Cheney | b006d38 | 2015-03-06 18:42:58 +1100 | [diff] [blame] | 385 | if v.Byval && v.Type.Width <= int64(2*Widthptr) && Thearch.Thechar == '6' { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 386 | // 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 Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 392 | xfunc.Func.Dcl = list(xfunc.Func.Dcl, v) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 393 | body = list(body, Nod(OAS, v, cv)) |
| 394 | } else { |
| 395 | // Declare variable holding addresses taken from closure |
| 396 | // and initialize in entry prologue. |
Matthew Dempsky | 8b3670f | 2015-03-06 12:02:24 -0800 | [diff] [blame] | 397 | addr = newname(Lookupf("&%s", v.Sym.Name)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 398 | addr.Ntype = Nod(OIND, typenod(v.Type), nil) |
| 399 | addr.Class = PAUTO |
Dave Cheney | 44e9031 | 2015-03-06 21:18:41 +1100 | [diff] [blame] | 400 | addr.Used = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 401 | addr.Curfn = xfunc |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 402 | xfunc.Func.Dcl = list(xfunc.Func.Dcl, addr) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 403 | v.Heapaddr = addr |
Dave Cheney | b006d38 | 2015-03-06 18:42:58 +1100 | [diff] [blame] | 404 | if v.Byval { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 405 | 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 Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 413 | xfunc.Func.Enter = body |
| 414 | xfunc.Func.Needctxt = nvar > 0 |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 415 | } |
| 416 | |
| 417 | lineno = int32(lno) |
| 418 | } |
| 419 | |
| 420 | func walkclosure(func_ *Node, init **NodeList) *Node { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 421 | // If no closure vars, don't bother wrapping. |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 422 | if func_.Func.Cvars == nil { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 423 | 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 Cox | f6791da | 2015-02-20 13:54:45 -0500 | [diff] [blame] | 431 | // clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s} |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 432 | // |
| 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 440 | typ := Nod(OTSTRUCT, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 441 | |
Russ Cox | f6791da | 2015-02-20 13:54:45 -0500 | [diff] [blame] | 442 | typ.List = list1(Nod(ODCLFIELD, newname(Lookup(".F")), typenod(Types[TUINTPTR]))) |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 443 | var typ1 *Node |
| 444 | var v *Node |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 445 | for l := func_.Func.Cvars; l != nil; l = l.Next { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 446 | v = l.N |
| 447 | if v.Op == OXXX { |
| 448 | continue |
| 449 | } |
| 450 | typ1 = typenod(v.Type) |
Dave Cheney | b006d38 | 2015-03-06 18:42:58 +1100 | [diff] [blame] | 451 | if !v.Byval { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 452 | typ1 = Nod(OIND, typ1, nil) |
| 453 | } |
| 454 | typ.List = list(typ.List, Nod(ODCLFIELD, newname(v.Sym), typ1)) |
| 455 | } |
| 456 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 457 | clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 458 | clos.Esc = func_.Esc |
Dave Cheney | 44e9031 | 2015-03-06 21:18:41 +1100 | [diff] [blame] | 459 | clos.Right.Implicit = true |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 460 | clos.List = concat(list1(Nod(OCFUNC, func_.Closure.Nname, nil)), func_.Func.Enter) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 461 | |
| 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 | |
| 487 | func typecheckpartialcall(fn *Node, sym *Node) { |
| 488 | switch fn.Op { |
Josh Bleecher Snyder | b09925b | 2015-04-01 09:38:44 -0700 | [diff] [blame] | 489 | case ODOTINTER, ODOTMETH: |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 490 | 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 | |
| 504 | var makepartialcall_gopkg *Pkg |
| 505 | |
| 506 | func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 507 | var p string |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 508 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 509 | rcvrtype := fn.Left.Type |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 510 | if exportname(meth.Sym.Name) { |
Russ Cox | f6791da | 2015-02-20 13:54:45 -0500 | [diff] [blame] | 511 | p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, obj.FmtLeft|obj.FmtShort), meth.Sym.Name) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 512 | } else { |
Russ Cox | f6791da | 2015-02-20 13:54:45 -0500 | [diff] [blame] | 513 | p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, obj.FmtLeft|obj.FmtShort), Sconv(meth.Sym, obj.FmtLeft)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 514 | } |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 515 | basetype := rcvrtype |
Josh Bleecher Snyder | 25da594 | 2015-03-01 07:54:01 +0000 | [diff] [blame] | 516 | if Isptr[rcvrtype.Etype] { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 517 | 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 Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 523 | var spkg *Pkg |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 524 | if basetype.Sym != nil { |
| 525 | spkg = basetype.Sym.Pkg |
| 526 | } |
| 527 | if spkg == nil { |
| 528 | if makepartialcall_gopkg == nil { |
Russ Cox | bed1f90 | 2015-03-02 16:03:26 -0500 | [diff] [blame] | 529 | makepartialcall_gopkg = mkpkg("go") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 530 | } |
| 531 | spkg = makepartialcall_gopkg |
| 532 | } |
| 533 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 534 | sym := Pkglookup(p, spkg) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 535 | |
| 536 | if sym.Flags&SymUniq != 0 { |
| 537 | return sym.Def |
| 538 | } |
| 539 | sym.Flags |= SymUniq |
| 540 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 541 | savecurfn := Curfn |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 542 | Curfn = nil |
| 543 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 544 | xtype := Nod(OTFUNC, nil, nil) |
| 545 | i := 0 |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 546 | var l *NodeList |
| 547 | var callargs *NodeList |
Dave Cheney | d328756 | 2015-03-09 16:24:07 +1100 | [diff] [blame] | 548 | ddd := false |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 549 | xfunc := Nod(ODCLFUNC, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 550 | Curfn = xfunc |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 551 | var fld *Node |
| 552 | var n *Node |
| 553 | for t := getinargx(t0).Type; t != nil; t = t.Down { |
Matthew Dempsky | 8b3670f | 2015-03-06 12:02:24 -0800 | [diff] [blame] | 554 | n = newname(Lookupf("a%d", i)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 555 | i++ |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 556 | n.Class = PPARAM |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 557 | xfunc.Func.Dcl = list(xfunc.Func.Dcl, n) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 558 | callargs = list(callargs, n) |
| 559 | fld = Nod(ODCLFIELD, n, typenod(t.Type)) |
Dave Cheney | d328756 | 2015-03-09 16:24:07 +1100 | [diff] [blame] | 560 | if t.Isddd { |
| 561 | fld.Isddd = true |
| 562 | ddd = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 563 | } |
| 564 | |
| 565 | l = list(l, fld) |
| 566 | } |
| 567 | |
| 568 | xtype.List = l |
| 569 | i = 0 |
| 570 | l = nil |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 571 | var retargs *NodeList |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 572 | for t := getoutargx(t0).Type; t != nil; t = t.Down { |
Matthew Dempsky | 8b3670f | 2015-03-06 12:02:24 -0800 | [diff] [blame] | 573 | n = newname(Lookupf("r%d", i)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 574 | i++ |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 575 | n.Class = PPARAMOUT |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 576 | xfunc.Func.Dcl = list(xfunc.Func.Dcl, n) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 577 | retargs = list(retargs, n) |
| 578 | l = list(l, Nod(ODCLFIELD, n, typenod(t.Type))) |
| 579 | } |
| 580 | |
| 581 | xtype.Rlist = l |
| 582 | |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 583 | xfunc.Func.Dupok = true |
Josh Bleecher Snyder | 57279ba | 2015-03-10 21:37:13 -0700 | [diff] [blame] | 584 | xfunc.Nname = newfuncname(sym) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 585 | 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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 591 | |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 592 | xfunc.Func.Needctxt = true |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 593 | cv := Nod(OCLOSUREVAR, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 594 | cv.Xoffset = int64(Widthptr) |
| 595 | cv.Type = rcvrtype |
| 596 | if int(cv.Type.Align) > Widthptr { |
| 597 | cv.Xoffset = int64(cv.Type.Align) |
| 598 | } |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 599 | ptr := Nod(ONAME, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 600 | ptr.Sym = Lookup("rcvr") |
| 601 | ptr.Class = PAUTO |
Josh Bleecher Snyder | 75883ba | 2015-04-02 19:58:37 -0700 | [diff] [blame] | 602 | ptr.Addable = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 603 | ptr.Ullman = 1 |
Dave Cheney | 44e9031 | 2015-03-06 21:18:41 +1100 | [diff] [blame] | 604 | ptr.Used = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 605 | ptr.Curfn = xfunc |
Josh Bleecher Snyder | 3ed9e4c | 2015-03-25 19:33:01 -0700 | [diff] [blame] | 606 | xfunc.Func.Dcl = list(xfunc.Func.Dcl, ptr) |
Russ Cox | 4492811 | 2015-03-02 20:34:22 -0500 | [diff] [blame] | 607 | var body *NodeList |
Josh Bleecher Snyder | 25da594 | 2015-03-01 07:54:01 +0000 | [diff] [blame] | 608 | if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 609 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 616 | call := Nod(OCALL, Nod(OXDOT, ptr, meth), nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 617 | call.List = callargs |
Dave Cheney | d328756 | 2015-03-09 16:24:07 +1100 | [diff] [blame] | 618 | call.Isddd = ddd |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 619 | if t0.Outtuple == 0 { |
| 620 | body = list(body, call) |
| 621 | } else { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 622 | n := Nod(OAS2, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 623 | 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 | |
| 640 | func walkpartialcall(n *Node, init **NodeList) *Node { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 641 | // 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 648 | if Isinter(n.Left.Type) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 649 | // 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 656 | typ := Nod(OTSTRUCT, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 657 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 660 | clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 661 | clos.Esc = n.Esc |
Dave Cheney | 44e9031 | 2015-03-06 21:18:41 +1100 | [diff] [blame] | 662 | clos.Right.Implicit = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 663 | 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 | } |