github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/go/types/sizes.go (about) 1 // Copyright 2013 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 // This file implements Sizes. 6 7 package types 8 9 // Sizes defines the sizing functions for package unsafe. 10 type Sizes interface { 11 // Alignof returns the alignment of a variable of type T. 12 // Alignof must implement the alignment guarantees required by the spec. 13 Alignof(T Type) int64 14 15 // Offsetsof returns the offsets of the given struct fields, in bytes. 16 // Offsetsof must implement the offset guarantees required by the spec. 17 Offsetsof(fields []*Var) []int64 18 19 // Sizeof returns the size of a variable of type T. 20 // Sizeof must implement the size guarantees required by the spec. 21 Sizeof(T Type) int64 22 } 23 24 // StdSizes is a convenience type for creating commonly used Sizes. 25 // It makes the following simplifying assumptions: 26 // 27 // - The size of explicitly sized basic types (int16, etc.) is the 28 // specified size. 29 // - The size of strings and interfaces is 2*WordSize. 30 // - The size of slices is 3*WordSize. 31 // - The size of an array of n elements corresponds to the size of 32 // a struct of n consecutive fields of the array's element type. 33 // - The size of a struct is the offset of the last field plus that 34 // field's size. As with all element types, if the struct is used 35 // in an array its size must first be aligned to a multiple of the 36 // struct's alignment. 37 // - All other types have size WordSize. 38 // - Arrays and structs are aligned per spec definition; all other 39 // types are naturally aligned with a maximum alignment MaxAlign. 40 // 41 // *StdSizes implements Sizes. 42 // 43 type StdSizes struct { 44 WordSize int64 // word size in bytes - must be >= 4 (32bits) 45 MaxAlign int64 // maximum alignment in bytes - must be >= 1 46 } 47 48 func (s *StdSizes) Alignof(T Type) int64 { 49 // For arrays and structs, alignment is defined in terms 50 // of alignment of the elements and fields, respectively. 51 switch t := T.Underlying().(type) { 52 case *Array: 53 // spec: "For a variable x of array type: unsafe.Alignof(x) 54 // is the same as unsafe.Alignof(x[0]), but at least 1." 55 return s.Alignof(t.elem) 56 case *Struct: 57 // spec: "For a variable x of struct type: unsafe.Alignof(x) 58 // is the largest of the values unsafe.Alignof(x.f) for each 59 // field f of x, but at least 1." 60 max := int64(1) 61 for _, f := range t.fields { 62 if a := s.Alignof(f.typ); a > max { 63 max = a 64 } 65 } 66 return max 67 case *Slice, *Interface: 68 // Multiword data structures are effectively structs 69 // in which each element has size WordSize. 70 return s.WordSize 71 case *Basic: 72 // Strings are like slices and interfaces. 73 if t.Info()&IsString != 0 { 74 return s.WordSize 75 } 76 } 77 a := s.Sizeof(T) // may be 0 78 // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1." 79 if a < 1 { 80 return 1 81 } 82 // complex{64,128} are aligned like [2]float{32,64}. 83 if isComplex(T) { 84 a /= 2 85 } 86 if a > s.MaxAlign { 87 return s.MaxAlign 88 } 89 return a 90 } 91 92 func (s *StdSizes) Offsetsof(fields []*Var) []int64 { 93 offsets := make([]int64, len(fields)) 94 var o int64 95 for i, f := range fields { 96 a := s.Alignof(f.typ) 97 o = align(o, a) 98 offsets[i] = o 99 o += s.Sizeof(f.typ) 100 } 101 return offsets 102 } 103 104 var basicSizes = [...]byte{ 105 Bool: 1, 106 Int8: 1, 107 Int16: 2, 108 Int32: 4, 109 Int64: 8, 110 Uint8: 1, 111 Uint16: 2, 112 Uint32: 4, 113 Uint64: 8, 114 Float32: 4, 115 Float64: 8, 116 Complex64: 8, 117 Complex128: 16, 118 } 119 120 func (s *StdSizes) Sizeof(T Type) int64 { 121 switch t := T.Underlying().(type) { 122 case *Basic: 123 assert(isTyped(T)) 124 k := t.kind 125 if int(k) < len(basicSizes) { 126 if s := basicSizes[k]; s > 0 { 127 return int64(s) 128 } 129 } 130 if k == String { 131 return s.WordSize * 2 132 } 133 case *Array: 134 n := t.len 135 if n == 0 { 136 return 0 137 } 138 a := s.Alignof(t.elem) 139 z := s.Sizeof(t.elem) 140 return align(z, a)*(n-1) + z 141 case *Slice: 142 return s.WordSize * 3 143 case *Struct: 144 n := t.NumFields() 145 if n == 0 { 146 return 0 147 } 148 offsets := s.Offsetsof(t.fields) 149 return offsets[n-1] + s.Sizeof(t.fields[n-1].typ) 150 case *Interface: 151 return s.WordSize * 2 152 } 153 return s.WordSize // catch-all 154 } 155 156 // common architecture word sizes and alignments 157 var gcArchSizes = map[string]*StdSizes{ 158 "386": {4, 4}, 159 "arm": {4, 4}, 160 "arm64": {8, 8}, 161 "amd64": {8, 8}, 162 "amd64p32": {4, 8}, 163 "mips": {4, 4}, 164 "mipsle": {4, 4}, 165 "mips64": {8, 8}, 166 "mips64le": {8, 8}, 167 "ppc64": {8, 8}, 168 "ppc64le": {8, 8}, 169 "s390x": {8, 8}, 170 // When adding more architectures here, 171 // update the doc string of SizesFor below. 172 } 173 174 // SizesFor returns the Sizes used by a compiler for an architecture. 175 // The result is nil if a compiler/architecture pair is not known. 176 // 177 // Supported architectures for compiler "gc": 178 // "386", "arm", "arm64", "amd64", "amd64p32", "mips", "mipsle", 179 // "mips64", "mips64le", "ppc64", "ppc64le", "s390x". 180 func SizesFor(compiler, arch string) Sizes { 181 if compiler != "gc" { 182 return nil 183 } 184 s, ok := gcArchSizes[arch] 185 if !ok { 186 return nil 187 } 188 return s 189 } 190 191 // stdSizes is used if Config.Sizes == nil. 192 var stdSizes = SizesFor("gc", "amd64") 193 194 func (conf *Config) alignof(T Type) int64 { 195 if s := conf.Sizes; s != nil { 196 if a := s.Alignof(T); a >= 1 { 197 return a 198 } 199 panic("Config.Sizes.Alignof returned an alignment < 1") 200 } 201 return stdSizes.Alignof(T) 202 } 203 204 func (conf *Config) offsetsof(T *Struct) []int64 { 205 var offsets []int64 206 if T.NumFields() > 0 { 207 // compute offsets on demand 208 if s := conf.Sizes; s != nil { 209 offsets = s.Offsetsof(T.fields) 210 // sanity checks 211 if len(offsets) != T.NumFields() { 212 panic("Config.Sizes.Offsetsof returned the wrong number of offsets") 213 } 214 for _, o := range offsets { 215 if o < 0 { 216 panic("Config.Sizes.Offsetsof returned an offset < 0") 217 } 218 } 219 } else { 220 offsets = stdSizes.Offsetsof(T.fields) 221 } 222 } 223 return offsets 224 } 225 226 // offsetof returns the offset of the field specified via 227 // the index sequence relative to typ. All embedded fields 228 // must be structs (rather than pointer to structs). 229 func (conf *Config) offsetof(typ Type, index []int) int64 { 230 var o int64 231 for _, i := range index { 232 s := typ.Underlying().(*Struct) 233 o += conf.offsetsof(s)[i] 234 typ = s.fields[i].typ 235 } 236 return o 237 } 238 239 func (conf *Config) sizeof(T Type) int64 { 240 if s := conf.Sizes; s != nil { 241 if z := s.Sizeof(T); z >= 0 { 242 return z 243 } 244 panic("Config.Sizes.Sizeof returned a size < 0") 245 } 246 return stdSizes.Sizeof(T) 247 } 248 249 // align returns the smallest y >= x such that y % a == 0. 250 func align(x, a int64) int64 { 251 y := x + a - 1 252 return y - y%a 253 }