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