Source file
src/runtime/gcinfo_test.go
1
2
3
4
5 package runtime_test
6
7 import (
8 "bytes"
9 "runtime"
10 "testing"
11 )
12
13 const (
14 typeScalar = 0
15 typePointer = 1
16 )
17
18
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)
28
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)
37
38 {
39 var x Ptr
40 verifyGCInfo(t, "stack Ptr", &x, infoPtr)
41 runtime.KeepAlive(x)
42 }
43 {
44 var x ScalarPtr
45 verifyGCInfo(t, "stack ScalarPtr", &x, infoScalarPtr)
46 runtime.KeepAlive(x)
47 }
48 {
49 var x PtrScalar
50 verifyGCInfo(t, "stack PtrScalar", &x, infoPtrScalar)
51 runtime.KeepAlive(x)
52 }
53 {
54 var x BigStruct
55 verifyGCInfo(t, "stack BigStruct", &x, infoBigStruct())
56 runtime.KeepAlive(x)
57 }
58 {
59 var x string
60 verifyGCInfo(t, "stack string", &x, infoString)
61 runtime.KeepAlive(x)
62 }
63 {
64 var x []string
65 verifyGCInfo(t, "stack slice", &x, infoSlice)
66 runtime.KeepAlive(x)
67 }
68 {
69 var x any
70 verifyGCInfo(t, "stack eface", &x, infoEface)
71 runtime.KeepAlive(x)
72 }
73 {
74 var x Iface
75 verifyGCInfo(t, "stack iface", &x, infoIface)
76 runtime.KeepAlive(x)
77 }
78
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))
89 }
90 }
91
92 func verifyGCInfo(t *testing.T, name string, p any, mask0 []byte) {
93 mask := runtime.GCMask(p)
94 if !bytes.Equal(mask, mask0) {
95 t.Errorf("bad GC program for %v:\nwant %+v\ngot %+v", name, mask0, mask)
96 return
97 }
98 }
99
100 func trimDead(mask []byte) []byte {
101 for len(mask) > 0 && mask[len(mask)-1] == typeScalar {
102 mask = mask[:len(mask)-1]
103 }
104 return mask
105 }
106
107 var infoPtr = []byte{typePointer}
108
109 type Ptr struct {
110 *byte
111 }
112
113 var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer}
114
115 type ScalarPtr struct {
116 q int
117 w *int
118 e int
119 r *int
120 t int
121 y *int
122 }
123
124 var infoScalarPtr = []byte{typeScalar, typePointer, typeScalar, typePointer, typeScalar, typePointer}
125
126 var infoScalarPtr4 = append(append(append(append([]byte(nil), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...)
127
128 type PtrScalar struct {
129 q *int
130 w int
131 e *int
132 r int
133 t *int
134 y int
135 }
136
137 var infoPtrScalar = []byte{typePointer, typeScalar, typePointer, typeScalar, typePointer, typeScalar}
138
139 type BigStruct struct {
140 q *int
141 w byte
142 e [17]byte
143 r []byte
144 t int
145 y uint16
146 u uint64
147 i string
148 }
149
150 func infoBigStruct() []byte {
151 switch runtime.GOARCH {
152 case "386", "arm", "mips", "mipsle":
153 return []byte{
154 typePointer,
155 typeScalar, typeScalar, typeScalar, typeScalar, typeScalar,
156 typePointer, typeScalar, typeScalar,
157 typeScalar, typeScalar, typeScalar, typeScalar,
158 typePointer, typeScalar,
159 }
160 case "arm64", "amd64", "loong64", "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "wasm":
161 return []byte{
162 typePointer,
163 typeScalar, typeScalar, typeScalar,
164 typePointer, typeScalar, typeScalar,
165 typeScalar, typeScalar, typeScalar,
166 typePointer, typeScalar,
167 }
168 default:
169 panic("unknown arch")
170 }
171 }
172
173 type Iface interface {
174 f()
175 }
176
177 type IfaceImpl int
178
179 func (IfaceImpl) f() {
180 }
181
182 var (
183
184 bssPtr Ptr
185 bssScalarPtr ScalarPtr
186 bssPtrScalar PtrScalar
187 bssBigStruct BigStruct
188 bssString string
189 bssSlice []string
190 bssEface any
191 bssIface Iface
192
193
194 dataPtr = Ptr{new(byte)}
195 dataScalarPtr = ScalarPtr{q: 1}
196 dataPtrScalar = PtrScalar{w: 1}
197 dataBigStruct = BigStruct{w: 1}
198 dataString = "foo"
199 dataSlice = []string{"foo"}
200 dataEface any = 42
201 dataIface Iface = IfaceImpl(42)
202
203 infoString = []byte{typePointer, typeScalar}
204 infoSlice = []byte{typePointer, typeScalar, typeScalar}
205 infoEface = []byte{typeScalar, typePointer}
206 infoIface = []byte{typeScalar, typePointer}
207 )
208
View as plain text