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 > 16 || 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.flags |= typeIsSIMD
473 if isTag {
474 st.width = 0
475 st.flags |= typeIsSIMDTag
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 sym.Name == "align128" && isAtomicStdPkg(sym.Pkg):
496 maxAlign = 16
497
498 case buildcfg.Experiment.SIMD && (sym.Pkg.Path == "simd/archsimd") && len(t.Fields()) >= 1:
499
500
501 switch sym.Name {
502 case "v128":
503 simdify(t, true)
504 return
505 case "v256":
506 simdify(t, true)
507 return
508 case "v512":
509 simdify(t, true)
510 return
511 case "vsve":
512 simdify(t, true)
513 return
514 case "psve":
515 simdify(t, true)
516 return
517 }
518 }
519 }
520
521 fields := t.Fields()
522
523 size := calcStructOffset(t, fields, 0)
524
525
526
527
528
529 if size > 0 && fields[len(fields)-1].Type.width == 0 {
530 size++
531 }
532
533 var intRegs, floatRegs uint64
534 for _, field := range fields {
535 typ := field.Type
536
537
538
539 if align := typ.align; align > maxAlign {
540 maxAlign = align
541 }
542
543
544
545 intRegs += uint64(typ.intRegs)
546 floatRegs += uint64(typ.floatRegs)
547 }
548
549
550 size = RoundUp(size, int64(maxAlign))
551
552 if intRegs > math.MaxUint8 || floatRegs > math.MaxUint8 {
553 intRegs = math.MaxUint8
554 floatRegs = math.MaxUint8
555 }
556
557 t.width = size
558 t.align = maxAlign
559 t.intRegs = uint8(intRegs)
560 t.floatRegs = uint8(floatRegs)
561
562
563 t.alg = AMEM
564 if t.Noalg() {
565 t.setAlg(ANOALG)
566 }
567 if len(fields) == 1 && !fields[0].Sym.IsBlank() {
568
569 t.setAlg(fields[0].Type.alg)
570 } else {
571 for i, f := range fields {
572 a := f.Type.alg
573 switch a {
574 case ANOEQ, ANOALG:
575 case AMEM:
576
577 if f.Sym.IsBlank() || IsPaddedField(t, i) {
578 a = ASPECIAL
579 }
580 default:
581
582 a = ASPECIAL
583 }
584 t.setAlg(a)
585 }
586 }
587
588 for i := len(fields) - 1; i >= 0; i-- {
589 f := fields[i]
590 if size := PtrDataSize(f.Type); size > 0 {
591 t.ptrBytes = f.Offset + size
592 break
593 }
594 }
595
596 if len(t.Fields()) >= 1 && t.Fields()[0].Type.flags&typeIsSIMDTag != 0 {
597
598 if t.Fields()[0].Type.Sym().Name == "psve" {
599 simdify(t, false)
600
601
602 t.intRegs = math.MaxUint8
603 t.floatRegs = math.MaxUint8
604 } else {
605 simdify(t, false)
606 }
607 }
608 }
609
610
611
612
613 func CalcArraySize(t *Type) {
614 elem := t.Elem()
615 n := t.NumElem()
616 CalcSize(elem)
617 t.SetNotInHeap(elem.NotInHeap())
618 if elem.width != 0 {
619 cap := (uint64(MaxWidth) - 1) / uint64(elem.width)
620 if uint64(n) > cap {
621 base.Errorf("type %L larger than address space", t)
622 }
623 }
624
625 t.width = elem.width * n
626 t.align = elem.align
627
628
629 switch n {
630 case 0:
631 t.intRegs = 0
632 t.floatRegs = 0
633 case 1:
634 t.intRegs = elem.intRegs
635 t.floatRegs = elem.floatRegs
636 default:
637 t.intRegs = math.MaxUint8
638 t.floatRegs = math.MaxUint8
639 }
640 t.alg = AMEM
641 if t.Noalg() {
642 t.setAlg(ANOALG)
643 }
644 switch a := elem.alg; a {
645 case AMEM, ANOEQ, ANOALG:
646 t.setAlg(a)
647 default:
648 switch n {
649 case 0:
650
651 t.setAlg(AMEM)
652 case 1:
653
654 t.setAlg(a)
655 default:
656 t.setAlg(ASPECIAL)
657 }
658 }
659 if n > 0 {
660 x := PtrDataSize(elem)
661 if x > 0 {
662 t.ptrBytes = elem.width*(n-1) + x
663 }
664 }
665 }
666
667 func (t *Type) widthCalculated() bool {
668 return t.align > 0
669 }
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687 var deferredTypeStack []*Type
688
689 func CheckSize(t *Type) {
690 if t == nil {
691 return
692 }
693
694
695
696 if t.IsFuncArgStruct() {
697 base.Fatalf("CheckSize %v", t)
698 }
699
700 if defercalc == 0 {
701 CalcSize(t)
702 return
703 }
704
705
706 if !t.Deferwidth() {
707 t.SetDeferwidth(true)
708 deferredTypeStack = append(deferredTypeStack, t)
709 }
710 }
711
712 func DeferCheckSize() {
713 defercalc++
714 }
715
716 func ResumeCheckSize() {
717 if defercalc == 1 {
718 for len(deferredTypeStack) > 0 {
719 t := deferredTypeStack[len(deferredTypeStack)-1]
720 deferredTypeStack = deferredTypeStack[:len(deferredTypeStack)-1]
721 t.SetDeferwidth(false)
722 CalcSize(t)
723 }
724 }
725
726 defercalc--
727 }
728
729
730
731
732
733
734 func PtrDataSize(t *Type) int64 {
735 CalcSize(t)
736 x := t.ptrBytes
737 if t.Kind() == TPTR && t.Elem().NotInHeap() {
738
739
740
741 x = 0
742 }
743 return x
744 }
745
View as plain text