// 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 "go.h" /* * machine size and rounding * alignment is dictated around * the size of a pointer, set in belexinit * (see ../6g/align.c). */ static int defercalc; uint32 rnd(uint32 o, uint32 r) { if(maxround == 0) fatal("rnd"); if(r > maxround) r = maxround; if(r != 0) while(o%r != 0) o++; return o; } 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("widstruct: not TFIELD: %lT", f); if(f->type->etype != TFUNC) continue; f->width = o; o += widthptr; } } static uint32 arrayelemwidth(Type *t) { while(t->etype == TARRAY && t->bound >= 0) t = t->type; return t->width; } static uint32 widstruct(Type *t, uint32 o, int flag) { Type *f; int32 w, m; for(f=t->type; f!=T; f=f->down) { if(f->etype != TFIELD) fatal("widstruct: not TFIELD: %lT", f); dowidth(f->type); if(f->type->width < 0) fatal("invalid width %lld", f->type->width); w = f->type->width; m = arrayelemwidth(f->type); o = rnd(o, m); 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; } // final width is rounded if(flag) o = rnd(o, maxround); // 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; uint32 w; int lno; Type *t1; if(maxround == 0 || widthptr == 0) fatal("dowidth without betypeinit"); if(t == T) return; if(t->width > 0) return; if(t->width == -2) { lno = lineno; lineno = t->lineno; 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; 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: w = 8; break; case TPTR32: w = 4; checkwidth(t->type); break; case TPTR64: w = 8; checkwidth(t->type); break; case TDDD: w = 2*widthptr; break; case TINTER: // implemented as 2 pointers w = 2*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)"); break; case TMAP: // implemented as pointer w = widthptr; checkwidth(t->type); checkwidth(t->down); break; case TFORW: // should have been filled in 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; break; case TARRAY: if(t->type == T) break; if(t->bound >= 0) { dowidth(t->type); w = t->bound * t->type->width; if(w == 0) w = maxround; } else if(t->bound == -1) { w = sizeof_Array; checkwidth(t->type); } else fatal("dowidth %T", t); // probably [...]T break; case TSTRUCT: if(t->funarg) fatal("dowidth fn struct %T", t); w = widstruct(t, 0, 1); if(w == 0) w = maxround; 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(*getthis(t1), 0, 0); w = widstruct(*getinarg(t1), w, 1); w = widstruct(*getoutarg(t1), w, 1); t1->argwid = w; break; } t->width = 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) // 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; 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 = s; dowidth(t); types[etype] = t; s1->def = typenod(t); } Array_array = rnd(0, widthptr); Array_nel = rnd(Array_array+widthptr, types[TUINT32]->width); Array_cap = rnd(Array_nel+types[TUINT32]->width, types[TUINT32]->width); sizeof_Array = rnd(Array_cap+types[TUINT32]->width, maxround); // string is same as slice wo the cap sizeof_String = rnd(Array_nel+types[TUINT32]->width, maxround); dowidth(types[TSTRING]); dowidth(idealstring); } /* * compute total size of f's in/out arguments. */ int argsize(Type *t) { Iter save; Type *fp; int 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+7) & ~7; return w; }