github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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 for(l=func->cvars; l; l=l->next) { 165 v = l->n; 166 if(v->op == 0) 167 continue; 168 addr = nod(ONAME, N, N); 169 p = smprint("&%s", v->sym->name); 170 addr->sym = lookup(p); 171 free(p); 172 addr->ntype = nod(OIND, typenod(v->type), N); 173 addr->class = PAUTO; 174 addr->addable = 1; 175 addr->ullman = 1; 176 addr->used = 1; 177 addr->curfn = xfunc; 178 xfunc->dcl = list(xfunc->dcl, addr); 179 v->heapaddr = addr; 180 cv = nod(OCLOSUREVAR, N, N); 181 cv->type = ptrto(v->type); 182 cv->xoffset = offset; 183 body = list(body, nod(OAS, addr, cv)); 184 offset += widthptr; 185 } 186 typechecklist(body, Etop); 187 walkstmtlist(body); 188 xfunc->enter = body; 189 190 xfunc->nbody = func->nbody; 191 xfunc->dcl = concat(func->dcl, xfunc->dcl); 192 if(xfunc->nbody == nil) 193 fatal("empty body - won't generate any code"); 194 typecheck(&xfunc, Etop); 195 196 xfunc->closure = func; 197 func->closure = xfunc; 198 199 func->nbody = nil; 200 func->list = nil; 201 func->rlist = nil; 202 203 return xfunc; 204 } 205 206 Node* 207 walkclosure(Node *func, NodeList **init) 208 { 209 Node *clos, *typ; 210 NodeList *l; 211 char buf[20]; 212 int narg; 213 214 // If no closure vars, don't bother wrapping. 215 if(func->cvars == nil) 216 return func->closure->nname; 217 218 // Create closure in the form of a composite literal. 219 // supposing the closure captures an int i and a string s 220 // and has one float64 argument and no results, 221 // the generated code looks like: 222 // 223 // clos = &struct{F uintptr; A0 *int; A1 *string}{func·001, &i, &s} 224 // 225 // The use of the struct provides type information to the garbage 226 // collector so that it can walk the closure. We could use (in this case) 227 // [3]unsafe.Pointer instead, but that would leave the gc in the dark. 228 // The information appears in the binary in the form of type descriptors; 229 // the struct is unnamed so that closures in multiple packages with the 230 // same struct type can share the descriptor. 231 232 narg = 0; 233 typ = nod(OTSTRUCT, N, N); 234 typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR]))); 235 for(l=func->cvars; l; l=l->next) { 236 if(l->n->op == 0) 237 continue; 238 snprint(buf, sizeof buf, "A%d", narg++); 239 typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup(buf)), l->n->heapaddr->ntype)); 240 } 241 242 clos = nod(OCOMPLIT, N, nod(OIND, typ, N)); 243 clos->esc = func->esc; 244 clos->right->implicit = 1; 245 clos->list = concat(list1(nod(OCFUNC, func->closure->nname, N)), func->enter); 246 247 // Force type conversion from *struct to the func type. 248 clos = nod(OCONVNOP, clos, N); 249 clos->type = func->type; 250 251 typecheck(&clos, Erv); 252 // typecheck will insert a PTRLIT node under CONVNOP, 253 // tag it with escape analysis result. 254 clos->left->esc = func->esc; 255 walkexpr(&clos, init); 256 257 return clos; 258 } 259 260 static Node *makepartialcall(Node*, Type*, Node*); 261 262 void 263 typecheckpartialcall(Node *fn, Node *sym) 264 { 265 switch(fn->op) { 266 case ODOTINTER: 267 case ODOTMETH: 268 break; 269 default: 270 fatal("invalid typecheckpartialcall"); 271 } 272 273 // Create top-level function. 274 fn->nname = makepartialcall(fn, fn->type, sym); 275 fn->right = sym; 276 fn->op = OCALLPART; 277 fn->type = fn->nname->type; 278 } 279 280 static Node* 281 makepartialcall(Node *fn, Type *t0, Node *meth) 282 { 283 Node *ptr, *n, *fld, *call, *xtype, *xfunc, *cv, *savecurfn; 284 Type *rcvrtype, *basetype, *t; 285 NodeList *body, *l, *callargs, *retargs; 286 char *p; 287 Sym *sym; 288 Pkg *spkg; 289 static Pkg* gopkg; 290 int i, ddd; 291 292 // TODO: names are not right 293 rcvrtype = fn->left->type; 294 if(exportname(meth->sym->name)) 295 p = smprint("%-hT.%s·fm", rcvrtype, meth->sym->name); 296 else 297 p = smprint("%-hT.(%-S)·fm", rcvrtype, meth->sym); 298 basetype = rcvrtype; 299 if(isptr[rcvrtype->etype]) 300 basetype = basetype->type; 301 if(basetype->etype != TINTER && basetype->sym == S) 302 fatal("missing base type for %T", rcvrtype); 303 304 spkg = nil; 305 if(basetype->sym != S) 306 spkg = basetype->sym->pkg; 307 if(spkg == nil) { 308 if(gopkg == nil) 309 gopkg = mkpkg(strlit("go")); 310 spkg = gopkg; 311 } 312 sym = pkglookup(p, spkg); 313 free(p); 314 if(sym->flags & SymUniq) 315 return sym->def; 316 sym->flags |= SymUniq; 317 318 savecurfn = curfn; 319 curfn = N; 320 321 xtype = nod(OTFUNC, N, N); 322 i = 0; 323 l = nil; 324 callargs = nil; 325 ddd = 0; 326 xfunc = nod(ODCLFUNC, N, N); 327 curfn = xfunc; 328 for(t = getinargx(t0)->type; t; t = t->down) { 329 snprint(namebuf, sizeof namebuf, "a%d", i++); 330 n = newname(lookup(namebuf)); 331 n->class = PPARAM; 332 xfunc->dcl = list(xfunc->dcl, n); 333 callargs = list(callargs, n); 334 fld = nod(ODCLFIELD, n, typenod(t->type)); 335 if(t->isddd) { 336 fld->isddd = 1; 337 ddd = 1; 338 } 339 l = list(l, fld); 340 } 341 xtype->list = l; 342 i = 0; 343 l = nil; 344 retargs = nil; 345 for(t = getoutargx(t0)->type; t; t = t->down) { 346 snprint(namebuf, sizeof namebuf, "r%d", i++); 347 n = newname(lookup(namebuf)); 348 n->class = PPARAMOUT; 349 xfunc->dcl = list(xfunc->dcl, n); 350 retargs = list(retargs, n); 351 l = list(l, nod(ODCLFIELD, n, typenod(t->type))); 352 } 353 xtype->rlist = l; 354 355 xfunc->dupok = 1; 356 xfunc->nname = newname(sym); 357 xfunc->nname->sym->flags |= SymExported; // disable export 358 xfunc->nname->ntype = xtype; 359 xfunc->nname->defn = xfunc; 360 declare(xfunc->nname, PFUNC); 361 362 // Declare and initialize variable holding receiver. 363 body = nil; 364 cv = nod(OCLOSUREVAR, N, N); 365 cv->xoffset = widthptr; 366 cv->type = rcvrtype; 367 ptr = nod(ONAME, N, N); 368 ptr->sym = lookup("rcvr"); 369 ptr->class = PAUTO; 370 ptr->addable = 1; 371 ptr->ullman = 1; 372 ptr->used = 1; 373 ptr->curfn = xfunc; 374 xfunc->dcl = list(xfunc->dcl, ptr); 375 if(isptr[rcvrtype->etype] || isinter(rcvrtype)) { 376 ptr->ntype = typenod(rcvrtype); 377 body = list(body, nod(OAS, ptr, cv)); 378 } else { 379 ptr->ntype = typenod(ptrto(rcvrtype)); 380 body = list(body, nod(OAS, ptr, nod(OADDR, cv, N))); 381 } 382 383 call = nod(OCALL, nod(OXDOT, ptr, meth), N); 384 call->list = callargs; 385 call->isddd = ddd; 386 if(t0->outtuple == 0) { 387 body = list(body, call); 388 } else { 389 n = nod(OAS2, N, N); 390 n->list = retargs; 391 n->rlist = list1(call); 392 body = list(body, n); 393 n = nod(ORETURN, N, N); 394 body = list(body, n); 395 } 396 397 xfunc->nbody = body; 398 399 typecheck(&xfunc, Etop); 400 sym->def = xfunc; 401 xtop = list(xtop, xfunc); 402 curfn = savecurfn; 403 404 return xfunc; 405 } 406 407 Node* 408 walkpartialcall(Node *n, NodeList **init) 409 { 410 Node *clos, *typ; 411 412 // Create closure in the form of a composite literal. 413 // For x.M with receiver (x) type T, the generated code looks like: 414 // 415 // clos = &struct{F uintptr; R T}{M.T·f, x} 416 // 417 // Like walkclosure above. 418 419 if(isinter(n->left->type)) { 420 // Trigger panic for method on nil interface now. 421 // Otherwise it happens in the wrapper and is confusing. 422 n->left = cheapexpr(n->left, init); 423 checknil(n->left, init); 424 } 425 426 typ = nod(OTSTRUCT, N, N); 427 typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR]))); 428 typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup("R")), typenod(n->left->type))); 429 430 clos = nod(OCOMPLIT, N, nod(OIND, typ, N)); 431 clos->esc = n->esc; 432 clos->right->implicit = 1; 433 clos->list = list1(nod(OCFUNC, n->nname->nname, N)); 434 clos->list = list(clos->list, n->left); 435 436 // Force type conversion from *struct to the func type. 437 clos = nod(OCONVNOP, clos, N); 438 clos->type = n->type; 439 440 typecheck(&clos, Erv); 441 // typecheck will insert a PTRLIT node under CONVNOP, 442 // tag it with escape analysis result. 443 clos->left->esc = n->esc; 444 walkexpr(&clos, init); 445 446 return clos; 447 }