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