1
2
3
4
5 package types
6
7 import (
8 "bytes"
9 "fmt"
10 "sort"
11
12 "cmd/compile/internal/base"
13 "cmd/internal/src"
14 )
15
16 var PtrSize int
17
18 var RegSize int
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 var (
37 SlicePtrOffset int64
38 SliceLenOffset int64
39 SliceCapOffset int64
40
41 SliceSize int64
42 StringSize int64
43 )
44
45 var SkipSizeForTracing bool
46
47
48
49 func typePos(t *Type) src.XPos {
50 if pos := t.Pos(); pos.IsKnown() {
51 return pos
52 }
53 base.Fatalf("bad type: %v", t)
54 panic("unreachable")
55 }
56
57
58 var MaxWidth int64
59
60
61
62 var CalcSizeDisabled bool
63
64
65
66 var defercalc int
67
68 func Rnd(o int64, r int64) int64 {
69 if r < 1 || r > 8 || r&(r-1) != 0 {
70 base.Fatalf("rnd %d", r)
71 }
72 return (o + r - 1) &^ (r - 1)
73 }
74
75
76
77 func expandiface(t *Type) {
78 seen := make(map[*Sym]*Field)
79 var methods []*Field
80
81 addMethod := func(m *Field, explicit bool) {
82 switch prev := seen[m.Sym]; {
83 case prev == nil:
84 seen[m.Sym] = m
85 case AllowsGoVersion(t.Pkg(), 1, 14) && !explicit && Identical(m.Type, prev.Type):
86 return
87 default:
88 base.ErrorfAt(m.Pos, "duplicate method %s", m.Sym.Name)
89 }
90 methods = append(methods, m)
91 }
92
93 for _, m := range t.Methods().Slice() {
94 if m.Sym == nil {
95 continue
96 }
97
98 CheckSize(m.Type)
99 addMethod(m, true)
100 }
101
102 for _, m := range t.Methods().Slice() {
103 if m.Sym != nil || m.Type == nil {
104 continue
105 }
106
107 if !m.Type.IsInterface() {
108 base.ErrorfAt(m.Pos, "interface contains embedded non-interface %v", m.Type)
109 m.SetBroke(true)
110 t.SetBroke(true)
111
112
113
114
115 methods = append(methods, m)
116 continue
117 }
118
119
120
121
122 for _, t1 := range m.Type.AllMethods().Slice() {
123
124 f := NewField(m.Pos, t1.Sym, t1.Type)
125 addMethod(f, false)
126 }
127 }
128
129 sort.Sort(MethodsByName(methods))
130
131 if int64(len(methods)) >= MaxWidth/int64(PtrSize) {
132 base.ErrorfAt(typePos(t), "interface too large")
133 }
134 for i, m := range methods {
135 m.Offset = int64(i) * int64(PtrSize)
136 }
137
138 t.SetAllMethods(methods)
139 }
140
141 func calcStructOffset(errtype *Type, t *Type, o int64, flag int) int64 {
142
143 isStruct := flag == 1
144 starto := o
145 maxalign := int32(flag)
146 if maxalign < 1 {
147 maxalign = 1
148 }
149 lastzero := int64(0)
150 for _, f := range t.Fields().Slice() {
151 if f.Type == nil {
152
153
154 continue
155 }
156
157 CalcSize(f.Type)
158 if int32(f.Type.Align) > maxalign {
159 maxalign = int32(f.Type.Align)
160 }
161 if f.Type.Align > 0 {
162 o = Rnd(o, int64(f.Type.Align))
163 }
164 if isStruct {
165 f.Offset = o
166 }
167
168 w := f.Type.Width
169 if w < 0 {
170 base.Fatalf("invalid width %d", f.Type.Width)
171 }
172 if w == 0 {
173 lastzero = o
174 }
175 o += w
176 maxwidth := MaxWidth
177
178
179 if maxwidth < 1<<32 {
180 maxwidth = 1<<31 - 1
181 }
182 if o >= maxwidth {
183 base.ErrorfAt(typePos(errtype), "type %L too large", errtype)
184 o = 8
185 }
186 }
187
188
189
190
191
192 if flag == 1 && o > starto && o == lastzero {
193 o++
194 }
195
196
197 if flag != 0 {
198 o = Rnd(o, int64(maxalign))
199 }
200 t.Align = uint8(maxalign)
201
202
203 t.Width = o - starto
204
205 return o
206 }
207
208
209
210
211
212
213
214
215 func findTypeLoop(t *Type, path *[]*Type) bool {
216
217
218
219 if t.Sym() != nil {
220
221
222
223
224
225
226
227 if t.Sym().Pkg != LocalPkg {
228 return false
229 }
230
231 for i, x := range *path {
232 if x == t {
233 *path = (*path)[i:]
234 return true
235 }
236 }
237
238 *path = append(*path, t)
239 if findTypeLoop(t.Obj().(TypeObject).TypeDefn(), path) {
240 return true
241 }
242 *path = (*path)[:len(*path)-1]
243 } else {
244
245
246 switch t.Kind() {
247 case TARRAY:
248 if findTypeLoop(t.Elem(), path) {
249 return true
250 }
251 case TSTRUCT:
252 for _, f := range t.Fields().Slice() {
253 if findTypeLoop(f.Type, path) {
254 return true
255 }
256 }
257 case TINTER:
258 for _, m := range t.Methods().Slice() {
259 if m.Type.IsInterface() {
260 if findTypeLoop(m.Type, path) {
261 return true
262 }
263 }
264 }
265 }
266 }
267
268 return false
269 }
270
271 func reportTypeLoop(t *Type) {
272 if t.Broke() {
273 return
274 }
275
276 var l []*Type
277 if !findTypeLoop(t, &l) {
278 base.Fatalf("failed to find type loop for: %v", t)
279 }
280
281
282 i := 0
283 for j, t := range l[1:] {
284 if typePos(t).Before(typePos(l[i])) {
285 i = j + 1
286 }
287 }
288 l = append(l[i:], l[:i]...)
289
290 var msg bytes.Buffer
291 fmt.Fprintf(&msg, "invalid recursive type %v\n", l[0])
292 for _, t := range l {
293 fmt.Fprintf(&msg, "\t%v: %v refers to\n", base.FmtPos(typePos(t)), t)
294 t.SetBroke(true)
295 }
296 fmt.Fprintf(&msg, "\t%v: %v", base.FmtPos(typePos(l[0])), l[0])
297 base.ErrorfAt(typePos(l[0]), msg.String())
298 }
299
300
301
302
303
304 func CalcSize(t *Type) {
305
306
307 if base.EnableTrace && SkipSizeForTracing {
308 return
309 }
310 if PtrSize == 0 {
311
312 return
313 }
314
315 if t == nil {
316 return
317 }
318
319 if t.Width == -2 {
320 reportTypeLoop(t)
321 t.Width = 0
322 t.Align = 1
323 return
324 }
325
326 if t.WidthCalculated() {
327 return
328 }
329
330 if CalcSizeDisabled {
331 if t.Broke() {
332
333 return
334 }
335 t.SetBroke(true)
336 base.Fatalf("width not calculated: %v", t)
337 }
338
339
340
341 if t.Broke() && t.Width == 0 {
342 return
343 }
344
345
346 DeferCheckSize()
347
348 lno := base.Pos
349 if pos := t.Pos(); pos.IsKnown() {
350 base.Pos = pos
351 }
352
353 t.Width = -2
354 t.Align = 0
355
356 et := t.Kind()
357 switch et {
358 case TFUNC, TCHAN, TMAP, TSTRING:
359 break
360
361
362 default:
363 if SimType[t.Kind()] != 0 {
364 et = SimType[t.Kind()]
365 }
366 }
367
368 var w int64
369 switch et {
370 default:
371 base.Fatalf("CalcSize: unknown type: %v", t)
372
373
374 case TINT8, TUINT8, TBOOL:
375
376 w = 1
377
378 case TINT16, TUINT16:
379 w = 2
380
381 case TINT32, TUINT32, TFLOAT32:
382 w = 4
383
384 case TINT64, TUINT64, TFLOAT64:
385 w = 8
386 t.Align = uint8(RegSize)
387
388 case TCOMPLEX64:
389 w = 8
390 t.Align = 4
391
392 case TCOMPLEX128:
393 w = 16
394 t.Align = uint8(RegSize)
395
396 case TPTR:
397 w = int64(PtrSize)
398 CheckSize(t.Elem())
399
400 case TUNSAFEPTR:
401 w = int64(PtrSize)
402
403 case TINTER:
404 w = 2 * int64(PtrSize)
405 t.Align = uint8(PtrSize)
406 expandiface(t)
407
408 case TCHAN:
409 w = int64(PtrSize)
410
411 CheckSize(t.Elem())
412
413
414
415 t1 := NewChanArgs(t)
416 CheckSize(t1)
417
418 case TCHANARGS:
419 t1 := t.ChanArgs()
420 CalcSize(t1)
421 if t1.Elem().Width >= 1<<16 {
422 base.ErrorfAt(typePos(t1), "channel element type too large (>64kB)")
423 }
424 w = 1
425
426 case TMAP:
427 w = int64(PtrSize)
428 CheckSize(t.Elem())
429 CheckSize(t.Key())
430
431 case TFORW:
432 reportTypeLoop(t)
433 w = 1
434
435 case TANY:
436
437 base.Fatalf("CalcSize any")
438
439 case TSTRING:
440 if StringSize == 0 {
441 base.Fatalf("early CalcSize string")
442 }
443 w = StringSize
444 t.Align = uint8(PtrSize)
445
446 case TARRAY:
447 if t.Elem() == nil {
448 break
449 }
450
451 CalcSize(t.Elem())
452 if t.Elem().Width != 0 {
453 cap := (uint64(MaxWidth) - 1) / uint64(t.Elem().Width)
454 if uint64(t.NumElem()) > cap {
455 base.ErrorfAt(typePos(t), "type %L larger than address space", t)
456 }
457 }
458 w = t.NumElem() * t.Elem().Width
459 t.Align = t.Elem().Align
460
461 case TSLICE:
462 if t.Elem() == nil {
463 break
464 }
465 w = SliceSize
466 CheckSize(t.Elem())
467 t.Align = uint8(PtrSize)
468
469 case TSTRUCT:
470 if t.IsFuncArgStruct() {
471 base.Fatalf("CalcSize fn struct %v", t)
472 }
473 w = calcStructOffset(t, t, 0, 1)
474
475
476
477 case TFUNC:
478 t1 := NewFuncArgs(t)
479 CheckSize(t1)
480 w = int64(PtrSize)
481
482
483
484 case TFUNCARGS:
485 t1 := t.FuncArgs()
486 w = calcStructOffset(t1, t1.Recvs(), 0, 0)
487 w = calcStructOffset(t1, t1.Params(), w, RegSize)
488 w = calcStructOffset(t1, t1.Results(), w, RegSize)
489 t1.Extra.(*Func).Argwid = w
490 if w%int64(RegSize) != 0 {
491 base.Warn("bad type %v %d\n", t1, w)
492 }
493 t.Align = 1
494
495 case TTYPEPARAM:
496
497
498 w = int64(PtrSize)
499 }
500
501 if PtrSize == 4 && w != int64(int32(w)) {
502 base.ErrorfAt(typePos(t), "type %v too large", t)
503 }
504
505 t.Width = w
506 if t.Align == 0 {
507 if w == 0 || w > 8 || w&(w-1) != 0 {
508 base.Fatalf("invalid alignment for %v", t)
509 }
510 t.Align = uint8(w)
511 }
512
513 base.Pos = lno
514
515 ResumeCheckSize()
516 }
517
518
519
520
521 func CalcStructSize(s *Type) {
522 s.Width = calcStructOffset(s, s, 0, 1)
523 }
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541 var deferredTypeStack []*Type
542
543 func CheckSize(t *Type) {
544 if t == nil {
545 return
546 }
547
548
549
550 if t.IsFuncArgStruct() {
551 base.Fatalf("CheckSize %v", t)
552 }
553
554 if defercalc == 0 {
555 CalcSize(t)
556 return
557 }
558
559
560 if !t.Deferwidth() {
561 t.SetDeferwidth(true)
562 deferredTypeStack = append(deferredTypeStack, t)
563 }
564 }
565
566 func DeferCheckSize() {
567 defercalc++
568 }
569
570 func ResumeCheckSize() {
571 if defercalc == 1 {
572 for len(deferredTypeStack) > 0 {
573 t := deferredTypeStack[len(deferredTypeStack)-1]
574 deferredTypeStack = deferredTypeStack[:len(deferredTypeStack)-1]
575 t.SetDeferwidth(false)
576 CalcSize(t)
577 }
578 }
579
580 defercalc--
581 }
582
583
584
585 func PtrDataSize(t *Type) int64 {
586 if !t.HasPointers() {
587 return 0
588 }
589
590 switch t.Kind() {
591 case TPTR,
592 TUNSAFEPTR,
593 TFUNC,
594 TCHAN,
595 TMAP:
596 return int64(PtrSize)
597
598 case TSTRING:
599
600 return int64(PtrSize)
601
602 case TINTER:
603
604
605
606 return 2 * int64(PtrSize)
607
608 case TSLICE:
609
610 return int64(PtrSize)
611
612 case TARRAY:
613
614 return (t.NumElem()-1)*t.Elem().Width + PtrDataSize(t.Elem())
615
616 case TSTRUCT:
617
618 var lastPtrField *Field
619 fs := t.Fields().Slice()
620 for i := len(fs) - 1; i >= 0; i-- {
621 if fs[i].Type.HasPointers() {
622 lastPtrField = fs[i]
623 break
624 }
625 }
626 return lastPtrField.Offset + PtrDataSize(lastPtrField.Type)
627
628 default:
629 base.Fatalf("PtrDataSize: unexpected type, %v", t)
630 return 0
631 }
632 }
633
View as plain text