1 // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
2 // Source: ../../cmd/compile/internal/types2/sizes.go
3 4 // Copyright 2013 The Go Authors. All rights reserved.
5 // Use of this source code is governed by a BSD-style
6 // license that can be found in the LICENSE file.
7 8 // This file implements Sizes.
9 10 package types
11 12 // Sizes defines the sizing functions for package unsafe.
13 type Sizes interface {
14 // Alignof returns the alignment of a variable of type T.
15 // Alignof must implement the alignment guarantees required by the spec.
16 // The result must be >= 1.
17 Alignof(T Type) int64
18 19 // Offsetsof returns the offsets of the given struct fields, in bytes.
20 // Offsetsof must implement the offset guarantees required by the spec.
21 // A negative entry in the result indicates that the struct is too large.
22 Offsetsof(fields []*Var) []int64
23 24 // Sizeof returns the size of a variable of type T.
25 // Sizeof must implement the size guarantees required by the spec.
26 // A negative result indicates that T is too large.
27 Sizeof(T Type) int64
28 }
29 30 // StdSizes is a convenience type for creating commonly used Sizes.
31 // It makes the following simplifying assumptions:
32 //
33 // - The size of explicitly sized basic types (int16, etc.) is the
34 // specified size.
35 // - The size of strings and interfaces is 2*WordSize.
36 // - The size of slices is 3*WordSize.
37 // - The size of an array of n elements corresponds to the size of
38 // a struct of n consecutive fields of the array's element type.
39 // - The size of a struct is the offset of the last field plus that
40 // field's size. As with all element types, if the struct is used
41 // in an array its size must first be aligned to a multiple of the
42 // struct's alignment.
43 // - All other types have size WordSize.
44 // - Arrays and structs are aligned per spec definition; all other
45 // types are naturally aligned with a maximum alignment MaxAlign.
46 //
47 // *StdSizes implements Sizes.
48 type StdSizes struct {
49 WordSize int64 // word size in bytes - must be >= 4 (32bits)
50 MaxAlign int64 // maximum alignment in bytes - must be >= 1
51 }
52 53 func (s *StdSizes) Alignof(T Type) (result int64) {
54 defer func() {
55 assert(result >= 1)
56 }()
57 58 // For arrays and structs, alignment is defined in terms
59 // of alignment of the elements and fields, respectively.
60 switch t := under(T).(type) {
61 case *Array:
62 // spec: "For a variable x of array type: unsafe.Alignof(x)
63 // is the same as unsafe.Alignof(x[0]), but at least 1."
64 return s.Alignof(t.elem)
65 case *Struct:
66 if len(t.fields) == 0 && _IsSyncAtomicAlign64(T) {
67 // Special case: sync/atomic.align64 is an
68 // empty struct we recognize as a signal that
69 // the struct it contains must be
70 // 64-bit-aligned.
71 //
72 // This logic is equivalent to the logic in
73 // cmd/compile/internal/types/size.go:calcStructOffset
74 return 8
75 }
76 77 // spec: "For a variable x of struct type: unsafe.Alignof(x)
78 // is the largest of the values unsafe.Alignof(x.f) for each
79 // field f of x, but at least 1."
80 max := int64(1)
81 for _, f := range t.fields {
82 if a := s.Alignof(f.typ); a > max {
83 max = a
84 }
85 }
86 return max
87 case *Slice, *Interface:
88 // Multiword data structures are effectively structs
89 // in which each element has size WordSize.
90 // Type parameters lead to variable sizes/alignments;
91 // StdSizes.Alignof won't be called for them.
92 assert(!isTypeParam(T))
93 return s.WordSize
94 case *Basic:
95 // Strings are like slices and interfaces.
96 if t.Info()&IsString != 0 {
97 return s.WordSize
98 }
99 case *TypeParam, *Union:
100 panic("unreachable")
101 }
102 a := s.Sizeof(T) // may be 0 or negative
103 // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
104 if a < 1 {
105 return 1
106 }
107 // complex{64,128} are aligned like [2]float{32,64}.
108 if isComplex(T) {
109 a /= 2
110 }
111 if a > s.MaxAlign {
112 return s.MaxAlign
113 }
114 return a
115 }
116 117 func _IsSyncAtomicAlign64(T Type) bool {
118 named := asNamed(T)
119 if named == nil {
120 return false
121 }
122 obj := named.Obj()
123 return obj.Name() == "align64" &&
124 obj.Pkg() != nil &&
125 (obj.Pkg().Path() == "sync/atomic" ||
126 obj.Pkg().Path() == "internal/runtime/atomic")
127 }
128 129 func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
130 offsets := make([]int64, len(fields))
131 var offs int64
132 for i, f := range fields {
133 if offs < 0 {
134 // all remaining offsets are too large
135 offsets[i] = -1
136 continue
137 }
138 // offs >= 0
139 a := s.Alignof(f.typ)
140 offs = align(offs, a) // possibly < 0 if align overflows
141 offsets[i] = offs
142 if d := s.Sizeof(f.typ); d >= 0 && offs >= 0 {
143 offs += d // ok to overflow to < 0
144 } else {
145 offs = -1 // f.typ or offs is too large
146 }
147 }
148 return offsets
149 }
150 151 var basicSizes = [...]byte{
152 Bool: 1,
153 Int8: 1,
154 Int16: 2,
155 Int32: 4,
156 Int64: 8,
157 Uint8: 1,
158 Uint16: 2,
159 Uint32: 4,
160 Uint64: 8,
161 Float32: 4,
162 Float64: 8,
163 Complex64: 8,
164 Complex128: 16,
165 }
166 167 func (s *StdSizes) Sizeof(T Type) int64 {
168 switch t := under(T).(type) {
169 case *Basic:
170 assert(isTyped(T))
171 k := t.kind
172 if int(k) < len(basicSizes) {
173 if s := basicSizes[k]; s > 0 {
174 return int64(s)
175 }
176 }
177 if k == String {
178 // Moxie: string=[]byte — 3-word struct (ptr, len, cap).
179 return s.WordSize * 3
180 }
181 case *Array:
182 n := t.len
183 if n <= 0 {
184 return 0
185 }
186 // n > 0
187 esize := s.Sizeof(t.elem)
188 if esize < 0 {
189 return -1 // element too large
190 }
191 if esize == 0 {
192 return 0 // 0-size element
193 }
194 // esize > 0
195 a := s.Alignof(t.elem)
196 ea := align(esize, a) // possibly < 0 if align overflows
197 if ea < 0 {
198 return -1
199 }
200 // ea >= 1
201 n1 := n - 1 // n1 >= 0
202 // Final size is ea*n1 + esize; and size must be <= maxInt64.
203 const maxInt64 = 1<<63 - 1
204 if n1 > 0 && ea > maxInt64/n1 {
205 return -1 // ea*n1 overflows
206 }
207 return ea*n1 + esize // may still overflow to < 0 which is ok
208 case *Slice:
209 return s.WordSize * 3
210 case *Struct:
211 n := t.NumFields()
212 if n == 0 {
213 return 0
214 }
215 offsets := s.Offsetsof(t.fields)
216 offs := offsets[n-1]
217 size := s.Sizeof(t.fields[n-1].typ)
218 if offs < 0 || size < 0 {
219 return -1 // type too large
220 }
221 return offs + size // may overflow to < 0 which is ok
222 case *Interface:
223 // Type parameters lead to variable sizes/alignments;
224 // StdSizes.Sizeof won't be called for them.
225 assert(!isTypeParam(T))
226 return s.WordSize * 2
227 case *TypeParam, *Union:
228 panic("unreachable")
229 }
230 return s.WordSize // catch-all
231 }
232 233 // common architecture word sizes and alignments
234 var gcArchSizes = map[string]*gcSizes{
235 "386": {4, 4},
236 "amd64": {8, 8},
237 "amd64p32": {4, 8},
238 "arm": {4, 4},
239 "arm64": {8, 8},
240 "loong64": {8, 8},
241 "mips": {4, 4},
242 "mipsle": {4, 4},
243 "mips64": {8, 8},
244 "mips64le": {8, 8},
245 "ppc64": {8, 8},
246 "ppc64le": {8, 8},
247 "riscv64": {8, 8},
248 "s390x": {8, 8},
249 "sparc64": {8, 8},
250 "wasm": {8, 8},
251 // When adding more architectures here,
252 // update the doc string of SizesFor below.
253 }
254 255 // SizesFor returns the Sizes used by a compiler for an architecture.
256 // The result is nil if a compiler/architecture pair is not known.
257 //
258 // Supported architectures for compiler "gc":
259 // "386", "amd64", "amd64p32", "arm", "arm64", "loong64", "mips", "mipsle",
260 // "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "sparc64", "wasm".
261 func SizesFor(compiler, arch string) Sizes {
262 switch compiler {
263 case "gc":
264 if s := gcSizesFor(compiler, arch); s != nil {
265 return Sizes(s)
266 }
267 case "gccgo":
268 if s, ok := gccgoArchSizes[arch]; ok {
269 return Sizes(s)
270 }
271 }
272 return nil
273 }
274 275 // stdSizes is used if Config.Sizes == nil.
276 var stdSizes = SizesFor("gc", "amd64")
277 278 func (conf *Config) alignof(T Type) int64 {
279 f := stdSizes.Alignof
280 if conf.Sizes != nil {
281 f = conf.Sizes.Alignof
282 }
283 if a := f(T); a >= 1 {
284 return a
285 }
286 panic("implementation of alignof returned an alignment < 1")
287 }
288 289 func (conf *Config) offsetsof(T *Struct) []int64 {
290 var offsets []int64
291 if T.NumFields() > 0 {
292 // compute offsets on demand
293 f := stdSizes.Offsetsof
294 if conf.Sizes != nil {
295 f = conf.Sizes.Offsetsof
296 }
297 offsets = f(T.fields)
298 // sanity checks
299 if len(offsets) != T.NumFields() {
300 panic("implementation of offsetsof returned the wrong number of offsets")
301 }
302 }
303 return offsets
304 }
305 306 // offsetof returns the offset of the field specified via
307 // the index sequence relative to T. All embedded fields
308 // must be structs (rather than pointers to structs).
309 // If the offset is too large (because T is too large),
310 // the result is negative.
311 func (conf *Config) offsetof(T Type, index []int) int64 {
312 var offs int64
313 for _, i := range index {
314 s := under(T).(*Struct)
315 d := conf.offsetsof(s)[i]
316 if d < 0 {
317 return -1
318 }
319 offs += d
320 if offs < 0 {
321 return -1
322 }
323 T = s.fields[i].typ
324 }
325 return offs
326 }
327 328 // sizeof returns the size of T.
329 // If T is too large, the result is negative.
330 func (conf *Config) sizeof(T Type) int64 {
331 f := stdSizes.Sizeof
332 if conf.Sizes != nil {
333 f = conf.Sizes.Sizeof
334 }
335 return f(T)
336 }
337 338 // align returns the smallest y >= x such that y % a == 0.
339 // a must be within 1 and 8 and it must be a power of 2.
340 // The result may be negative due to overflow.
341 func align(x, a int64) int64 {
342 assert(x >= 0 && 1 <= a && a <= 8 && a&(a-1) == 0)
343 return (x + a - 1) &^ (a - 1)
344 }
345