Source file
src/go/types/sizes.go
1
2
3
4
5
6
7
8
9 package types
10
11
12 type Sizes interface {
13
14
15
16 Alignof(T Type) int64
17
18
19
20
21 Offsetsof(fields []*Var) []int64
22
23
24
25
26 Sizeof(T Type) int64
27 }
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 type StdSizes struct {
48 WordSize int64
49 MaxAlign int64
50 }
51
52 func (s *StdSizes) Alignof(T Type) (result int64) {
53 defer func() {
54 assert(result >= 1)
55 }()
56
57
58
59 switch t := under(T).(type) {
60 case *Array:
61
62
63 return s.Alignof(t.elem)
64 case *Struct:
65 if len(t.fields) == 0 && _IsSyncAtomicAlign64(T) {
66
67
68
69
70
71
72
73 return 8
74 }
75
76
77
78
79 max := int64(1)
80 for _, f := range t.fields {
81 if a := s.Alignof(f.typ); a > max {
82 max = a
83 }
84 }
85 return max
86 case *Slice, *Interface:
87
88
89
90
91 assert(!isTypeParam(T))
92 return s.WordSize
93 case *Basic:
94
95 if t.Info()&IsString != 0 {
96 return s.WordSize
97 }
98 case *TypeParam, *Union:
99 unreachable()
100 }
101 a := s.Sizeof(T)
102
103 if a < 1 {
104 return 1
105 }
106
107 if isComplex(T) {
108 a /= 2
109 }
110 if a > s.MaxAlign {
111 return s.MaxAlign
112 }
113 return a
114 }
115
116 func _IsSyncAtomicAlign64(T Type) bool {
117 named := asNamed(T)
118 if named == nil {
119 return false
120 }
121 obj := named.Obj()
122 return obj.Name() == "align64" &&
123 obj.Pkg() != nil &&
124 (obj.Pkg().Path() == "sync/atomic" ||
125 obj.Pkg().Path() == "runtime/internal/atomic")
126 }
127
128 func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
129 offsets := make([]int64, len(fields))
130 var offs int64
131 for i, f := range fields {
132 if offs < 0 {
133
134 offsets[i] = -1
135 continue
136 }
137
138 a := s.Alignof(f.typ)
139 offs = align(offs, a)
140 offsets[i] = offs
141 if d := s.Sizeof(f.typ); d >= 0 && offs >= 0 {
142 offs += d
143 } else {
144 offs = -1
145 }
146 }
147 return offsets
148 }
149
150 var basicSizes = [...]byte{
151 Bool: 1,
152 Int8: 1,
153 Int16: 2,
154 Int32: 4,
155 Int64: 8,
156 Uint8: 1,
157 Uint16: 2,
158 Uint32: 4,
159 Uint64: 8,
160 Float32: 4,
161 Float64: 8,
162 Complex64: 8,
163 Complex128: 16,
164 }
165
166 func (s *StdSizes) Sizeof(T Type) int64 {
167 switch t := under(T).(type) {
168 case *Basic:
169 assert(isTyped(T))
170 k := t.kind
171 if int(k) < len(basicSizes) {
172 if s := basicSizes[k]; s > 0 {
173 return int64(s)
174 }
175 }
176 if k == String {
177 return s.WordSize * 2
178 }
179 case *Array:
180 n := t.len
181 if n <= 0 {
182 return 0
183 }
184
185 esize := s.Sizeof(t.elem)
186 if esize < 0 {
187 return -1
188 }
189 if esize == 0 {
190 return 0
191 }
192
193 a := s.Alignof(t.elem)
194 ea := align(esize, a)
195 if ea < 0 {
196 return -1
197 }
198
199 n1 := n - 1
200
201 const maxInt64 = 1<<63 - 1
202 if n1 > 0 && ea > maxInt64/n1 {
203 return -1
204 }
205 return ea*n1 + esize
206 case *Slice:
207 return s.WordSize * 3
208 case *Struct:
209 n := t.NumFields()
210 if n == 0 {
211 return 0
212 }
213 offsets := s.Offsetsof(t.fields)
214 offs := offsets[n-1]
215 size := s.Sizeof(t.fields[n-1].typ)
216 if offs < 0 || size < 0 {
217 return -1
218 }
219 return offs + size
220 case *Interface:
221
222
223 assert(!isTypeParam(T))
224 return s.WordSize * 2
225 case *TypeParam, *Union:
226 unreachable()
227 }
228 return s.WordSize
229 }
230
231
232 var gcArchSizes = map[string]*gcSizes{
233 "386": {4, 4},
234 "amd64": {8, 8},
235 "amd64p32": {4, 8},
236 "arm": {4, 4},
237 "arm64": {8, 8},
238 "loong64": {8, 8},
239 "mips": {4, 4},
240 "mipsle": {4, 4},
241 "mips64": {8, 8},
242 "mips64le": {8, 8},
243 "ppc64": {8, 8},
244 "ppc64le": {8, 8},
245 "riscv64": {8, 8},
246 "s390x": {8, 8},
247 "sparc64": {8, 8},
248 "wasm": {8, 8},
249
250
251 }
252
253
254
255
256
257
258
259 func SizesFor(compiler, arch string) Sizes {
260 switch compiler {
261 case "gc":
262 if s := gcSizesFor(compiler, arch); s != nil {
263 return Sizes(s)
264 }
265 case "gccgo":
266 if s, ok := gccgoArchSizes[arch]; ok {
267 return Sizes(s)
268 }
269 }
270 return nil
271 }
272
273
274 var stdSizes = SizesFor("gc", "amd64")
275
276 func (conf *Config) alignof(T Type) int64 {
277 f := stdSizes.Alignof
278 if conf.Sizes != nil {
279 f = conf.Sizes.Alignof
280 }
281 if a := f(T); a >= 1 {
282 return a
283 }
284 panic("implementation of alignof returned an alignment < 1")
285 }
286
287 func (conf *Config) offsetsof(T *Struct) []int64 {
288 var offsets []int64
289 if T.NumFields() > 0 {
290
291 f := stdSizes.Offsetsof
292 if conf.Sizes != nil {
293 f = conf.Sizes.Offsetsof
294 }
295 offsets = f(T.fields)
296
297 if len(offsets) != T.NumFields() {
298 panic("implementation of offsetsof returned the wrong number of offsets")
299 }
300 }
301 return offsets
302 }
303
304
305
306
307
308
309 func (conf *Config) offsetof(T Type, index []int) int64 {
310 var offs int64
311 for _, i := range index {
312 s := under(T).(*Struct)
313 d := conf.offsetsof(s)[i]
314 if d < 0 {
315 return -1
316 }
317 offs += d
318 if offs < 0 {
319 return -1
320 }
321 T = s.fields[i].typ
322 }
323 return offs
324 }
325
326
327
328 func (conf *Config) sizeof(T Type) int64 {
329 f := stdSizes.Sizeof
330 if conf.Sizes != nil {
331 f = conf.Sizes.Sizeof
332 }
333 return f(T)
334 }
335
336
337
338
339 func align(x, a int64) int64 {
340 assert(x >= 0 && 1 <= a && a <= 8 && a&(a-1) == 0)
341 return (x + a - 1) &^ (a - 1)
342 }
343
View as plain text