1 // Copyright 2014 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.
18 // TestGCInfo tests that various objects in heap, data and bss receive correct GC pointer type info.
19 func TestGCInfo(t *testing.T) {
20 verifyGCInfo(t, "bss Ptr", &bssPtr, infoPtr)
21 verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, infoScalarPtr)
22 verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, infoPtrScalar)
23 verifyGCInfo(t, "bss BigStruct", &bssBigStruct, infoBigStruct())
24 verifyGCInfo(t, "bss string", &bssString, infoString)
25 verifyGCInfo(t, "bss slice", &bssSlice, infoSlice)
26 verifyGCInfo(t, "bss eface", &bssEface, infoEface)
27 verifyGCInfo(t, "bss iface", &bssIface, infoIface)
29 verifyGCInfo(t, "data Ptr", &dataPtr, infoPtr)
30 verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, infoScalarPtr)
31 verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, infoPtrScalar)
32 verifyGCInfo(t, "data BigStruct", &dataBigStruct, infoBigStruct())
33 verifyGCInfo(t, "data string", &dataString, infoString)
34 verifyGCInfo(t, "data slice", &dataSlice, infoSlice)
35 verifyGCInfo(t, "data eface", &dataEface, infoEface)
36 verifyGCInfo(t, "data iface", &dataIface, infoIface)
40 verifyGCInfo(t, "stack Ptr", &x, infoPtr)
45 verifyGCInfo(t, "stack ScalarPtr", &x, infoScalarPtr)
50 verifyGCInfo(t, "stack PtrScalar", &x, infoPtrScalar)
55 verifyGCInfo(t, "stack BigStruct", &x, infoBigStruct())
60 verifyGCInfo(t, "stack string", &x, infoString)
65 verifyGCInfo(t, "stack slice", &x, infoSlice)
70 verifyGCInfo(t, "stack eface", &x, infoEface)
75 verifyGCInfo(t, "stack iface", &x, infoIface)
79 for i := 0; i < 10; i++ {
80 verifyGCInfo(t, "heap Ptr", runtime.Escape(new(Ptr)), trimDead(infoPtr))
81 verifyGCInfo(t, "heap PtrSlice", runtime.Escape(&make([]*byte, 10)[0]), trimDead(infoPtr10))
82 verifyGCInfo(t, "heap ScalarPtr", runtime.Escape(new(ScalarPtr)), trimDead(infoScalarPtr))
83 verifyGCInfo(t, "heap ScalarPtrSlice", runtime.Escape(&make([]ScalarPtr, 4)[0]), trimDead(infoScalarPtr4))
84 verifyGCInfo(t, "heap PtrScalar", runtime.Escape(new(PtrScalar)), trimDead(infoPtrScalar))
85 verifyGCInfo(t, "heap BigStruct", runtime.Escape(new(BigStruct)), trimDead(infoBigStruct()))
86 verifyGCInfo(t, "heap string", runtime.Escape(new(string)), trimDead(infoString))
87 verifyGCInfo(t, "heap eface", runtime.Escape(new(any)), trimDead(infoEface))
88 verifyGCInfo(t, "heap iface", runtime.Escape(new(Iface)), trimDead(infoIface))
92 func verifyGCInfo(t *testing.T, name string, p any, mask0 []byte) {
93 mask := runtime.GCMask(p)
94 if bytes.HasPrefix(mask, mask0) {
95 // Just the prefix matching is OK.
97 // The Go runtime's pointer/scalar iterator generates pointers beyond
98 // the size of the type, up to the size of the size class. This space
99 // is safe for the GC to scan since it's zero, and GCBits checks to
100 // make sure that's true. But we need to handle the fact that the bitmap
101 // may be larger than we expect.
104 t.Errorf("bad GC program for %v:\nwant %+v\ngot %+v", name, mask0, mask)
107 func trimDead(mask []byte) []byte {
108 for len(mask) > 0 && mask[len(mask)-1] == typeScalar {
109 mask = mask[:len(mask)-1]
114 var infoPtr = []byte{typePointer}
120 var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer}
122 type ScalarPtr struct {
131 var infoScalarPtr = []byte{typeScalar, typePointer, typeScalar, typePointer, typeScalar, typePointer}
133 var infoScalarPtr4 = append(append(append(append([]byte(nil), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...)
135 type PtrScalar struct {
144 var infoPtrScalar = []byte{typePointer, typeScalar, typePointer, typeScalar, typePointer, typeScalar}
146 type BigStruct struct {
157 func infoBigStruct() []byte {
158 switch runtime.GOARCH {
159 case "386", "arm", "mips", "mipsle":
161 typePointer, // q *int
162 typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
163 typePointer, typeScalar, typeScalar, // r []byte
164 typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
165 typePointer, typeScalar, // i string
167 case "arm64", "amd64", "loong64", "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "wasm":
169 typePointer, // q *int
170 typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
171 typePointer, typeScalar, typeScalar, // r []byte
172 typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
173 typePointer, typeScalar, // i string
176 panic("unknown arch")
180 type Iface interface {
186 func (IfaceImpl) f() {
192 bssScalarPtr ScalarPtr
193 bssPtrScalar PtrScalar
194 bssBigStruct BigStruct
201 dataPtr = Ptr{new(byte)}
202 dataScalarPtr = ScalarPtr{q: 1}
203 dataPtrScalar = PtrScalar{w: 1}
204 dataBigStruct = BigStruct{w: 1}
206 dataSlice = []string{"foo"}
208 dataIface Iface = IfaceImpl(42)
210 infoString = []byte{typePointer, typeScalar}
211 infoSlice = []byte{typePointer, typeScalar, typeScalar}
212 infoEface = []byte{typeScalar, typePointer}
213 infoIface = []byte{typeScalar, typePointer}