Source file
src/go/types/sizes.go
1
2
3
4
5
6
7
8
9
10 package types
11
12
13 type Sizes interface {
14
15
16
17 Alignof(T Type) int64
18
19
20
21
22 Offsetsof(fields []*Var) []int64
23
24
25
26
27 Sizeof(T Type) int64
28 }
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 type StdSizes struct {
49 WordSize int64
50 MaxAlign int64
51 }
52
53 func (s *StdSizes) Alignof(T Type) (result int64) {
54 defer func() {
55 assert(result >= 1)
56 }()
57
58
59
60 switch t := under(T).(type) {
61 case *Array:
62
63
64 return s.Alignof(t.elem)
65 case *Struct:
66 if len(t.fields) == 0 && _IsSyncAtomicAlign64(T) {
67
68
69
70
71
72
73
74 return 8
75 }
76
77
78
79
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
89
90
91
92 assert(!isTypeParam(T))
93 return s.WordSize
94 case *Basic:
95
96 if t.Info()&IsString != 0 {
97 return s.WordSize
98 }
99 case *TypeParam, *Union:
100 panic("unreachable")
101 }
102 a := s.Sizeof(T)
103
104 if a < 1 {
105 return 1
106 }
107
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
135 offsets[i] = -1
136 continue
137 }
138
139 a := s.Alignof(f.typ)
140 offs = align(offs, a)
141 offsets[i] = offs
142 if d := s.Sizeof(f.typ); d >= 0 && offs >= 0 {
143 offs += d
144 } else {
145 offs = -1
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 return s.WordSize * 2
179 }
180 case *Array:
181 n := t.len
182 if n <= 0 {
183 return 0
184 }
185
186 esize := s.Sizeof(t.elem)
187 if esize < 0 {
188 return -1
189 }
190 if esize == 0 {
191 return 0
192 }
193
194 a := s.Alignof(t.elem)
195 ea := align(esize, a)
196 if ea < 0 {
197 return -1
198 }
199
200 n1 := n - 1
201
202 const maxInt64 = 1<<63 - 1
203 if n1 > 0 && ea > maxInt64/n1 {
204 return -1
205 }
206 return ea*n1 + esize
207 case *Slice:
208 return s.WordSize * 3
209 case *Struct:
210 n := t.NumFields()
211 if n == 0 {
212 return 0
213 }
214 offsets := s.Offsetsof(t.fields)
215 offs := offsets[n-1]
216 size := s.Sizeof(t.fields[n-1].typ)
217 if offs < 0 || size < 0 {
218 return -1
219 }
220 return offs + size
221 case *Interface:
222
223
224 assert(!isTypeParam(T))
225 return s.WordSize * 2
226 case *TypeParam, *Union:
227 panic("unreachable")
228 }
229 return s.WordSize
230 }
231
232
233 var gcArchSizes = map[string]*gcSizes{
234 "386": {4, 4},
235 "amd64": {8, 8},
236 "amd64p32": {4, 8},
237 "arm": {4, 4},
238 "arm64": {8, 8},
239 "loong64": {8, 8},
240 "mips": {4, 4},
241 "mipsle": {4, 4},
242 "mips64": {8, 8},
243 "mips64le": {8, 8},
244 "ppc64": {8, 8},
245 "ppc64le": {8, 8},
246 "riscv64": {8, 8},
247 "s390x": {8, 8},
248 "sparc64": {8, 8},
249 "wasm": {8, 8},
250
251
252 }
253
254
255
256
257
258
259
260 func SizesFor(compiler, arch string) Sizes {
261 switch compiler {
262 case "gc":
263 if s := gcSizesFor(compiler, arch); s != nil {
264 return Sizes(s)
265 }
266 case "gccgo":
267 if s, ok := gccgoArchSizes[arch]; ok {
268 return Sizes(s)
269 }
270 }
271 return nil
272 }
273
274
275 var stdSizes = SizesFor("gc", "amd64")
276
277 func (conf *Config) alignof(T Type) int64 {
278 f := stdSizes.Alignof
279 if conf.Sizes != nil {
280 f = conf.Sizes.Alignof
281 }
282 if a := f(T); a >= 1 {
283 return a
284 }
285 panic("implementation of alignof returned an alignment < 1")
286 }
287
288 func (conf *Config) offsetsof(T *Struct) []int64 {
289 var offsets []int64
290 if T.NumFields() > 0 {
291
292 f := stdSizes.Offsetsof
293 if conf.Sizes != nil {
294 f = conf.Sizes.Offsetsof
295 }
296 offsets = f(T.fields)
297
298 if len(offsets) != T.NumFields() {
299 panic("implementation of offsetsof returned the wrong number of offsets")
300 }
301 }
302 return offsets
303 }
304
305
306
307
308
309
310 func (conf *Config) offsetof(T Type, index []int) int64 {
311 var offs int64
312 for _, i := range index {
313 s := under(T).(*Struct)
314 d := conf.offsetsof(s)[i]
315 if d < 0 {
316 return -1
317 }
318 offs += d
319 if offs < 0 {
320 return -1
321 }
322 T = s.fields[i].typ
323 }
324 return offs
325 }
326
327
328
329 func (conf *Config) sizeof(T Type) int64 {
330 f := stdSizes.Sizeof
331 if conf.Sizes != nil {
332 f = conf.Sizes.Sizeof
333 }
334 return f(T)
335 }
336
337
338
339
340 func align(x, a int64) int64 {
341 assert(x >= 0 && 1 <= a && a <= 8 && a&(a-1) == 0)
342 return (x + a - 1) &^ (a - 1)
343 }
344
View as plain text