github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/compile/internal/gc/align.go (about) 1 // Copyright 2009 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 package gc 6 7 // machine size and rounding alignment is dictated around 8 // the size of a pointer, set in betypeinit (see ../amd64/galign.go). 9 var defercalc int 10 11 func Rnd(o int64, r int64) int64 { 12 if r < 1 || r > 8 || r&(r-1) != 0 { 13 Fatalf("rnd %d", r) 14 } 15 return (o + r - 1) &^ (r - 1) 16 } 17 18 func offmod(t *Type) { 19 o := int32(0) 20 for _, f := range t.Fields().Slice() { 21 f.Offset = int64(o) 22 o += int32(Widthptr) 23 if int64(o) >= Thearch.MAXWIDTH { 24 Yyerror("interface too large") 25 o = int32(Widthptr) 26 } 27 } 28 } 29 30 func widstruct(errtype *Type, t *Type, o int64, flag int) int64 { 31 starto := o 32 maxalign := int32(flag) 33 if maxalign < 1 { 34 maxalign = 1 35 } 36 lastzero := int64(0) 37 var w int64 38 for _, f := range t.Fields().Slice() { 39 if f.Type == nil { 40 // broken field, just skip it so that other valid fields 41 // get a width. 42 continue 43 } 44 45 dowidth(f.Type) 46 if int32(f.Type.Align) > maxalign { 47 maxalign = int32(f.Type.Align) 48 } 49 if f.Type.Width < 0 { 50 Fatalf("invalid width %d", f.Type.Width) 51 } 52 w = f.Type.Width 53 if f.Type.Align > 0 { 54 o = Rnd(o, int64(f.Type.Align)) 55 } 56 f.Offset = o 57 if f.Nname != nil { 58 // this same stackparam logic is in addrescapes 59 // in typecheck.go. usually addrescapes runs after 60 // widstruct, in which case we could drop this, 61 // but function closure functions are the exception. 62 if f.Nname.Name.Param.Stackparam != nil { 63 f.Nname.Name.Param.Stackparam.Xoffset = o 64 f.Nname.Xoffset = 0 65 } else { 66 f.Nname.Xoffset = o 67 } 68 } 69 70 if w == 0 { 71 lastzero = o 72 } 73 o += w 74 if o >= Thearch.MAXWIDTH { 75 Yyerror("type %v too large", Tconv(errtype, FmtLong)) 76 o = 8 // small but nonzero 77 } 78 } 79 80 // For nonzero-sized structs which end in a zero-sized thing, we add 81 // an extra byte of padding to the type. This padding ensures that 82 // taking the address of the zero-sized thing can't manufacture a 83 // pointer to the next object in the heap. See issue 9401. 84 if flag == 1 && o > starto && o == lastzero { 85 o++ 86 } 87 88 // final width is rounded 89 if flag != 0 { 90 o = Rnd(o, int64(maxalign)) 91 } 92 t.Align = uint8(maxalign) 93 94 // type width only includes back to first field's offset 95 t.Width = o - starto 96 97 return o 98 } 99 100 func dowidth(t *Type) { 101 if Widthptr == 0 { 102 Fatalf("dowidth without betypeinit") 103 } 104 105 if t == nil { 106 return 107 } 108 109 if t.Width > 0 { 110 if t.Align == 0 { 111 // See issue 11354 112 Fatalf("zero alignment with nonzero size %v", t) 113 } 114 return 115 } 116 117 if t.Width == -2 { 118 if !t.Broke { 119 t.Broke = true 120 yyerrorl(t.Lineno, "invalid recursive type %v", t) 121 } 122 123 t.Width = 0 124 return 125 } 126 127 // break infinite recursion if the broken recursive type 128 // is referenced again 129 if t.Broke && t.Width == 0 { 130 return 131 } 132 133 // defer checkwidth calls until after we're done 134 defercalc++ 135 136 lno := lineno 137 lineno = t.Lineno 138 t.Width = -2 139 t.Align = 0 140 141 et := t.Etype 142 switch et { 143 case TFUNC, TCHAN, TMAP, TSTRING: 144 break 145 146 // simtype == 0 during bootstrap 147 default: 148 if Simtype[t.Etype] != 0 { 149 et = Simtype[t.Etype] 150 } 151 } 152 153 w := int64(0) 154 switch et { 155 default: 156 Fatalf("dowidth: unknown type: %v", t) 157 158 // compiler-specific stuff 159 case TINT8, TUINT8, TBOOL: 160 // bool is int8 161 w = 1 162 163 case TINT16, TUINT16: 164 w = 2 165 166 case TINT32, TUINT32, TFLOAT32: 167 w = 4 168 169 case TINT64, TUINT64, TFLOAT64, TCOMPLEX64: 170 w = 8 171 t.Align = uint8(Widthreg) 172 173 case TCOMPLEX128: 174 w = 16 175 t.Align = uint8(Widthreg) 176 177 case TPTR32: 178 w = 4 179 checkwidth(t.Elem()) 180 181 case TPTR64: 182 w = 8 183 checkwidth(t.Elem()) 184 185 case TUNSAFEPTR: 186 w = int64(Widthptr) 187 188 case TINTER: // implemented as 2 pointers 189 w = 2 * int64(Widthptr) 190 191 t.Align = uint8(Widthptr) 192 offmod(t) 193 194 case TCHAN: // implemented as pointer 195 w = int64(Widthptr) 196 197 checkwidth(t.Elem()) 198 199 // make fake type to check later to 200 // trigger channel argument check. 201 t1 := typWrapper(TCHANARGS, t) 202 checkwidth(t1) 203 204 case TCHANARGS: 205 t1 := t.Wrapped() 206 dowidth(t1) // just in case 207 if t1.Elem().Width >= 1<<16 { 208 Yyerror("channel element type too large (>64kB)") 209 } 210 t.Width = 1 211 212 case TMAP: // implemented as pointer 213 w = int64(Widthptr) 214 checkwidth(t.Val()) 215 checkwidth(t.Key()) 216 217 case TFORW: // should have been filled in 218 if !t.Broke { 219 Yyerror("invalid recursive type %v", t) 220 } 221 w = 1 // anything will do 222 223 // dummy type; should be replaced before use. 224 case TANY: 225 if Debug['A'] == 0 { 226 Fatalf("dowidth any") 227 } 228 w = 1 // anything will do 229 230 case TSTRING: 231 if sizeof_String == 0 { 232 Fatalf("early dowidth string") 233 } 234 w = int64(sizeof_String) 235 t.Align = uint8(Widthptr) 236 237 case TARRAY: 238 if t.Elem() == nil { 239 break 240 } 241 if t.IsArray() { 242 dowidth(t.Elem()) 243 if t.Elem().Width != 0 { 244 cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width) 245 if uint64(t.NumElem()) > cap { 246 Yyerror("type %v larger than address space", Tconv(t, FmtLong)) 247 } 248 } 249 250 w = t.NumElem() * t.Elem().Width 251 t.Align = t.Elem().Align 252 } else if t.IsSlice() { 253 w = int64(sizeof_Array) 254 checkwidth(t.Elem()) 255 t.Align = uint8(Widthptr) 256 } else if t.isDDDArray() { 257 if !t.Broke { 258 Yyerror("use of [...] array outside of array literal") 259 t.Broke = true 260 } 261 } else { 262 Fatalf("dowidth %v", t) // probably [...]T 263 } 264 265 case TSTRUCT: 266 if t.Funarg { 267 Fatalf("dowidth fn struct %v", t) 268 } 269 w = widstruct(t, t, 0, 1) 270 271 // make fake type to check later to 272 // trigger function argument computation. 273 case TFUNC: 274 t1 := typWrapper(TFUNCARGS, t) 275 checkwidth(t1) 276 w = int64(Widthptr) // width of func type is pointer 277 278 // function is 3 cated structures; 279 // compute their widths as side-effect. 280 case TFUNCARGS: 281 t1 := t.Wrapped() 282 w = widstruct(t1, t1.Recvs(), 0, 0) 283 w = widstruct(t1, t1.Params(), w, Widthreg) 284 w = widstruct(t1, t1.Results(), w, Widthreg) 285 t1.Argwid = w 286 if w%int64(Widthreg) != 0 { 287 Warn("bad type %v %d\n", t1, w) 288 } 289 t.Align = 1 290 } 291 292 if Widthptr == 4 && w != int64(int32(w)) { 293 Yyerror("type %v too large", t) 294 } 295 296 t.Width = w 297 if t.Align == 0 { 298 if w > 8 || w&(w-1) != 0 { 299 Fatalf("invalid alignment for %v", t) 300 } 301 t.Align = uint8(w) 302 } 303 304 lineno = lno 305 306 if defercalc == 1 { 307 resumecheckwidth() 308 } else { 309 defercalc-- 310 } 311 } 312 313 // when a type's width should be known, we call checkwidth 314 // to compute it. during a declaration like 315 // 316 // type T *struct { next T } 317 // 318 // it is necessary to defer the calculation of the struct width 319 // until after T has been initialized to be a pointer to that struct. 320 // similarly, during import processing structs may be used 321 // before their definition. in those situations, calling 322 // defercheckwidth() stops width calculations until 323 // resumecheckwidth() is called, at which point all the 324 // checkwidths that were deferred are executed. 325 // dowidth should only be called when the type's size 326 // is needed immediately. checkwidth makes sure the 327 // size is evaluated eventually. 328 329 var deferredTypeStack []*Type 330 331 func checkwidth(t *Type) { 332 if t == nil { 333 return 334 } 335 336 // function arg structs should not be checked 337 // outside of the enclosing function. 338 if t.Funarg { 339 Fatalf("checkwidth %v", t) 340 } 341 342 if defercalc == 0 { 343 dowidth(t) 344 return 345 } 346 347 if t.Deferwidth { 348 return 349 } 350 t.Deferwidth = true 351 352 deferredTypeStack = append(deferredTypeStack, t) 353 } 354 355 func defercheckwidth() { 356 // we get out of sync on syntax errors, so don't be pedantic. 357 if defercalc != 0 && nerrors == 0 { 358 Fatalf("defercheckwidth") 359 } 360 defercalc = 1 361 } 362 363 func resumecheckwidth() { 364 if defercalc == 0 { 365 Fatalf("resumecheckwidth") 366 } 367 for len(deferredTypeStack) > 0 { 368 t := deferredTypeStack[len(deferredTypeStack)-1] 369 deferredTypeStack = deferredTypeStack[:len(deferredTypeStack)-1] 370 t.Deferwidth = false 371 dowidth(t) 372 } 373 374 defercalc = 0 375 } 376 377 // compute total size of f's in/out arguments. 378 func Argsize(t *Type) int { 379 var w int64 380 381 for _, p := range recvsParamsResults { 382 for _, f := range p(t).Fields().Slice() { 383 if x := f.End(); x > w { 384 w = x 385 } 386 } 387 } 388 389 w = (w + int64(Widthptr) - 1) &^ (int64(Widthptr) - 1) 390 if int64(int(w)) != w { 391 Fatalf("argsize too big") 392 } 393 return int(w) 394 }