]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/gcinfo_test.go
runtime: implement experiment to replace heap bitmap with alloc headers
[gostls13.git] / src / runtime / gcinfo_test.go
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.
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 // 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)
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                 // Just the prefix matching is OK.
96                 //
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.
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,                                                // 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
166                 }
167         case "arm64", "amd64", "loong64", "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "wasm":
168                 return []byte{
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
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         // BSS
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         // DATA
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 )