1// Copyright 2013 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 typebits
6
7import (
8	"cmd/compile/internal/base"
9	"cmd/compile/internal/bitvec"
10	"cmd/compile/internal/types"
11)
12
13// NOTE: The bitmap for a specific type t could be cached in t after
14// the first run and then simply copied into bv at the correct offset
15// on future calls with the same type t.
16func Set(t *types.Type, off int64, bv bitvec.BitVec) {
17	set(t, off, bv, false)
18}
19
20// SetNoCheck is like Set, but do not check for alignment.
21func SetNoCheck(t *types.Type, off int64, bv bitvec.BitVec) {
22	set(t, off, bv, true)
23}
24
25func set(t *types.Type, off int64, bv bitvec.BitVec, skip bool) {
26	if !skip && uint8(t.Alignment()) > 0 && off&int64(uint8(t.Alignment())-1) != 0 {
27		base.Fatalf("typebits.Set: invalid initial alignment: type %v has alignment %d, but offset is %v", t, uint8(t.Alignment()), off)
28	}
29	if !t.HasPointers() {
30		// Note: this case ensures that pointers to not-in-heap types
31		// are not considered pointers by garbage collection and stack copying.
32		return
33	}
34
35	switch t.Kind() {
36	case types.TPTR, types.TUNSAFEPTR, types.TFUNC, types.TCHAN, types.TMAP:
37		if off&int64(types.PtrSize-1) != 0 {
38			base.Fatalf("typebits.Set: invalid alignment, %v", t)
39		}
40		bv.Set(int32(off / int64(types.PtrSize))) // pointer
41
42	case types.TSTRING:
43		// struct { byte *str; intgo len; }
44		if off&int64(types.PtrSize-1) != 0 {
45			base.Fatalf("typebits.Set: invalid alignment, %v", t)
46		}
47		bv.Set(int32(off / int64(types.PtrSize))) //pointer in first slot
48
49	case types.TINTER:
50		// struct { Itab *tab;	void *data; }
51		// or, when isnilinter(t)==true:
52		// struct { Type *type; void *data; }
53		if off&int64(types.PtrSize-1) != 0 {
54			base.Fatalf("typebits.Set: invalid alignment, %v", t)
55		}
56		// The first word of an interface is a pointer, but we don't
57		// treat it as such.
58		// 1. If it is a non-empty interface, the pointer points to an itab
59		//    which is always in persistentalloc space.
60		// 2. If it is an empty interface, the pointer points to a _type.
61		//   a. If it is a compile-time-allocated type, it points into
62		//      the read-only data section.
63		//   b. If it is a reflect-allocated type, it points into the Go heap.
64		//      Reflect is responsible for keeping a reference to
65		//      the underlying type so it won't be GCd.
66		// If we ever have a moving GC, we need to change this for 2b (as
67		// well as scan itabs to update their itab._type fields).
68		bv.Set(int32(off/int64(types.PtrSize) + 1)) // pointer in second slot
69
70	case types.TSLICE:
71		// struct { byte *array; uintgo len; uintgo cap; }
72		if off&int64(types.PtrSize-1) != 0 {
73			base.Fatalf("typebits.Set: invalid TARRAY alignment, %v", t)
74		}
75		bv.Set(int32(off / int64(types.PtrSize))) // pointer in first slot (BitsPointer)
76
77	case types.TARRAY:
78		elt := t.Elem()
79		if elt.Size() == 0 {
80			// Short-circuit for #20739.
81			break
82		}
83		for i := int64(0); i < t.NumElem(); i++ {
84			set(elt, off, bv, skip)
85			off += elt.Size()
86		}
87
88	case types.TSTRUCT:
89		for _, f := range t.Fields() {
90			set(f.Type, off+f.Offset, bv, skip)
91		}
92
93	default:
94		base.Fatalf("typebits.Set: unexpected type, %v", t)
95	}
96}
97