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  }