1
2
3
4
5 package types
6
7 import (
8 "math"
9 "slices"
10
11 "cmd/compile/internal/base"
12 "cmd/internal/src"
13 "internal/buildcfg"
14 "internal/types/errors"
15 )
16
17 var PtrSize int
18
19 var RegSize int
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 var (
38 SlicePtrOffset int64
39 SliceLenOffset int64
40 SliceCapOffset int64
41
42 SliceSize int64
43 StringSize int64
44 )
45
46 var SkipSizeForTracing bool
47
48
49
50 func typePos(t *Type) src.XPos {
51 if pos := t.Pos(); pos.IsKnown() {
52 return pos
53 }
54 base.Fatalf("bad type: %v", t)
55 panic("unreachable")
56 }
57
58
59 var MaxWidth int64
60
61
62
63 var CalcSizeDisabled bool
64
65
66
67 var defercalc int
68
69
70 func RoundUp(o int64, r int64) int64 {
71 if r < 1 || r > 8 || r&(r-1) != 0 {
72 base.Fatalf("Round %d", r)
73 }
74 return (o + r - 1) &^ (r - 1)
75 }
76
77
78
79 func expandiface(t *Type) {
80 seen := make(map[*Sym]*Field)
81 var methods []*Field
82
83 addMethod := func(m *Field, explicit bool) {
84 switch prev := seen[m.Sym]; {
85 case prev == nil:
86 seen[m.Sym] = m
87 case !explicit && Identical(m.Type, prev.Type):
88 return
89 default:
90 base.ErrorfAt(m.Pos, errors.DuplicateDecl, "duplicate method %s", m.Sym.Name)
91 }
92 methods = append(methods, m)
93 }
94
95 {
96 methods := t.Methods()
97 slices.SortStableFunc(methods, func(a, b *Field) int {
98
99 if a.Sym == nil && b.Sym == nil {
100 return CompareSyms(a.Type.Sym(), b.Type.Sym())
101 }
102
103
104 if a.Sym == nil {
105 return -1
106 } else if b.Sym == nil {
107 return +1
108 }
109
110
111 return CompareSyms(a.Sym, b.Sym)
112 })
113 }
114
115 for _, m := range t.Methods() {
116 if m.Sym == nil {
117 continue
118 }
119
120 CheckSize(m.Type)
121 addMethod(m, true)
122 }
123
124 for _, m := range t.Methods() {
125 if m.Sym != nil || m.Type == nil {
126 continue
127 }
128
129
130
131
132 if !m.Type.IsInterface() {
133 continue
134 }
135
136
137
138 for _, t1 := range m.Type.AllMethods() {
139 f := NewField(m.Pos, t1.Sym, t1.Type)
140 addMethod(f, false)
141
142
143 f.Pos = src.NoXPos
144 }
145
146
147 m.Pos = src.NoXPos
148 }
149
150 slices.SortFunc(methods, CompareFields)
151
152 if int64(len(methods)) >= MaxWidth/int64(PtrSize) {
153 base.ErrorfAt(typePos(t), 0, "interface too large")
154 }
155 for i, m := range methods {
156 m.Offset = int64(i) * int64(PtrSize)
157 }
158
159 t.SetAllMethods(methods)
160 }
161
162
163
164
165 func calcStructOffset(t *Type, fields []*Field, offset int64) int64 {
166 for _, f := range fields {
167 CalcSize(f.Type)
168 offset = RoundUp(offset, int64(f.Type.align))
169
170 if t.IsStruct() {
171 f.Offset = offset
172
173
174
175
176
177 if f.Type.NotInHeap() {
178 t.SetNotInHeap(true)
179 }
180 }
181
182 offset += f.Type.width
183
184 maxwidth := MaxWidth
185
186
187 if maxwidth < 1<<32 {
188 maxwidth = 1<<31 - 1
189 }
190 if offset >= maxwidth {
191 base.ErrorfAt(typePos(t), 0, "type %L too large", t)
192 offset = 8
193 }
194 }
195
196 return offset
197 }
198
199 func isAtomicStdPkg(p *Pkg) bool {
200 if p.Prefix == `""` {
201 panic("bad package prefix")
202 }
203 return p.Prefix == "sync/atomic" || p.Prefix == "internal/runtime/atomic"
204 }
205
206
207
208
209
210
211 func CalcSize(t *Type) {
212
213
214 if base.EnableTrace && SkipSizeForTracing {
215 return
216 }
217 if PtrSize == 0 {
218
219 return
220 }
221
222 if t == nil {
223 return
224 }
225
226 if t.width == -2 {
227 t.width = 0
228 t.align = 1
229 base.Fatalf("invalid recursive type %v", t)
230 return
231 }
232
233 if t.widthCalculated() {
234 return
235 }
236
237 if CalcSizeDisabled {
238 base.Fatalf("width not calculated: %v", t)
239 }
240
241
242 DeferCheckSize()
243
244 lno := base.Pos
245 if pos := t.Pos(); pos.IsKnown() {
246 base.Pos = pos
247 }
248
249 t.width = -2
250 t.align = 0
251 t.alg = AMEM
252
253 if t.Noalg() {
254 t.setAlg(ANOALG)
255 }
256
257 et := t.Kind()
258 switch et {
259 case TFUNC, TCHAN, TMAP, TSTRING:
260 break
261
262
263 default:
264 if SimType[t.Kind()] != 0 {
265 et = SimType[t.Kind()]
266 }
267 }
268
269 var w int64
270 switch et {
271 default:
272 base.Fatalf("CalcSize: unknown type: %v", t)
273
274
275 case TINT8, TUINT8, TBOOL:
276
277 w = 1
278 t.intRegs = 1
279
280 case TINT16, TUINT16:
281 w = 2
282 t.intRegs = 1
283
284 case TINT32, TUINT32:
285 w = 4
286 t.intRegs = 1
287
288 case TINT64, TUINT64:
289 w = 8
290 t.align = uint8(RegSize)
291 t.intRegs = uint8(8 / RegSize)
292
293 case TFLOAT32:
294 w = 4
295 t.floatRegs = 1
296 t.setAlg(AFLOAT32)
297
298 case TFLOAT64:
299 w = 8
300 t.align = uint8(RegSize)
301 t.floatRegs = 1
302 t.setAlg(AFLOAT64)
303
304 case TCOMPLEX64:
305 w = 8
306 t.align = 4
307 t.floatRegs = 2
308 t.setAlg(ACPLX64)
309
310 case TCOMPLEX128:
311 w = 16
312 t.align = uint8(RegSize)
313 t.floatRegs = 2
314 t.setAlg(ACPLX128)
315
316 case TPTR:
317 w = int64(PtrSize)
318 t.intRegs = 1
319 CheckSize(t.Elem())
320 t.ptrBytes = int64(PtrSize)
321
322 case TUNSAFEPTR:
323 w = int64(PtrSize)
324 t.intRegs = 1
325 t.ptrBytes = int64(PtrSize)
326
327 case TINTER:
328 w = 2 * int64(PtrSize)
329 t.align = uint8(PtrSize)
330 t.intRegs = 2
331 expandiface(t)
332 if len(t.allMethods.Slice()) == 0 {
333 t.setAlg(ANILINTER)
334 } else {
335 t.setAlg(AINTER)
336 }
337 t.ptrBytes = int64(2 * PtrSize)
338
339 case TCHAN:
340 w = int64(PtrSize)
341 t.intRegs = 1
342 t.ptrBytes = int64(PtrSize)
343
344 CheckSize(t.Elem())
345
346
347
348 t1 := NewChanArgs(t)
349 CheckSize(t1)
350
351 case TCHANARGS:
352 t1 := t.ChanArgs()
353 CalcSize(t1)
354
355
356
357
358 CalcSize(t1.Elem())
359 if t1.Elem().width >= 1<<16 {
360 base.Errorf("channel element type too large (>64kB)")
361 }
362 w = 1
363
364 case TMAP:
365 w = int64(PtrSize)
366 t.intRegs = 1
367 CheckSize(t.Elem())
368 CheckSize(t.Key())
369 if t.Elem().width >= 1<<31 {
370 base.Errorf("map element type too large")
371 }
372 if t.Key().width >= 1<<31 {
373 base.Errorf("map key type too large")
374 }
375 t.setAlg(ANOEQ)
376 t.ptrBytes = int64(PtrSize)
377
378 case TFORW:
379 base.Fatalf("invalid recursive type %v", t)
380
381 case TANY:
382 base.Fatalf("CalcSize any")
383
384 case TSTRING:
385 if StringSize == 0 {
386 base.Fatalf("early CalcSize string")
387 }
388 w = StringSize
389 t.align = uint8(PtrSize)
390 t.intRegs = 2
391 t.setAlg(ASTRING)
392 t.ptrBytes = int64(PtrSize)
393
394 case TARRAY:
395 if t.Elem() == nil {
396 break
397 }
398 CalcArraySize(t)
399 w = t.width
400
401 case TSLICE:
402 if t.Elem() == nil {
403 break
404 }
405 w = SliceSize
406 CheckSize(t.Elem())
407 t.align = uint8(PtrSize)
408 t.intRegs = 3
409 t.setAlg(ANOEQ)
410 if !t.Elem().NotInHeap() {
411 t.ptrBytes = int64(PtrSize)
412 }
413
414 case TSTRUCT:
415 if t.IsFuncArgStruct() {
416 base.Fatalf("CalcSize fn struct %v", t)
417 }
418 CalcStructSize(t)
419 w = t.width
420
421
422
423 case TFUNC:
424 t1 := NewFuncArgs(t)
425 CheckSize(t1)
426 w = int64(PtrSize)
427 t.intRegs = 1
428 t.setAlg(ANOEQ)
429 t.ptrBytes = int64(PtrSize)
430
431
432
433 case TFUNCARGS:
434 t1 := t.FuncArgs()
435
436 w = calcStructOffset(t1, t1.Recvs(), 0)
437 w = calcStructOffset(t1, t1.Params(), w)
438 w = RoundUp(w, int64(RegSize))
439 w = calcStructOffset(t1, t1.Results(), w)
440 w = RoundUp(w, int64(RegSize))
441 t1.extra.(*Func).Argwid = w
442 t.align = 1
443 }
444
445 if PtrSize == 4 && w != int64(int32(w)) {
446 base.Errorf("type %v too large", t)
447 }
448
449 t.width = w
450 if t.align == 0 {
451 if w == 0 || w > 8 || w&(w-1) != 0 {
452 base.Fatalf("invalid alignment for %v", t)
453 }
454 t.align = uint8(w)
455 }
456
457 base.Pos = lno
458
459 ResumeCheckSize()
460 }
461
462
463
464
465
466
467
468 func simdify(st *Type, isTag bool) {
469 st.align = 8
470 st.alg = ANOALG
471 st.intRegs = 0
472 st.isSIMD = true
473 if isTag {
474 st.width = 0
475 st.isSIMDTag = true
476 st.floatRegs = 0
477 } else {
478 st.floatRegs = 1
479 }
480 }
481
482
483
484
485 func CalcStructSize(t *Type) {
486 var maxAlign uint8 = 1
487
488
489
490 if sym := t.Sym(); sym != nil {
491 switch {
492 case sym.Name == "align64" && isAtomicStdPkg(sym.Pkg):
493 maxAlign = 8
494
495 case buildcfg.Experiment.SIMD && (sym.Pkg.Path == "simd/archsimd") && len(t.Fields()) >= 1:
496
497
498 switch sym.Name {
499 case "v128":
500 simdify(t, true)
501 return
502 case "v256":
503 simdify(t, true)
504 return
505 case "v512":
506 simdify(t, true)
507 return
508 }
509 }
510 }
511
512 fields := t.Fields()
513
514 size := calcStructOffset(t, fields, 0)
515
516
517
518
519
520 if size > 0 && fields[len(fields)-1].Type.width == 0 {
521 size++
522 }
523
524 var intRegs, floatRegs uint64
525 for _, field := range fields {
526 typ := field.Type
527
528
529
530 if align := typ.align; align > maxAlign {
531 maxAlign = align
532 }
533
534
535
536 intRegs += uint64(typ.intRegs)
537 floatRegs += uint64(typ.floatRegs)
538 }
539
540
541 size = RoundUp(size, int64(maxAlign))
542
543 if intRegs > math.MaxUint8 || floatRegs > math.MaxUint8 {
544 intRegs = math.MaxUint8
545 floatRegs = math.MaxUint8
546 }
547
548 t.width = size
549 t.align = maxAlign
550 t.intRegs = uint8(intRegs)
551 t.floatRegs = uint8(floatRegs)
552
553
554 t.alg = AMEM
555 if t.Noalg() {
556 t.setAlg(ANOALG)
557 }
558 if len(fields) == 1 && !fields[0].Sym.IsBlank() {
559
560 t.setAlg(fields[0].Type.alg)
561 } else {
562 for i, f := range fields {
563 a := f.Type.alg
564 switch a {
565 case ANOEQ, ANOALG:
566 case AMEM:
567
568 if f.Sym.IsBlank() || IsPaddedField(t, i) {
569 a = ASPECIAL
570 }
571 default:
572
573 a = ASPECIAL
574 }
575 t.setAlg(a)
576 }
577 }
578
579 for i := len(fields) - 1; i >= 0; i-- {
580 f := fields[i]
581 if size := PtrDataSize(f.Type); size > 0 {
582 t.ptrBytes = f.Offset + size
583 break
584 }
585 }
586
587 if len(t.Fields()) >= 1 && t.Fields()[0].Type.isSIMDTag {
588
589 simdify(t, false)
590 }
591 }
592
593
594
595
596 func CalcArraySize(t *Type) {
597 elem := t.Elem()
598 n := t.NumElem()
599 CalcSize(elem)
600 t.SetNotInHeap(elem.NotInHeap())
601 if elem.width != 0 {
602 cap := (uint64(MaxWidth) - 1) / uint64(elem.width)
603 if uint64(n) > cap {
604 base.Errorf("type %L larger than address space", t)
605 }
606 }
607
608 t.width = elem.width * n
609 t.align = elem.align
610
611
612 switch n {
613 case 0:
614 t.intRegs = 0
615 t.floatRegs = 0
616 case 1:
617 t.intRegs = elem.intRegs
618 t.floatRegs = elem.floatRegs
619 default:
620 t.intRegs = math.MaxUint8
621 t.floatRegs = math.MaxUint8
622 }
623 t.alg = AMEM
624 if t.Noalg() {
625 t.setAlg(ANOALG)
626 }
627 switch a := elem.alg; a {
628 case AMEM, ANOEQ, ANOALG:
629 t.setAlg(a)
630 default:
631 switch n {
632 case 0:
633
634 t.setAlg(AMEM)
635 case 1:
636
637 t.setAlg(a)
638 default:
639 t.setAlg(ASPECIAL)
640 }
641 }
642 if n > 0 {
643 x := PtrDataSize(elem)
644 if x > 0 {
645 t.ptrBytes = elem.width*(n-1) + x
646 }
647 }
648 }
649
650 func (t *Type) widthCalculated() bool {
651 return t.align > 0
652 }
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670 var deferredTypeStack []*Type
671
672 func CheckSize(t *Type) {
673 if t == nil {
674 return
675 }
676
677
678
679 if t.IsFuncArgStruct() {
680 base.Fatalf("CheckSize %v", t)
681 }
682
683 if defercalc == 0 {
684 CalcSize(t)
685 return
686 }
687
688
689 if !t.Deferwidth() {
690 t.SetDeferwidth(true)
691 deferredTypeStack = append(deferredTypeStack, t)
692 }
693 }
694
695 func DeferCheckSize() {
696 defercalc++
697 }
698
699 func ResumeCheckSize() {
700 if defercalc == 1 {
701 for len(deferredTypeStack) > 0 {
702 t := deferredTypeStack[len(deferredTypeStack)-1]
703 deferredTypeStack = deferredTypeStack[:len(deferredTypeStack)-1]
704 t.SetDeferwidth(false)
705 CalcSize(t)
706 }
707 }
708
709 defercalc--
710 }
711
712
713
714
715
716
717 func PtrDataSize(t *Type) int64 {
718 CalcSize(t)
719 x := t.ptrBytes
720 if t.Kind() == TPTR && t.Elem().NotInHeap() {
721
722
723
724 x = 0
725 }
726 return x
727 }
728
View as plain text