Match: Add pattern for `(a ? b : 0) | (a ? 0 : c)` into `a ? b : c` [PR103660]
[official-gcc.git] / libgo / go / runtime / mfinal_test.go
blob2eb60b9ee26002881973e58b5e15b260ad87dbef
1 // Copyright 2011 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.
5 package runtime_test
7 import (
8 "runtime"
9 "testing"
10 "time"
11 "unsafe"
14 type Tintptr *int // assignable to *int
15 type Tint int // *Tint implements Tinter, interface{}
17 func (t *Tint) m() {}
19 type Tinter interface {
20 m()
23 func TestFinalizerType(t *testing.T) {
24 if runtime.GOARCH != "amd64" {
25 t.Skipf("Skipping on non-amd64 machine")
27 if runtime.Compiler == "gccgo" {
28 t.Skip("skipping for gccgo")
31 ch := make(chan bool, 10)
32 finalize := func(x *int) {
33 if *x != 97531 {
34 t.Errorf("finalizer %d, want %d", *x, 97531)
36 ch <- true
39 var finalizerTests = []struct {
40 convert func(*int) any
41 finalizer any
43 {func(x *int) any { return x }, func(v *int) { finalize(v) }},
44 {func(x *int) any { return Tintptr(x) }, func(v Tintptr) { finalize(v) }},
45 {func(x *int) any { return Tintptr(x) }, func(v *int) { finalize(v) }},
46 {func(x *int) any { return (*Tint)(x) }, func(v *Tint) { finalize((*int)(v)) }},
47 {func(x *int) any { return (*Tint)(x) }, func(v Tinter) { finalize((*int)(v.(*Tint))) }},
48 // Test case for argument spill slot.
49 // If the spill slot was not counted for the frame size, it will (incorrectly) choose
50 // call32 as the result has (exactly) 32 bytes. When the argument actually spills,
51 // it clobbers the caller's frame (likely the return PC).
52 {func(x *int) any { return x }, func(v any) [4]int64 {
53 print() // force spill
54 finalize(v.(*int))
55 return [4]int64{}
56 }},
59 for i, tt := range finalizerTests {
60 done := make(chan bool, 1)
61 go func() {
62 // allocate struct with pointer to avoid hitting tinyalloc.
63 // Otherwise we can't be sure when the allocation will
64 // be freed.
65 type T struct {
66 v int
67 p unsafe.Pointer
69 v := &new(T).v
70 *v = 97531
71 runtime.SetFinalizer(tt.convert(v), tt.finalizer)
72 v = nil
73 done <- true
74 }()
75 <-done
76 runtime.GC()
77 select {
78 case <-ch:
79 case <-time.After(time.Second * 4):
80 t.Errorf("#%d: finalizer for type %T didn't run", i, tt.finalizer)
85 type bigValue struct {
86 fill uint64
87 it bool
88 up string
91 func TestFinalizerInterfaceBig(t *testing.T) {
92 if runtime.GOARCH != "amd64" {
93 t.Skipf("Skipping on non-amd64 machine")
95 if runtime.Compiler == "gccgo" {
96 t.Skip("skipping for gccgo")
98 ch := make(chan bool)
99 done := make(chan bool, 1)
100 go func() {
101 v := &bigValue{0xDEADBEEFDEADBEEF, true, "It matters not how strait the gate"}
102 old := *v
103 runtime.SetFinalizer(v, func(v any) {
104 i, ok := v.(*bigValue)
105 if !ok {
106 t.Errorf("finalizer called with type %T, want *bigValue", v)
108 if *i != old {
109 t.Errorf("finalizer called with %+v, want %+v", *i, old)
111 close(ch)
113 v = nil
114 done <- true
116 <-done
117 runtime.GC()
118 select {
119 case <-ch:
120 case <-time.After(4 * time.Second):
121 t.Errorf("finalizer for type *bigValue didn't run")
125 func fin(v *int) {
128 // Verify we don't crash at least. golang.org/issue/6857
129 func TestFinalizerZeroSizedStruct(t *testing.T) {
130 type Z struct{}
131 z := new(Z)
132 runtime.SetFinalizer(z, func(*Z) {})
135 func BenchmarkFinalizer(b *testing.B) {
136 const Batch = 1000
137 b.RunParallel(func(pb *testing.PB) {
138 var data [Batch]*int
139 for i := 0; i < Batch; i++ {
140 data[i] = new(int)
142 for pb.Next() {
143 for i := 0; i < Batch; i++ {
144 runtime.SetFinalizer(data[i], fin)
146 for i := 0; i < Batch; i++ {
147 runtime.SetFinalizer(data[i], nil)
153 func BenchmarkFinalizerRun(b *testing.B) {
154 b.RunParallel(func(pb *testing.PB) {
155 for pb.Next() {
156 v := new(int)
157 runtime.SetFinalizer(v, fin)
162 // One chunk must be exactly one sizeclass in size.
163 // It should be a sizeclass not used much by others, so we
164 // have a greater chance of finding adjacent ones.
165 // size class 19: 320 byte objects, 25 per page, 1 page alloc at a time
166 const objsize = 320
168 type objtype [objsize]byte
170 func adjChunks() (*objtype, *objtype) {
171 var s []*objtype
173 for {
174 c := new(objtype)
175 for _, d := range s {
176 if uintptr(unsafe.Pointer(c))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(d)) {
177 return c, d
179 if uintptr(unsafe.Pointer(d))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(c)) {
180 return d, c
183 s = append(s, c)
187 // Make sure an empty slice on the stack doesn't pin the next object in memory.
188 func TestEmptySlice(t *testing.T) {
189 if runtime.Compiler == "gccgo" {
190 t.Skip("skipping for gccgo")
192 x, y := adjChunks()
194 // the pointer inside xs points to y.
195 xs := x[objsize:] // change objsize to objsize-1 and the test passes
197 fin := make(chan bool, 1)
198 runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
199 runtime.GC()
200 select {
201 case <-fin:
202 case <-time.After(4 * time.Second):
203 t.Errorf("finalizer of next object in memory didn't run")
205 xsglobal = xs // keep empty slice alive until here
208 var xsglobal []byte
210 func adjStringChunk() (string, *objtype) {
211 b := make([]byte, objsize)
212 for {
213 s := string(b)
214 t := new(objtype)
215 p := *(*uintptr)(unsafe.Pointer(&s))
216 q := uintptr(unsafe.Pointer(t))
217 if p+objsize == q {
218 return s, t
223 // Make sure an empty string on the stack doesn't pin the next object in memory.
224 func TestEmptyString(t *testing.T) {
225 if runtime.Compiler == "gccgo" {
226 t.Skip("skipping for gccgo")
229 x, y := adjStringChunk()
231 ss := x[objsize:] // change objsize to objsize-1 and the test passes
232 fin := make(chan bool, 1)
233 // set finalizer on string contents of y
234 runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
235 runtime.GC()
236 select {
237 case <-fin:
238 case <-time.After(4 * time.Second):
239 t.Errorf("finalizer of next string in memory didn't run")
241 ssglobal = ss // keep 0-length string live until here
244 var ssglobal string
246 // Test for issue 7656.
247 func TestFinalizerOnGlobal(t *testing.T) {
248 runtime.SetFinalizer(Foo1, func(p *Object1) {})
249 runtime.SetFinalizer(Foo2, func(p *Object2) {})
250 runtime.SetFinalizer(Foo1, nil)
251 runtime.SetFinalizer(Foo2, nil)
254 type Object1 struct {
255 Something []byte
258 type Object2 struct {
259 Something byte
262 var (
263 Foo2 = &Object2{}
264 Foo1 = &Object1{}
267 func TestDeferKeepAlive(t *testing.T) {
268 if *flagQuick {
269 t.Skip("-quick")
272 // See issue 21402.
273 t.Parallel()
274 type T *int // needs to be a pointer base type to avoid tinyalloc and its never-finalized behavior.
275 x := new(T)
276 finRun := false
277 runtime.SetFinalizer(x, func(x *T) {
278 finRun = true
280 defer runtime.KeepAlive(x)
281 runtime.GC()
282 time.Sleep(time.Second)
283 if finRun {
284 t.Errorf("finalizer ran prematurely")