github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/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 #include <u.h> 6 #include <libc.h> 7 #include "gg.h" 8 #include "opt.h" 9 10 static void allocauto(Prog* p); 11 12 void 13 compile(Node *fn) 14 { 15 Plist *pl; 16 Node nod1, *n; 17 Prog *plocals, *ptxt, *p, *p1; 18 int32 lno; 19 Type *t; 20 Iter save; 21 vlong oldstksize; 22 NodeList *l; 23 24 if(newproc == N) { 25 newproc = sysfunc("newproc"); 26 deferproc = sysfunc("deferproc"); 27 deferreturn = sysfunc("deferreturn"); 28 panicindex = sysfunc("panicindex"); 29 panicslice = sysfunc("panicslice"); 30 throwreturn = sysfunc("throwreturn"); 31 } 32 33 lno = setlineno(fn); 34 35 if(fn->nbody == nil) { 36 if(pure_go || memcmp(fn->nname->sym->name, "init·", 6) == 0) 37 yyerror("missing function body", fn); 38 goto ret; 39 } 40 41 saveerrors(); 42 43 // set up domain for labels 44 clearlabels(); 45 46 curfn = fn; 47 dowidth(curfn->type); 48 49 if(curfn->type->outnamed) { 50 // add clearing of the output parameters 51 t = structfirst(&save, getoutarg(curfn->type)); 52 while(t != T) { 53 if(t->nname != N) { 54 n = nod(OAS, t->nname, N); 55 typecheck(&n, Etop); 56 curfn->nbody = concat(list1(n), curfn->nbody); 57 } 58 t = structnext(&save); 59 } 60 } 61 62 order(curfn); 63 if(nerrors != 0) 64 goto ret; 65 66 hasdefer = 0; 67 walk(curfn); 68 if(nerrors != 0) 69 goto ret; 70 if(flag_race) 71 racewalk(curfn); 72 if(nerrors != 0) 73 goto ret; 74 75 continpc = P; 76 breakpc = P; 77 78 pl = newplist(); 79 pl->name = curfn->nname; 80 81 setlineno(curfn); 82 83 nodconst(&nod1, types[TINT32], 0); 84 ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1); 85 if(fn->dupok) 86 ptxt->TEXTFLAG = DUPOK; 87 afunclit(&ptxt->from, curfn->nname); 88 89 ginit(); 90 91 plocals = gins(ALOCALS, N, N); 92 93 for(t=curfn->paramfld; t; t=t->down) 94 gtrack(tracksym(t->type)); 95 96 for(l=fn->dcl; l; l=l->next) { 97 n = l->n; 98 if(n->op != ONAME) // might be OTYPE or OLITERAL 99 continue; 100 switch(n->class) { 101 case PAUTO: 102 case PPARAM: 103 case PPARAMOUT: 104 nodconst(&nod1, types[TUINTPTR], l->n->type->width); 105 p = gins(ATYPE, l->n, &nod1); 106 p->from.gotype = ngotype(l->n); 107 break; 108 } 109 } 110 111 genlist(curfn->enter); 112 113 retpc = nil; 114 if(hasdefer || curfn->exit) { 115 p1 = gjmp(nil); 116 retpc = gjmp(nil); 117 patch(p1, pc); 118 } 119 120 genlist(curfn->nbody); 121 gclean(); 122 checklabels(); 123 if(nerrors != 0) 124 goto ret; 125 if(curfn->endlineno) 126 lineno = curfn->endlineno; 127 128 if(curfn->type->outtuple != 0) 129 ginscall(throwreturn, 0); 130 131 if(retpc) 132 patch(retpc, pc); 133 ginit(); 134 if(hasdefer) 135 ginscall(deferreturn, 0); 136 if(curfn->exit) 137 genlist(curfn->exit); 138 gclean(); 139 if(nerrors != 0) 140 goto ret; 141 142 pc->as = ARET; // overwrite AEND 143 pc->lineno = lineno; 144 145 if(!debug['N'] || debug['R'] || debug['P']) { 146 regopt(ptxt); 147 } 148 149 oldstksize = stksize; 150 allocauto(ptxt); 151 152 plocals->to.type = D_CONST; 153 plocals->to.offset = stksize; 154 155 if(0) 156 print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize); 157 158 setlineno(curfn); 159 if((int64)stksize+maxarg > (1ULL<<31)) 160 yyerror("stack frame too large (>2GB)"); 161 162 defframe(ptxt); 163 164 if(0) 165 frame(0); 166 167 ret: 168 lineno = lno; 169 } 170 171 172 // Sort the list of stack variables. autos after anything else, 173 // within autos, unused after used, and within used on reverse alignment. 174 // non-autos sort on offset. 175 static int 176 cmpstackvar(Node *a, Node *b) 177 { 178 if (a->class != b->class) 179 return (a->class == PAUTO) ? 1 : -1; 180 if (a->class != PAUTO) { 181 if (a->xoffset < b->xoffset) 182 return -1; 183 if (a->xoffset > b->xoffset) 184 return 1; 185 return 0; 186 } 187 if ((a->used == 0) != (b->used == 0)) 188 return b->used - a->used; 189 return b->type->align - a->type->align; 190 191 } 192 193 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from. 194 static void 195 allocauto(Prog* ptxt) 196 { 197 NodeList *ll; 198 Node* n; 199 vlong w; 200 201 if(curfn->dcl == nil) 202 return; 203 204 // Mark the PAUTO's unused. 205 for(ll=curfn->dcl; ll != nil; ll=ll->next) 206 if (ll->n->class == PAUTO) 207 ll->n->used = 0; 208 209 markautoused(ptxt); 210 211 listsort(&curfn->dcl, cmpstackvar); 212 213 // Unused autos are at the end, chop 'em off. 214 ll = curfn->dcl; 215 n = ll->n; 216 if (n->class == PAUTO && n->op == ONAME && !n->used) { 217 // No locals used at all 218 curfn->dcl = nil; 219 stksize = 0; 220 fixautoused(ptxt); 221 return; 222 } 223 224 for(ll = curfn->dcl; ll->next != nil; ll=ll->next) { 225 n = ll->next->n; 226 if (n->class == PAUTO && n->op == ONAME && !n->used) { 227 ll->next = nil; 228 curfn->dcl->end = ll; 229 break; 230 } 231 } 232 233 // Reassign stack offsets of the locals that are still there. 234 stksize = 0; 235 for(ll = curfn->dcl; ll != nil; ll=ll->next) { 236 n = ll->n; 237 if (n->class != PAUTO || n->op != ONAME) 238 continue; 239 240 dowidth(n->type); 241 w = n->type->width; 242 if(w >= MAXWIDTH || w < 0) 243 fatal("bad width"); 244 stksize += w; 245 stksize = rnd(stksize, n->type->align); 246 if(thechar == '5') 247 stksize = rnd(stksize, widthptr); 248 if(stksize >= (1ULL<<31)) { 249 setlineno(curfn); 250 yyerror("stack frame too large (>2GB)"); 251 } 252 n->stkdelta = -stksize - n->xoffset; 253 } 254 255 fixautoused(ptxt); 256 257 // The debug information needs accurate offsets on the symbols. 258 for(ll = curfn->dcl ;ll != nil; ll=ll->next) { 259 if (ll->n->class != PAUTO || ll->n->op != ONAME) 260 continue; 261 ll->n->xoffset += ll->n->stkdelta; 262 ll->n->stkdelta = 0; 263 } 264 }