github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/cmd/gc/closure.c (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 /* 6 * function literals aka closures 7 */ 8 9 #include <u.h> 10 #include <libc.h> 11 #include "go.h" 12 13 void 14 closurehdr(Node *ntype) 15 { 16 Node *n, *name, *a; 17 NodeList *l; 18 19 n = nod(OCLOSURE, N, N); 20 n->ntype = ntype; 21 n->funcdepth = funcdepth; 22 23 funchdr(n); 24 25 // steal ntype's argument names and 26 // leave a fresh copy in their place. 27 // references to these variables need to 28 // refer to the variables in the external 29 // function declared below; see walkclosure. 30 n->list = ntype->list; 31 n->rlist = ntype->rlist; 32 ntype->list = nil; 33 ntype->rlist = nil; 34 for(l=n->list; l; l=l->next) { 35 name = l->n->left; 36 if(name) 37 name = newname(name->sym); 38 a = nod(ODCLFIELD, name, l->n->right); 39 a->isddd = l->n->isddd; 40 if(name) 41 name->isddd = a->isddd; 42 ntype->list = list(ntype->list, a); 43 } 44 for(l=n->rlist; l; l=l->next) { 45 name = l->n->left; 46 if(name) 47 name = newname(name->sym); 48 ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, name, l->n->right)); 49 } 50 } 51 52 Node* 53 closurebody(NodeList *body) 54 { 55 Node *func, *v; 56 NodeList *l; 57 58 if(body == nil) 59 body = list1(nod(OEMPTY, N, N)); 60 61 func = curfn; 62 func->nbody = body; 63 func->endlineno = lineno; 64 funcbody(func); 65 66 // closure-specific variables are hanging off the 67 // ordinary ones in the symbol table; see oldname. 68 // unhook them. 69 // make the list of pointers for the closure call. 70 for(l=func->cvars; l; l=l->next) { 71 v = l->n; 72 v->closure->closure = v->outer; 73 v->heapaddr = nod(OADDR, oldname(v->sym), N); 74 } 75 76 return func; 77 } 78 79 static Node* makeclosure(Node *func); 80 81 void 82 typecheckclosure(Node *func, int top) 83 { 84 Node *oldfn; 85 NodeList *l; 86 Node *v; 87 88 oldfn = curfn; 89 typecheck(&func->ntype, Etype); 90 func->type = func->ntype->type; 91 92 // Type check the body now, but only if we're inside a function. 93 // At top level (in a variable initialization: curfn==nil) we're not 94 // ready to type check code yet; we'll check it later, because the 95 // underlying closure function we create is added to xtop. 96 if(curfn && func->type != T) { 97 curfn = func; 98 typechecklist(func->nbody, Etop); 99 curfn = oldfn; 100 } 101 102 // type check the & of closed variables outside the closure, 103 // so that the outer frame also grabs them and knows they 104 // escape. 105 func->enter = nil; 106 for(l=func->cvars; l; l=l->next) { 107 v = l->n; 108 if(v->type == T) { 109 // if v->type is nil, it means v looked like it was 110 // going to be used in the closure but wasn't. 111 // this happens because when parsing a, b, c := f() 112 // the a, b, c gets parsed as references to older 113 // a, b, c before the parser figures out this is a 114 // declaration. 115 v->op = 0; 116 continue; 117 } 118 // For a closure that is called in place, but not 119 // inside a go statement, avoid moving variables to the heap. 120 if ((top & (Ecall|Eproc)) == Ecall) 121 v->heapaddr->etype = 1; 122 typecheck(&v->heapaddr, Erv); 123 func->enter = list(func->enter, v->heapaddr); 124 v->heapaddr = N; 125 } 126 127 // Create top-level function 128 xtop = list(xtop, makeclosure(func)); 129 } 130 131 static Node* 132 makeclosure(Node *func) 133 { 134 Node *xtype, *v, *addr, *xfunc, *cv; 135 NodeList *l, *body; 136 static int closgen; 137 char *p; 138 vlong offset; 139 140 /* 141 * wrap body in external function 142 * that begins by reading closure parameters. 143 */ 144 xtype = nod(OTFUNC, N, N); 145 xtype->list = func->list; 146 xtype->rlist = func->rlist; 147 148 // create the function 149 xfunc = nod(ODCLFUNC, N, N); 150 snprint(namebuf, sizeof namebuf, "func·%.3d", ++closgen); 151 xfunc->nname = newname(lookup(namebuf)); 152 xfunc->nname->sym->flags |= SymExported; // disable export 153 xfunc->nname->ntype = xtype; 154 xfunc->nname->defn = xfunc; 155 declare(xfunc->nname, PFUNC); 156 xfunc->nname->funcdepth = func->funcdepth; 157 xfunc->funcdepth = func->funcdepth; 158 xfunc->endlineno = func->endlineno; 159 160 // declare variables holding addresses taken from closure 161 // and initialize in entry prologue. 162 body = nil; 163 offset = widthptr; 164 xfunc->needctxt = func->cvars != nil; 165 for(l=func->cvars; l; l=l->next) { 166 v = l->n; 167 if(v->op == 0) 168 continue; 169 addr = nod(ONAME, N, N); 170 p = smprint("&%s", v->sym->name); 171 addr->sym = lookup(p); 172 free(p); 173 addr->ntype = nod(OIND, typenod(v->type), N); 174 addr->class = PAUTO; 175 addr->addable = 1; 176 addr->ullman = 1; 177 addr->used = 1; 178 addr->curfn = xfunc; 179 xfunc->dcl = list(xfunc->dcl, addr); 180 v->heapaddr = addr; 181 cv = nod(OCLOSUREVAR, N, N); 182 cv->type = ptrto(v->type); 183 cv->xoffset = offset; 184 body = list(body, nod(OAS, addr, cv)); 185 offset += widthptr; 186 } 187 typechecklist(body, Etop); 188 walkstmtlist(body); 189 xfunc->enter = body; 190 191 xfunc->nbody = func->nbody; 192 xfunc->dcl = concat(func->dcl, xfunc->dcl); 193 if(xfunc->nbody == nil) 194 fatal("empty body - won't generate any code"); 195 typecheck(&xfunc, Etop); 196 197 xfunc->closure = func; 198 func->closure = xfunc; 199 200 func->nbody = nil; 201 func->list = nil; 202 func->rlist = nil; 203 204 return xfunc; 205 } 206 207 Node* 208 walkclosure(Node *func, NodeList **init) 209 { 210 Node *clos, *typ; 211 NodeList *l; 212 char buf[20]; 213 int narg; 214 215 // If no closure vars, don't bother wrapping. 216 if(func->cvars == nil) 217 return func->closure->nname; 218 219 // Create closure in the form of a composite literal. 220 // supposing the closure captures an int i and a string s 221 // and has one float64 argument and no results, 222 // the generated code looks like: 223 // 224 // clos = &struct{F uintptr; A0 *int; A1 *string}{func·001, &i, &s} 225 // 226 // The use of the struct provides type information to the garbage 227 // collector so that it can walk the closure. We could use (in this case) 228 // [3]unsafe.Pointer instead, but that would leave the gc in the dark. 229 // The information appears in the binary in the form of type descriptors; 230 // the struct is unnamed so that closures in multiple packages with the 231 // same struct type can share the descriptor. 232 233 narg = 0; 234 typ = nod(OTSTRUCT, N, N); 235 typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR]))); 236 for(l=func->cvars; l; l=l->next) { 237 if(l->n->op == 0) 238 continue; 239 snprint(buf, sizeof buf, "A%d", narg++); 240 typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup(buf)), l->n->heapaddr->ntype)); 241 } 242 243 clos = nod(OCOMPLIT, N, nod(OIND, typ, N)); 244 clos->esc = func->esc; 245 clos->right->implicit = 1; 246 clos->list = concat(list1(nod(OCFUNC, func->closure->nname, N)), func->enter); 247 248 // Force type conversion from *struct to the func type. 249 clos = nod(OCONVNOP, clos, N); 250 clos->type = func->type; 251 252 typecheck(&clos, Erv); 253 // typecheck will insert a PTRLIT node under CONVNOP, 254 // tag it with escape analysis result. 255 clos->left->esc = func->esc; 256 // non-escaping temp to use, if any. 257 // orderexpr did not compute the type; fill it in now. 258 if(func->alloc != N) { 259 func->alloc->type = clos->left->left->type; 260 func->alloc->orig->type = func->alloc->type; 261 clos->left->right = func->alloc; 262 func->alloc = N; 263 } 264 walkexpr(&clos, init); 265 266 return clos; 267 } 268 269 static Node *makepartialcall(Node*, Type*, Node*); 270 271 void 272 typecheckpartialcall(Node *fn, Node *sym) 273 { 274 switch(fn->op) { 275 case ODOTINTER: 276 case ODOTMETH: 277 break; 278 default: 279 fatal("invalid typecheckpartialcall"); 280 } 281 282 // Create top-level function. 283 fn->nname = makepartialcall(fn, fn->type, sym); 284 fn->right = sym; 285 fn->op = OCALLPART; 286 fn->type = fn->nname->type; 287 } 288 289 static Node* 290 makepartialcall(Node *fn, Type *t0, Node *meth) 291 { 292 Node *ptr, *n, *fld, *call, *xtype, *xfunc, *cv, *savecurfn; 293 Type *rcvrtype, *basetype, *t; 294 NodeList *body, *l, *callargs, *retargs; 295 char *p; 296 Sym *sym; 297 Pkg *spkg; 298 static Pkg* gopkg; 299 int i, ddd; 300 301 // TODO: names are not right 302 rcvrtype = fn->left->type; 303 if(exportname(meth->sym->name)) 304 p = smprint("%-hT.%s·fm", rcvrtype, meth->sym->name); 305 else 306 p = smprint("%-hT.(%-S)·fm", rcvrtype, meth->sym); 307 basetype = rcvrtype; 308 if(isptr[rcvrtype->etype]) 309 basetype = basetype->type; 310 if(basetype->etype != TINTER && basetype->sym == S) 311 fatal("missing base type for %T", rcvrtype); 312 313 spkg = nil; 314 if(basetype->sym != S) 315 spkg = basetype->sym->pkg; 316 if(spkg == nil) { 317 if(gopkg == nil) 318 gopkg = mkpkg(strlit("go")); 319 spkg = gopkg; 320 } 321 sym = pkglookup(p, spkg); 322 free(p); 323 if(sym->flags & SymUniq) 324 return sym->def; 325 sym->flags |= SymUniq; 326 327 savecurfn = curfn; 328 curfn = N; 329 330 xtype = nod(OTFUNC, N, N); 331 i = 0; 332 l = nil; 333 callargs = nil; 334 ddd = 0; 335 xfunc = nod(ODCLFUNC, N, N); 336 curfn = xfunc; 337 for(t = getinargx(t0)->type; t; t = t->down) { 338 snprint(namebuf, sizeof namebuf, "a%d", i++); 339 n = newname(lookup(namebuf)); 340 n->class = PPARAM; 341 xfunc->dcl = list(xfunc->dcl, n); 342 callargs = list(callargs, n); 343 fld = nod(ODCLFIELD, n, typenod(t->type)); 344 if(t->isddd) { 345 fld->isddd = 1; 346 ddd = 1; 347 } 348 l = list(l, fld); 349 } 350 xtype->list = l; 351 i = 0; 352 l = nil; 353 retargs = nil; 354 for(t = getoutargx(t0)->type; t; t = t->down) { 355 snprint(namebuf, sizeof namebuf, "r%d", i++); 356 n = newname(lookup(namebuf)); 357 n->class = PPARAMOUT; 358 xfunc->dcl = list(xfunc->dcl, n); 359 retargs = list(retargs, n); 360 l = list(l, nod(ODCLFIELD, n, typenod(t->type))); 361 } 362 xtype->rlist = l; 363 364 xfunc->dupok = 1; 365 xfunc->nname = newname(sym); 366 xfunc->nname->sym->flags |= SymExported; // disable export 367 xfunc->nname->ntype = xtype; 368 xfunc->nname->defn = xfunc; 369 declare(xfunc->nname, PFUNC); 370 371 // Declare and initialize variable holding receiver. 372 body = nil; 373 xfunc->needctxt = 1; 374 cv = nod(OCLOSUREVAR, N, N); 375 cv->xoffset = widthptr; 376 cv->type = rcvrtype; 377 if(cv->type->align > widthptr) 378 cv->xoffset = cv->type->align; 379 ptr = nod(ONAME, N, N); 380 ptr->sym = lookup("rcvr"); 381 ptr->class = PAUTO; 382 ptr->addable = 1; 383 ptr->ullman = 1; 384 ptr->used = 1; 385 ptr->curfn = xfunc; 386 xfunc->dcl = list(xfunc->dcl, ptr); 387 if(isptr[rcvrtype->etype] || isinter(rcvrtype)) { 388 ptr->ntype = typenod(rcvrtype); 389 body = list(body, nod(OAS, ptr, cv)); 390 } else { 391 ptr->ntype = typenod(ptrto(rcvrtype)); 392 body = list(body, nod(OAS, ptr, nod(OADDR, cv, N))); 393 } 394 395 call = nod(OCALL, nod(OXDOT, ptr, meth), N); 396 call->list = callargs; 397 call->isddd = ddd; 398 if(t0->outtuple == 0) { 399 body = list(body, call); 400 } else { 401 n = nod(OAS2, N, N); 402 n->list = retargs; 403 n->rlist = list1(call); 404 body = list(body, n); 405 n = nod(ORETURN, N, N); 406 body = list(body, n); 407 } 408 409 xfunc->nbody = body; 410 411 typecheck(&xfunc, Etop); 412 sym->def = xfunc; 413 xtop = list(xtop, xfunc); 414 curfn = savecurfn; 415 416 return xfunc; 417 } 418 419 Node* 420 walkpartialcall(Node *n, NodeList **init) 421 { 422 Node *clos, *typ; 423 424 // Create closure in the form of a composite literal. 425 // For x.M with receiver (x) type T, the generated code looks like: 426 // 427 // clos = &struct{F uintptr; R T}{M.T·f, x} 428 // 429 // Like walkclosure above. 430 431 if(isinter(n->left->type)) { 432 // Trigger panic for method on nil interface now. 433 // Otherwise it happens in the wrapper and is confusing. 434 n->left = cheapexpr(n->left, init); 435 checknil(n->left, init); 436 } 437 438 typ = nod(OTSTRUCT, N, N); 439 typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR]))); 440 typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup("R")), typenod(n->left->type))); 441 442 clos = nod(OCOMPLIT, N, nod(OIND, typ, N)); 443 clos->esc = n->esc; 444 clos->right->implicit = 1; 445 clos->list = list1(nod(OCFUNC, n->nname->nname, N)); 446 clos->list = list(clos->list, n->left); 447 448 // Force type conversion from *struct to the func type. 449 clos = nod(OCONVNOP, clos, N); 450 clos->type = n->type; 451 452 typecheck(&clos, Erv); 453 // typecheck will insert a PTRLIT node under CONVNOP, 454 // tag it with escape analysis result. 455 clos->left->esc = n->esc; 456 // non-escaping temp to use, if any. 457 // orderexpr did not compute the type; fill it in now. 458 if(n->alloc != N) { 459 n->alloc->type = clos->left->left->type; 460 n->alloc->orig->type = n->alloc->type; 461 clos->left->right = n->alloc; 462 n->alloc = N; 463 } 464 walkexpr(&clos, init); 465 466 return clos; 467 }