static void dumpglobls(void) { Node *n; NodeList *l; // add globals for(l=externdcl; l; l=l->next) { n = l->n; if(n->op != ONAME) continue; if(n->type == T) fatal("external %N nil type\n", n); if(n->class == PFUNC) continue; if(n->sym->pkg != localpkg) continue; dowidth(n->type); ggloblnod(n); } for(l=funcsyms; l; l=l->next) { n = l->n; dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0); ggloblsym(n->sym, widthptr, 1, 1); } // Do not reprocess funcsyms on next dumpglobls call. funcsyms = nil; }
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; }
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 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; }
static uint32 widstruct(Type *t, uint32 o, int flag) { Type *f; int32 w, 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); 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; } // 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; }
static void dumpglobls(void) { Node *n; NodeList *l; // add globals for(l=externdcl; l; l=l->next) { n = l->n; if(n->op != ONAME) continue; if(n->type == T) fatal("external %N nil type\n", n); if(n->class == PFUNC) continue; if(n->sym->pkg != localpkg) continue; dowidth(n->type); ggloblnod(n, n->type->width); } }
void dumpglobls(void) { Node *n; NodeList *l; // add globals for(l=externdcl; l; l=l->next) { n = l->n; if(n->op != ONAME) continue; if(n->type == T) fatal("external %#N nil type\n", n); if(n->class == PFUNC) continue; if(n->sym->pkg != localpkg) continue; dowidth(n->type); // TODO(rsc): why is this not s/n->sym->def/n/ ? ggloblnod(n->sym->def, n->type->width); } }
void typeinit(void) { int i, etype, sameas; Type *t; Sym *s, *s1; if(widthptr == 0) fatal("typeinit before betypeinit"); for(i=0; i<NTYPE; i++) simtype[i] = i; types[TPTR32] = typ(TPTR32); dowidth(types[TPTR32]); types[TPTR64] = typ(TPTR64); dowidth(types[TPTR64]); t = typ(TUNSAFEPTR); types[TUNSAFEPTR] = t; t->sym = 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<NTYPE; i++) { if(isint[i] || i == TIDEAL) { okforeq[i] = 1; okforcmp[i] = 1; okforarith[i] = 1; okforadd[i] = 1; okforand[i] = 1; okforconst[i] = 1; issimple[i] = 1; minintval[i] = mal(sizeof(*minintval[i])); maxintval[i] = mal(sizeof(*maxintval[i])); } if(isfloat[i]) { okforeq[i] = 1; okforcmp[i] = 1; okforadd[i] = 1; okforarith[i] = 1; okforconst[i] = 1; issimple[i] = 1; minfltval[i] = mal(sizeof(*minfltval[i])); maxfltval[i] = mal(sizeof(*maxfltval[i])); } if(iscomplex[i]) { okforeq[i] = 1; okforadd[i] = 1; okforarith[i] = 1; okforconst[i] = 1; issimple[i] = 1; } } issimple[TBOOL] = 1; okforadd[TSTRING] = 1; okforbool[TBOOL] = 1; okforcap[TARRAY] = 1; okforcap[TCHAN] = 1; okforconst[TBOOL] = 1; okforconst[TSTRING] = 1; okforlen[TARRAY] = 1; okforlen[TCHAN] = 1; okforlen[TMAP] = 1; okforlen[TSTRING] = 1; okforeq[TPTR32] = 1; okforeq[TPTR64] = 1; okforeq[TUNSAFEPTR] = 1; okforeq[TINTER] = 1; okforeq[TCHAN] = 1; okforeq[TSTRING] = 1; okforeq[TBOOL] = 1; okforeq[TMAP] = 1; // nil only; refined in typecheck okforeq[TFUNC] = 1; // nil only; refined in typecheck okforeq[TARRAY] = 1; // nil slice only; refined in typecheck okforeq[TSTRUCT] = 1; // it's complicated; refined in typecheck okforcmp[TSTRING] = 1; for(i=0; i<nelem(okfor); i++) okfor[i] = okfornone; // binary okfor[OADD] = okforadd; okfor[OAND] = okforand; okfor[OANDAND] = okforbool; okfor[OANDNOT] = okforand; okfor[ODIV] = okforarith; okfor[OEQ] = okforeq; okfor[OGE] = okforcmp; okfor[OGT] = okforcmp; okfor[OLE] = okforcmp; okfor[OLT] = okforcmp; okfor[OMOD] = okforand; okfor[OMUL] = okforarith; okfor[ONE] = okforeq; okfor[OOR] = okforand; okfor[OOROR] = okforbool; okfor[OSUB] = okforarith; okfor[OXOR] = okforand; okfor[OLSH] = okforand; okfor[ORSH] = okforand; // unary okfor[OCOM] = okforand; okfor[OMINUS] = okforarith; okfor[ONOT] = okforbool; okfor[OPLUS] = okforarith; // special okfor[OCAP] = okforcap; okfor[OLEN] = okforlen; // comparison iscmp[OLT] = 1; iscmp[OGT] = 1; iscmp[OGE] = 1; iscmp[OLE] = 1; iscmp[OEQ] = 1; iscmp[ONE] = 1; mpatofix(maxintval[TINT8], "0x7f"); mpatofix(minintval[TINT8], "-0x80"); mpatofix(maxintval[TINT16], "0x7fff"); mpatofix(minintval[TINT16], "-0x8000"); mpatofix(maxintval[TINT32], "0x7fffffff"); mpatofix(minintval[TINT32], "-0x80000000"); mpatofix(maxintval[TINT64], "0x7fffffffffffffff"); mpatofix(minintval[TINT64], "-0x8000000000000000"); mpatofix(maxintval[TUINT8], "0xff"); mpatofix(maxintval[TUINT16], "0xffff"); mpatofix(maxintval[TUINT32], "0xffffffff"); mpatofix(maxintval[TUINT64], "0xffffffffffffffff"); /* f is valid float if min < f < max. (min and max are not themselves valid.) */ mpatoflt(maxfltval[TFLOAT32], "33554431p103"); /* 2^24-1 p (127-23) + 1/2 ulp*/ mpatoflt(minfltval[TFLOAT32], "-33554431p103"); mpatoflt(maxfltval[TFLOAT64], "18014398509481983p970"); /* 2^53-1 p (1023-52) + 1/2 ulp */ mpatoflt(minfltval[TFLOAT64], "-18014398509481983p970"); maxfltval[TCOMPLEX64] = maxfltval[TFLOAT32]; minfltval[TCOMPLEX64] = minfltval[TFLOAT32]; maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64]; minfltval[TCOMPLEX128] = minfltval[TFLOAT64]; /* for walk to use in error messages */ types[TFUNC] = functype(N, nil, nil); /* types used in front end */ // types[TNIL] got set early in lexinit types[TIDEAL] = typ(TIDEAL); types[TINTER] = typ(TINTER); /* simple aliases */ simtype[TMAP] = tptr; simtype[TCHAN] = tptr; simtype[TFUNC] = tptr; simtype[TUNSAFEPTR] = tptr; /* pick up the backend typedefs */ for(i=0; typedefs[i].name; i++) { s = lookup(typedefs[i].name); s1 = pkglookup(typedefs[i].name, builtinpkg); etype = typedefs[i].etype; if(etype < 0 || etype >= 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); }
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; }
static void maplit(int ctxt, Node *n, Node *var, NodeList **init) { Node *r, *a; NodeList *l; int nerr, b; Type *t, *tk, *tv, *t1; Node *vstat, *index, *value; Sym *syma, *symb; ctxt = 0; // make the map var nerr = nerrors; a = nod(OMAKE, N, N); a->list = list1(typenod(n->type)); litas(var, a, init); // count the initializers b = 0; for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; if(isliteral(index) && isliteral(value)) b++; } t = T; if(b != 0) { // build type [count]struct { a Tindex, b Tvalue } t = n->type; tk = t->down; tv = t->type; symb = lookup("b"); t = typ(TFIELD); t->type = tv; t->sym = symb; syma = lookup("a"); t1 = t; t = typ(TFIELD); t->type = tk; t->sym = syma; t->down = t1; t1 = t; t = typ(TSTRUCT); t->type = t1; t1 = t; t = typ(TARRAY); t->bound = b; t->type = t1; dowidth(t); // make and initialize static array vstat = staticname(t, ctxt); b = 0; for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; if(isliteral(index) && isliteral(value)) { // build vstat[b].a = key; a = nodintconst(b); a = nod(OINDEX, vstat, a); a = nod(ODOT, a, newname(syma)); a = nod(OAS, a, index); typecheck(&a, Etop); walkexpr(&a, init); a->dodata = 2; *init = list(*init, a); // build vstat[b].b = value; a = nodintconst(b); a = nod(OINDEX, vstat, a); a = nod(ODOT, a, newname(symb)); a = nod(OAS, a, value); typecheck(&a, Etop); walkexpr(&a, init); a->dodata = 2; *init = list(*init, a); b++; } } // loop adding structure elements to map // for i = 0; i < len(vstat); i++ { // map[vstat[i].a] = vstat[i].b // } index = nod(OXXX, N, N); tempname(index, types[TINT]); a = nod(OINDEX, vstat, index); a->etype = 1; // no bounds checking a = nod(ODOT, a, newname(symb)); r = nod(OINDEX, vstat, index); r->etype = 1; // no bounds checking r = nod(ODOT, r, newname(syma)); r = nod(OINDEX, var, r); r = nod(OAS, r, a); a = nod(OFOR, N, N); a->nbody = list1(r); a->ninit = list1(nod(OAS, index, nodintconst(0))); a->ntest = nod(OLT, index, nodintconst(t->bound)); a->nincr = nod(OASOP, index, nodintconst(1)); a->nincr->etype = OADD; typecheck(&a, Etop); walkstmt(&a); *init = list(*init, a); } // put in dynamic entries one-at-a-time for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; if(isliteral(index) && isliteral(value)) continue; // build list of var[c] = expr a = nod(OINDEX, var, r->left); a = nod(OAS, a, r->right); typecheck(&a, Etop); walkexpr(&a, init); if(nerr != nerrors) break; *init = list(*init, a); } }
static void slicelit(int ctxt, Node *n, Node *var, NodeList **init) { Node *r, *a; NodeList *l; Type *t; Node *vstat, *vauto; Node *index, *value; int mode; // make an array type t = shallow(n->type); t->bound = mpgetfix(n->right->val.u.xval); t->width = 0; t->sym = nil; dowidth(t); if(ctxt != 0) { // put everything into static array vstat = staticname(t, ctxt); arraylit(ctxt, 1, n, vstat, init); arraylit(ctxt, 2, n, vstat, init); // copy static to slice a = nod(OSLICE, vstat, nod(OKEY, N, N)); a = nod(OAS, var, a); typecheck(&a, Etop); a->dodata = 2; *init = list(*init, a); return; } // recipe for var = []t{...} // 1. make a static array // var vstat [...]t // 2. assign (data statements) the constant part // vstat = constpart{} // 3. make an auto pointer to array and allocate heap to it // var vauto *[...]t = new([...]t) // 4. copy the static array to the auto array // *vauto = vstat // 5. assign slice of allocated heap to var // var = [0:]*auto // 6. for each dynamic part assign to the slice // var[i] = dynamic part // // an optimization is done if there is no constant part // 3. var vauto *[...]t = new([...]t) // 5. var = [0:]*auto // 6. var[i] = dynamic part // if the literal contains constants, // make static initialized array (1),(2) vstat = N; mode = getdyn(n, 1); if(mode & MODECONST) { vstat = staticname(t, ctxt); arraylit(ctxt, 1, n, vstat, init); } // make new auto *array (3 declare) vauto = nod(OXXX, N, N); tempname(vauto, ptrto(t)); // set auto to point at new heap (3 assign) a = nod(ONEW, N, N); a->list = list1(typenod(t)); a = nod(OAS, vauto, a); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); if(vstat != N) { // copy static to heap (4) a = nod(OIND, vauto, N); a = nod(OAS, a, vstat); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); } // make slice out of heap (5) a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N))); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); // put dynamics into slice (6) for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; a = nod(OINDEX, var, index); a->etype = 1; // no bounds checking // TODO need to check bounds? switch(value->op) { case OARRAYLIT: if(value->type->bound < 0) break; arraylit(ctxt, 2, value, a, init); continue; case OSTRUCTLIT: structlit(ctxt, 2, value, a, init); continue; } if(isliteral(index) && isliteral(value)) continue; // build list of var[c] = expr a = nod(OAS, a, value); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); } }
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); break; case TMAP: // implemented as pointer w = widthptr; checkwidth(t->type); checkwidth(t->down); break; case TFORW: // should have been filled in 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; }
void typeinit(void) { int i, etype, sameas; Type *t; Sym *s, *s1; if(widthptr == 0) fatal("typeinit before betypeinit"); for(i=0; i<NTYPE; i++) simtype[i] = i; types[TPTR32] = typ(TPTR32); dowidth(types[TPTR32]); types[TPTR64] = typ(TPTR64); dowidth(types[TPTR64]); 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; for(i=TFLOAT32; i<=TFLOAT64; i++) isfloat[i] = 1; isfloat[TFLOAT] = 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<NTYPE; i++) { if(isint[i] || i == TIDEAL) { okforeq[i] = 1; okforcmp[i] = 1; okforarith[i] = 1; okforadd[i] = 1; okforand[i] = 1; issimple[i] = 1; minintval[i] = mal(sizeof(*minintval[i])); maxintval[i] = mal(sizeof(*maxintval[i])); } if(isfloat[i]) { okforeq[i] = 1; okforcmp[i] = 1; okforadd[i] = 1; okforarith[i] = 1; issimple[i] = 1; minfltval[i] = mal(sizeof(*minfltval[i])); maxfltval[i] = mal(sizeof(*maxfltval[i])); } } issimple[TBOOL] = 1; okforadd[TSTRING] = 1; okforbool[TBOOL] = 1; okforcap[TARRAY] = 1; okforcap[TCHAN] = 1; okforlen[TARRAY] = 1; okforlen[TCHAN] = 1; okforlen[TMAP] = 1; okforlen[TSTRING] = 1; okforeq[TPTR32] = 1; okforeq[TPTR64] = 1; okforeq[TINTER] = 1; okforeq[TMAP] = 1; okforeq[TCHAN] = 1; okforeq[TFUNC] = 1; okforeq[TSTRING] = 1; okforeq[TBOOL] = 1; okforeq[TARRAY] = 1; // refined in typecheck okforcmp[TSTRING] = 1; for(i=0; i<nelem(okfor); i++) okfor[i] = okfornone; // binary okfor[OADD] = okforadd; okfor[OAND] = okforand; okfor[OANDAND] = okforbool; okfor[OANDNOT] = okforand; okfor[ODIV] = okforarith; okfor[OEQ] = okforeq; okfor[OGE] = okforcmp; okfor[OGT] = okforcmp; okfor[OLE] = okforcmp; okfor[OLT] = okforcmp; okfor[OMOD] = okforarith; okfor[OMUL] = okforarith; okfor[ONE] = okforeq; okfor[OOR] = okforand; okfor[OOROR] = okforbool; okfor[OSUB] = okforarith; okfor[OXOR] = okforand; okfor[OLSH] = okforand; okfor[ORSH] = okforand; // unary okfor[OCOM] = okforand; okfor[OMINUS] = okforarith; okfor[ONOT] = okforbool; okfor[OPLUS] = okforadd; // special okfor[OCAP] = okforcap; okfor[OLEN] = okforlen; // comparison iscmp[OLT] = 1; iscmp[OGT] = 1; iscmp[OGE] = 1; iscmp[OLE] = 1; iscmp[OEQ] = 1; iscmp[ONE] = 1; mpatofix(maxintval[TINT8], "0x7f"); mpatofix(minintval[TINT8], "-0x80"); mpatofix(maxintval[TINT16], "0x7fff"); mpatofix(minintval[TINT16], "-0x8000"); mpatofix(maxintval[TINT32], "0x7fffffff"); mpatofix(minintval[TINT32], "-0x80000000"); mpatofix(maxintval[TINT64], "0x7fffffffffffffff"); mpatofix(minintval[TINT64], "-0x8000000000000000"); mpatofix(maxintval[TUINT8], "0xff"); mpatofix(maxintval[TUINT16], "0xffff"); mpatofix(maxintval[TUINT32], "0xffffffff"); mpatofix(maxintval[TUINT64], "0xffffffffffffffff"); mpatoflt(maxfltval[TFLOAT32], "3.40282347e+38"); mpatoflt(minfltval[TFLOAT32], "-3.40282347e+38"); mpatoflt(maxfltval[TFLOAT64], "1.7976931348623157e+308"); mpatoflt(minfltval[TFLOAT64], "-1.7976931348623157e+308"); /* for walk to use in error messages */ types[TFUNC] = functype(N, nil, nil); /* types used in front end */ // types[TNIL] got set early in lexinit types[TIDEAL] = typ(TIDEAL); /* simple aliases */ simtype[TMAP] = tptr; simtype[TCHAN] = tptr; simtype[TFUNC] = tptr; /* pick up the backend typedefs */ for(i=0; typedefs[i].name; i++) { s = lookup(typedefs[i].name); s1 = pkglookup(typedefs[i].name, "/builtin/"); etype = typedefs[i].etype; if(etype < 0 || etype >= 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); }
/* * look for * unsafe.Sizeof * unsafe.Offsetof * rewrite with a constant */ Node* unsafenmagic(Node *fn, NodeList *args) { Node *r, *n; Sym *s; Type *t, *tr; long v; Val val; if(fn == N || fn->op != ONAME || (s = fn->sym) == S) goto no; if(strcmp(s->package, "unsafe") != 0) goto no; if(args == nil) { yyerror("missing argument for %S", s); goto no; } r = args->n; n = nod(OLITERAL, N, N); if(strcmp(s->name, "Sizeof") == 0) { typecheck(&r, Erv); tr = r->type; if(r->op == OLITERAL && r->val.ctype == CTSTR) tr = types[TSTRING]; if(tr == T) goto no; v = tr->width; goto yes; } if(strcmp(s->name, "Offsetof") == 0) { if(r->op != ODOT && r->op != ODOTPTR) goto no; typecheck(&r, Erv); v = r->xoffset; goto yes; } if(strcmp(s->name, "Alignof") == 0) { typecheck(&r, Erv); tr = r->type; if(r->op == OLITERAL && r->val.ctype == CTSTR) tr = types[TSTRING]; if(tr == T) goto no; // make struct { byte; T; } t = typ(TSTRUCT); t->type = typ(TFIELD); t->type->type = types[TUINT8]; t->type->down = typ(TFIELD); t->type->down->type = tr; // compute struct widths dowidth(t); // the offset of T is its required alignment v = t->type->down->width; goto yes; } no: return N; yes: if(args->next != nil) yyerror("extra arguments for %S", s); // any side effects disappear; ignore init val.ctype = CTINT; val.u.xval = mal(sizeof(*n->val.u.xval)); mpmovecfix(val.u.xval, v); n = nod(OLITERAL, N, N); n->val = val; n->type = types[TINT]; return n; }
/* * look for * unsafe.Sizeof * unsafe.Offsetof * rewrite with a constant */ Node* unsafenmagic(Node *nn) { Node *r, *n; Sym *s; Type *t, *tr; long v; Val val; Node *fn; NodeList *args; fn = nn->left; args = nn->list; if(safemode || fn == N || fn->op != ONAME || (s = fn->sym) == S) goto no; if(s->pkg != unsafepkg) goto no; if(args == nil) { yyerror("missing argument for %S", s); goto no; } r = args->n; if(strcmp(s->name, "Sizeof") == 0) { typecheck(&r, Erv); defaultlit(&r, T); tr = r->type; if(tr == T) goto bad; dowidth(tr); v = tr->width; goto yes; } if(strcmp(s->name, "Offsetof") == 0) { typecheck(&r, Erv); if(r->op != ODOT && r->op != ODOTPTR) goto bad; typecheck(&r, Erv); v = r->xoffset; goto yes; } if(strcmp(s->name, "Alignof") == 0) { typecheck(&r, Erv); defaultlit(&r, T); tr = r->type; if(tr == T) goto bad; // make struct { byte; T; } t = typ(TSTRUCT); t->type = typ(TFIELD); t->type->type = types[TUINT8]; t->type->down = typ(TFIELD); t->type->down->type = tr; // compute struct widths dowidth(t); // the offset of T is its required alignment v = t->type->down->width; goto yes; } no: return N; bad: yyerror("invalid expression %#N", nn); v = 0; goto ret; yes: if(args->next != nil) yyerror("extra arguments for %S", s); ret: // any side effects disappear; ignore init val.ctype = CTINT; val.u.xval = mal(sizeof(*n->val.u.xval)); mpmovecfix(val.u.xval, v); n = nod(OLITERAL, N, N); n->val = val; n->type = types[TINT]; return n; }
static vlong widstruct(Type *errtype, Type *t, vlong o, int flag) { Type *f; int64 w; int32 maxalign; vlong starto, lastzero; starto = o; maxalign = flag; if(maxalign < 1) maxalign = 1; lastzero = 0; 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; } if(w == 0) lastzero = o; o += w; if(o >= MAXWIDTH) { yyerror("type %lT too large", errtype); o = 8; // small but nonzero } } // For nonzero-sized structs which end in a zero-sized thing, we add // an extra byte of padding to the type. This padding ensures that // taking the address of the zero-sized thing can't manufacture a // pointer to the next object in the heap. See issue 9401. if(flag == 1 && o > starto && o == lastzero) o++; // final width is rounded if(flag) o = rnd(o, maxalign); t->align = maxalign; // type width only includes back to first field's offset t->width = o - starto; return o; }