2018-23-01 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / libgo / go / runtime / mfinal_test.go
blob2086e42ba3365d0f0898bb91991ac732ff8c330d
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) interface{}
41 finalizer interface{}
43 {func(x *int) interface{} { return x }, func(v *int) { finalize(v) }},
44 {func(x *int) interface{} { return Tintptr(x) }, func(v Tintptr) { finalize(v) }},
45 {func(x *int) interface{} { return Tintptr(x) }, func(v *int) { finalize(v) }},
46 {func(x *int) interface{} { return (*Tint)(x) }, func(v *Tint) { finalize((*int)(v)) }},
47 {func(x *int) interface{} { return (*Tint)(x) }, func(v Tinter) { finalize((*int)(v.(*Tint))) }},
50 for i, tt := range finalizerTests {
51 done := make(chan bool, 1)
52 go func() {
53 // allocate struct with pointer to avoid hitting tinyalloc.
54 // Otherwise we can't be sure when the allocation will
55 // be freed.
56 type T struct {
57 v int
58 p unsafe.Pointer
60 v := &new(T).v
61 *v = 97531
62 runtime.SetFinalizer(tt.convert(v), tt.finalizer)
63 v = nil
64 done <- true
65 }()
66 <-done
67 runtime.GC()
68 select {
69 case <-ch:
70 case <-time.After(time.Second * 4):
71 t.Errorf("#%d: finalizer for type %T didn't run", i, tt.finalizer)
76 type bigValue struct {
77 fill uint64
78 it bool
79 up string
82 func TestFinalizerInterfaceBig(t *testing.T) {
83 if runtime.GOARCH != "amd64" {
84 t.Skipf("Skipping on non-amd64 machine")
86 if runtime.Compiler == "gccgo" {
87 t.Skip("skipping for gccgo")
89 ch := make(chan bool)
90 done := make(chan bool, 1)
91 go func() {
92 v := &bigValue{0xDEADBEEFDEADBEEF, true, "It matters not how strait the gate"}
93 old := *v
94 runtime.SetFinalizer(v, func(v interface{}) {
95 i, ok := v.(*bigValue)
96 if !ok {
97 t.Errorf("finalizer called with type %T, want *bigValue", v)
99 if *i != old {
100 t.Errorf("finalizer called with %+v, want %+v", *i, old)
102 close(ch)
104 v = nil
105 done <- true
107 <-done
108 runtime.GC()
109 select {
110 case <-ch:
111 case <-time.After(4 * time.Second):
112 t.Errorf("finalizer for type *bigValue didn't run")
116 func fin(v *int) {
119 // Verify we don't crash at least. golang.org/issue/6857
120 func TestFinalizerZeroSizedStruct(t *testing.T) {
121 type Z struct{}
122 z := new(Z)
123 runtime.SetFinalizer(z, func(*Z) {})
126 func BenchmarkFinalizer(b *testing.B) {
127 const Batch = 1000
128 b.RunParallel(func(pb *testing.PB) {
129 var data [Batch]*int
130 for i := 0; i < Batch; i++ {
131 data[i] = new(int)
133 for pb.Next() {
134 for i := 0; i < Batch; i++ {
135 runtime.SetFinalizer(data[i], fin)
137 for i := 0; i < Batch; i++ {
138 runtime.SetFinalizer(data[i], nil)
144 func BenchmarkFinalizerRun(b *testing.B) {
145 b.RunParallel(func(pb *testing.PB) {
146 for pb.Next() {
147 v := new(int)
148 runtime.SetFinalizer(v, fin)
153 // One chunk must be exactly one sizeclass in size.
154 // It should be a sizeclass not used much by others, so we
155 // have a greater chance of finding adjacent ones.
156 // size class 19: 320 byte objects, 25 per page, 1 page alloc at a time
157 const objsize = 320
159 type objtype [objsize]byte
161 func adjChunks() (*objtype, *objtype) {
162 var s []*objtype
164 for {
165 c := new(objtype)
166 for _, d := range s {
167 if uintptr(unsafe.Pointer(c))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(d)) {
168 return c, d
170 if uintptr(unsafe.Pointer(d))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(c)) {
171 return d, c
174 s = append(s, c)
178 // Make sure an empty slice on the stack doesn't pin the next object in memory.
179 func TestEmptySlice(t *testing.T) {
180 if runtime.Compiler == "gccgo" {
181 t.Skip("skipping for gccgo")
183 x, y := adjChunks()
185 // the pointer inside xs points to y.
186 xs := x[objsize:] // change objsize to objsize-1 and the test passes
188 fin := make(chan bool, 1)
189 runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
190 runtime.GC()
191 select {
192 case <-fin:
193 case <-time.After(4 * time.Second):
194 t.Errorf("finalizer of next object in memory didn't run")
196 xsglobal = xs // keep empty slice alive until here
199 var xsglobal []byte
201 func adjStringChunk() (string, *objtype) {
202 b := make([]byte, objsize)
203 for {
204 s := string(b)
205 t := new(objtype)
206 p := *(*uintptr)(unsafe.Pointer(&s))
207 q := uintptr(unsafe.Pointer(t))
208 if p+objsize == q {
209 return s, t
214 // Make sure an empty string on the stack doesn't pin the next object in memory.
215 func TestEmptyString(t *testing.T) {
216 if runtime.Compiler == "gccgo" {
217 t.Skip("skipping for gccgo")
220 x, y := adjStringChunk()
222 ss := x[objsize:] // change objsize to objsize-1 and the test passes
223 fin := make(chan bool, 1)
224 // set finalizer on string contents of y
225 runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
226 runtime.GC()
227 select {
228 case <-fin:
229 case <-time.After(4 * time.Second):
230 t.Errorf("finalizer of next string in memory didn't run")
232 ssglobal = ss // keep 0-length string live until here
235 var ssglobal string
237 // Test for issue 7656.
238 func TestFinalizerOnGlobal(t *testing.T) {
239 runtime.SetFinalizer(Foo1, func(p *Object1) {})
240 runtime.SetFinalizer(Foo2, func(p *Object2) {})
241 runtime.SetFinalizer(Foo1, nil)
242 runtime.SetFinalizer(Foo2, nil)
245 type Object1 struct {
246 Something []byte
249 type Object2 struct {
250 Something byte
253 var (
254 Foo2 = &Object2{}
255 Foo1 = &Object1{}
258 func TestDeferKeepAlive(t *testing.T) {
259 if *flagQuick {
260 t.Skip("-quick")
263 // See issue 21402.
264 t.Parallel()
265 type T *int // needs to be a pointer base type to avoid tinyalloc and its never-finalized behavior.
266 x := new(T)
267 finRun := false
268 runtime.SetFinalizer(x, func(x *T) {
269 finRun = true
271 defer runtime.KeepAlive(x)
272 runtime.GC()
273 time.Sleep(time.Second)
274 if finRun {
275 t.Errorf("finalizer ran prematurely")