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 // stdSizes is used if Config.Sizes == nil. 157 var stdSizes = StdSizes{8, 8} 158 159 func (conf *Config) alignof(T Type) int64 { 160 if s := conf.Sizes; s != nil { 161 if a := s.Alignof(T); a >= 1 { 162 return a 163 } 164 panic("Config.Sizes.Alignof returned an alignment < 1") 165 } 166 return stdSizes.Alignof(T) 167 } 168 169 func (conf *Config) offsetsof(T *Struct) []int64 { 170 var offsets []int64 171 if T.NumFields() > 0 { 172 // compute offsets on demand 173 if s := conf.Sizes; s != nil { 174 offsets = s.Offsetsof(T.fields) 175 // sanity checks 176 if len(offsets) != T.NumFields() { 177 panic("Config.Sizes.Offsetsof returned the wrong number of offsets") 178 } 179 for _, o := range offsets { 180 if o < 0 { 181 panic("Config.Sizes.Offsetsof returned an offset < 0") 182 } 183 } 184 } else { 185 offsets = stdSizes.Offsetsof(T.fields) 186 } 187 } 188 return offsets 189 } 190 191 // offsetof returns the offset of the field specified via 192 // the index sequence relative to typ. All embedded fields 193 // must be structs (rather than pointer to structs). 194 func (conf *Config) offsetof(typ Type, index []int) int64 { 195 var o int64 196 for _, i := range index { 197 s := typ.Underlying().(*Struct) 198 o += conf.offsetsof(s)[i] 199 typ = s.fields[i].typ 200 } 201 return o 202 } 203 204 func (conf *Config) sizeof(T Type) int64 { 205 if s := conf.Sizes; s != nil { 206 if z := s.Sizeof(T); z >= 0 { 207 return z 208 } 209 panic("Config.Sizes.Sizeof returned a size < 0") 210 } 211 return stdSizes.Sizeof(T) 212 } 213 214 // align returns the smallest y >= x such that y % a == 0. 215 func align(x, a int64) int64 { 216 y := x + a - 1 217 return y - y%a 218 } 219