rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/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 } 68 a := s.Sizeof(T) // may be 0 69 // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1." 70 if a < 1 { 71 return 1 72 } 73 if a > s.MaxAlign { 74 return s.MaxAlign 75 } 76 return a 77 } 78 79 func (s *StdSizes) Offsetsof(fields []*Var) []int64 { 80 offsets := make([]int64, len(fields)) 81 var o int64 82 for i, f := range fields { 83 a := s.Alignof(f.typ) 84 o = align(o, a) 85 offsets[i] = o 86 o += s.Sizeof(f.typ) 87 } 88 return offsets 89 } 90 91 var basicSizes = [...]byte{ 92 Bool: 1, 93 Int8: 1, 94 Int16: 2, 95 Int32: 4, 96 Int64: 8, 97 Uint8: 1, 98 Uint16: 2, 99 Uint32: 4, 100 Uint64: 8, 101 Float32: 4, 102 Float64: 8, 103 Complex64: 8, 104 Complex128: 16, 105 } 106 107 func (s *StdSizes) Sizeof(T Type) int64 { 108 switch t := T.Underlying().(type) { 109 case *Basic: 110 assert(isTyped(T)) 111 k := t.kind 112 if int(k) < len(basicSizes) { 113 if s := basicSizes[k]; s > 0 { 114 return int64(s) 115 } 116 } 117 if k == String { 118 return s.WordSize * 2 119 } 120 case *Array: 121 n := t.len 122 if n == 0 { 123 return 0 124 } 125 a := s.Alignof(t.elem) 126 z := s.Sizeof(t.elem) 127 return align(z, a)*(n-1) + z 128 case *Slice: 129 return s.WordSize * 3 130 case *Struct: 131 n := t.NumFields() 132 if n == 0 { 133 return 0 134 } 135 offsets := t.offsets 136 if t.offsets == nil { 137 // compute offsets on demand 138 offsets = s.Offsetsof(t.fields) 139 t.offsets = offsets 140 } 141 return offsets[n-1] + s.Sizeof(t.fields[n-1].typ) 142 case *Interface: 143 return s.WordSize * 2 144 } 145 return s.WordSize // catch-all 146 } 147 148 // stdSizes is used if Config.Sizes == nil. 149 var stdSizes = StdSizes{8, 8} 150 151 func (conf *Config) alignof(T Type) int64 { 152 if s := conf.Sizes; s != nil { 153 if a := s.Alignof(T); a >= 1 { 154 return a 155 } 156 panic("Config.Sizes.Alignof returned an alignment < 1") 157 } 158 return stdSizes.Alignof(T) 159 } 160 161 func (conf *Config) offsetsof(T *Struct) []int64 { 162 offsets := T.offsets 163 if offsets == nil && T.NumFields() > 0 { 164 // compute offsets on demand 165 if s := conf.Sizes; s != nil { 166 offsets = s.Offsetsof(T.fields) 167 // sanity checks 168 if len(offsets) != T.NumFields() { 169 panic("Config.Sizes.Offsetsof returned the wrong number of offsets") 170 } 171 for _, o := range offsets { 172 if o < 0 { 173 panic("Config.Sizes.Offsetsof returned an offset < 0") 174 } 175 } 176 } else { 177 offsets = stdSizes.Offsetsof(T.fields) 178 } 179 T.offsets = offsets 180 } 181 return offsets 182 } 183 184 // offsetof returns the offset of the field specified via 185 // the index sequence relative to typ. All embedded fields 186 // must be structs (rather than pointer to structs). 187 func (conf *Config) offsetof(typ Type, index []int) int64 { 188 var o int64 189 for _, i := range index { 190 s := typ.Underlying().(*Struct) 191 o += conf.offsetsof(s)[i] 192 typ = s.fields[i].typ 193 } 194 return o 195 } 196 197 func (conf *Config) sizeof(T Type) int64 { 198 if s := conf.Sizes; s != nil { 199 if z := s.Sizeof(T); z >= 0 { 200 return z 201 } 202 panic("Config.Sizes.Sizeof returned a size < 0") 203 } 204 return stdSizes.Sizeof(T) 205 } 206 207 // align returns the smallest y >= x such that y % a == 0. 208 func align(x, a int64) int64 { 209 y := x + a - 1 210 return y - y%a 211 }