1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package types
6
7import (
8	"bytes"
9	"fmt"
10	"sort"
11
12	"cmd/compile/internal/base"
13	"cmd/internal/src"
14)
15
16var PtrSize int
17
18var RegSize int
19
20// Slices in the runtime are represented by three components:
21//
22// type slice struct {
23// 	ptr unsafe.Pointer
24// 	len int
25// 	cap int
26// }
27//
28// Strings in the runtime are represented by two components:
29//
30// type string struct {
31// 	ptr unsafe.Pointer
32// 	len int
33// }
34//
35// These variables are the offsets of fields and sizes of these structs.
36var (
37	SlicePtrOffset int64
38	SliceLenOffset int64
39	SliceCapOffset int64
40
41	SliceSize  int64
42	StringSize int64
43)
44
45var SkipSizeForTracing bool
46
47// typePos returns the position associated with t.
48// This is where t was declared or where it appeared as a type expression.
49func 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// MaxWidth is the maximum size of a value on the target architecture.
58var MaxWidth int64
59
60// CalcSizeDisabled indicates whether it is safe
61// to calculate Types' widths and alignments. See CalcSize.
62var CalcSizeDisabled bool
63
64// machine size and rounding alignment is dictated around
65// the size of a pointer, set in betypeinit (see ../amd64/galign.go).
66var defercalc int
67
68func 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// expandiface computes the method set for interface type t by
76// expanding embedded interfaces.
77func 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	{
94		methods := t.Methods().Slice()
95		sort.SliceStable(methods, func(i, j int) bool {
96			mi, mj := methods[i], methods[j]
97
98			// Sort embedded types by type name (if any).
99			if mi.Sym == nil && mj.Sym == nil {
100				return mi.Type.Sym().Less(mj.Type.Sym())
101			}
102
103			// Sort methods before embedded types.
104			if mi.Sym == nil || mj.Sym == nil {
105				return mi.Sym != nil
106			}
107
108			// Sort methods by symbol name.
109			return mi.Sym.Less(mj.Sym)
110		})
111	}
112
113	for _, m := range t.Methods().Slice() {
114		if m.Sym == nil {
115			continue
116		}
117
118		CheckSize(m.Type)
119		addMethod(m, true)
120	}
121
122	for _, m := range t.Methods().Slice() {
123		if m.Sym != nil || m.Type == nil {
124			continue
125		}
126
127		if m.Type.IsUnion() {
128			continue
129		}
130
131		// In 1.18, embedded types can be anything. In Go 1.17, we disallow
132		// embedding anything other than interfaces.
133		if !m.Type.IsInterface() {
134			if AllowsGoVersion(t.Pkg(), 1, 18) {
135				continue
136			}
137			base.ErrorfAt(m.Pos, "interface contains embedded non-interface, non-union %v", m.Type)
138			m.SetBroke(true)
139			t.SetBroke(true)
140			// Add to fields so that error messages
141			// include the broken embedded type when
142			// printing t.
143			// TODO(mdempsky): Revisit this.
144			methods = append(methods, m)
145			continue
146		}
147
148		// Embedded interface: duplicate all methods
149		// (including broken ones, if any) and add to t's
150		// method set.
151		for _, t1 := range m.Type.AllMethods().Slice() {
152			f := NewField(m.Pos, t1.Sym, t1.Type)
153			addMethod(f, false)
154
155			// Clear position after typechecking, for consistency with types2.
156			f.Pos = src.NoXPos
157		}
158
159		// Clear position after typechecking, for consistency with types2.
160		m.Pos = src.NoXPos
161	}
162
163	sort.Sort(MethodsByName(methods))
164
165	if int64(len(methods)) >= MaxWidth/int64(PtrSize) {
166		base.ErrorfAt(typePos(t), "interface too large")
167	}
168	for i, m := range methods {
169		m.Offset = int64(i) * int64(PtrSize)
170	}
171
172	t.SetAllMethods(methods)
173}
174
175func calcStructOffset(errtype *Type, t *Type, o int64, flag int) int64 {
176	// flag is 0 (receiver), 1 (actual struct), or RegSize (in/out parameters)
177	isStruct := flag == 1
178	starto := o
179	maxalign := int32(flag)
180	if maxalign < 1 {
181		maxalign = 1
182	}
183	lastzero := int64(0)
184	for _, f := range t.Fields().Slice() {
185		if f.Type == nil {
186			// broken field, just skip it so that other valid fields
187			// get a width.
188			continue
189		}
190
191		CalcSize(f.Type)
192		if int32(f.Type.align) > maxalign {
193			maxalign = int32(f.Type.align)
194		}
195		if f.Type.align > 0 {
196			o = Rnd(o, int64(f.Type.align))
197		}
198		if isStruct { // For receiver/args/results, do not set, it depends on ABI
199			f.Offset = o
200		}
201
202		w := f.Type.width
203		if w < 0 {
204			base.Fatalf("invalid width %d", f.Type.width)
205		}
206		if w == 0 {
207			lastzero = o
208		}
209		o += w
210		maxwidth := MaxWidth
211		// On 32-bit systems, reflect tables impose an additional constraint
212		// that each field start offset must fit in 31 bits.
213		if maxwidth < 1<<32 {
214			maxwidth = 1<<31 - 1
215		}
216		if o >= maxwidth {
217			base.ErrorfAt(typePos(errtype), "type %L too large", errtype)
218			o = 8 // small but nonzero
219		}
220	}
221
222	// For nonzero-sized structs which end in a zero-sized thing, we add
223	// an extra byte of padding to the type. This padding ensures that
224	// taking the address of the zero-sized thing can't manufacture a
225	// pointer to the next object in the heap. See issue 9401.
226	if flag == 1 && o > starto && o == lastzero {
227		o++
228	}
229
230	// final width is rounded
231	if flag != 0 {
232		o = Rnd(o, int64(maxalign))
233	}
234	t.align = uint8(maxalign)
235
236	// type width only includes back to first field's offset
237	t.width = o - starto
238
239	return o
240}
241
242// findTypeLoop searches for an invalid type declaration loop involving
243// type t and reports whether one is found. If so, path contains the
244// loop.
245//
246// path points to a slice used for tracking the sequence of types
247// visited. Using a pointer to a slice allows the slice capacity to
248// grow and limit reallocations.
249func findTypeLoop(t *Type, path *[]*Type) bool {
250	// We implement a simple DFS loop-finding algorithm. This
251	// could be faster, but type cycles are rare.
252
253	if t.Sym() != nil {
254		// Declared type. Check for loops and otherwise
255		// recurse on the type expression used in the type
256		// declaration.
257
258		// Type imported from package, so it can't be part of
259		// a type loop (otherwise that package should have
260		// failed to compile).
261		if t.Sym().Pkg != LocalPkg {
262			return false
263		}
264
265		for i, x := range *path {
266			if x == t {
267				*path = (*path)[i:]
268				return true
269			}
270		}
271
272		*path = append(*path, t)
273		if findTypeLoop(t.Obj().(TypeObject).TypeDefn(), path) {
274			return true
275		}
276		*path = (*path)[:len(*path)-1]
277	} else {
278		// Anonymous type. Recurse on contained types.
279
280		switch t.Kind() {
281		case TARRAY:
282			if findTypeLoop(t.Elem(), path) {
283				return true
284			}
285		case TSTRUCT:
286			for _, f := range t.Fields().Slice() {
287				if findTypeLoop(f.Type, path) {
288					return true
289				}
290			}
291		case TINTER:
292			for _, m := range t.Methods().Slice() {
293				if m.Type.IsInterface() { // embedded interface
294					if findTypeLoop(m.Type, path) {
295						return true
296					}
297				}
298			}
299		}
300	}
301
302	return false
303}
304
305func reportTypeLoop(t *Type) {
306	if t.Broke() {
307		return
308	}
309
310	var l []*Type
311	if !findTypeLoop(t, &l) {
312		base.Fatalf("failed to find type loop for: %v", t)
313	}
314
315	// Rotate loop so that the earliest type declaration is first.
316	i := 0
317	for j, t := range l[1:] {
318		if typePos(t).Before(typePos(l[i])) {
319			i = j + 1
320		}
321	}
322	l = append(l[i:], l[:i]...)
323
324	var msg bytes.Buffer
325	fmt.Fprintf(&msg, "invalid recursive type %v\n", l[0])
326	for _, t := range l {
327		fmt.Fprintf(&msg, "\t%v: %v refers to\n", base.FmtPos(typePos(t)), t)
328		t.SetBroke(true)
329	}
330	fmt.Fprintf(&msg, "\t%v: %v", base.FmtPos(typePos(l[0])), l[0])
331	base.ErrorfAt(typePos(l[0]), msg.String())
332}
333
334// CalcSize calculates and stores the size and alignment for t.
335// If CalcSizeDisabled is set, and the size/alignment
336// have not already been calculated, it calls Fatal.
337// This is used to prevent data races in the back end.
338func CalcSize(t *Type) {
339	// Calling CalcSize when typecheck tracing enabled is not safe.
340	// See issue #33658.
341	if base.EnableTrace && SkipSizeForTracing {
342		return
343	}
344	if PtrSize == 0 {
345		// Assume this is a test.
346		return
347	}
348
349	if t == nil {
350		return
351	}
352
353	if t.width == -2 {
354		reportTypeLoop(t)
355		t.width = 0
356		t.align = 1
357		return
358	}
359
360	if t.widthCalculated() {
361		return
362	}
363
364	if CalcSizeDisabled {
365		if t.Broke() {
366			// break infinite recursion from Fatal call below
367			return
368		}
369		t.SetBroke(true)
370		base.Fatalf("width not calculated: %v", t)
371	}
372
373	// break infinite recursion if the broken recursive type
374	// is referenced again
375	if t.Broke() && t.width == 0 {
376		return
377	}
378
379	// defer CheckSize calls until after we're done
380	DeferCheckSize()
381
382	lno := base.Pos
383	if pos := t.Pos(); pos.IsKnown() {
384		base.Pos = pos
385	}
386
387	t.width = -2
388	t.align = 0 // 0 means use t.Width, below
389
390	et := t.Kind()
391	switch et {
392	case TFUNC, TCHAN, TMAP, TSTRING:
393		break
394
395	// SimType == 0 during bootstrap
396	default:
397		if SimType[t.Kind()] != 0 {
398			et = SimType[t.Kind()]
399		}
400	}
401
402	var w int64
403	switch et {
404	default:
405		base.Fatalf("CalcSize: unknown type: %v", t)
406
407	// compiler-specific stuff
408	case TINT8, TUINT8, TBOOL:
409		// bool is int8
410		w = 1
411
412	case TINT16, TUINT16:
413		w = 2
414
415	case TINT32, TUINT32, TFLOAT32:
416		w = 4
417
418	case TINT64, TUINT64, TFLOAT64:
419		w = 8
420		t.align = uint8(RegSize)
421
422	case TCOMPLEX64:
423		w = 8
424		t.align = 4
425
426	case TCOMPLEX128:
427		w = 16
428		t.align = uint8(RegSize)
429
430	case TPTR:
431		w = int64(PtrSize)
432		CheckSize(t.Elem())
433
434	case TUNSAFEPTR:
435		w = int64(PtrSize)
436
437	case TINTER: // implemented as 2 pointers
438		w = 2 * int64(PtrSize)
439		t.align = uint8(PtrSize)
440		expandiface(t)
441
442	case TUNION:
443		// Always part of an interface for now, so size/align don't matter.
444		// Pretend a union is represented like an interface.
445		w = 2 * int64(PtrSize)
446		t.align = uint8(PtrSize)
447
448	case TCHAN: // implemented as pointer
449		w = int64(PtrSize)
450
451		CheckSize(t.Elem())
452
453		// Make fake type to trigger channel element size check after
454		// any top-level recursive type has been completed.
455		t1 := NewChanArgs(t)
456		CheckSize(t1)
457
458	case TCHANARGS:
459		t1 := t.ChanArgs()
460		CalcSize(t1) // just in case
461		// Make sure size of t1.Elem() is calculated at this point. We can
462		// use CalcSize() here rather than CheckSize(), because the top-level
463		// (possibly recursive) type will have been calculated before the fake
464		// chanargs is handled.
465		CalcSize(t1.Elem())
466		if t1.Elem().width >= 1<<16 {
467			base.Errorf("channel element type too large (>64kB)")
468		}
469		w = 1 // anything will do
470
471	case TMAP: // implemented as pointer
472		w = int64(PtrSize)
473		CheckSize(t.Elem())
474		CheckSize(t.Key())
475
476	case TFORW: // should have been filled in
477		reportTypeLoop(t)
478		w = 1 // anything will do
479
480	case TANY:
481		// not a real type; should be replaced before use.
482		base.Fatalf("CalcSize any")
483
484	case TSTRING:
485		if StringSize == 0 {
486			base.Fatalf("early CalcSize string")
487		}
488		w = StringSize
489		t.align = uint8(PtrSize)
490
491	case TARRAY:
492		if t.Elem() == nil {
493			break
494		}
495
496		CalcSize(t.Elem())
497		if t.Elem().width != 0 {
498			cap := (uint64(MaxWidth) - 1) / uint64(t.Elem().width)
499			if uint64(t.NumElem()) > cap {
500				base.Errorf("type %L larger than address space", t)
501			}
502		}
503		w = t.NumElem() * t.Elem().width
504		t.align = t.Elem().align
505
506	case TSLICE:
507		if t.Elem() == nil {
508			break
509		}
510		w = SliceSize
511		CheckSize(t.Elem())
512		t.align = uint8(PtrSize)
513
514	case TSTRUCT:
515		if t.IsFuncArgStruct() {
516			base.Fatalf("CalcSize fn struct %v", t)
517		}
518		w = calcStructOffset(t, t, 0, 1)
519
520	// make fake type to check later to
521	// trigger function argument computation.
522	case TFUNC:
523		t1 := NewFuncArgs(t)
524		CheckSize(t1)
525		w = int64(PtrSize) // width of func type is pointer
526
527	// function is 3 cated structures;
528	// compute their widths as side-effect.
529	case TFUNCARGS:
530		t1 := t.FuncArgs()
531		w = calcStructOffset(t1, t1.Recvs(), 0, 0)
532		w = calcStructOffset(t1, t1.Params(), w, RegSize)
533		w = calcStructOffset(t1, t1.Results(), w, RegSize)
534		t1.extra.(*Func).Argwid = w
535		if w%int64(RegSize) != 0 {
536			base.Warn("bad type %v %d\n", t1, w)
537		}
538		t.align = 1
539
540	case TTYPEPARAM:
541		// TODO(danscales) - remove when we eliminate the need
542		// to do CalcSize in noder2 (which shouldn't be needed in the noder)
543		w = int64(PtrSize)
544	}
545
546	if PtrSize == 4 && w != int64(int32(w)) {
547		base.Errorf("type %v too large", t)
548	}
549
550	t.width = w
551	if t.align == 0 {
552		if w == 0 || w > 8 || w&(w-1) != 0 {
553			base.Fatalf("invalid alignment for %v", t)
554		}
555		t.align = uint8(w)
556	}
557
558	base.Pos = lno
559
560	ResumeCheckSize()
561}
562
563// CalcStructSize calculates the size of s,
564// filling in s.Width and s.Align,
565// even if size calculation is otherwise disabled.
566func CalcStructSize(s *Type) {
567	s.width = calcStructOffset(s, s, 0, 1) // sets align
568}
569
570// RecalcSize is like CalcSize, but recalculates t's size even if it
571// has already been calculated before. It does not recalculate other
572// types.
573func RecalcSize(t *Type) {
574	t.align = 0
575	CalcSize(t)
576}
577
578func (t *Type) widthCalculated() bool {
579	return t.align > 0
580}
581
582// when a type's width should be known, we call CheckSize
583// to compute it.  during a declaration like
584//
585//	type T *struct { next T }
586//
587// it is necessary to defer the calculation of the struct width
588// until after T has been initialized to be a pointer to that struct.
589// similarly, during import processing structs may be used
590// before their definition.  in those situations, calling
591// DeferCheckSize() stops width calculations until
592// ResumeCheckSize() is called, at which point all the
593// CalcSizes that were deferred are executed.
594// CalcSize should only be called when the type's size
595// is needed immediately.  CheckSize makes sure the
596// size is evaluated eventually.
597
598var deferredTypeStack []*Type
599
600func CheckSize(t *Type) {
601	if t == nil {
602		return
603	}
604
605	// function arg structs should not be checked
606	// outside of the enclosing function.
607	if t.IsFuncArgStruct() {
608		base.Fatalf("CheckSize %v", t)
609	}
610
611	if defercalc == 0 {
612		CalcSize(t)
613		return
614	}
615
616	// if type has not yet been pushed on deferredTypeStack yet, do it now
617	if !t.Deferwidth() {
618		t.SetDeferwidth(true)
619		deferredTypeStack = append(deferredTypeStack, t)
620	}
621}
622
623func DeferCheckSize() {
624	defercalc++
625}
626
627func ResumeCheckSize() {
628	if defercalc == 1 {
629		for len(deferredTypeStack) > 0 {
630			t := deferredTypeStack[len(deferredTypeStack)-1]
631			deferredTypeStack = deferredTypeStack[:len(deferredTypeStack)-1]
632			t.SetDeferwidth(false)
633			CalcSize(t)
634		}
635	}
636
637	defercalc--
638}
639
640// PtrDataSize returns the length in bytes of the prefix of t
641// containing pointer data. Anything after this offset is scalar data.
642//
643// PtrDataSize is only defined for actual Go types. It's an error to
644// use it on compiler-internal types (e.g., TSSA, TRESULTS).
645func PtrDataSize(t *Type) int64 {
646	switch t.Kind() {
647	case TBOOL, TINT8, TUINT8, TINT16, TUINT16, TINT32,
648		TUINT32, TINT64, TUINT64, TINT, TUINT,
649		TUINTPTR, TCOMPLEX64, TCOMPLEX128, TFLOAT32, TFLOAT64:
650		return 0
651
652	case TPTR:
653		if t.Elem().NotInHeap() {
654			return 0
655		}
656		return int64(PtrSize)
657
658	case TUNSAFEPTR, TFUNC, TCHAN, TMAP:
659		return int64(PtrSize)
660
661	case TSTRING:
662		// struct { byte *str; intgo len; }
663		return int64(PtrSize)
664
665	case TINTER:
666		// struct { Itab *tab;	void *data; } or
667		// struct { Type *type; void *data; }
668		// Note: see comment in typebits.Set
669		return 2 * int64(PtrSize)
670
671	case TSLICE:
672		if t.Elem().NotInHeap() {
673			return 0
674		}
675		// struct { byte *array; uintgo len; uintgo cap; }
676		return int64(PtrSize)
677
678	case TARRAY:
679		if t.NumElem() == 0 {
680			return 0
681		}
682		// t.NumElem() > 0
683		size := PtrDataSize(t.Elem())
684		if size == 0 {
685			return 0
686		}
687		return (t.NumElem()-1)*t.Elem().Size() + size
688
689	case TSTRUCT:
690		// Find the last field that has pointers, if any.
691		fs := t.Fields().Slice()
692		for i := len(fs) - 1; i >= 0; i-- {
693			if size := PtrDataSize(fs[i].Type); size > 0 {
694				return fs[i].Offset + size
695			}
696		}
697		return 0
698
699	default:
700		base.Fatalf("PtrDataSize: unexpected type, %v", t)
701		return 0
702	}
703}
704