// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #include #include #include "go.h" /* * machine size and rounding * alignment is dictated around * the size of a pointer, set in betypeinit * (see ../6g/galign.c). */ static int defercalc; vlong rnd(vlong o, vlong r) { if(r < 1 || r > 8 || (r&(r-1)) != 0) fatal("rnd"); return (o+r-1)&~(r-1); } static void offmod(Type *t) { Type *f; int32 o; o = 0; for(f=t->type; f!=T; f=f->down) { if(f->etype != TFIELD) fatal("offmod: not TFIELD: %lT", f); f->width = o; o += widthptr; if(o >= MAXWIDTH) { yyerror("interface too large"); o = widthptr; } } } static vlong widstruct(Type *errtype, Type *t, vlong o, int flag) { Type *f; int64 w; int32 maxalign; maxalign = flag; if(maxalign < 1) maxalign = 1; for(f=t->type; f!=T; f=f->down) { if(f->etype != TFIELD) fatal("widstruct: not TFIELD: %lT", f); if(f->type == T) { // broken field, just skip it so that other valid fields // get a width. continue; } dowidth(f->type); if(f->type->align > maxalign) maxalign = f->type->align; if(f->type->width < 0) fatal("invalid width %lld", f->type->width); w = f->type->width; if(f->type->align > 0) o = rnd(o, f->type->align); f->width = o; // really offset for TFIELD if(f->nname != N) { // this same stackparam logic is in addrescapes // in typecheck.c. usually addrescapes runs after // widstruct, in which case we could drop this, // but function closure functions are the exception. if(f->nname->stackparam) { f->nname->stackparam->xoffset = o; f->nname->xoffset = 0; } else f->nname->xoffset = o; } o += w; if(o >= MAXWIDTH) { yyerror("type %lT too large", errtype); o = 8; // small but nonzero } } // final width is rounded if(flag) o = rnd(o, maxalign); t->align = maxalign; // type width only includes back to first field's offset if(t->type == T) t->width = 0; else t->width = o - t->type->width; return o; } void dowidth(Type *t) { int32 et; int64 w; int lno; Type *t1; if(widthptr == 0) fatal("dowidth without betypeinit"); if(t == T) return; if(t->width > 0) return; if(t->width == -2) { lno = lineno; lineno = t->lineno; if(!t->broke) yyerror("invalid recursive type %T", t); t->width = 0; lineno = lno; return; } // defer checkwidth calls until after we're done defercalc++; lno = lineno; lineno = t->lineno; t->width = -2; t->align = 0; et = t->etype; switch(et) { case TFUNC: case TCHAN: case TMAP: case TSTRING: break; default: /* simtype == 0 during bootstrap */ if(simtype[t->etype] != 0) et = simtype[t->etype]; break; } w = 0; switch(et) { default: fatal("dowidth: unknown type: %T", t); break; /* compiler-specific stuff */ case TINT8: case TUINT8: case TBOOL: // bool is int8 w = 1; break; case TINT16: case TUINT16: w = 2; break; case TINT32: case TUINT32: case TFLOAT32: w = 4; break; case TINT64: case TUINT64: case TFLOAT64: case TCOMPLEX64: w = 8; t->align = widthreg; break; case TCOMPLEX128: w = 16; t->align = widthreg; break; case TPTR32: w = 4; checkwidth(t->type); break; case TPTR64: w = 8; checkwidth(t->type); break; case TUNSAFEPTR: w = widthptr; break; case TINTER: // implemented as 2 pointers w = 2*widthptr; t->align = widthptr; offmod(t); break; case TCHAN: // implemented as pointer w = widthptr; checkwidth(t->type); // make fake type to check later to // trigger channel argument check. t1 = typ(TCHANARGS); t1->type = t; checkwidth(t1); break; case TCHANARGS: t1 = t->type; dowidth(t->type); // just in case if(t1->type->width >= (1<<16)) yyerror("channel element type too large (>64kB)"); t->width = 1; break; case TMAP: // implemented as pointer w = widthptr; checkwidth(t->type); checkwidth(t->down); break; case TFORW: // should have been filled in if(!t->broke) yyerror("invalid recursive type %T", t); w = 1; // anything will do break; case TANY: // dummy type; should be replaced before use. if(!debug['A']) fatal("dowidth any"); w = 1; // anything will do break; case TSTRING: if(sizeof_String == 0) fatal("early dowidth string"); w = sizeof_String; t->align = widthptr; break; case TARRAY: if(t->type == T) break; if(t->bound >= 0) { uint64 cap; dowidth(t->type); if(t->type->width != 0) { cap = (MAXWIDTH-1) / t->type->width; if(t->bound > cap) yyerror("type %lT larger than address space", t); } w = t->bound * t->type->width; t->align = t->type->align; } else if(t->bound == -1) { w = sizeof_Array; checkwidth(t->type); t->align = widthptr; } else if(t->bound == -100) { if(!t->broke) { yyerror("use of [...] array outside of array literal"); t->broke = 1; } } else fatal("dowidth %T", t); // probably [...]T break; case TSTRUCT: if(t->funarg) fatal("dowidth fn struct %T", t); w = widstruct(t, t, 0, 1); break; case TFUNC: // make fake type to check later to // trigger function argument computation. t1 = typ(TFUNCARGS); t1->type = t; checkwidth(t1); // width of func type is pointer w = widthptr; break; case TFUNCARGS: // function is 3 cated structures; // compute their widths as side-effect. t1 = t->type; w = widstruct(t->type, *getthis(t1), 0, 0); w = widstruct(t->type, *getinarg(t1), w, widthreg); w = widstruct(t->type, *getoutarg(t1), w, widthreg); t1->argwid = w; if(w%widthreg) warn("bad type %T %d\n", t1, w); t->align = 1; break; } if(widthptr == 4 && w != (int32)w) yyerror("type %T too large", t); t->width = w; if(t->align == 0) { if(w > 8 || (w&(w-1)) != 0) fatal("invalid alignment for %T", t); t->align = w; } lineno = lno; if(defercalc == 1) resumecheckwidth(); else --defercalc; } /* * when a type's width should be known, we call checkwidth * to compute it. during a declaration like * * type T *struct { next T } * * it is necessary to defer the calculation of the struct width * until after T has been initialized to be a pointer to that struct. * similarly, during import processing structs may be used * before their definition. in those situations, calling * defercheckwidth() stops width calculations until * resumecheckwidth() is called, at which point all the * checkwidths that were deferred are executed. * dowidth should only be called when the type's size * is needed immediately. checkwidth makes sure the * size is evaluated eventually. */ typedef struct TypeList TypeList; struct TypeList { Type *t; TypeList *next; }; static TypeList *tlfree; static TypeList *tlq; void checkwidth(Type *t) { TypeList *l; if(t == T) return; // function arg structs should not be checked // outside of the enclosing function. if(t->funarg) fatal("checkwidth %T", t); if(!defercalc) { dowidth(t); return; } if(t->deferwidth) return; t->deferwidth = 1; l = tlfree; if(l != nil) tlfree = l->next; else l = mal(sizeof *l); l->t = t; l->next = tlq; tlq = l; } void defercheckwidth(void) { // we get out of sync on syntax errors, so don't be pedantic. if(defercalc && nerrors == 0) fatal("defercheckwidth"); defercalc = 1; } void resumecheckwidth(void) { TypeList *l; if(!defercalc) fatal("resumecheckwidth"); for(l = tlq; l != nil; l = tlq) { l->t->deferwidth = 0; tlq = l->next; dowidth(l->t); l->next = tlfree; tlfree = l; } defercalc = 0; } void typeinit(void) { int i, etype, sameas; Type *t; Sym *s, *s1; if(widthptr == 0) fatal("typeinit before betypeinit"); for(i=0; isym = pkglookup("Pointer", unsafepkg); t->sym->def = typenod(t); dowidth(types[TUNSAFEPTR]); tptr = TPTR32; if(widthptr == 8) tptr = TPTR64; for(i=TINT8; i<=TUINT64; i++) isint[i] = 1; isint[TINT] = 1; isint[TUINT] = 1; isint[TUINTPTR] = 1; isfloat[TFLOAT32] = 1; isfloat[TFLOAT64] = 1; iscomplex[TCOMPLEX64] = 1; iscomplex[TCOMPLEX128] = 1; isptr[TPTR32] = 1; isptr[TPTR64] = 1; isforw[TFORW] = 1; issigned[TINT] = 1; issigned[TINT8] = 1; issigned[TINT16] = 1; issigned[TINT32] = 1; issigned[TINT64] = 1; /* * initialize okfor */ for(i=0; i= nelem(types)) fatal("typeinit: %s bad etype", s->name); sameas = typedefs[i].sameas; if(sameas < 0 || sameas >= nelem(types)) fatal("typeinit: %s bad sameas", s->name); simtype[etype] = sameas; minfltval[etype] = minfltval[sameas]; maxfltval[etype] = maxfltval[sameas]; minintval[etype] = minintval[sameas]; maxintval[etype] = maxintval[sameas]; t = types[etype]; if(t != T) fatal("typeinit: %s already defined", s->name); t = typ(etype); t->sym = s1; dowidth(t); types[etype] = t; s1->def = typenod(t); } Array_array = rnd(0, widthptr); Array_nel = rnd(Array_array+widthptr, widthint); Array_cap = rnd(Array_nel+widthint, widthint); sizeof_Array = rnd(Array_cap+widthint, widthptr); // string is same as slice wo the cap sizeof_String = rnd(Array_nel+widthint, widthptr); dowidth(types[TSTRING]); dowidth(idealstring); } /* * compute total size of f's in/out arguments. */ int argsize(Type *t) { Iter save; Type *fp; int64 w, x; w = 0; fp = structfirst(&save, getoutarg(t)); while(fp != T) { x = fp->width + fp->type->width; if(x > w) w = x; fp = structnext(&save); } fp = funcfirst(&save, t); while(fp != T) { x = fp->width + fp->type->width; if(x > w) w = x; fp = funcnext(&save); } w = (w+widthptr-1) & ~(widthptr-1); if((int)w != w) fatal("argsize too big"); return w; }