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