github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/gc/pgen.c (about) 1 // Copyright 2011 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 // "Portable" code generation. 6 // Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h. 7 // Must code to the intersection of the three back ends. 8 9 #include <u.h> 10 #include <libc.h> 11 #include "gg.h" 12 #include "opt.h" 13 #include "../../pkg/runtime/funcdata.h" 14 15 enum { BitsPerPointer = 2 }; 16 17 static void allocauto(Prog* p); 18 static void dumpgcargs(Node*, Sym*); 19 static Bvec* dumpgclocals(Node*, Sym*); 20 21 void 22 compile(Node *fn) 23 { 24 Bvec *bv; 25 Plist *pl; 26 Node nod1, *n, *gcargsnod, *gclocalsnod; 27 Prog *ptxt, *p, *p1; 28 int32 lno; 29 Type *t; 30 Iter save; 31 vlong oldstksize; 32 NodeList *l; 33 Sym *gcargssym, *gclocalssym; 34 static int ngcargs, ngclocals; 35 36 if(newproc == N) { 37 newproc = sysfunc("newproc"); 38 deferproc = sysfunc("deferproc"); 39 deferreturn = sysfunc("deferreturn"); 40 panicindex = sysfunc("panicindex"); 41 panicslice = sysfunc("panicslice"); 42 throwreturn = sysfunc("throwreturn"); 43 } 44 45 lno = setlineno(fn); 46 47 if(fn->nbody == nil) { 48 if(pure_go || memcmp(fn->nname->sym->name, "init·", 6) == 0) 49 yyerror("missing function body", fn); 50 goto ret; 51 } 52 53 saveerrors(); 54 55 // set up domain for labels 56 clearlabels(); 57 58 curfn = fn; 59 dowidth(curfn->type); 60 61 if(curfn->type->outnamed) { 62 // add clearing of the output parameters 63 t = structfirst(&save, getoutarg(curfn->type)); 64 while(t != T) { 65 if(t->nname != N) { 66 n = nod(OAS, t->nname, N); 67 typecheck(&n, Etop); 68 curfn->nbody = concat(list1(n), curfn->nbody); 69 } 70 t = structnext(&save); 71 } 72 } 73 74 order(curfn); 75 if(nerrors != 0) 76 goto ret; 77 78 hasdefer = 0; 79 walk(curfn); 80 if(nerrors != 0) 81 goto ret; 82 if(flag_race) 83 racewalk(curfn); 84 if(nerrors != 0) 85 goto ret; 86 87 continpc = P; 88 breakpc = P; 89 90 pl = newplist(); 91 pl->name = curfn->nname; 92 93 setlineno(curfn); 94 95 nodconst(&nod1, types[TINT32], 0); 96 ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1); 97 if(fn->dupok) 98 ptxt->TEXTFLAG |= DUPOK; 99 if(fn->wrapper) 100 ptxt->TEXTFLAG |= WRAPPER; 101 102 // Clumsy but important. 103 // See test/recover.go for test cases and src/pkg/reflect/value.go 104 // for the actual functions being considered. 105 if(myimportpath != nil && strcmp(myimportpath, "reflect") == 0) { 106 if(strcmp(curfn->nname->sym->name, "callReflect") == 0 || strcmp(curfn->nname->sym->name, "callMethod") == 0) 107 ptxt->TEXTFLAG |= WRAPPER; 108 } 109 110 afunclit(&ptxt->from, curfn->nname); 111 112 ginit(); 113 114 snprint(namebuf, sizeof namebuf, "gcargs·%d", ngcargs++); 115 gcargssym = lookup(namebuf); 116 gcargsnod = newname(gcargssym); 117 gcargsnod->class = PEXTERN; 118 119 nodconst(&nod1, types[TINT32], FUNCDATA_GCArgs); 120 gins(AFUNCDATA, &nod1, gcargsnod); 121 122 snprint(namebuf, sizeof(namebuf), "gclocals·%d", ngclocals++); 123 gclocalssym = lookup(namebuf); 124 gclocalsnod = newname(gclocalssym); 125 gclocalsnod->class = PEXTERN; 126 127 nodconst(&nod1, types[TINT32], FUNCDATA_GCLocals); 128 gins(AFUNCDATA, &nod1, gclocalsnod); 129 130 for(t=curfn->paramfld; t; t=t->down) 131 gtrack(tracksym(t->type)); 132 133 for(l=fn->dcl; l; l=l->next) { 134 n = l->n; 135 if(n->op != ONAME) // might be OTYPE or OLITERAL 136 continue; 137 switch(n->class) { 138 case PAUTO: 139 case PPARAM: 140 case PPARAMOUT: 141 nodconst(&nod1, types[TUINTPTR], l->n->type->width); 142 p = gins(ATYPE, l->n, &nod1); 143 p->from.gotype = ngotype(l->n); 144 break; 145 } 146 } 147 148 genlist(curfn->enter); 149 150 retpc = nil; 151 if(hasdefer || curfn->exit) { 152 p1 = gjmp(nil); 153 retpc = gjmp(nil); 154 patch(p1, pc); 155 } 156 157 genlist(curfn->nbody); 158 gclean(); 159 checklabels(); 160 if(nerrors != 0) 161 goto ret; 162 if(curfn->endlineno) 163 lineno = curfn->endlineno; 164 165 if(curfn->type->outtuple != 0) 166 ginscall(throwreturn, 0); 167 168 if(retpc) 169 patch(retpc, pc); 170 ginit(); 171 if(hasdefer) 172 ginscall(deferreturn, 0); 173 if(curfn->exit) 174 genlist(curfn->exit); 175 gclean(); 176 if(nerrors != 0) 177 goto ret; 178 179 pc->as = ARET; // overwrite AEND 180 pc->lineno = lineno; 181 182 if(!debug['N'] || debug['R'] || debug['P']) { 183 regopt(ptxt); 184 nilopt(ptxt); 185 } 186 expandchecks(ptxt); 187 188 oldstksize = stksize; 189 allocauto(ptxt); 190 191 if(0) 192 print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize); 193 194 setlineno(curfn); 195 if((int64)stksize+maxarg > (1ULL<<31)) { 196 yyerror("stack frame too large (>2GB)"); 197 goto ret; 198 } 199 200 // Emit garbage collection symbols. 201 dumpgcargs(fn, gcargssym); 202 bv = dumpgclocals(curfn, gclocalssym); 203 204 defframe(ptxt, bv); 205 free(bv); 206 207 if(0) 208 frame(0); 209 210 ret: 211 lineno = lno; 212 } 213 214 static void 215 walktype1(Type *t, vlong *xoffset, Bvec *bv) 216 { 217 vlong fieldoffset, i, o; 218 Type *t1; 219 220 if(t->align > 0 && (*xoffset % t->align) != 0) 221 fatal("walktype1: invalid initial alignment, %T", t); 222 223 switch(t->etype) { 224 case TINT8: 225 case TUINT8: 226 case TINT16: 227 case TUINT16: 228 case TINT32: 229 case TUINT32: 230 case TINT64: 231 case TUINT64: 232 case TINT: 233 case TUINT: 234 case TUINTPTR: 235 case TBOOL: 236 case TFLOAT32: 237 case TFLOAT64: 238 case TCOMPLEX64: 239 case TCOMPLEX128: 240 *xoffset += t->width; 241 break; 242 243 case TPTR32: 244 case TPTR64: 245 case TUNSAFEPTR: 246 case TFUNC: 247 case TCHAN: 248 case TMAP: 249 if(*xoffset % widthptr != 0) 250 fatal("walktype1: invalid alignment, %T", t); 251 bvset(bv, (*xoffset / widthptr) * BitsPerPointer); 252 *xoffset += t->width; 253 break; 254 255 case TSTRING: 256 // struct { byte *str; intgo len; } 257 if(*xoffset % widthptr != 0) 258 fatal("walktype1: invalid alignment, %T", t); 259 bvset(bv, (*xoffset / widthptr) * BitsPerPointer); 260 *xoffset += t->width; 261 break; 262 263 case TINTER: 264 // struct { Itab* tab; union { void* ptr, uintptr val } data; } 265 // or, when isnilinter(t)==true: 266 // struct { Type* type; union { void* ptr, uintptr val } data; } 267 if(*xoffset % widthptr != 0) 268 fatal("walktype1: invalid alignment, %T", t); 269 bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 1); 270 if(isnilinter(t)) 271 bvset(bv, ((*xoffset / widthptr) * BitsPerPointer)); 272 *xoffset += t->width; 273 break; 274 275 case TARRAY: 276 // The value of t->bound is -1 for slices types and >0 for 277 // for fixed array types. All other values are invalid. 278 if(t->bound < -1) 279 fatal("walktype1: invalid bound, %T", t); 280 if(isslice(t)) { 281 // struct { byte* array; uintgo len; uintgo cap; } 282 if(*xoffset % widthptr != 0) 283 fatal("walktype1: invalid TARRAY alignment, %T", t); 284 bvset(bv, (*xoffset / widthptr) * BitsPerPointer); 285 *xoffset += t->width; 286 } else if(!haspointers(t->type)) 287 *xoffset += t->width; 288 else 289 for(i = 0; i < t->bound; ++i) 290 walktype1(t->type, xoffset, bv); 291 break; 292 293 case TSTRUCT: 294 o = 0; 295 for(t1 = t->type; t1 != T; t1 = t1->down) { 296 fieldoffset = t1->width; 297 *xoffset += fieldoffset - o; 298 walktype1(t1->type, xoffset, bv); 299 o = fieldoffset + t1->type->width; 300 } 301 *xoffset += t->width - o; 302 break; 303 304 default: 305 fatal("walktype1: unexpected type, %T", t); 306 } 307 } 308 309 static void 310 walktype(Type *type, Bvec *bv) 311 { 312 vlong xoffset; 313 314 // Start the walk at offset 0. The correct offset will be 315 // filled in by the first type encountered during the walk. 316 xoffset = 0; 317 walktype1(type, &xoffset, bv); 318 } 319 320 // Compute a bit vector to describe the pointer-containing locations 321 // in the in and out argument list and dump the bitvector length and 322 // data to the provided symbol. 323 static void 324 dumpgcargs(Node *fn, Sym *sym) 325 { 326 Type *thistype, *inargtype, *outargtype; 327 Bvec *bv; 328 int32 i; 329 int off; 330 331 thistype = getthisx(fn->type); 332 inargtype = getinargx(fn->type); 333 outargtype = getoutargx(fn->type); 334 bv = bvalloc((fn->type->argwid / widthptr) * BitsPerPointer); 335 if(thistype != nil) 336 walktype(thistype, bv); 337 if(inargtype != nil) 338 walktype(inargtype, bv); 339 if(outargtype != nil) 340 walktype(outargtype, bv); 341 off = duint32(sym, 0, bv->n); 342 for(i = 0; i < bv->n; i += 32) 343 off = duint32(sym, off, bv->b[i/32]); 344 free(bv); 345 ggloblsym(sym, off, 0, 1); 346 } 347 348 // Compute a bit vector to describe the pointer-containing locations 349 // in local variables and dump the bitvector length and data out to 350 // the provided symbol. Return the vector for use and freeing by caller. 351 static Bvec* 352 dumpgclocals(Node* fn, Sym *sym) 353 { 354 Bvec *bv; 355 NodeList *ll; 356 Node *node; 357 vlong xoffset; 358 int32 i; 359 int off; 360 361 bv = bvalloc((stkptrsize / widthptr) * BitsPerPointer); 362 for(ll = fn->dcl; ll != nil; ll = ll->next) { 363 node = ll->n; 364 if(node->class == PAUTO && node->op == ONAME) { 365 if(haspointers(node->type)) { 366 xoffset = node->xoffset + stkptrsize; 367 walktype1(node->type, &xoffset, bv); 368 } 369 } 370 } 371 off = duint32(sym, 0, bv->n); 372 for(i = 0; i < bv->n; i += 32) { 373 off = duint32(sym, off, bv->b[i/32]); 374 } 375 ggloblsym(sym, off, 0, 1); 376 return bv; 377 } 378 379 // Sort the list of stack variables. Autos after anything else, 380 // within autos, unused after used, within used, things with 381 // pointers first, zeroed things first, and then decreasing size. 382 // Because autos are laid out in decreasing addresses 383 // on the stack, pointers first, zeroed things first and decreasing size 384 // really means, in memory, things with pointers needing zeroing at 385 // the top of the stack and increasing in size. 386 // Non-autos sort on offset. 387 static int 388 cmpstackvar(Node *a, Node *b) 389 { 390 int ap, bp; 391 392 if (a->class != b->class) 393 return (a->class == PAUTO) ? +1 : -1; 394 if (a->class != PAUTO) { 395 if (a->xoffset < b->xoffset) 396 return -1; 397 if (a->xoffset > b->xoffset) 398 return +1; 399 return 0; 400 } 401 if ((a->used == 0) != (b->used == 0)) 402 return b->used - a->used; 403 404 ap = haspointers(a->type); 405 bp = haspointers(b->type); 406 if(ap != bp) 407 return bp - ap; 408 409 ap = a->needzero; 410 bp = b->needzero; 411 if(ap != bp) 412 return bp - ap; 413 414 if(a->type->width < b->type->width) 415 return +1; 416 if(a->type->width > b->type->width) 417 return -1; 418 return 0; 419 } 420 421 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from. 422 static void 423 allocauto(Prog* ptxt) 424 { 425 NodeList *ll; 426 Node* n; 427 vlong w; 428 429 stksize = 0; 430 stkptrsize = 0; 431 stkzerosize = 0; 432 433 if(curfn->dcl == nil) 434 return; 435 436 // Mark the PAUTO's unused. 437 for(ll=curfn->dcl; ll != nil; ll=ll->next) 438 if (ll->n->class == PAUTO) 439 ll->n->used = 0; 440 441 markautoused(ptxt); 442 443 if(precisestack_enabled) { 444 // TODO: Remove when liveness analysis sets needzero instead. 445 for(ll=curfn->dcl; ll != nil; ll=ll->next) 446 if(ll->n->class == PAUTO) 447 ll->n->needzero = 1; // ll->n->addrtaken; 448 } 449 450 listsort(&curfn->dcl, cmpstackvar); 451 452 // Unused autos are at the end, chop 'em off. 453 ll = curfn->dcl; 454 n = ll->n; 455 if (n->class == PAUTO && n->op == ONAME && !n->used) { 456 // No locals used at all 457 curfn->dcl = nil; 458 fixautoused(ptxt); 459 return; 460 } 461 462 for(ll = curfn->dcl; ll->next != nil; ll=ll->next) { 463 n = ll->next->n; 464 if (n->class == PAUTO && n->op == ONAME && !n->used) { 465 ll->next = nil; 466 curfn->dcl->end = ll; 467 break; 468 } 469 } 470 471 // Reassign stack offsets of the locals that are still there. 472 for(ll = curfn->dcl; ll != nil; ll=ll->next) { 473 n = ll->n; 474 if (n->class != PAUTO || n->op != ONAME) 475 continue; 476 477 dowidth(n->type); 478 w = n->type->width; 479 if(w >= MAXWIDTH || w < 0) 480 fatal("bad width"); 481 stksize += w; 482 stksize = rnd(stksize, n->type->align); 483 if(haspointers(n->type)) { 484 stkptrsize = stksize; 485 if(n->needzero) 486 stkzerosize = stksize; 487 } 488 if(thechar == '5') 489 stksize = rnd(stksize, widthptr); 490 if(stksize >= (1ULL<<31)) { 491 setlineno(curfn); 492 yyerror("stack frame too large (>2GB)"); 493 } 494 n->stkdelta = -stksize - n->xoffset; 495 } 496 stksize = rnd(stksize, widthptr); 497 stkptrsize = rnd(stkptrsize, widthptr); 498 stkzerosize = rnd(stkzerosize, widthptr); 499 500 fixautoused(ptxt); 501 502 // The debug information needs accurate offsets on the symbols. 503 for(ll = curfn->dcl; ll != nil; ll=ll->next) { 504 if (ll->n->class != PAUTO || ll->n->op != ONAME) 505 continue; 506 ll->n->xoffset += ll->n->stkdelta; 507 ll->n->stkdelta = 0; 508 } 509 } 510 511 static void movelargefn(Node*); 512 513 void 514 movelarge(NodeList *l) 515 { 516 for(; l; l=l->next) 517 if(l->n->op == ODCLFUNC) 518 movelargefn(l->n); 519 } 520 521 static void 522 movelargefn(Node *fn) 523 { 524 NodeList *l; 525 Node *n; 526 527 for(l=fn->dcl; l != nil; l=l->next) { 528 n = l->n; 529 if(n->class == PAUTO && n->type != T && n->type->width > MaxStackVarSize) 530 addrescapes(n); 531 } 532 } 533 534 void 535 cgen_checknil(Node *n) 536 { 537 Node reg; 538 539 if(disable_checknil) 540 return; 541 // Ideally we wouldn't see any TUINTPTR here, but we do. 542 if(n->type == T || (!isptr[n->type->etype] && n->type->etype != TUINTPTR && n->type->etype != TUNSAFEPTR)) { 543 dump("checknil", n); 544 fatal("bad checknil"); 545 } 546 if((thechar == '5' && n->op != OREGISTER) || !n->addable) { 547 regalloc(®, types[tptr], n); 548 cgen(n, ®); 549 gins(ACHECKNIL, ®, N); 550 regfree(®); 551 return; 552 } 553 gins(ACHECKNIL, n, N); 554 }