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.HasPrefix(mask, mask0) {
95
96
97
98
99
100
101
102 return
103 }
104 t.Errorf("bad GC program for %v:\nwant %+v\ngot %+v", name, mask0, mask)
105 }
106
107 func trimDead(mask []byte) []byte {
108 for len(mask) > 0 && mask[len(mask)-1] == typeScalar {
109 mask = mask[:len(mask)-1]
110 }
111 return mask
112 }
113
114 var infoPtr = []byte{typePointer}
115
116 type Ptr struct {
117 *byte
118 }
119
120 var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer}
121
122 type ScalarPtr struct {
123 q int
124 w *int
125 e int
126 r *int
127 t int
128 y *int
129 }
130
131 var infoScalarPtr = []byte{typeScalar, typePointer, typeScalar, typePointer, typeScalar, typePointer}
132
133 var infoScalarPtr4 = append(append(append(append([]byte(nil), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...)
134
135 type PtrScalar struct {
136 q *int
137 w int
138 e *int
139 r int
140 t *int
141 y int
142 }
143
144 var infoPtrScalar = []byte{typePointer, typeScalar, typePointer, typeScalar, typePointer, typeScalar}
145
146 type BigStruct struct {
147 q *int
148 w byte
149 e [17]byte
150 r []byte
151 t int
152 y uint16
153 u uint64
154 i string
155 }
156
157 func infoBigStruct() []byte {
158 switch runtime.GOARCH {
159 case "386", "arm", "mips", "mipsle":
160 return []byte{
161 typePointer,
162 typeScalar, typeScalar, typeScalar, typeScalar, typeScalar,
163 typePointer, typeScalar, typeScalar,
164 typeScalar, typeScalar, typeScalar, typeScalar,
165 typePointer, typeScalar,
166 }
167 case "arm64", "amd64", "loong64", "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "wasm":
168 return []byte{
169 typePointer,
170 typeScalar, typeScalar, typeScalar,
171 typePointer, typeScalar, typeScalar,
172 typeScalar, typeScalar, typeScalar,
173 typePointer, typeScalar,
174 }
175 default:
176 panic("unknown arch")
177 }
178 }
179
180 type Iface interface {
181 f()
182 }
183
184 type IfaceImpl int
185
186 func (IfaceImpl) f() {
187 }
188
189 var (
190
191 bssPtr Ptr
192 bssScalarPtr ScalarPtr
193 bssPtrScalar PtrScalar
194 bssBigStruct BigStruct
195 bssString string
196 bssSlice []string
197 bssEface any
198 bssIface Iface
199
200
201 dataPtr = Ptr{new(byte)}
202 dataScalarPtr = ScalarPtr{q: 1}
203 dataPtrScalar = PtrScalar{w: 1}
204 dataBigStruct = BigStruct{w: 1}
205 dataString = "foo"
206 dataSlice = []string{"foo"}
207 dataEface any = 42
208 dataIface Iface = IfaceImpl(42)
209
210 infoString = []byte{typePointer, typeScalar}
211 infoSlice = []byte{typePointer, typeScalar, typeScalar}
212 infoEface = []byte{typeScalar, typePointer}
213 infoIface = []byte{typeScalar, typePointer}
214 )
215
View as plain text