// 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. package gc import "cmd/internal/obj" /* * machine size and rounding * alignment is dictated around * the size of a pointer, set in betypeinit * (see ../6g/galign.c). */ var defercalc int func Rnd(o int64, r int64) int64 { if r < 1 || r > 8 || r&(r-1) != 0 { Fatal("rnd %d", r) } return (o + r - 1) &^ (r - 1) } func offmod(t *Type) { o := int32(0) for f := t.Type; f != nil; f = f.Down { if f.Etype != TFIELD { Fatal("offmod: not TFIELD: %v", Tconv(f, obj.FmtLong)) } f.Width = int64(o) o += int32(Widthptr) if int64(o) >= Thearch.MAXWIDTH { Yyerror("interface too large") o = int32(Widthptr) } } } func widstruct(errtype *Type, t *Type, o int64, flag int) int64 { starto := o maxalign := int32(flag) if maxalign < 1 { maxalign = 1 } lastzero := int64(0) var w int64 for f := t.Type; f != nil; f = f.Down { if f.Etype != TFIELD { Fatal("widstruct: not TFIELD: %v", Tconv(f, obj.FmtLong)) } if f.Type == nil { // broken field, just skip it so that other valid fields // get a width. continue } dowidth(f.Type) if int32(f.Type.Align) > maxalign { maxalign = int32(f.Type.Align) } if f.Type.Width < 0 { Fatal("invalid width %d", f.Type.Width) } w = f.Type.Width if f.Type.Align > 0 { o = Rnd(o, int64(f.Type.Align)) } f.Width = o // really offset for TFIELD if f.Nname != nil { // 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.Name.Param.Stackparam != nil { f.Nname.Name.Param.Stackparam.Xoffset = o f.Nname.Xoffset = 0 } else { f.Nname.Xoffset = o } } if w == 0 { lastzero = o } o += w if o >= Thearch.MAXWIDTH { Yyerror("type %v too large", Tconv(errtype, obj.FmtLong)) 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 != 0 { o = Rnd(o, int64(maxalign)) } t.Align = uint8(maxalign) // type width only includes back to first field's offset t.Width = o - starto return o } func dowidth(t *Type) { if Widthptr == 0 { Fatal("dowidth without betypeinit") } if t == nil { return } if t.Width > 0 { if t.Align == 0 { // See issue 11354 Fatal("zero alignment with nonzero size %v", t) } return } if t.Width == -2 { lno := int(lineno) lineno = int32(t.Lineno) if t.Broke == 0 { t.Broke = 1 Yyerror("invalid recursive type %v", t) } t.Width = 0 lineno = int32(lno) return } // break infinite recursion if the broken recursive type // is referenced again if t.Broke != 0 && t.Width == 0 { return } // defer checkwidth calls until after we're done defercalc++ lno := int(lineno) lineno = int32(t.Lineno) t.Width = -2 t.Align = 0 et := int32(t.Etype) switch et { case TFUNC, TCHAN, TMAP, TSTRING: break /* simtype == 0 during bootstrap */ default: if Simtype[t.Etype] != 0 { et = int32(Simtype[t.Etype]) } } w := int64(0) switch et { default: Fatal("dowidth: unknown type: %v", t) /* compiler-specific stuff */ case TINT8, TUINT8, TBOOL: // bool is int8 w = 1 case TINT16, TUINT16: w = 2 case TINT32, TUINT32, TFLOAT32: w = 4 case TINT64, TUINT64, TFLOAT64, TCOMPLEX64: w = 8 t.Align = uint8(Widthreg) case TCOMPLEX128: w = 16 t.Align = uint8(Widthreg) case TPTR32: w = 4 checkwidth(t.Type) case TPTR64: w = 8 checkwidth(t.Type) case TUNSAFEPTR: w = int64(Widthptr) case TINTER: // implemented as 2 pointers w = 2 * int64(Widthptr) t.Align = uint8(Widthptr) offmod(t) case TCHAN: // implemented as pointer w = int64(Widthptr) checkwidth(t.Type) // make fake type to check later to // trigger channel argument check. t1 := typ(TCHANARGS) t1.Type = t checkwidth(t1) 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 case TMAP: // implemented as pointer w = int64(Widthptr) checkwidth(t.Type) checkwidth(t.Down) case TFORW: // should have been filled in if t.Broke == 0 { Yyerror("invalid recursive type %v", t) } w = 1 // anything will do // dummy type; should be replaced before use. case TANY: if Debug['A'] == 0 { Fatal("dowidth any") } w = 1 // anything will do case TSTRING: if sizeof_String == 0 { Fatal("early dowidth string") } w = int64(sizeof_String) t.Align = uint8(Widthptr) case TARRAY: if t.Type == nil { break } if t.Bound >= 0 { dowidth(t.Type) if t.Type.Width != 0 { cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Type.Width) if uint64(t.Bound) > cap { Yyerror("type %v larger than address space", Tconv(t, obj.FmtLong)) } } w = t.Bound * t.Type.Width t.Align = t.Type.Align } else if t.Bound == -1 { w = int64(sizeof_Array) checkwidth(t.Type) t.Align = uint8(Widthptr) } else if t.Bound == -100 { if t.Broke == 0 { Yyerror("use of [...] array outside of array literal") t.Broke = 1 } } else { Fatal("dowidth %v", t) // probably [...]T } case TSTRUCT: if t.Funarg != 0 { Fatal("dowidth fn struct %v", t) } w = widstruct(t, t, 0, 1) // make fake type to check later to // trigger function argument computation. case TFUNC: t1 := typ(TFUNCARGS) t1.Type = t checkwidth(t1) // width of func type is pointer w = int64(Widthptr) // function is 3 cated structures; // compute their widths as side-effect. case TFUNCARGS: 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%int64(Widthreg) != 0 { Warn("bad type %v %d\n", t1, w) } t.Align = 1 } if Widthptr == 4 && w != int64(int32(w)) { Yyerror("type %v too large", t) } t.Width = w if t.Align == 0 { if w > 8 || w&(w-1) != 0 { Fatal("invalid alignment for %v", t) } t.Align = uint8(w) } lineno = int32(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. */ type TypeList struct { t *Type next *TypeList } var tlfree *TypeList var tlq *TypeList func checkwidth(t *Type) { if t == nil { return } // function arg structs should not be checked // outside of the enclosing function. if t.Funarg != 0 { Fatal("checkwidth %v", t) } if defercalc == 0 { dowidth(t) return } if t.Deferwidth != 0 { return } t.Deferwidth = 1 l := tlfree if l != nil { tlfree = l.next } else { l = new(TypeList) } l.t = t l.next = tlq tlq = l } func defercheckwidth() { // we get out of sync on syntax errors, so don't be pedantic. if defercalc != 0 && nerrors == 0 { Fatal("defercheckwidth") } defercalc = 1 } func resumecheckwidth() { if defercalc == 0 { 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 } var itable *Type // distinguished *byte func typeinit() { if Widthptr == 0 { Fatal("typeinit before betypeinit") } for i := 0; i < NTYPE; i++ { Simtype[i] = uint8(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) t.Sym.Def.Name = new(Name) dowidth(Types[TUNSAFEPTR]) Tptr = TPTR32 if Widthptr == 8 { Tptr = TPTR64 } for i := TINT8; i <= TUINT64; i++ { Isint[i] = true } Isint[TINT] = true Isint[TUINT] = true Isint[TUINTPTR] = true Isfloat[TFLOAT32] = true Isfloat[TFLOAT64] = true Iscomplex[TCOMPLEX64] = true Iscomplex[TCOMPLEX128] = true Isptr[TPTR32] = true Isptr[TPTR64] = true isforw[TFORW] = true Issigned[TINT] = true Issigned[TINT8] = true Issigned[TINT16] = true Issigned[TINT32] = true Issigned[TINT64] = true /* * initialize okfor */ for i := 0; i < NTYPE; i++ { if Isint[i] || i == TIDEAL { okforeq[i] = true okforcmp[i] = true okforarith[i] = true okforadd[i] = true okforand[i] = true okforconst[i] = true issimple[i] = true Minintval[i] = new(Mpint) Maxintval[i] = new(Mpint) } if Isfloat[i] { okforeq[i] = true okforcmp[i] = true okforadd[i] = true okforarith[i] = true okforconst[i] = true issimple[i] = true minfltval[i] = newMpflt() maxfltval[i] = newMpflt() } if Iscomplex[i] { okforeq[i] = true okforadd[i] = true okforarith[i] = true okforconst[i] = true issimple[i] = true } } issimple[TBOOL] = true okforadd[TSTRING] = true okforbool[TBOOL] = true okforcap[TARRAY] = true okforcap[TCHAN] = true okforconst[TBOOL] = true okforconst[TSTRING] = true okforlen[TARRAY] = true okforlen[TCHAN] = true okforlen[TMAP] = true okforlen[TSTRING] = true okforeq[TPTR32] = true okforeq[TPTR64] = true okforeq[TUNSAFEPTR] = true okforeq[TINTER] = true okforeq[TCHAN] = true okforeq[TSTRING] = true okforeq[TBOOL] = true okforeq[TMAP] = true // nil only; refined in typecheck okforeq[TFUNC] = true // nil only; refined in typecheck okforeq[TARRAY] = true // nil slice only; refined in typecheck okforeq[TSTRUCT] = true // it's complicated; refined in typecheck okforcmp[TSTRING] = true var i int for i = 0; i < len(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[OHMUL] = 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] = okforarith[:] // special okfor[OCAP] = okforcap[:] okfor[OLEN] = okforlen[:] // comparison iscmp[OLT] = true iscmp[OGT] = true iscmp[OGE] = true iscmp[OLE] = true iscmp[OEQ] = true iscmp[ONE] = true 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(nil, 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] = uint8(Tptr) Simtype[TCHAN] = uint8(Tptr) Simtype[TFUNC] = uint8(Tptr) Simtype[TUNSAFEPTR] = uint8(Tptr) /* pick up the backend thearch.typedefs */ var s1 *Sym var etype int var sameas int var s *Sym for i = range Thearch.Typedefs { s = Lookup(Thearch.Typedefs[i].Name) s1 = Pkglookup(Thearch.Typedefs[i].Name, builtinpkg) etype = Thearch.Typedefs[i].Etype if etype < 0 || etype >= len(Types) { Fatal("typeinit: %s bad etype", s.Name) } sameas = Thearch.Typedefs[i].Sameas if sameas < 0 || sameas >= len(Types) { Fatal("typeinit: %s bad sameas", s.Name) } Simtype[etype] = uint8(sameas) minfltval[etype] = minfltval[sameas] maxfltval[etype] = maxfltval[sameas] Minintval[etype] = Minintval[sameas] Maxintval[etype] = Maxintval[sameas] t = Types[etype] if t != nil { Fatal("typeinit: %s already defined", s.Name) } t = typ(etype) t.Sym = s1 dowidth(t) Types[etype] = t s1.Def = typenod(t) s1.Def.Name = new(Name) } Array_array = int(Rnd(0, int64(Widthptr))) Array_nel = int(Rnd(int64(Array_array)+int64(Widthptr), int64(Widthint))) Array_cap = int(Rnd(int64(Array_nel)+int64(Widthint), int64(Widthint))) sizeof_Array = int(Rnd(int64(Array_cap)+int64(Widthint), int64(Widthptr))) // string is same as slice wo the cap sizeof_String = int(Rnd(int64(Array_nel)+int64(Widthint), int64(Widthptr))) dowidth(Types[TSTRING]) dowidth(idealstring) itable = typ(Tptr) itable.Type = Types[TUINT8] } /* * compute total size of f's in/out arguments. */ func Argsize(t *Type) int { var save Iter var x int64 w := int64(0) fp := Structfirst(&save, Getoutarg(t)) for fp != nil { x = fp.Width + fp.Type.Width if x > w { w = x } fp = structnext(&save) } fp = funcfirst(&save, t) for fp != nil { x = fp.Width + fp.Type.Width if x > w { w = x } fp = funcnext(&save) } w = (w + int64(Widthptr) - 1) &^ (int64(Widthptr) - 1) if int64(int(w)) != w { Fatal("argsize too big") } return int(w) }