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(&reg, types[tptr], n);
   548  		cgen(n, &reg);
   549  		gins(ACHECKNIL, &reg, N);
   550  		regfree(&reg);
   551  		return;
   552  	}
   553  	gins(ACHECKNIL, n, N);
   554  }